Merge "drm/msm: fix Y420CMDB EDID block parsing"
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
index 8a3e704..c3c8212 100644
--- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
@@ -9,7 +9,7 @@
- compatible
Usage: required
Value type: <string>
- Definition: must be "qcom,clk-cpu-osm".
+ Definition: must be "qcom,clk-cpu-osm" or "qcom,clk-cpu-osm-v2".
- reg
Usage: required
@@ -85,24 +85,6 @@
by the OSM hardware for each supported DCVS setpoint
of the Performance cluster.
-- qcom,l3-min-cpr-vc-binX
- Usage: required
- Value type: <u32>
- Definition: First virtual corner which does not use PLL post-divider
- for the L3 clock domain.
-
-- qcom,pwrcl-min-cpr-vc-binX
- Usage: required
- Value type: <u32>
- Definition: First virtual corner which does not use PLL post-divider
- for the power cluster.
-
-- qcom,perfcl-min-cpr-vc-binX
- Usage: required
- Value type: <u32>
- Definition: First virtual corner which does not use PLL post-divider
- for the performance cluster.
-
- qcom,osm-no-tz
Usage: optional
Value type: <empty>
@@ -501,10 +483,6 @@
< 1881600000 0x404c1462 0x00004e4e 0x2 21 >,
< 1958400000 0x404c1566 0x00005252 0x3 22 >;
- qcom,l3-min-cpr-vc-bin0 = <7>;
- qcom,pwrcl-min-cpr-vc-bin0 = <6>;
- qcom,perfcl-min-cpr-vc-bin0 = <7>;
-
qcom,up-timer =
<1000 1000 1000>;
qcom,down-timer =
diff --git a/Documentation/devicetree/bindings/arm/msm/qmp-debugfs-client.txt b/Documentation/devicetree/bindings/arm/msm/qmp-debugfs-client.txt
new file mode 100644
index 0000000..655bf89
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/qmp-debugfs-client.txt
@@ -0,0 +1,17 @@
+QMP debugfs client:
+-----------------
+
+QTI Messaging Protocol(QMP) debugfs client is an interface for clients to
+send data to the Always on processor using QMP.
+
+Required properties :
+- compatible : must be "qcom,debugfs-qmp-client"
+- mboxes : list of QMP mailbox phandle and channel identifier tuples.
+- mbox-names : names of the listed mboxes
+
+Example :
+ qcom,qmp-client {
+ compatible = "qcom,debugfs-qmp-client";
+ mboxes = <&qmp_aop 0>;
+ mbox-names = "aop";
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt b/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt
index ce2d8bd..1114308 100644
--- a/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt
+++ b/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt
@@ -2,12 +2,15 @@
Required properties:
-compatible : Should be one of
- To communicate with modem
+ To communicate with adsp
qcom,smp2pgpio_client_rdbg_2_in (inbound)
qcom,smp2pgpio_client_rdbg_2_out (outbound)
To communicate with modem
qcom,smp2pgpio_client_rdbg_1_in (inbound)
qcom,smp2pgpio_client_rdbg_1_out (outbound)
+ To communicate with cdsp
+ qcom,smp2pgpio_client_rdbg_5_in (inbound)
+ qcom,smp2pgpio_client_rdbg_5_out (outbound)
-gpios : the relevant gpio pins of the entry.
Example:
diff --git a/Documentation/devicetree/bindings/display/msm/sde.txt b/Documentation/devicetree/bindings/display/msm/sde.txt
index d3222fb..dd668cb 100644
--- a/Documentation/devicetree/bindings/display/msm/sde.txt
+++ b/Documentation/devicetree/bindings/display/msm/sde.txt
@@ -52,6 +52,9 @@
The number of offsets defined should reflect the
amount of mixers that can drive data to a panel
interface.
+- qcom,sde-dspp-top-off: Offset address for the dspp top block.
+ The offset is calculated from register "mdp_phys"
+ defined in reg property.
- qcom,sde-dspp-off: Array of offset addresses for the available dspp
blocks. These offsets are calculated from
register "mdp_phys" defined in reg property.
@@ -207,6 +210,7 @@
e.g. qcom,sde-dspp-blocks
-- qcom,sde-dspp-pcc: offset and version of PCC hardware
-- qcom,sde-dspp-gc: offset and version of GC hardware
+ -- qcom,sde-dspp-igc: offset and version of IGC hardware
-- qcom,sde-dspp-hsic: offset and version of global PA adjustment
-- qcom,sde-dspp-memcolor: offset and version of PA memcolor hardware
-- qcom,sde-dspp-sixzone: offset and version of PA sixzone hardware
@@ -424,6 +428,7 @@
0x00002600 0x00002800>;
qcom,sde-mixer-off = <0x00045000 0x00046000
0x00047000 0x0004a000>;
+ qcom,sde-dspp-top-off = <0x1300>;
qcom,sde-dspp-off = <0x00055000 0x00057000>;
qcom,sde-dspp-ad-off = <0x24000 0x22800>;
qcom,sde-dspp-ad-version = <0x00030000>;
@@ -481,6 +486,7 @@
qcom,sde-sspp-src-size = <0x100>;
qcom,sde-mixer-size = <0x100>;
qcom,sde-ctl-size = <0x100>;
+ qcom,sde-dspp-top-size = <0xc>;
qcom,sde-dspp-size = <0x100>;
qcom,sde-intf-size = <0x100>;
qcom,sde-dsc-size = <0x100>;
@@ -599,6 +605,7 @@
};
qcom,sde-dspp-blocks {
+ qcom,sde-dspp-igc = <0x0 0x00010000>;
qcom,sde-dspp-pcc = <0x1700 0x00010000>;
qcom,sde-dspp-gc = <0x17c0 0x00010000>;
qcom,sde-dspp-hsic = <0x0 0x00010000>;
diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
index 669997c..cbe8378 100644
--- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
@@ -144,10 +144,11 @@
0xff = default value.
- qcom,mdss-dsi-border-color: Defines the border color value if border is present.
0 = default value.
-- qcom,mdss-dsi-panel-jitter: An integer value defines the panel jitter timing for rsc
- backoff time. The jitter configurition causes the early
- wakeup if panel needs to adjust before vsync.
- Default jitter value is 5%. Max allowed value is 25%.
+- qcom,mdss-dsi-panel-jitter: Panel jitter value is expressed in terms of numerator
+ and denominator. It contains two u32 values - numerator
+ followed by denominator. The jitter configurition causes
+ the early wakeup if panel needs to adjust before vsync.
+ Default jitter value is 2.0%. Max allowed value is 10%.
- qcom,mdss-dsi-panel-prefill-lines: An integer value defines the panel prefill lines required to
calculate the backoff time of rsc.
Default value is 16 lines. Max allowed value is vtotal.
@@ -664,7 +665,7 @@
<40 120 128>,
<128 240 64>;
qcom,mdss-dsi-panel-orientation = "180"
- qcom,mdss-dsi-panel-jitter = <0x8>;
+ qcom,mdss-dsi-panel-jitter = <0x8 0x10>;
qcom,mdss-dsi-panel-prefill-lines = <0x10>;
qcom,mdss-dsi-force-clock-lane-hs;
qcom,compression-mode = "dsc";
diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-qcom-geni.txt b/Documentation/devicetree/bindings/i2c/qcom,i2c-qcom-geni.txt
index 51abe56..21edaa0 100644
--- a/Documentation/devicetree/bindings/i2c/qcom,i2c-qcom-geni.txt
+++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-qcom-geni.txt
@@ -14,6 +14,10 @@
- #size-cells: Should be <0> as i2c addresses have no size component
- qcom,wrapper-core: Wrapper QUPv3 core containing this I2C controller.
+Optional property:
+ - qcom,clk-freq-out : Desired I2C bus clock frequency in Hz.
+ When missing default to 400000Hz.
+
Child nodes should conform to i2c bus binding.
Example:
@@ -32,4 +36,5 @@
#address-cells = <1>;
#size-cells = <0>;
qcom,wrapper-core = <&qupv3_0>;
+ qcom,clk-freq-out = <400000>;
};
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 375eaf2..196f6f7 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -91,6 +91,11 @@
a four level page table configuration. Set to use a three
level page table instead.
+- qcom,no-asid-retention:
+ Some hardware may lose internal state for asid after
+ retention. No cache invalidation operations involving asid
+ may be used.
+
- clocks : List of clocks to be used during SMMU register access. See
Documentation/devicetree/bindings/clock/clock-bindings.txt
for information about the format. For each clock specified
diff --git a/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt b/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
index 58bac0b..46649af 100644
--- a/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
@@ -81,6 +81,7 @@
limits.
- qcom,mdss-rot-vbif-qos-setting: This array is used to program vbif qos remapper register
priority for rotator clients.
+- qcom,mdss-rot-vbif-memtype: Array of u32 vbif memory type settings for each xin port.
- qcom,mdss-rot-cdp-setting: Integer array of size two, to indicate client driven
prefetch is available or not. Index 0 represents
if CDP is enabled for read and index 1, if CDP
@@ -173,6 +174,7 @@
/* VBIF QoS remapper settings*/
qcom,mdss-rot-vbif-qos-setting = <1 1 1 1>;
+ qcom,mdss-rot-vbif-memtype = <3 3>;
com,mdss-rot-cdp-setting = <1 1>;
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index da9a632..24c75e2 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -16,6 +16,9 @@
Required "interrupt-names" are "hc_irq" and "pwr_irq".
- <supply-name>-supply: phandle to the regulator device tree node
Required "supply-name" are "vdd" and "vdd-io".
+ - qcom,ice-clk-rates: this is an array that specifies supported Inline
+ Crypto Engine (ICE) clock frequencies, Units - Hz.
+ - sdhc-msm-crypto: phandle to SDHC ICE node
Required alias:
- The slot number is specified via an alias with the following format
@@ -77,6 +80,11 @@
register dumps on CRC errors and also downgrade bus speed mode to
SDR50/DDR50 in case of continuous CRC errors. Set this flag to enable
this workaround.
+ - qcom,restore-after-cx-collapse - specifies whether the SDCC registers contents need
+ to be saved and restored by software when the CX Power Collapse feature is enabled.
+ 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.
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.
@@ -116,6 +124,7 @@
reg-names = "hc_mem", "core_mem";
interrupts = <0 123 0>, <0 138 0>;
interrupt-names = "hc_irq", "pwr_irq";
+ sdhc-msm-crypto = <&sdcc1_ice>;
vdd-supply = <&pm8941_l21>;
vdd-io-supply = <&pm8941_l13>;
@@ -138,6 +147,7 @@
qcom,nonremovable;
qcom,large-address-bus;
qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,ice-clk-rates = <300000000 150000000>;
qcom,scaling-lower-bus-speed-mode = "DDR52";
diff --git a/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt b/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt
index 1398309..072f920 100644
--- a/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt
+++ b/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt
@@ -24,10 +24,6 @@
- qcom, msm_bus,vectors: Vectors for bus topology.
- pinctrl-names: Names for the TSIF mode configuration to specify which TSIF interface is active.
-Optional properties:
- - qcom,lpass-timer-tts : Indicates to add time stamps to TS packets from LPASS timer.
- bydefault time stamps will be added from TFIS internal counter.
-
Example:
tspp: msm_tspp@0x8880000 {
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
index 3e59c43..67ffaed 100644
--- a/Documentation/devicetree/bindings/thermal/tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -18,6 +18,7 @@
should be "qcom,sdm660-tsens" for 660 TSENS driver.
should be "qcom,sdm630-tsens" for 630 TSENS driver.
should be "qcom,sdm845-tsens" for SDM845 TSENS driver.
+ should be "qcom,tsens24xx" for 2.4 TSENS controller.
The compatible property is used to identify the respective controller to use
for the corresponding SoC.
- reg : offset and length of the TSENS registers with associated property in reg-names
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 6e027ae..ea40927 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -138,6 +138,7 @@
maps Memory maps to executables and library files (2.4)
mem Memory held by this process
root Link to the root directory of this process
+ reclaim Reclaim pages in this process
stat Process status
statm Process memory status information
status Process status in human readable form
@@ -528,6 +529,25 @@
Any other value written to /proc/PID/clear_refs will have no effect.
+The file /proc/PID/reclaim is used to reclaim pages in this process.
+To reclaim file-backed pages,
+ > echo file > /proc/PID/reclaim
+
+To reclaim anonymous pages,
+ > echo anon > /proc/PID/reclaim
+
+To reclaim all pages,
+ > echo all > /proc/PID/reclaim
+
+Also, you can specify address range of process so part of address space
+will be reclaimed. The format is following as
+ > echo addr size-byte > /proc/PID/reclaim
+
+NOTE: addr should be page-aligned.
+
+Below is example which try to reclaim 2M from 0x100000.
+ > echo 0x100000 2M > /proc/PID/reclaim
+
The /proc/pid/pagemap gives the PFN, which can be used to find the pageflags
using /proc/kpageflags and number of times a page is mapped using
/proc/kpagecount. For detailed explanation, see Documentation/vm/pagemap.txt.
diff --git a/Documentation/misc-devices/qcom_invoke_driver.txt b/Documentation/misc-devices/qcom_invoke_driver.txt
new file mode 100644
index 0000000..38c976a
--- /dev/null
+++ b/Documentation/misc-devices/qcom_invoke_driver.txt
@@ -0,0 +1,54 @@
+Introduction:
+=============
+Invoke driver is a misc driver which helps communication between non secure
+and secure world. Invoke driver communicates with secure side using SCM
+driver. To use invoke driver, open must be called on invoke device i.e.
+/dev/invoke. Invoke driver exposes only one IOCTL invoke which passes
+userspace request to TZ.
+
+SW Architecture
+===============
+Following is SW stack for Invoke driver.
+
++++++++++++++++++++++++++++++++++++++++++
++ Applications +
++++++++++++++++++++++++++++++++++++++++++
++ System Layer +
++++++++++++++++++++++++++++++++++++++++++
++ Kernel +
++ +++++++++++++++++++ +
++ + Invoke driver + +
++ +++++++++++++++++++ +
++ + SCM Driver + +
++++++++++++++++++++++++++++++++++++++++++
+ ||
+ ||
+ \/
++++++++++++++++++++++++++++++++++++++++++
++ Trust Zone +
++ +++++++++++ +++++++++++ +
++ + TZ App1 + + TZ App2 + +
++++++++++++++++++++++++++++++++++++++++++
+
+
+Interfaces
+==========
+Invoke driver exposes INVOKE_IOCTL_INVOKE_REQ IOCTL for userspace to
+communicate with driver. More details of IOCTL are avilable in
+corresponding header file.
+
+
+Driver Parameters
+=================
+This driver is built and statically linked into the kernel; therefore,
+there are no module parameters supported by this driver.
+
+There are no kernel command line parameters supported by this driver.
+
+Power Management
+================
+TBD
+
+Dependencies
+============
+Invoke driver depends on SCM driver to communicate with TZ.
diff --git a/Makefile b/Makefile
index 88cab97..04b3557 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 4
PATCHLEVEL = 9
-SUBLEVEL = 36
+SUBLEVEL = 38
EXTRAVERSION =
NAME = Roaring Lionus
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e06ecbb..21c66eb 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -117,7 +117,7 @@
config ARM_DMA_IOMMU_ALIGNMENT
int "Maximum PAGE_SIZE order of alignment for DMA IOMMU buffers"
range 4 9
- default 8
+ default 9
help
DMA mapping framework by default aligns all buffers to the smallest
PAGE_SIZE order which is greater than or equal to the requested buffer
@@ -1764,6 +1764,29 @@
source "mm/Kconfig"
+choice
+ prompt "Virtual Memory Reclaim"
+ default NO_VM_RECLAIM
+ help
+ Select the method of reclaiming virtual memory
+
+config ENABLE_VMALLOC_SAVING
+ bool "Reclaim memory for each subsystem"
+ help
+ Enable this config to reclaim the virtual space belonging
+ to any subsystem which is expected to have a lifetime of
+ the entire system. This feature allows lowmem to be non-
+ contiguous.
+
+config NO_VM_RECLAIM
+ bool "Do not reclaim memory"
+ help
+ Do not reclaim any memory. This might result in less lowmem
+ and wasting virtual memory space which could otherwise be
+ reclaimed by using any of the other two config options.
+
+endchoice
+
config FORCE_MAX_ZONEORDER
int "Maximum zone order"
default "12" if SOC_AM33XX
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index a2a3231..f2a4063 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -211,6 +211,89 @@
reg-names = "pshold-base", "tcsr-boot-misc-detect";
};
+ tsens0: tsens@c222000 {
+ compatible = "qcom,tsens24xx";
+ reg = <0xc222000 0x4>,
+ <0xc263000 0x1ff>;
+ reg-names = "tsens_srot_physical",
+ "tsens_tm_physical";
+ interrupts = <0 163 0>, <0 165 0>;
+ interrupt-names = "tsens-upper-lower", "tsens-critical";
+ #thermal-sensor-cells = <1>;
+ };
+
+ thermal_zones: thermal-zones {
+ mpm-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 0>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ q6-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 1>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ ctile-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 2>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 3>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ mdm-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 4>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+ };
+
};
#include "sdxpoorwills-regulator.dtsi"
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index c2252c0..b531fa5 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -210,6 +210,7 @@
CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_SUPPLY=y
CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_SOUND=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index e8fa052..88bd16c 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -203,6 +203,7 @@
CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_SUPPLY=y
CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS=y
CONFIG_MSM_CDC_PINCTRL=y
CONFIG_MSM_CDC_SUPPLY=y
CONFIG_REGULATOR=y
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 58c6398..ee4a723 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -182,6 +182,20 @@ extern void dmac_inv_range(const void *, const void *);
extern void dmac_clean_range(const void *, const void *);
extern void dmac_flush_range(const void *, const void *);
+static inline void __dma_inv_area(const void *start, size_t len)
+{
+ dmac_inv_range(start, start + len);
+}
+
+static inline void __dma_clean_area(const void *start, size_t len)
+{
+ dmac_clean_range(start, start + len);
+}
+
+static inline void __dma_flush_area(const void *start, size_t len)
+{
+ dmac_flush_range(start, start + len);
+}
#endif
/*
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 776757d..f23454d 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -148,6 +148,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
#define TIF_USING_IWMMXT 17
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 20
+#define TIF_MM_RELEASED 21 /* task MM has been released */
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 19f444e..441063f 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -2170,6 +2170,9 @@ arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size)
if (!bitmap_size)
return ERR_PTR(-EINVAL);
+ WARN(!IS_ALIGNED(size, SZ_128M),
+ "size is not aligned to 128M, alignment enforced");
+
if (bitmap_size > PAGE_SIZE) {
extensions = bitmap_size / PAGE_SIZE;
bitmap_size = PAGE_SIZE;
@@ -2192,7 +2195,7 @@ arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size)
mapping->nr_bitmaps = 1;
mapping->extensions = extensions;
mapping->base = base;
- mapping->bits = bits;
+ mapping->bits = BITS_PER_BYTE * bitmap_size;
spin_lock_init(&mapping->lock);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 370581a..51496dd 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -469,6 +469,54 @@ static void __init free_highpages(void)
#endif
}
+#define MLK(b, t) (b), (t), (((t) - (b)) >> 10)
+#define MLM(b, t) (b), (t), (((t) - (b)) >> 20)
+#define MLK_ROUNDUP(b, t) (b), (t), (DIV_ROUND_UP(((t) - (b)), SZ_1K))
+
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+static void print_vmalloc_lowmem_info(void)
+{
+ struct memblock_region *reg, *prev_reg = NULL;
+
+ pr_notice(
+ " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n",
+ MLM((unsigned long)high_memory, VMALLOC_END));
+
+ for_each_memblock_rev(memory, reg) {
+ phys_addr_t start_phys = reg->base;
+ phys_addr_t end_phys = reg->base + reg->size;
+
+ if (start_phys > arm_lowmem_limit)
+ continue;
+
+ if (end_phys > arm_lowmem_limit)
+ end_phys = arm_lowmem_limit;
+
+ if (prev_reg == NULL) {
+ prev_reg = reg;
+
+ pr_notice(
+ " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n",
+ MLM((unsigned long)__va(start_phys),
+ (unsigned long)__va(end_phys)));
+
+ continue;
+ }
+
+ pr_notice(
+ " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n",
+ MLM((unsigned long)__va(end_phys),
+ (unsigned long)__va(prev_reg->base)));
+
+
+ pr_notice(
+ " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n",
+ MLM((unsigned long)__va(start_phys),
+ (unsigned long)__va(end_phys)));
+ }
+}
+#endif
+
/*
* mem_init() marks the free areas in the mem_map and tells us how much
* memory is free. This is done after various parts of the system have
@@ -497,9 +545,6 @@ void __init mem_init(void)
mem_init_print_info(NULL);
-#define MLK(b, t) b, t, ((t) - (b)) >> 10
-#define MLM(b, t) b, t, ((t) - (b)) >> 20
-#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
pr_notice("Virtual kernel memory layout:\n"
" vector : 0x%08lx - 0x%08lx (%4ld kB)\n"
@@ -507,29 +552,34 @@ void __init mem_init(void)
" DTCM : 0x%08lx - 0x%08lx (%4ld kB)\n"
" ITCM : 0x%08lx - 0x%08lx (%4ld kB)\n"
#endif
- " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
- " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n"
- " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n"
-#ifdef CONFIG_HIGHMEM
- " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n"
-#endif
-#ifdef CONFIG_MODULES
- " modules : 0x%08lx - 0x%08lx (%4ld MB)\n"
-#endif
- " .text : 0x%p" " - 0x%p" " (%4td kB)\n"
- " .init : 0x%p" " - 0x%p" " (%4td kB)\n"
- " .data : 0x%p" " - 0x%p" " (%4td kB)\n"
- " .bss : 0x%p" " - 0x%p" " (%4td kB)\n",
-
+ " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n",
MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
(PAGE_SIZE)),
#ifdef CONFIG_HAVE_TCM
MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
MLK(ITCM_OFFSET, (unsigned long) itcm_end),
#endif
- MLK(FIXADDR_START, FIXADDR_END),
+ MLK(FIXADDR_START, FIXADDR_END));
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+ print_vmalloc_lowmem_info();
+#else
+ printk(KERN_NOTICE
+ " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n"
+ " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n",
MLM(VMALLOC_START, VMALLOC_END),
- MLM(PAGE_OFFSET, (unsigned long)high_memory),
+ MLM(PAGE_OFFSET, (unsigned long)high_memory));
+#endif
+ printk(KERN_NOTICE
+#ifdef CONFIG_HIGHMEM
+ " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n"
+#endif
+#ifdef CONFIG_MODULES
+ " modules : 0x%08lx - 0x%08lx (%4ld MB)\n"
+#endif
+ " .text : 0x%p" " - 0x%p" " (%4d kB)\n"
+ " .init : 0x%p" " - 0x%p" " (%4d kB)\n"
+ " .data : 0x%p" " - 0x%p" " (%4d kB)\n"
+ " .bss : 0x%p" " - 0x%p" " (%4d kB)\n",
#ifdef CONFIG_HIGHMEM
MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
(PAGE_SIZE)),
@@ -543,10 +593,6 @@ void __init mem_init(void)
MLK_ROUNDUP(_sdata, _edata),
MLK_ROUNDUP(__bss_start, __bss_stop));
-#undef MLK
-#undef MLM
-#undef MLK_ROUNDUP
-
/*
* Check boundaries twice: Some fundamental inconsistencies can
* be detected at build time already.
@@ -573,6 +619,10 @@ void __init mem_init(void)
}
#ifdef CONFIG_DEBUG_RODATA
+#undef MLK
+#undef MLM
+#undef MLK_ROUNDUP
+
struct section_perm {
const char *name;
unsigned long start;
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index ff0eed2..203728d 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -92,7 +92,8 @@ void __init add_static_vm_early(struct static_vm *svm)
void *vaddr;
vm = &svm->vm;
- vm_area_add_early(vm);
+ if (!vm_area_check_early(vm))
+ vm_area_add_early(vm);
vaddr = vm->addr;
list_for_each_entry(curr_svm, &static_vmlist, list) {
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index f7c7413..ddc72dc 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1168,6 +1168,19 @@ void __init adjust_lowmem_bounds(void)
*/
vmalloc_limit = (u64)(uintptr_t)vmalloc_min - PAGE_OFFSET + PHYS_OFFSET;
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+ struct memblock_region *prev_reg = NULL;
+
+ for_each_memblock(memory, reg) {
+ if (prev_reg == NULL) {
+ prev_reg = reg;
+ continue;
+ }
+ vmalloc_limit += reg->base - (prev_reg->base + prev_reg->size);
+ prev_reg = reg;
+ }
+#endif
+
for_each_memblock(memory, reg) {
phys_addr_t block_start = reg->base;
phys_addr_t block_end = reg->base + reg->size;
@@ -1428,12 +1441,21 @@ static void __init map_lowmem(void)
phys_addr_t kernel_x_start = round_down(__pa(_stext), SECTION_SIZE);
#endif
phys_addr_t kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE);
+ struct static_vm *svm;
+ phys_addr_t start;
+ phys_addr_t end;
+ unsigned long vaddr;
+ unsigned long pfn;
+ unsigned long length;
+ unsigned int type;
+ int nr = 0;
/* Map all the lowmem memory banks. */
for_each_memblock(memory, reg) {
- phys_addr_t start = reg->base;
- phys_addr_t end = start + reg->size;
struct map_desc map;
+ start = reg->base;
+ end = start + reg->size;
+ nr++;
if (memblock_is_nomap(reg))
continue;
@@ -1485,6 +1507,34 @@ static void __init map_lowmem(void)
}
}
}
+ svm = early_alloc_aligned(sizeof(*svm) * nr, __alignof__(*svm));
+
+ for_each_memblock(memory, reg) {
+ struct vm_struct *vm;
+
+ start = reg->base;
+ end = start + reg->size;
+
+ if (end > arm_lowmem_limit)
+ end = arm_lowmem_limit;
+ if (start >= end)
+ break;
+
+ vm = &svm->vm;
+ pfn = __phys_to_pfn(start);
+ vaddr = __phys_to_virt(start);
+ length = end - start;
+ type = MT_MEMORY_RW;
+
+ vm->addr = (void *)(vaddr & PAGE_MASK);
+ vm->size = PAGE_ALIGN(length + (vaddr & ~PAGE_MASK));
+ vm->phys_addr = __pfn_to_phys(pfn);
+ vm->flags = VM_LOWMEM;
+ vm->flags |= VM_ARM_MTYPE(type);
+ vm->caller = map_lowmem;
+ add_static_vm_early(svm++);
+ mark_vmalloc_reserved_area(vm->addr, vm->size);
+ }
}
#ifdef CONFIG_ARM_PV_FIXUP
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 9b20651..20288fe 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -2,16 +2,27 @@
dtb-$(CONFIG_ARCH_QCOM) += msm8996-mtp.dtb
dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb
-
ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
dtbo-$(CONFIG_ARCH_SDM845) += \
sdm845-cdp-overlay.dtbo \
sdm845-mtp-overlay.dtbo \
- sdm845-qrd-overlay.dtbo
+ sdm845-qrd-overlay.dtbo \
+ sdm845-v2-cdp-overlay.dtbo \
+ sdm845-v2-mtp-overlay.dtbo \
+ sdm845-v2-qrd-overlay.dtbo \
+ sdm845-4k-panel-mtp-overlay.dtbo \
+ sdm845-4k-panel-cdp-overlay.dtbo \
+ sdm845-4k-panel-qrd-overlay.dtbo
sdm845-cdp-overlay.dtbo-base := sdm845.dtb
sdm845-mtp-overlay.dtbo-base := sdm845.dtb
sdm845-qrd-overlay.dtbo-base := sdm845.dtb
+sdm845-v2-cdp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-mtp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-qrd-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-4k-panel-mtp-overlay.dtbo-base := sdm845.dtb
+sdm845-4k-panel-cdp-overlay.dtbo-base := sdm845.dtb
+sdm845-4k-panel-qrd-overlay.dtbo-base := sdm845.dtb
else
dtb-$(CONFIG_ARCH_SDM845) += sdm845-sim.dtb \
sdm845-rumi.dtb \
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi
index c52c18b..44b817e 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi
@@ -35,6 +35,11 @@
qcom,mdss-dsi-color-order = "rgb_swap_rgb";
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-panel-hdr-enabled;
+ qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000
+ 17000 15500 30000 8000 3000>;
+ qcom,mdss-dsi-panel-peak-brightness = <4200000>;
+ qcom,mdss-dsi-panel-blackness-level = <3230>;
qcom,mdss-dsi-on-command = [
/* CMD2_P0 */
15 01 00 00 00 00 02 ff 20
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi
index fe9129c..515949e 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi
@@ -30,6 +30,11 @@
qcom,mdss-dsi-bpp = <24>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-panel-hdr-enabled;
+ qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000
+ 17000 15500 30000 8000 3000>;
+ qcom,mdss-dsi-panel-peak-brightness = <4200000>;
+ qcom,mdss-dsi-panel-blackness-level = <3230>;
qcom,mdss-dsi-on-command = [
/* CMD2_P0 */
15 01 00 00 00 00 02 ff 20
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
index e4a0370..647ea4e 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
@@ -54,6 +54,11 @@
qcom,mdss-dsi-te-dcs-command = <1>;
qcom,mdss-dsi-te-check-enable;
qcom,mdss-dsi-te-using-te-pin;
+ qcom,mdss-dsi-panel-hdr-enabled;
+ qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000
+ 17000 15500 30000 8000 3000>;
+ qcom,mdss-dsi-panel-peak-brightness = <4200000>;
+ qcom,mdss-dsi-panel-blackness-level = <3230>;
qcom,mdss-dsi-on-command = [
/* CMD2_P0 */
15 01 00 00 00 00 02 FF 20
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 d6ef3d8..346a8b4 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
@@ -30,6 +30,11 @@
qcom,mdss-dsi-bpp = <24>;
qcom,mdss-dsi-underflow-color = <0x3ff>;
qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-panel-hdr-enabled;
+ qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000
+ 17000 15500 30000 8000 3000>;
+ qcom,mdss-dsi-panel-peak-brightness = <4200000>;
+ qcom,mdss-dsi-panel-blackness-level = <3230>;
qcom,mdss-dsi-on-command = [
/* CMD2_P0 */
15 01 00 00 00 00 02 FF 20
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 1a2ca5b..02fedbe 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -65,6 +65,7 @@
#iommu-cells = <2>;
qcom,skip-init;
qcom,use-3-lvl-tables;
+ qcom,no-asid-retention;
#global-interrupts = <1>;
#size-cells = <1>;
#address-cells = <1>;
@@ -339,10 +340,10 @@
apps_iommu_coherent_test_device {
compatible = "iommu-debug-test";
/*
- * This SID belongs to QUP1-DMA. We can't use a fake SID for
+ * This SID belongs to TSIF. We can't use a fake SID for
* the apps_smmu device.
*/
- iommus = <&apps_smmu 0x3 0>;
+ iommus = <&apps_smmu 0x20 0>;
dma-coherent;
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi
index 2194a42..dcc646c93b 100644
--- a/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi
@@ -196,28 +196,15 @@
hw-ctrl-addr = <&gpu_cx_hw_ctrl>;
qcom,no-status-check-on-disable;
qcom,gds-timeout = <500>;
+ qcom,clk-dis-wait-val = <8>;
status = "disabled";
};
- gpu_gx_domain_addr: syscon@0x5091508 {
- compatible = "syscon";
- reg = <0x5091508 0x4>;
- };
-
- gpu_gx_sw_reset: syscon@0x5091008 {
- compatible = "syscon";
- reg = <0x5091008 0x4>;
- };
-
gpu_gx_gdsc: qcom,gdsc@0x509100c {
compatible = "qcom,gdsc";
regulator-name = "gpu_gx_gdsc";
reg = <0x509100c 0x4>;
- domain-addr = <&gpu_gx_domain_addr>;
- sw-reset = <&gpu_gx_sw_reset>;
- qcom,reset-aon-logic;
qcom,poll-cfg-gdscr;
- qcom,toggle-sw-collapse-in-disable;
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi b/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi
index 2b8f22e..d9d1be4 100644
--- a/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi
@@ -72,4 +72,35 @@
compatible = "qcom,smp2pgpio_client_rdbg_1_out";
gpios = <&smp2pgpio_rdbg_1_out 0 0>;
};
+
+ smp2pgpio_rdbg_5_in: qcom,smp2pgpio-rdbg-5-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "rdbg";
+ qcom,remote-pid = <5>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_client_rdbg_5_in {
+ compatible = "qcom,smp2pgpio_client_rdbg_5_in";
+ gpios = <&smp2pgpio_rdbg_5_in 0 0>;
+ };
+
+ smp2pgpio_rdbg_5_out: qcom,smp2pgpio-rdbg-5-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "rdbg";
+ qcom,remote-pid = <5>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_client_rdbg_5_out {
+ compatible = "qcom,smp2pgpio_client_rdbg_5_out";
+ gpios = <&smp2pgpio_rdbg_5_out 0 0>;
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
index 4abf260..5d71f2d 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -488,6 +488,7 @@
qcom,adc_tm-vadc = <&pm660_vadc>;
qcom,decimation = <0>;
qcom,fast-avg-setup = <0>;
+ #thermal-sensor-cells = <1>;
chan@83 {
label = "vph_pwr";
@@ -531,6 +532,28 @@
qcom,btm-channel-number = <0x78>;
qcom,thermal-node;
};
+
+ chan@4e {
+ label = "emmc_therm";
+ reg = <0x4e>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x80>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4f {
+ label = "pa_therm0";
+ reg = <0x4f>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x88>;
+ qcom,vadc-thermal-node;
+ };
};
pm660_rradc: rradc@4500 {
@@ -631,3 +654,80 @@
#size-cells = <0>;
};
};
+
+&thermal_zones {
+ xo-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm660_adc_tm 0x4c>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ msm-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm660_adc_tm 0x4d>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ emmc-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm660_adc_tm 0x4e>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ pa-therm0-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm660_adc_tm 0x4f>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ quiet-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm660_adc_tm 0x51>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
index c8dc1f4..09405ee 100644
--- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
@@ -97,6 +97,7 @@
qcom,boost-threshold-ua = <100000>;
qcom,wipower-max-uw = <5000000>;
+ dpdm-supply = <&qusb_phy0>;
qcom,thermal-mitigation
= <3000000 1500000 1000000 500000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
index 6ea92ee..0cf48a3 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
@@ -9,3 +9,27 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+
+&qupv3_se9_2uart {
+ status = "disabled";
+};
+
+&qupv3_se12_2uart {
+ status = "ok";
+};
+
+&qupv3_se8_spi {
+ status = "disabled";
+};
+
+&qupv3_se3_i2c {
+ status = "disabled";
+};
+
+&qupv3_se10_i2c {
+ status = "disabled";
+};
+
+&qupv3_se6_4uart {
+ status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
index 6ea92ee..0cf48a3 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
@@ -9,3 +9,27 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+
+&qupv3_se9_2uart {
+ status = "disabled";
+};
+
+&qupv3_se12_2uart {
+ status = "ok";
+};
+
+&qupv3_se8_spi {
+ status = "disabled";
+};
+
+&qupv3_se3_i2c {
+ status = "disabled";
+};
+
+&qupv3_se10_i2c {
+ status = "disabled";
+};
+
+&qupv3_se6_4uart {
+ status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
index cce0860..dcc5d1b 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
@@ -904,6 +904,34 @@
};
};
+ qupv3_se12_2uart_pins: qupv3_se12_2uart_pins {
+ qupv3_se12_2uart_active: qupv3_se12_2uart_active {
+ mux {
+ pins = "gpio51", "gpio52";
+ function = "qup9";
+ };
+
+ config {
+ pins = "gpio51", "gpio52";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se12_2uart_sleep: qupv3_se12_2uart_sleep {
+ mux {
+ pins = "gpio51", "gpio52";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio51", "gpio52";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
qupv3_se12_spi_pins: qupv3_se12_spi_pins {
qupv3_se12_spi_active: qupv3_se12_spi_active {
mux {
diff --git a/arch/arm64/boot/dts/qcom/sdm670-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qupv3.dtsi
index 1fa6e26..657363f 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-qupv3.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-qupv3.dtsi
@@ -407,6 +407,23 @@
status = "disabled";
};
+ /* Debug UART Instance for CDP/MTP platform on SDM670 */
+ qupv3_se12_2uart: qcom,qup_uart@0xa90000 {
+ compatible = "qcom,msm-geni-console", "qcom,msm-geni-uart";
+ reg = <0xa90000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se12_2uart_active>;
+ pinctrl-1 = <&qupv3_se12_2uart_sleep>;
+ interrupts = <GIC_SPI 357 0>;
+ qcom,wrapper-core = <&qupv3_1>;
+ status = "disabled";
+ };
+
/* I2C */
qupv3_se8_i2c: i2c@a80000 {
compatible = "qcom,i2c-geni";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi b/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
index b790c04..6dd1b749 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
@@ -222,4 +222,27 @@
interrupt-controller;
#interrupt-cells = <2>;
};
+
+ /* 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/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 3eae5f3..21c40fc 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -32,6 +32,14 @@
ufshc1 = &ufshc_mem; /* Embedded UFS slot */
};
+ aliases {
+ serial0 = &qupv3_se12_2uart;
+ spi0 = &qupv3_se8_spi;
+ i2c0 = &qupv3_se10_i2c;
+ i2c1 = &qupv3_se3_i2c;
+ hsuart0 = &qupv3_se6_4uart;
+ };
+
cpus {
#address-cells = <2>;
#size-cells = <0>;
@@ -433,6 +441,324 @@
qcom,pipe-attr-ee;
};
+ thermal_zones: thermal-zones {
+ aoss0-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 0>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu0-silver-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 1>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu1-silver-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 2>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu2-silver-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 3>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu3-silver-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 4>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu4-silver-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 5>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu5-silver-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 6>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ kryo-l3-0-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 7>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ kryo-l3-1-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 8>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu0-gold-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 9>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu1-gold-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 10>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ gpu0-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 11>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ gpu1-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 12>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ aoss1-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 0>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ mdm-dsp-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 1>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ ddr-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 2>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ wlan-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 3>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ compute-hvx-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 4>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ camera-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 5>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ mmss-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 6>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ mdm-core-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 7>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+ };
+
+ tsens0: tsens@c222000 {
+ compatible = "qcom,tsens24xx";
+ reg = <0xc222000 0x4>,
+ <0xc263000 0x1ff>;
+ reg-names = "tsens_srot_physical",
+ "tsens_tm_physical";
+ interrupts = <0 506 0>, <0 508 0>;
+ interrupt-names = "tsens-upper-lower", "tsens-critical";
+ #thermal-sensor-cells = <1>;
+ };
+
+ tsens1: tsens@c223000 {
+ compatible = "qcom,tsens24xx";
+ reg = <0xc223000 0x4>,
+ <0xc265000 0x1ff>;
+ reg-names = "tsens_srot_physical",
+ "tsens_tm_physical";
+ interrupts = <0 507 0>, <0 509 0>;
+ interrupt-names = "tsens-upper-lower", "tsens-critical";
+ #thermal-sensor-cells = <1>;
+ };
+
timer@0x17c90000{
#address-cells = <1>;
#size-cells = <1>;
@@ -1329,6 +1655,66 @@
qcom,pas-id = <0xf>;
qcom,firmware-name = "ipa_fws";
};
+
+ pil_modem: qcom,mss@4080000 {
+ compatible = "qcom,pil-q6v55-mss";
+ reg = <0x4080000 0x100>,
+ <0x1f63000 0x008>,
+ <0x1f65000 0x008>,
+ <0x1f64000 0x008>,
+ <0x4180000 0x020>,
+ <0xc2b0000 0x004>,
+ <0xb2e0100 0x004>,
+ <0x4180044 0x004>;
+ reg-names = "qdsp6_base", "halt_q6", "halt_modem",
+ "halt_nc", "rmb_base", "restart_reg",
+ "pdc_sync", "alt_reset";
+
+ clocks = <&clock_rpmh RPMH_CXO_CLK>,
+ <&clock_gcc GCC_MSS_CFG_AHB_CLK>,
+ <&clock_gcc GCC_MSS_Q6_MEMNOC_AXI_CLK>,
+ <&clock_gcc GCC_BOOT_ROM_AHB_CLK>,
+ <&clock_gcc GCC_MSS_GPLL0_DIV_CLK_SRC>,
+ <&clock_gcc GCC_MSS_SNOC_AXI_CLK>,
+ <&clock_gcc GCC_MSS_MFAB_AXIS_CLK>,
+ <&clock_gcc GCC_PRNG_AHB_CLK>;
+ clock-names = "xo", "iface_clk", "bus_clk",
+ "mem_clk", "gpll0_mss_clk", "snoc_axi_clk",
+ "mnoc_axi_clk", "prng_clk";
+ qcom,proxy-clock-names = "xo", "prng_clk";
+ qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk",
+ "gpll0_mss_clk", "snoc_axi_clk",
+ "mnoc_axi_clk";
+
+ interrupts = <0 266 1>;
+ vdd_cx-supply = <&pm660l_s3_level>;
+ vdd_cx-voltage = <RPMH_REGULATOR_LEVEL_TURBO>;
+ vdd_mx-supply = <&pm660l_s1_level>;
+ vdd_mx-uV = <RPMH_REGULATOR_LEVEL_TURBO>;
+ qcom,firmware-name = "modem";
+ qcom,pil-self-auth;
+ qcom,sysmon-id = <0>;
+ qcom,ssctl-instance-id = <0x12>;
+ qcom,override-acc;
+ qcom,qdsp6v65-1-0;
+ status = "ok";
+ memory-region = <&pil_modem_mem>;
+ qcom,mem-protect-id = <0xF>;
+
+ /* 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>;
+ qcom,gpio-shutdown-ack = <&smp2pgpio_ssr_smp2p_1_in 7 0>;
+
+ /* GPIO output to mss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
+ qcom,mba-mem@0 {
+ compatible = "qcom,pil-mba-mem";
+ memory-region = <&pil_mba_mem>;
+ };
+ };
};
#include "sdm670-pinctrl.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts
new file mode 100644
index 0000000..0006937
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts
@@ -0,0 +1,66 @@
+/* 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 "sdm845-sde-display.dtsi"
+#include "sdm845-cdp.dtsi"
+#include "sdm845-cdp-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel CDP";
+ compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
+ qcom,msm-id = <321 0x0>;
+ qcom,board-id = <1 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+ connectors = <&sde_rscc &sde_wb>;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
index 94d74e2..faf09c4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-cdp.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts
new file mode 100644
index 0000000..2675b96
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts
@@ -0,0 +1,66 @@
+/* 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 "sdm845-sde-display.dtsi"
+#include "sdm845-mtp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel MTP";
+ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
+ qcom,msm-id = <321 0x0>;
+ qcom,board-id = <8 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+ connectors = <&sde_rscc &sde_wb &sde_dp>;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
index fca87e1..2ae9345 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-mtp.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts
new file mode 100644
index 0000000..39c9d37
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-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 "sdm845-sde-display.dtsi"
+#include "sdm845-qrd.dtsi"
+#include "sdm845-qrd-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel QRD";
+ compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
+ qcom,msm-id = <321 0x0>;
+ qcom,board-id = <11 1>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
index 6171c7b..5951f6d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-qrd.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
index 5db4c35..9d799cb 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
@@ -153,6 +153,7 @@
status = "ok";
clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
clock-rates = <24000000>;
};
@@ -192,6 +193,7 @@
status = "ok";
clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
clock-rates = <24000000>;
};
@@ -234,6 +236,7 @@
status = "ok";
clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
clock-rates = <24000000>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
index 5db4c35..ab6ba18 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
@@ -153,6 +153,7 @@
status = "ok";
clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
clock-rates = <24000000>;
};
@@ -192,6 +193,7 @@
status = "ok";
clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
clock-rates = <24000000>;
};
@@ -234,6 +236,7 @@
status = "ok";
clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
clock-rates = <24000000>;
};
@@ -333,7 +336,7 @@
compatible = "qcom,cam-sensor";
reg = <0x02>;
csiphy-sd-index = <2>;
- sensor-position-roll = <90>;
+ sensor-position-roll = <270>;
sensor-position-pitch = <0>;
sensor-position-yaw = <0>;
eeprom-src = <&eeprom_front>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
index 4747c99..efc78e0 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
@@ -15,9 +15,11 @@
#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 "sdm845-sde-display.dtsi"
#include "sdm845-cdp.dtsi"
#include "sdm845-cdp-audio-overlay.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-cdp.dts
index 22e3aea..0a6aa5e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dts
@@ -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
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-cdp.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index 1ce68e1..3f05846 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -195,10 +195,10 @@
qcom,gpu-pwrlevel@3 {
reg = <3>;
- qcom,gpu-freq = <280000000>;
- qcom,bus-freq = <4>;
- qcom,bus-min = <3>;
- qcom,bus-max = <5>;
+ qcom,gpu-freq = <0>;
+ qcom,bus-freq = <0>;
+ qcom,bus-min = <0>;
+ qcom,bus-max = <0>;
};
};
@@ -218,7 +218,6 @@
clock-names = "iface_clk", "mem_clk", "mem_iface_clk";
qcom,secure_align_mask = <0xfff>;
- qcom,global_pt;
qcom,hyp_secure_alloc;
gfx3d_user: gfx3d_user {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
index 52c0f05..45941a1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
@@ -15,9 +15,11 @@
#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 "sdm845-sde-display.dtsi"
#include "sdm845-mtp.dtsi"
#include "sdm845-audio-overlay.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
index f7af60c..e74b342 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
@@ -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
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-mtp.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi
index 2ee9031..b11c912 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi
@@ -15,6 +15,8 @@
&soc {
sound-tavil {
+ qcom,model = "sdm845-tavil-qrd-snd-card";
+
qcom,wsa-max-devs = <1>;
qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>;
qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrRight";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
index 5729d76..6cead9d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
@@ -15,9 +15,11 @@
#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 "sdm845-sde-display.dtsi"
#include "sdm845-qrd.dtsi"
#include "sdm845-qrd-audio-overlay.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-qrd.dts
index 228b924..6cb7815 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-qrd.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index bde64b9..6fb4f37 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -496,7 +496,7 @@
qcom,display-topology = <1 1 1>,
<2 2 1>, /* dsc merge */
<2 1 1>; /* 3d mux */
- qcom,default-topology-index = <0>;
+ qcom,default-topology-index = <1>;
};
&dsi_nt35597_truly_dsc_video {
@@ -506,7 +506,7 @@
qcom,display-topology = <1 1 1>,
<2 2 1>, /* dsc merge */
<2 1 1>; /* 3d mux */
- qcom,default-topology-index = <0>;
+ qcom,default-topology-index = <1>;
};
&dsi_sharp_4k_dsc_video {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 41c1876..17adbf4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -57,14 +57,18 @@
0x48000 0x49000 0x4a000>;
qcom,sde-mixer-size = <0x320>;
+ qcom,sde-dspp-top-off = <0x1300>;
+ qcom,sde-dspp-top-size = <0xc>;
+
qcom,sde-dspp-off = <0x55000 0x57000 0x59000 0x5b000>;
qcom,sde-dspp-size = <0x17e0>;
qcom,sde-wb-off = <0x66000>;
qcom,sde-wb-size = <0x2c8>;
-
qcom,sde-wb-xin-id = <6>;
qcom,sde-wb-id = <2>;
+ qcom,sde-wb-clk-ctrl = <0x3b8 24>;
+
qcom,sde-intf-off = <0x6b000 0x6b800
0x6c000 0x6c800>;
qcom,sde-intf-size = <0x280>;
@@ -188,8 +192,10 @@
};
qcom,sde-dspp-blocks {
+ qcom,sde-dspp-igc = <0x0 0x00030001>;
qcom,sde-dspp-vlut = <0xa00 0x00010008>;
qcom,sde-dspp-gamut = <0x1000 0x00040000>;
+ qcom,sde-dspp-pcc = <0x1700 0x00040000>;
qcom,sde-dspp-gc = <0x17c0 0x00010008>;
};
@@ -349,6 +355,7 @@
/* Offline rotator QoS setting */
qcom,mdss-rot-vbif-qos-setting = <3 3 3 3 3 3 3 3>;
+ qcom,mdss-rot-vbif-memtype = <3 3>;
qcom,mdss-rot-cdp-setting = <1 1>;
qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>;
qcom,mdss-rot-danger-lut = <0x0 0x0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
index ac16d03..ec048ca 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
@@ -229,12 +229,12 @@
0x12a4 0x12 0x00 /* TXA_RCV_DETECT_LVL_2 */
0x128c 0x16 0x00 /* TXA_LANE_MODE_1 */
0x1248 0x09 0x00 /* TXA_RES_CODE_LANE_OFFSET_RX */
- 0x1244 0x0d 0x00 /* TXA_RES_CODE_LANE_OFFSET_TX */
+ 0x1244 0x06 0x00 /* TXA_RES_CODE_LANE_OFFSET_TX */
0x1660 0x10 0x00 /* TXB_HIGHZ_DRVR_EN */
0x16a4 0x12 0x00 /* TXB_RCV_DETECT_LVL_2 */
0x168c 0x16 0x00 /* TXB_LANE_MODE_1 */
0x1648 0x09 0x00 /* TXB_RES_CODE_LANE_OFFSET_RX */
- 0x1644 0x0d 0x00 /* TXB_RES_CODE_LANE_OFFSET_TX */
+ 0x1644 0x06 0x00 /* TXB_RES_CODE_LANE_OFFSET_TX */
0x1cc8 0x83 0x00 /* PCS_FLL_CNTRL2 */
0x1ccc 0x09 0x00 /* PCS_FLL_CNT_VAL_L */
0x1cd0 0xa2 0x00 /* PCS_FLL_CNT_VAL_H_TOL */
@@ -502,8 +502,8 @@
0x260 0x10 0x00 /* QSERDES_TX_HIGHZ_DRVR_EN */
0x2a4 0x12 0x00 /* QSERDES_TX_RCV_DETECT_LVL_2 */
0x28c 0xc6 0x00 /* QSERDES_TX_LANE_MODE_1 */
- 0x248 0x09 0x00 /* TX_RES_CODE_LANE_OFFSET_RX */
- 0x244 0x0d 0x00 /* TX_RES_CODE_LANE_OFFSET_TX */
+ 0x248 0x06 0x00 /* TX_RES_CODE_LANE_OFFSET_RX */
+ 0x244 0x06 0x00 /* TX_RES_CODE_LANE_OFFSET_TX */
0x8c8 0x83 0x00 /* USB3_UNI_PCS_FLL_CNTRL2 */
0x8cc 0x09 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_L */
0x8d0 0xa2 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_H_TOL */
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-cdp-overlay.dts
new file mode 100644
index 0000000..3cd7678
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-cdp-overlay.dts
@@ -0,0 +1,31 @@
+/* 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 "sdm845-sde-display.dtsi"
+#include "sdm845-cdp.dtsi"
+#include "sdm845-cdp-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM845 v2 CDP";
+ compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
+ qcom,msm-id = <321 0x20000>;
+ qcom,board-id = <1 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-cdp.dts
index 8ab0593..66ee4c7 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-cdp.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845-v2.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-cdp.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts
new file mode 100644
index 0000000..e049357
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts
@@ -0,0 +1,31 @@
+/* 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 "sdm845-sde-display.dtsi"
+#include "sdm845-mtp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM845 v2 MTP";
+ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
+ qcom,msm-id = <321 0x20000>;
+ qcom,board-id = <8 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts
index 57c3e71..cea38e6 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845-v2.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-mtp.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd-overlay.dts
new file mode 100644
index 0000000..a5a32ab
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd-overlay.dts
@@ -0,0 +1,31 @@
+/* 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 "sdm845-sde-display.dtsi"
+#include "sdm845-qrd.dtsi"
+#include "sdm845-qrd-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM845 v2 QRD";
+ compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
+ qcom,msm-id = <321 0x20000>;
+ qcom,board-id = <11 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts
index 8a9a544..9a87617 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "sdm845-v2.dtsi"
+#include "sdm845-sde-display.dtsi"
#include "sdm845-qrd.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.dts
new file mode 100644
index 0000000..d36d0fd
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dts
@@ -0,0 +1,21 @@
+/* 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 "sdm845-v2.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM845 v2 SoC";
+ compatible = "qcom,sdm845";
+ qcom,board-id = <0 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 95ee14c..f5848c1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -17,10 +17,6 @@
qcom,msm-id = <321 0x20000>;
};
-&spmi_debug_bus {
- status = "ok";
-};
-
&clock_gcc {
compatible = "qcom,gcc-sdm845-v2";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 8f9618d..11d553d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -645,7 +645,6 @@
#include "sdm845-sde-pll.dtsi"
#include "msm-rdbg.dtsi"
#include "sdm845-sde.dtsi"
-#include "sdm845-sde-display.dtsi"
#include "sdm845-qupv3.dtsi"
&soc {
@@ -741,6 +740,12 @@
reg-names = "pshold-base", "tcsr-boot-misc-detect";
};
+ aop-msg-client {
+ compatible = "qcom,debugfs-qmp-client";
+ mboxes = <&qmp_aop 0>;
+ mbox-names = "aop";
+ };
+
spmi_bus: qcom,spmi@c440000 {
compatible = "qcom,spmi-pmic-arb";
reg = <0xc440000 0x1100>,
@@ -769,7 +774,6 @@
qcom,fuse-disable-bit = <12>;
#address-cells = <2>;
#size-cells = <0>;
- status = "disabled";
qcom,pm8998-debug@0 {
compatible = "qcom,spmi-pmic";
@@ -979,7 +983,7 @@
< 1209600 806400000 >,
< 1516800 883200000 >,
< 1593600 960000000 >,
- < 1708800 1094400000 >;
+ < 1708800 1305600000 >;
};
devfreq_l3lat_4: qcom,cpu4-l3lat-mon {
@@ -993,7 +997,7 @@
< 1190400 806400000 >,
< 1574400 883200000 >,
< 1804800 960000000 >,
- < 2092800 1094400000 >;
+ < 1958400 1305600000 >;
};
cpu_pmu: cpu-pmu {
@@ -1319,10 +1323,6 @@
< 2112000000 0x4054176e 0x00005858 0x3 24 >,
< 2208000000 0x40541873 0x00005c5c 0x3 25 >;
- qcom,l3-min-cpr-vc-bin0 = <7>;
- qcom,pwrcl-min-cpr-vc-bin0 = <6>;
- qcom,perfcl-min-cpr-vc-bin0 = <7>;
-
qcom,up-timer =
<1000 1000 1000>;
qcom,down-timer =
@@ -1680,6 +1680,8 @@
qcom,sdr104-wa;
+ qcom,restore-after-cx-collapse;
+
qcom,devfreq,freq-table = <50000000 200000000>;
clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>,
<&clock_gcc GCC_SDCC2_APPS_CLK>;
@@ -1969,63 +1971,75 @@
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
iommus = <&apps_smmu 0x1401 0x30>;
+ dma-coherent;
};
qcom,msm_fastrpc_compute_cb2 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
iommus = <&apps_smmu 0x1402 0x30>;
+ dma-coherent;
};
qcom,msm_fastrpc_compute_cb3 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
iommus = <&apps_smmu 0x1403 0x30>;
+ dma-coherent;
};
qcom,msm_fastrpc_compute_cb4 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
iommus = <&apps_smmu 0x1404 0x30>;
+ dma-coherent;
};
qcom,msm_fastrpc_compute_cb5 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
iommus = <&apps_smmu 0x1405 0x30>;
+ dma-coherent;
};
qcom,msm_fastrpc_compute_cb6 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
iommus = <&apps_smmu 0x1406 0x30>;
+ dma-coherent;
};
qcom,msm_fastrpc_compute_cb7 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
iommus = <&apps_smmu 0x1407 0x30>;
+ dma-coherent;
};
qcom,msm_fastrpc_compute_cb8 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
iommus = <&apps_smmu 0x1408 0x30>;
+ dma-coherent;
};
qcom,msm_fastrpc_compute_cb9 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
qcom,secure-context-bank;
iommus = <&apps_smmu 0x1409 0x30>;
+ dma-coherent;
};
qcom,msm_fastrpc_compute_cb10 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "cdsprpc-smd";
qcom,secure-context-bank;
iommus = <&apps_smmu 0x140A 0x30>;
+ dma-coherent;
};
qcom,msm_fastrpc_compute_cb11 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "adsprpc-smd";
iommus = <&apps_smmu 0x1823 0x0>;
+ dma-coherent;
};
qcom,msm_fastrpc_compute_cb12 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "adsprpc-smd";
iommus = <&apps_smmu 0x1824 0x0>;
+ dma-coherent;
};
};
@@ -2239,7 +2253,6 @@
compatible = "qcom,sdm845-llcc";
#cache-cells = <1>;
max-slices = <32>;
- qcom,dump-size = <0x3c0000>;
};
qcom,llcc-erp {
@@ -2253,19 +2266,19 @@
};
LLCC_1: llcc_1_dcache {
- qcom,dump-size = <0xd8000>;
+ qcom,dump-size = <0x114100>;
};
LLCC_2: llcc_2_dcache {
- qcom,dump-size = <0xd8000>;
+ qcom,dump-size = <0x114100>;
};
LLCC_3: llcc_3_dcache {
- qcom,dump-size = <0xd8000>;
+ qcom,dump-size = <0x114100>;
};
LLCC_4: llcc_4_dcache {
- qcom,dump-size = <0xd8000>;
+ qcom,dump-size = <0x114100>;
};
};
@@ -2975,6 +2988,7 @@
vdd-3.3-ch0-supply = <&pm8998_l25>;
qcom,vdd-0.8-cx-mx-config = <800000 800000>;
qcom,vdd-3.3-ch0-config = <3104000 3312000>;
+ qcom,smmu-s1-bypass;
};
qmi-tmd-devices {
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 14243fb..b8f115b 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -86,7 +86,6 @@
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
CONFIG_CPU_BOOST=y
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
-CONFIG_CPU_FREQ_MSM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index b60dd01..5872f88 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -131,6 +131,7 @@
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
CONFIG_NETFILTER_XT_TARGET_LOG=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
@@ -520,6 +521,7 @@
CONFIG_MSM_PERFORMANCE=y
CONFIG_MSM_CDSP_LOADER=y
CONFIG_MSM_AVTIMER=y
+CONFIG_QCOM_SMCINVOKE=y
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_PM=y
CONFIG_MSM_QBT1000=y
@@ -576,6 +578,7 @@
CONFIG_CORESIGHT_TPDA=y
CONFIG_CORESIGHT_TPDM=y
CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_DUMMY=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 37f7d32..82455e5 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -136,6 +136,7 @@
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
CONFIG_NETFILTER_XT_TARGET_LOG=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
@@ -538,6 +539,7 @@
CONFIG_MSM_PERFORMANCE=y
CONFIG_MSM_CDSP_LOADER=y
CONFIG_MSM_AVTIMER=y
+CONFIG_QCOM_SMCINVOKE=y
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_PM=y
CONFIG_MSM_QBT1000=y
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index bb24b4e..b325f74 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -1189,20 +1189,24 @@ static int armv8_pmu_device_probe(struct platform_device *pdev)
{
int ret, cpu;
- for_each_possible_cpu(cpu)
- per_cpu(is_hotplugging, cpu) = false;
+ /* set to true so armv8pmu_idle_update doesn't try to load
+ * hw_events before arm_pmu_device_probe has initialized it.
+ */
+ for_each_possible_cpu(cpu) {
+ per_cpu(is_hotplugging, cpu) = true;
+ }
- ret = perf_event_cpu_hp_init();
+ ret = arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids,
+ (acpi_disabled ? NULL : armv8_pmu_probe_table));
- if (ret)
- return ret;
+ if (!ret) {
+ for_each_possible_cpu(cpu)
+ per_cpu(is_hotplugging, cpu) = false;
- if (acpi_disabled)
- return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids,
- NULL);
+ ret = perf_event_cpu_hp_init();
+ }
- return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids,
- armv8_pmu_probe_table);
+ return ret;
}
static struct platform_driver armv8_pmu_driver = {
diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h
index 053baff..14fc4d2 100644
--- a/arch/um/include/asm/thread_info.h
+++ b/arch/um/include/asm/thread_info.h
@@ -63,6 +63,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_RESTORE_SIGMASK 7
#define TIF_NOTIFY_RESUME 8
#define TIF_SECCOMP 9 /* secure computing */
+#define TIF_MM_RELEASED 10 /* task MM has been released */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h
index 0b1ff4c..fffb279 100644
--- a/arch/x86/include/asm/pat.h
+++ b/arch/x86/include/asm/pat.h
@@ -7,6 +7,7 @@
bool pat_enabled(void);
void pat_disable(const char *reason);
extern void pat_init(void);
+extern void init_cache_modes(void);
extern int reserve_memtype(u64 start, u64 end,
enum page_cache_mode req_pcm, enum page_cache_mode *ret_pcm);
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 9c337b0..feaab07 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1054,6 +1054,13 @@ void __init setup_arch(char **cmdline_p)
max_possible_pfn = max_pfn;
/*
+ * This call is required when the CPU does not support PAT. If
+ * mtrr_bp_init() invoked it already via pat_init() the call has no
+ * effect.
+ */
+ init_cache_modes();
+
+ /*
* Define random base addresses for memory sections after max_pfn is
* defined and before each memory section base is used.
*/
diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S
index d376e4b..04c067b 100644
--- a/arch/x86/lib/copy_user_64.S
+++ b/arch/x86/lib/copy_user_64.S
@@ -84,7 +84,7 @@
movl %edx,%ecx
andl $63,%edx
shrl $6,%ecx
- jz 17f
+ jz .L_copy_short_string
1: movq (%rsi),%r8
2: movq 1*8(%rsi),%r9
3: movq 2*8(%rsi),%r10
@@ -105,7 +105,8 @@
leaq 64(%rdi),%rdi
decl %ecx
jnz 1b
-17: movl %edx,%ecx
+.L_copy_short_string:
+ movl %edx,%ecx
andl $7,%edx
shrl $3,%ecx
jz 20f
@@ -221,6 +222,8 @@
*/
ENTRY(copy_user_enhanced_fast_string)
ASM_STAC
+ cmpl $64,%edx
+ jb .L_copy_short_string /* less then 64 bytes, avoid the costly 'rep' */
movl %edx,%ecx
1: rep
movsb
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 83e701f..89d7907 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -36,14 +36,14 @@
#undef pr_fmt
#define pr_fmt(fmt) "" fmt
-static bool boot_cpu_done;
-
-static int __read_mostly __pat_enabled = IS_ENABLED(CONFIG_X86_PAT);
-static void init_cache_modes(void);
+static bool __read_mostly boot_cpu_done;
+static bool __read_mostly pat_disabled = !IS_ENABLED(CONFIG_X86_PAT);
+static bool __read_mostly pat_initialized;
+static bool __read_mostly init_cm_done;
void pat_disable(const char *reason)
{
- if (!__pat_enabled)
+ if (pat_disabled)
return;
if (boot_cpu_done) {
@@ -51,10 +51,8 @@ void pat_disable(const char *reason)
return;
}
- __pat_enabled = 0;
+ pat_disabled = true;
pr_info("x86/PAT: %s\n", reason);
-
- init_cache_modes();
}
static int __init nopat(char *str)
@@ -66,7 +64,7 @@ early_param("nopat", nopat);
bool pat_enabled(void)
{
- return !!__pat_enabled;
+ return pat_initialized;
}
EXPORT_SYMBOL_GPL(pat_enabled);
@@ -204,6 +202,8 @@ static void __init_cache_modes(u64 pat)
update_cache_mode_entry(i, cache);
}
pr_info("x86/PAT: Configuration [0-7]: %s\n", pat_msg);
+
+ init_cm_done = true;
}
#define PAT(x, y) ((u64)PAT_ ## y << ((x)*8))
@@ -224,6 +224,7 @@ static void pat_bsp_init(u64 pat)
}
wrmsrl(MSR_IA32_CR_PAT, pat);
+ pat_initialized = true;
__init_cache_modes(pat);
}
@@ -241,10 +242,9 @@ static void pat_ap_init(u64 pat)
wrmsrl(MSR_IA32_CR_PAT, pat);
}
-static void init_cache_modes(void)
+void init_cache_modes(void)
{
u64 pat = 0;
- static int init_cm_done;
if (init_cm_done)
return;
@@ -286,8 +286,6 @@ static void init_cache_modes(void)
}
__init_cache_modes(pat);
-
- init_cm_done = 1;
}
/**
@@ -305,10 +303,8 @@ void pat_init(void)
u64 pat;
struct cpuinfo_x86 *c = &boot_cpu_data;
- if (!pat_enabled()) {
- init_cache_modes();
+ if (pat_disabled)
return;
- }
if ((c->x86_vendor == X86_VENDOR_INTEL) &&
(((c->x86 == 0x6) && (c->x86_model <= 0xd)) ||
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index 0c2fae8..73eb7fd 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -992,11 +992,12 @@ static void emit_relocs(int as_text, int use_real_mode)
die("Segment relocations found but --realmode not specified\n");
/* Order the relocations for more efficient processing */
- sort_relocs(&relocs16);
sort_relocs(&relocs32);
#if ELF_BITS == 64
sort_relocs(&relocs32neg);
sort_relocs(&relocs64);
+#else
+ sort_relocs(&relocs16);
#endif
/* Print the relocations */
diff --git a/crypto/drbg.c b/crypto/drbg.c
index 123d211..8cac3d3 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -1691,6 +1691,7 @@ static int drbg_init_sym_kernel(struct drbg_state *drbg)
return PTR_ERR(sk_tfm);
}
drbg->ctr_handle = sk_tfm;
+ init_completion(&drbg->ctr_completion);
req = skcipher_request_alloc(sk_tfm, GFP_KERNEL);
if (!req) {
diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c
index 8baab43..7830d30 100644
--- a/crypto/rsa-pkcs1pad.c
+++ b/crypto/rsa-pkcs1pad.c
@@ -496,7 +496,7 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err)
goto done;
pos++;
- if (memcmp(out_buf + pos, digest_info->data, digest_info->size))
+ if (crypto_memneq(out_buf + pos, digest_info->data, digest_info->size))
goto done;
pos += digest_info->size;
diff --git a/drivers/android/Makefile b/drivers/android/Makefile
index 3b7e4b0..4b7c726 100644
--- a/drivers/android/Makefile
+++ b/drivers/android/Makefile
@@ -1,3 +1,3 @@
ccflags-y += -I$(src) # needed for trace events
-obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o
+obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 6485c77..b351c85 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -15,6 +15,40 @@
*
*/
+/*
+ * Locking overview
+ *
+ * There are 3 main spinlocks which must be acquired in the
+ * order shown:
+ *
+ * 1) proc->outer_lock : protects binder_ref
+ * binder_proc_lock() and binder_proc_unlock() are
+ * used to acq/rel.
+ * 2) node->lock : protects most fields of binder_node.
+ * binder_node_lock() and binder_node_unlock() are
+ * used to acq/rel
+ * 3) proc->inner_lock : protects the thread and node lists
+ * (proc->threads, proc->nodes) and all todo lists associated
+ * with the binder_proc (proc->todo, thread->todo,
+ * proc->delivered_death and node->async_todo), as well as
+ * thread->transaction_stack
+ * binder_inner_proc_lock() and binder_inner_proc_unlock()
+ * are used to acq/rel
+ *
+ * Any lock under procA must never be nested under any lock at the same
+ * level or below on procB.
+ *
+ * Functions that require a lock held on entry indicate which lock
+ * in the suffix of the function name:
+ *
+ * foo_olocked() : requires node->outer_lock
+ * foo_nlocked() : requires node->lock
+ * foo_ilocked() : requires proc->inner_lock
+ * foo_oilocked(): requires proc->outer_lock and proc->inner_lock
+ * foo_nilocked(): requires node->lock and proc->inner_lock
+ * ...
+ */
+
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <asm/cacheflush.h>
@@ -24,7 +58,6 @@
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/miscdevice.h>
-#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/nsproxy.h>
@@ -34,30 +67,31 @@
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
#include <linux/pid_namespace.h>
#include <linux/security.h>
+#include <linux/spinlock.h>
#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT
#define BINDER_IPC_32BIT 1
#endif
#include <uapi/linux/android/binder.h>
+#include "binder_alloc.h"
#include "binder_trace.h"
-static DEFINE_MUTEX(binder_main_lock);
+static HLIST_HEAD(binder_deferred_list);
static DEFINE_MUTEX(binder_deferred_lock);
-static DEFINE_MUTEX(binder_mmap_lock);
static HLIST_HEAD(binder_devices);
static HLIST_HEAD(binder_procs);
-static HLIST_HEAD(binder_deferred_list);
+static DEFINE_MUTEX(binder_procs_lock);
+
static HLIST_HEAD(binder_dead_nodes);
+static DEFINE_SPINLOCK(binder_dead_nodes_lock);
static struct dentry *binder_debugfs_dir_entry_root;
static struct dentry *binder_debugfs_dir_entry_proc;
-static int binder_last_id;
+static atomic_t binder_last_id;
#define BINDER_DEBUG_ENTRY(name) \
static int binder_##name##_open(struct inode *inode, struct file *file) \
@@ -103,17 +137,13 @@ enum {
BINDER_DEBUG_TRANSACTION_COMPLETE = 1U << 10,
BINDER_DEBUG_FREE_BUFFER = 1U << 11,
BINDER_DEBUG_INTERNAL_REFS = 1U << 12,
- BINDER_DEBUG_BUFFER_ALLOC = 1U << 13,
- BINDER_DEBUG_PRIORITY_CAP = 1U << 14,
- BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 15,
+ BINDER_DEBUG_PRIORITY_CAP = 1U << 13,
+ BINDER_DEBUG_SPINLOCKS = 1U << 14,
};
static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR |
BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION;
module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO);
-static bool binder_debug_no_lock;
-module_param_named(proc_no_lock, binder_debug_no_lock, bool, S_IWUSR | S_IRUGO);
-
static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES;
module_param_named(devices, binder_devices_param, charp, S_IRUGO);
@@ -170,26 +200,27 @@ enum binder_stat_types {
};
struct binder_stats {
- int br[_IOC_NR(BR_FAILED_REPLY) + 1];
- int bc[_IOC_NR(BC_REPLY_SG) + 1];
- int obj_created[BINDER_STAT_COUNT];
- int obj_deleted[BINDER_STAT_COUNT];
+ atomic_t br[_IOC_NR(BR_FAILED_REPLY) + 1];
+ atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1];
+ atomic_t obj_created[BINDER_STAT_COUNT];
+ atomic_t obj_deleted[BINDER_STAT_COUNT];
};
static struct binder_stats binder_stats;
static inline void binder_stats_deleted(enum binder_stat_types type)
{
- binder_stats.obj_deleted[type]++;
+ atomic_inc(&binder_stats.obj_deleted[type]);
}
static inline void binder_stats_created(enum binder_stat_types type)
{
- binder_stats.obj_created[type]++;
+ atomic_inc(&binder_stats.obj_created[type]);
}
struct binder_transaction_log_entry {
int debug_id;
+ int debug_id_done;
int call_type;
int from_proc;
int from_thread;
@@ -199,11 +230,14 @@ struct binder_transaction_log_entry {
int to_node;
int data_size;
int offsets_size;
+ int return_error_line;
+ uint32_t return_error;
+ uint32_t return_error_param;
const char *context_name;
};
struct binder_transaction_log {
- int next;
- int full;
+ atomic_t cur;
+ bool full;
struct binder_transaction_log_entry entry[32];
};
static struct binder_transaction_log binder_transaction_log;
@@ -213,19 +247,26 @@ static struct binder_transaction_log_entry *binder_transaction_log_add(
struct binder_transaction_log *log)
{
struct binder_transaction_log_entry *e;
+ unsigned int cur = atomic_inc_return(&log->cur);
- e = &log->entry[log->next];
- memset(e, 0, sizeof(*e));
- log->next++;
- if (log->next == ARRAY_SIZE(log->entry)) {
- log->next = 0;
+ if (cur >= ARRAY_SIZE(log->entry))
log->full = 1;
- }
+ e = &log->entry[cur % ARRAY_SIZE(log->entry)];
+ WRITE_ONCE(e->debug_id_done, 0);
+ /*
+ * write-barrier to synchronize access to e->debug_id_done.
+ * We make sure the initialized 0 value is seen before
+ * memset() other fields are zeroed by memset.
+ */
+ smp_wmb();
+ memset(e, 0, sizeof(*e));
return e;
}
struct binder_context {
struct binder_node *binder_context_mgr_node;
+ struct mutex context_mgr_node_lock;
+
kuid_t binder_context_mgr_uid;
const char *name;
};
@@ -236,11 +277,20 @@ struct binder_device {
struct binder_context context;
};
+/**
+ * struct binder_work - work enqueued on a worklist
+ * @entry: node enqueued on list
+ * @type: type of work to be performed
+ *
+ * There are separate work lists for proc, thread, and node (async).
+ */
struct binder_work {
struct list_head entry;
+
enum {
BINDER_WORK_TRANSACTION = 1,
BINDER_WORK_TRANSACTION_COMPLETE,
+ BINDER_WORK_RETURN_ERROR,
BINDER_WORK_NODE,
BINDER_WORK_DEAD_BINDER,
BINDER_WORK_DEAD_BINDER_AND_CLEAR,
@@ -248,8 +298,72 @@ struct binder_work {
} type;
};
+struct binder_error {
+ struct binder_work work;
+ uint32_t cmd;
+};
+
+/**
+ * struct binder_node - binder node bookkeeping
+ * @debug_id: unique ID for debugging
+ * (invariant after initialized)
+ * @lock: lock for node fields
+ * @work: worklist element for node work
+ * (protected by @proc->inner_lock)
+ * @rb_node: element for proc->nodes tree
+ * (protected by @proc->inner_lock)
+ * @dead_node: element for binder_dead_nodes list
+ * (protected by binder_dead_nodes_lock)
+ * @proc: binder_proc that owns this node
+ * (invariant after initialized)
+ * @refs: list of references on this node
+ * (protected by @lock)
+ * @internal_strong_refs: used to take strong references when
+ * initiating a transaction
+ * (protected by @proc->inner_lock if @proc
+ * and by @lock)
+ * @local_weak_refs: weak user refs from local process
+ * (protected by @proc->inner_lock if @proc
+ * and by @lock)
+ * @local_strong_refs: strong user refs from local process
+ * (protected by @proc->inner_lock if @proc
+ * and by @lock)
+ * @tmp_refs: temporary kernel refs
+ * (protected by @proc->inner_lock while @proc
+ * is valid, and by binder_dead_nodes_lock
+ * if @proc is NULL. During inc/dec and node release
+ * it is also protected by @lock to provide safety
+ * as the node dies and @proc becomes NULL)
+ * @ptr: userspace pointer for node
+ * (invariant, no lock needed)
+ * @cookie: userspace cookie for node
+ * (invariant, no lock needed)
+ * @has_strong_ref: userspace notified of strong ref
+ * (protected by @proc->inner_lock if @proc
+ * and by @lock)
+ * @pending_strong_ref: userspace has acked notification of strong ref
+ * (protected by @proc->inner_lock if @proc
+ * and by @lock)
+ * @has_weak_ref: userspace notified of weak ref
+ * (protected by @proc->inner_lock if @proc
+ * and by @lock)
+ * @pending_weak_ref: userspace has acked notification of weak ref
+ * (protected by @proc->inner_lock if @proc
+ * and by @lock)
+ * @has_async_transaction: async transaction to node in progress
+ * (protected by @lock)
+ * @accept_fds: file descriptor operations supported for node
+ * (invariant after initialized)
+ * @min_priority: minimum scheduling priority
+ * (invariant after initialized)
+ * @async_todo: list of async work items
+ * (protected by @proc->inner_lock)
+ *
+ * Bookkeeping structure for binder nodes.
+ */
struct binder_node {
int debug_id;
+ spinlock_t lock;
struct binder_work work;
union {
struct rb_node rb_node;
@@ -260,64 +374,153 @@ struct binder_node {
int internal_strong_refs;
int local_weak_refs;
int local_strong_refs;
+ int tmp_refs;
binder_uintptr_t ptr;
binder_uintptr_t cookie;
- unsigned has_strong_ref:1;
- unsigned pending_strong_ref:1;
- unsigned has_weak_ref:1;
- unsigned pending_weak_ref:1;
- unsigned has_async_transaction:1;
- unsigned accept_fds:1;
- unsigned min_priority:8;
+ struct {
+ /*
+ * bitfield elements protected by
+ * proc inner_lock
+ */
+ u8 has_strong_ref:1;
+ u8 pending_strong_ref:1;
+ u8 has_weak_ref:1;
+ u8 pending_weak_ref:1;
+ };
+ struct {
+ /*
+ * invariant after initialization
+ */
+ u8 accept_fds:1;
+ u8 min_priority;
+ };
+ bool has_async_transaction;
struct list_head async_todo;
};
struct binder_ref_death {
+ /**
+ * @work: worklist element for death notifications
+ * (protected by inner_lock of the proc that
+ * this ref belongs to)
+ */
struct binder_work work;
binder_uintptr_t cookie;
};
+/**
+ * struct binder_ref_data - binder_ref counts and id
+ * @debug_id: unique ID for the ref
+ * @desc: unique userspace handle for ref
+ * @strong: strong ref count (debugging only if not locked)
+ * @weak: weak ref count (debugging only if not locked)
+ *
+ * Structure to hold ref count and ref id information. Since
+ * the actual ref can only be accessed with a lock, this structure
+ * is used to return information about the ref to callers of
+ * ref inc/dec functions.
+ */
+struct binder_ref_data {
+ int debug_id;
+ uint32_t desc;
+ int strong;
+ int weak;
+};
+
+/**
+ * struct binder_ref - struct to track references on nodes
+ * @data: binder_ref_data containing id, handle, and current refcounts
+ * @rb_node_desc: node for lookup by @data.desc in proc's rb_tree
+ * @rb_node_node: node for lookup by @node in proc's rb_tree
+ * @node_entry: list entry for node->refs list in target node
+ * (protected by @node->lock)
+ * @proc: binder_proc containing ref
+ * @node: binder_node of target node. When cleaning up a
+ * ref for deletion in binder_cleanup_ref, a non-NULL
+ * @node indicates the node must be freed
+ * @death: pointer to death notification (ref_death) if requested
+ * (protected by @node->lock)
+ *
+ * Structure to track references from procA to target node (on procB). This
+ * structure is unsafe to access without holding @proc->outer_lock.
+ */
struct binder_ref {
/* Lookups needed: */
/* node + proc => ref (transaction) */
/* desc + proc => ref (transaction, inc/dec ref) */
/* node => refs + procs (proc exit) */
- int debug_id;
+ struct binder_ref_data data;
struct rb_node rb_node_desc;
struct rb_node rb_node_node;
struct hlist_node node_entry;
struct binder_proc *proc;
struct binder_node *node;
- uint32_t desc;
- int strong;
- int weak;
struct binder_ref_death *death;
};
-struct binder_buffer {
- struct list_head entry; /* free and allocated entries by address */
- struct rb_node rb_node; /* free entry by size or allocated entry */
- /* by address */
- unsigned free:1;
- unsigned allow_user_free:1;
- unsigned async_transaction:1;
- unsigned debug_id:29;
-
- struct binder_transaction *transaction;
-
- struct binder_node *target_node;
- size_t data_size;
- size_t offsets_size;
- size_t extra_buffers_size;
- uint8_t data[0];
-};
-
enum binder_deferred_state {
BINDER_DEFERRED_PUT_FILES = 0x01,
BINDER_DEFERRED_FLUSH = 0x02,
BINDER_DEFERRED_RELEASE = 0x04,
};
+/**
+ * struct binder_proc - binder process bookkeeping
+ * @proc_node: element for binder_procs list
+ * @threads: rbtree of binder_threads in this proc
+ * (protected by @inner_lock)
+ * @nodes: rbtree of binder nodes associated with
+ * this proc ordered by node->ptr
+ * (protected by @inner_lock)
+ * @refs_by_desc: rbtree of refs ordered by ref->desc
+ * (protected by @outer_lock)
+ * @refs_by_node: rbtree of refs ordered by ref->node
+ * (protected by @outer_lock)
+ * @pid PID of group_leader of process
+ * (invariant after initialized)
+ * @tsk task_struct for group_leader of process
+ * (invariant after initialized)
+ * @files files_struct for process
+ * (invariant after initialized)
+ * @deferred_work_node: element for binder_deferred_list
+ * (protected by binder_deferred_lock)
+ * @deferred_work: bitmap of deferred work to perform
+ * (protected by binder_deferred_lock)
+ * @is_dead: process is dead and awaiting free
+ * when outstanding transactions are cleaned up
+ * (protected by @inner_lock)
+ * @todo: list of work for this process
+ * (protected by @inner_lock)
+ * @wait: wait queue head to wait for proc work
+ * (invariant after initialized)
+ * @stats: per-process binder statistics
+ * (atomics, no lock needed)
+ * @delivered_death: list of delivered death notification
+ * (protected by @inner_lock)
+ * @max_threads: cap on number of binder threads
+ * (protected by @inner_lock)
+ * @requested_threads: number of binder threads requested but not
+ * yet started. In current implementation, can
+ * only be 0 or 1.
+ * (protected by @inner_lock)
+ * @requested_threads_started: number binder threads started
+ * (protected by @inner_lock)
+ * @ready_threads: number of threads waiting for proc work
+ * (protected by @inner_lock)
+ * @tmp_ref: temporary reference to indicate proc is in use
+ * (protected by @inner_lock)
+ * @default_priority: default scheduler priority
+ * (invariant after initialized)
+ * @debugfs_entry: debugfs node
+ * @alloc: binder allocator bookkeeping
+ * @context: binder_context for this proc
+ * (invariant after initialized)
+ * @inner_lock: can nest under outer_lock and/or node lock
+ * @outer_lock: no nesting under innor or node lock
+ * Lock order: 1) outer, 2) node, 3) inner
+ *
+ * Bookkeeping structure for binder processes
+ */
struct binder_proc {
struct hlist_node proc_node;
struct rb_root threads;
@@ -325,23 +528,12 @@ struct binder_proc {
struct rb_root refs_by_desc;
struct rb_root refs_by_node;
int pid;
- struct vm_area_struct *vma;
- struct mm_struct *vma_vm_mm;
struct task_struct *tsk;
struct files_struct *files;
struct hlist_node deferred_work_node;
int deferred_work;
- void *buffer;
- ptrdiff_t user_buffer_offset;
+ bool is_dead;
- struct list_head buffers;
- struct rb_root free_buffers;
- struct rb_root allocated_buffers;
- size_t free_async_space;
-
- struct page **pages;
- size_t buffer_size;
- uint32_t buffer_free;
struct list_head todo;
wait_queue_head_t wait;
struct binder_stats stats;
@@ -350,9 +542,13 @@ struct binder_proc {
int requested_threads;
int requested_threads_started;
int ready_threads;
+ int tmp_ref;
long default_priority;
struct dentry *debugfs_entry;
+ struct binder_alloc alloc;
struct binder_context *context;
+ spinlock_t inner_lock;
+ spinlock_t outer_lock;
};
enum {
@@ -361,22 +557,54 @@ enum {
BINDER_LOOPER_STATE_EXITED = 0x04,
BINDER_LOOPER_STATE_INVALID = 0x08,
BINDER_LOOPER_STATE_WAITING = 0x10,
- BINDER_LOOPER_STATE_NEED_RETURN = 0x20
};
+/**
+ * struct binder_thread - binder thread bookkeeping
+ * @proc: binder process for this thread
+ * (invariant after initialization)
+ * @rb_node: element for proc->threads rbtree
+ * (protected by @proc->inner_lock)
+ * @pid: PID for this thread
+ * (invariant after initialization)
+ * @looper: bitmap of looping state
+ * (only accessed by this thread)
+ * @looper_needs_return: looping thread needs to exit driver
+ * (no lock needed)
+ * @transaction_stack: stack of in-progress transactions for this thread
+ * (protected by @proc->inner_lock)
+ * @todo: list of work to do for this thread
+ * (protected by @proc->inner_lock)
+ * @return_error: transaction errors reported by this thread
+ * (only accessed by this thread)
+ * @reply_error: transaction errors reported by target thread
+ * (protected by @proc->inner_lock)
+ * @wait: wait queue for thread work
+ * @stats: per-thread statistics
+ * (atomics, no lock needed)
+ * @tmp_ref: temporary reference to indicate thread is in use
+ * (atomic since @proc->inner_lock cannot
+ * always be acquired)
+ * @is_dead: thread is dead and awaiting free
+ * when outstanding transactions are cleaned up
+ * (protected by @proc->inner_lock)
+ *
+ * Bookkeeping structure for binder threads.
+ */
struct binder_thread {
struct binder_proc *proc;
struct rb_node rb_node;
int pid;
- int looper;
+ int looper; /* only modified by this thread */
+ bool looper_need_return; /* can be written by other thread */
struct binder_transaction *transaction_stack;
struct list_head todo;
- uint32_t return_error; /* Write failed, return error code in read buf */
- uint32_t return_error2; /* Write failed, return error code in read */
- /* buffer. Used when sending a reply to a dead process that */
- /* we are also waiting on */
+ struct binder_error return_error;
+ struct binder_error reply_error;
wait_queue_head_t wait;
struct binder_stats stats;
+ atomic_t tmp_ref;
+ bool is_dead;
};
struct binder_transaction {
@@ -396,17 +624,259 @@ struct binder_transaction {
long priority;
long saved_priority;
kuid_t sender_euid;
+ /**
+ * @lock: protects @from, @to_proc, and @to_thread
+ *
+ * @from, @to_proc, and @to_thread can be set to NULL
+ * during thread teardown
+ */
+ spinlock_t lock;
};
+/**
+ * binder_proc_lock() - Acquire outer lock for given binder_proc
+ * @proc: struct binder_proc to acquire
+ *
+ * Acquires proc->outer_lock. Used to protect binder_ref
+ * structures associated with the given proc.
+ */
+#define binder_proc_lock(proc) _binder_proc_lock(proc, __LINE__)
+static void
+_binder_proc_lock(struct binder_proc *proc, int line)
+{
+ binder_debug(BINDER_DEBUG_SPINLOCKS,
+ "%s: line=%d\n", __func__, line);
+ spin_lock(&proc->outer_lock);
+}
+
+/**
+ * binder_proc_unlock() - Release spinlock for given binder_proc
+ * @proc: struct binder_proc to acquire
+ *
+ * Release lock acquired via binder_proc_lock()
+ */
+#define binder_proc_unlock(_proc) _binder_proc_unlock(_proc, __LINE__)
+static void
+_binder_proc_unlock(struct binder_proc *proc, int line)
+{
+ binder_debug(BINDER_DEBUG_SPINLOCKS,
+ "%s: line=%d\n", __func__, line);
+ spin_unlock(&proc->outer_lock);
+}
+
+/**
+ * binder_inner_proc_lock() - Acquire inner lock for given binder_proc
+ * @proc: struct binder_proc to acquire
+ *
+ * Acquires proc->inner_lock. Used to protect todo lists
+ */
+#define binder_inner_proc_lock(proc) _binder_inner_proc_lock(proc, __LINE__)
+static void
+_binder_inner_proc_lock(struct binder_proc *proc, int line)
+{
+ binder_debug(BINDER_DEBUG_SPINLOCKS,
+ "%s: line=%d\n", __func__, line);
+ spin_lock(&proc->inner_lock);
+}
+
+/**
+ * binder_inner_proc_unlock() - Release inner lock for given binder_proc
+ * @proc: struct binder_proc to acquire
+ *
+ * Release lock acquired via binder_inner_proc_lock()
+ */
+#define binder_inner_proc_unlock(proc) _binder_inner_proc_unlock(proc, __LINE__)
+static void
+_binder_inner_proc_unlock(struct binder_proc *proc, int line)
+{
+ binder_debug(BINDER_DEBUG_SPINLOCKS,
+ "%s: line=%d\n", __func__, line);
+ spin_unlock(&proc->inner_lock);
+}
+
+/**
+ * binder_node_lock() - Acquire spinlock for given binder_node
+ * @node: struct binder_node to acquire
+ *
+ * Acquires node->lock. Used to protect binder_node fields
+ */
+#define binder_node_lock(node) _binder_node_lock(node, __LINE__)
+static void
+_binder_node_lock(struct binder_node *node, int line)
+{
+ binder_debug(BINDER_DEBUG_SPINLOCKS,
+ "%s: line=%d\n", __func__, line);
+ spin_lock(&node->lock);
+}
+
+/**
+ * binder_node_unlock() - Release spinlock for given binder_proc
+ * @node: struct binder_node to acquire
+ *
+ * Release lock acquired via binder_node_lock()
+ */
+#define binder_node_unlock(node) _binder_node_unlock(node, __LINE__)
+static void
+_binder_node_unlock(struct binder_node *node, int line)
+{
+ binder_debug(BINDER_DEBUG_SPINLOCKS,
+ "%s: line=%d\n", __func__, line);
+ spin_unlock(&node->lock);
+}
+
+/**
+ * binder_node_inner_lock() - Acquire node and inner locks
+ * @node: struct binder_node to acquire
+ *
+ * Acquires node->lock. If node->proc also acquires
+ * proc->inner_lock. Used to protect binder_node fields
+ */
+#define binder_node_inner_lock(node) _binder_node_inner_lock(node, __LINE__)
+static void
+_binder_node_inner_lock(struct binder_node *node, int line)
+{
+ binder_debug(BINDER_DEBUG_SPINLOCKS,
+ "%s: line=%d\n", __func__, line);
+ spin_lock(&node->lock);
+ if (node->proc)
+ binder_inner_proc_lock(node->proc);
+}
+
+/**
+ * binder_node_unlock() - Release node and inner locks
+ * @node: struct binder_node to acquire
+ *
+ * Release lock acquired via binder_node_lock()
+ */
+#define binder_node_inner_unlock(node) _binder_node_inner_unlock(node, __LINE__)
+static void
+_binder_node_inner_unlock(struct binder_node *node, int line)
+{
+ struct binder_proc *proc = node->proc;
+
+ binder_debug(BINDER_DEBUG_SPINLOCKS,
+ "%s: line=%d\n", __func__, line);
+ if (proc)
+ binder_inner_proc_unlock(proc);
+ spin_unlock(&node->lock);
+}
+
+static bool binder_worklist_empty_ilocked(struct list_head *list)
+{
+ return list_empty(list);
+}
+
+/**
+ * binder_worklist_empty() - Check if no items on the work list
+ * @proc: binder_proc associated with list
+ * @list: list to check
+ *
+ * Return: true if there are no items on list, else false
+ */
+static bool binder_worklist_empty(struct binder_proc *proc,
+ struct list_head *list)
+{
+ bool ret;
+
+ binder_inner_proc_lock(proc);
+ ret = binder_worklist_empty_ilocked(list);
+ binder_inner_proc_unlock(proc);
+ return ret;
+}
+
+static void
+binder_enqueue_work_ilocked(struct binder_work *work,
+ struct list_head *target_list)
+{
+ BUG_ON(target_list == NULL);
+ BUG_ON(work->entry.next && !list_empty(&work->entry));
+ list_add_tail(&work->entry, target_list);
+}
+
+/**
+ * binder_enqueue_work() - Add an item to the work list
+ * @proc: binder_proc associated with list
+ * @work: struct binder_work to add to list
+ * @target_list: list to add work to
+ *
+ * Adds the work to the specified list. Asserts that work
+ * is not already on a list.
+ */
+static void
+binder_enqueue_work(struct binder_proc *proc,
+ struct binder_work *work,
+ struct list_head *target_list)
+{
+ binder_inner_proc_lock(proc);
+ binder_enqueue_work_ilocked(work, target_list);
+ binder_inner_proc_unlock(proc);
+}
+
+static void
+binder_dequeue_work_ilocked(struct binder_work *work)
+{
+ list_del_init(&work->entry);
+}
+
+/**
+ * binder_dequeue_work() - Removes an item from the work list
+ * @proc: binder_proc associated with list
+ * @work: struct binder_work to remove from list
+ *
+ * Removes the specified work item from whatever list it is on.
+ * Can safely be called if work is not on any list.
+ */
+static void
+binder_dequeue_work(struct binder_proc *proc, struct binder_work *work)
+{
+ binder_inner_proc_lock(proc);
+ binder_dequeue_work_ilocked(work);
+ binder_inner_proc_unlock(proc);
+}
+
+static struct binder_work *binder_dequeue_work_head_ilocked(
+ struct list_head *list)
+{
+ struct binder_work *w;
+
+ w = list_first_entry_or_null(list, struct binder_work, entry);
+ if (w)
+ list_del_init(&w->entry);
+ return w;
+}
+
+/**
+ * binder_dequeue_work_head() - Dequeues the item at head of list
+ * @proc: binder_proc associated with list
+ * @list: list to dequeue head
+ *
+ * Removes the head of the list if there are items on the list
+ *
+ * Return: pointer dequeued binder_work, NULL if list was empty
+ */
+static struct binder_work *binder_dequeue_work_head(
+ struct binder_proc *proc,
+ struct list_head *list)
+{
+ struct binder_work *w;
+
+ binder_inner_proc_lock(proc);
+ w = binder_dequeue_work_head_ilocked(list);
+ binder_inner_proc_unlock(proc);
+ return w;
+}
+
static void
binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer);
+static void binder_free_thread(struct binder_thread *thread);
+static void binder_free_proc(struct binder_proc *proc);
+static void binder_inc_node_tmpref_ilocked(struct binder_node *node);
static int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
{
struct files_struct *files = proc->files;
unsigned long rlim_cur;
unsigned long irqs;
- int ret;
if (files == NULL)
return -ESRCH;
@@ -417,11 +887,7 @@ static int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE);
unlock_task_sighand(proc->tsk, &irqs);
- preempt_enable_no_resched();
- ret = __alloc_fd(files, 0, rlim_cur, flags);
- preempt_disable();
-
- return ret;
+ return __alloc_fd(files, 0, rlim_cur, flags);
}
/*
@@ -430,11 +896,8 @@ static int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
static void task_fd_install(
struct binder_proc *proc, unsigned int fd, struct file *file)
{
- if (proc->files) {
- preempt_enable_no_resched();
+ if (proc->files)
__fd_install(proc->files, fd, file);
- preempt_disable();
- }
}
/*
@@ -458,74 +921,6 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd)
return retval;
}
-static inline void binder_lock(const char *tag)
-{
- trace_binder_lock(tag);
- mutex_lock(&binder_main_lock);
- preempt_disable();
- trace_binder_locked(tag);
-}
-
-static inline void binder_unlock(const char *tag)
-{
- trace_binder_unlock(tag);
- mutex_unlock(&binder_main_lock);
- preempt_enable();
-}
-
-static inline void *kzalloc_preempt_disabled(size_t size)
-{
- void *ptr;
-
- ptr = kzalloc(size, GFP_NOWAIT);
- if (ptr)
- return ptr;
-
- preempt_enable_no_resched();
- ptr = kzalloc(size, GFP_KERNEL);
- preempt_disable();
-
- return ptr;
-}
-
-static inline long copy_to_user_preempt_disabled(void __user *to, const void *from, long n)
-{
- long ret;
-
- preempt_enable_no_resched();
- ret = copy_to_user(to, from, n);
- preempt_disable();
- return ret;
-}
-
-static inline long copy_from_user_preempt_disabled(void *to, const void __user *from, long n)
-{
- long ret;
-
- preempt_enable_no_resched();
- ret = copy_from_user(to, from, n);
- preempt_disable();
- return ret;
-}
-
-#define get_user_preempt_disabled(x, ptr) \
-({ \
- int __ret; \
- preempt_enable_no_resched(); \
- __ret = get_user(x, ptr); \
- preempt_disable(); \
- __ret; \
-})
-
-#define put_user_preempt_disabled(x, ptr) \
-({ \
- int __ret; \
- preempt_enable_no_resched(); \
- __ret = put_user(x, ptr); \
- preempt_disable(); \
- __ret; \
-})
-
static void binder_set_nice(long nice)
{
long min_nice;
@@ -544,439 +939,14 @@ static void binder_set_nice(long nice)
binder_user_error("%d RLIMIT_NICE not set\n", current->pid);
}
-static size_t binder_buffer_size(struct binder_proc *proc,
- struct binder_buffer *buffer)
-{
- if (list_is_last(&buffer->entry, &proc->buffers))
- return proc->buffer + proc->buffer_size - (void *)buffer->data;
- return (size_t)list_entry(buffer->entry.next,
- struct binder_buffer, entry) - (size_t)buffer->data;
-}
-
-static void binder_insert_free_buffer(struct binder_proc *proc,
- struct binder_buffer *new_buffer)
-{
- struct rb_node **p = &proc->free_buffers.rb_node;
- struct rb_node *parent = NULL;
- struct binder_buffer *buffer;
- size_t buffer_size;
- size_t new_buffer_size;
-
- BUG_ON(!new_buffer->free);
-
- new_buffer_size = binder_buffer_size(proc, new_buffer);
-
- binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: add free buffer, size %zd, at %p\n",
- proc->pid, new_buffer_size, new_buffer);
-
- while (*p) {
- parent = *p;
- buffer = rb_entry(parent, struct binder_buffer, rb_node);
- BUG_ON(!buffer->free);
-
- buffer_size = binder_buffer_size(proc, buffer);
-
- if (new_buffer_size < buffer_size)
- p = &parent->rb_left;
- else
- p = &parent->rb_right;
- }
- rb_link_node(&new_buffer->rb_node, parent, p);
- rb_insert_color(&new_buffer->rb_node, &proc->free_buffers);
-}
-
-static void binder_insert_allocated_buffer(struct binder_proc *proc,
- struct binder_buffer *new_buffer)
-{
- struct rb_node **p = &proc->allocated_buffers.rb_node;
- struct rb_node *parent = NULL;
- struct binder_buffer *buffer;
-
- BUG_ON(new_buffer->free);
-
- while (*p) {
- parent = *p;
- buffer = rb_entry(parent, struct binder_buffer, rb_node);
- BUG_ON(buffer->free);
-
- if (new_buffer < buffer)
- p = &parent->rb_left;
- else if (new_buffer > buffer)
- p = &parent->rb_right;
- else
- BUG();
- }
- rb_link_node(&new_buffer->rb_node, parent, p);
- rb_insert_color(&new_buffer->rb_node, &proc->allocated_buffers);
-}
-
-static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc,
- uintptr_t user_ptr)
-{
- struct rb_node *n = proc->allocated_buffers.rb_node;
- struct binder_buffer *buffer;
- struct binder_buffer *kern_ptr;
-
- kern_ptr = (struct binder_buffer *)(user_ptr - proc->user_buffer_offset
- - offsetof(struct binder_buffer, data));
-
- while (n) {
- buffer = rb_entry(n, struct binder_buffer, rb_node);
- BUG_ON(buffer->free);
-
- if (kern_ptr < buffer)
- n = n->rb_left;
- else if (kern_ptr > buffer)
- n = n->rb_right;
- else
- return buffer;
- }
- return NULL;
-}
-
-static int binder_update_page_range(struct binder_proc *proc, int allocate,
- void *start, void *end,
- struct vm_area_struct *vma)
-{
- void *page_addr;
- unsigned long user_page_addr;
- struct page **page;
- struct mm_struct *mm;
-
- binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: %s pages %p-%p\n", proc->pid,
- allocate ? "allocate" : "free", start, end);
-
- if (end <= start)
- return 0;
-
- trace_binder_update_page_range(proc, allocate, start, end);
-
- if (vma)
- mm = NULL;
- else
- mm = get_task_mm(proc->tsk);
-
- preempt_enable_no_resched();
-
- if (mm) {
- down_write(&mm->mmap_sem);
- vma = proc->vma;
- if (vma && mm != proc->vma_vm_mm) {
- pr_err("%d: vma mm and task mm mismatch\n",
- proc->pid);
- vma = NULL;
- }
- }
-
- if (allocate == 0)
- goto free_range;
-
- if (vma == NULL) {
- pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n",
- proc->pid);
- goto err_no_vma;
- }
-
- for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
- int ret;
-
- page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE];
-
- BUG_ON(*page);
- *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
- if (*page == NULL) {
- pr_err("%d: binder_alloc_buf failed for page at %p\n",
- proc->pid, page_addr);
- goto err_alloc_page_failed;
- }
- ret = map_kernel_range_noflush((unsigned long)page_addr,
- PAGE_SIZE, PAGE_KERNEL, page);
- flush_cache_vmap((unsigned long)page_addr,
- (unsigned long)page_addr + PAGE_SIZE);
- if (ret != 1) {
- pr_err("%d: binder_alloc_buf failed to map page at %p in kernel\n",
- proc->pid, page_addr);
- goto err_map_kernel_failed;
- }
- user_page_addr =
- (uintptr_t)page_addr + proc->user_buffer_offset;
- ret = vm_insert_page(vma, user_page_addr, page[0]);
- if (ret) {
- pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n",
- proc->pid, user_page_addr);
- goto err_vm_insert_page_failed;
- }
- /* vm_insert_page does not seem to increment the refcount */
- }
- if (mm) {
- up_write(&mm->mmap_sem);
- mmput(mm);
- }
-
- preempt_disable();
-
- return 0;
-
-free_range:
- for (page_addr = end - PAGE_SIZE; page_addr >= start;
- page_addr -= PAGE_SIZE) {
- page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE];
- if (vma)
- zap_page_range(vma, (uintptr_t)page_addr +
- proc->user_buffer_offset, PAGE_SIZE, NULL);
-err_vm_insert_page_failed:
- unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
-err_map_kernel_failed:
- __free_page(*page);
- *page = NULL;
-err_alloc_page_failed:
- ;
- }
-err_no_vma:
- if (mm) {
- up_write(&mm->mmap_sem);
- mmput(mm);
- }
-
- preempt_disable();
-
- return -ENOMEM;
-}
-
-static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
- size_t data_size,
- size_t offsets_size,
- size_t extra_buffers_size,
- int is_async)
-{
- struct rb_node *n = proc->free_buffers.rb_node;
- struct binder_buffer *buffer;
- size_t buffer_size;
- struct rb_node *best_fit = NULL;
- void *has_page_addr;
- void *end_page_addr;
- size_t size, data_offsets_size;
-
- if (proc->vma == NULL) {
- pr_err("%d: binder_alloc_buf, no vma\n",
- proc->pid);
- return NULL;
- }
-
- data_offsets_size = ALIGN(data_size, sizeof(void *)) +
- ALIGN(offsets_size, sizeof(void *));
-
- if (data_offsets_size < data_size || data_offsets_size < offsets_size) {
- binder_user_error("%d: got transaction with invalid size %zd-%zd\n",
- proc->pid, data_size, offsets_size);
- return NULL;
- }
- size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *));
- if (size < data_offsets_size || size < extra_buffers_size) {
- binder_user_error("%d: got transaction with invalid extra_buffers_size %zd\n",
- proc->pid, extra_buffers_size);
- return NULL;
- }
- if (is_async &&
- proc->free_async_space < size + sizeof(struct binder_buffer)) {
- binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: binder_alloc_buf size %zd failed, no async space left\n",
- proc->pid, size);
- return NULL;
- }
-
- while (n) {
- buffer = rb_entry(n, struct binder_buffer, rb_node);
- BUG_ON(!buffer->free);
- buffer_size = binder_buffer_size(proc, buffer);
-
- if (size < buffer_size) {
- best_fit = n;
- n = n->rb_left;
- } else if (size > buffer_size)
- n = n->rb_right;
- else {
- best_fit = n;
- break;
- }
- }
- if (best_fit == NULL) {
- pr_err("%d: binder_alloc_buf size %zd failed, no address space\n",
- proc->pid, size);
- return NULL;
- }
- if (n == NULL) {
- buffer = rb_entry(best_fit, struct binder_buffer, rb_node);
- buffer_size = binder_buffer_size(proc, buffer);
- }
-
- binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: binder_alloc_buf size %zd got buffer %p size %zd\n",
- proc->pid, size, buffer, buffer_size);
-
- 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);
- }
- end_page_addr =
- (void *)PAGE_ALIGN((uintptr_t)buffer->data + buffer_size);
- if (end_page_addr > has_page_addr)
- end_page_addr = has_page_addr;
- if (binder_update_page_range(proc, 1,
- (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL))
- return NULL;
-
- rb_erase(best_fit, &proc->free_buffers);
- buffer->free = 0;
- binder_insert_allocated_buffer(proc, buffer);
- if (buffer_size != size) {
- struct binder_buffer *new_buffer = (void *)buffer->data + size;
-
- list_add(&new_buffer->entry, &buffer->entry);
- new_buffer->free = 1;
- binder_insert_free_buffer(proc, new_buffer);
- }
- binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: binder_alloc_buf size %zd got %p\n",
- proc->pid, size, buffer);
- buffer->data_size = data_size;
- buffer->offsets_size = offsets_size;
- buffer->extra_buffers_size = extra_buffers_size;
- buffer->async_transaction = is_async;
- if (is_async) {
- proc->free_async_space -= size + sizeof(struct binder_buffer);
- binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
- "%d: binder_alloc_buf size %zd async free %zd\n",
- proc->pid, size, proc->free_async_space);
- }
-
- return buffer;
-}
-
-static void *buffer_start_page(struct binder_buffer *buffer)
-{
- return (void *)((uintptr_t)buffer & PAGE_MASK);
-}
-
-static void *buffer_end_page(struct binder_buffer *buffer)
-{
- return (void *)(((uintptr_t)(buffer + 1) - 1) & PAGE_MASK);
-}
-
-static void binder_delete_free_buffer(struct binder_proc *proc,
- struct binder_buffer *buffer)
-{
- struct binder_buffer *prev, *next = NULL;
- int free_page_end = 1;
- int free_page_start = 1;
-
- BUG_ON(proc->buffers.next == &buffer->entry);
- prev = list_entry(buffer->entry.prev, struct binder_buffer, entry);
- 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;
- binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %p share page with %p\n",
- proc->pid, buffer, prev);
- }
-
- if (!list_is_last(&buffer->entry, &proc->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;
- binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %p share page with %p\n",
- proc->pid, buffer, prev);
- }
- }
- list_del(&buffer->entry);
- if (free_page_start || free_page_end) {
- binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %p do not share page%s%s with %p or %p\n",
- proc->pid, buffer, free_page_start ? "" : " end",
- free_page_end ? "" : " start", prev, next);
- binder_update_page_range(proc, 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);
- }
-}
-
-static void binder_free_buf(struct binder_proc *proc,
- struct binder_buffer *buffer)
-{
- size_t size, buffer_size;
-
- buffer_size = binder_buffer_size(proc, buffer);
-
- size = ALIGN(buffer->data_size, sizeof(void *)) +
- ALIGN(buffer->offsets_size, sizeof(void *)) +
- ALIGN(buffer->extra_buffers_size, sizeof(void *));
-
- binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: binder_free_buf %p size %zd buffer_size %zd\n",
- proc->pid, buffer, size, buffer_size);
-
- BUG_ON(buffer->free);
- BUG_ON(size > buffer_size);
- BUG_ON(buffer->transaction != NULL);
- BUG_ON((void *)buffer < proc->buffer);
- BUG_ON((void *)buffer > proc->buffer + proc->buffer_size);
-
- if (buffer->async_transaction) {
- proc->free_async_space += size + sizeof(struct binder_buffer);
-
- binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
- "%d: binder_free_buf size %zd async free %zd\n",
- proc->pid, size, proc->free_async_space);
- }
-
- binder_update_page_range(proc, 0,
- (void *)PAGE_ALIGN((uintptr_t)buffer->data),
- (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK),
- NULL);
- rb_erase(&buffer->rb_node, &proc->allocated_buffers);
- buffer->free = 1;
- if (!list_is_last(&buffer->entry, &proc->buffers)) {
- struct binder_buffer *next = list_entry(buffer->entry.next,
- struct binder_buffer, entry);
-
- if (next->free) {
- rb_erase(&next->rb_node, &proc->free_buffers);
- binder_delete_free_buffer(proc, next);
- }
- }
- if (proc->buffers.next != &buffer->entry) {
- struct binder_buffer *prev = list_entry(buffer->entry.prev,
- struct binder_buffer, entry);
-
- if (prev->free) {
- binder_delete_free_buffer(proc, buffer);
- rb_erase(&prev->rb_node, &proc->free_buffers);
- buffer = prev;
- }
- }
- binder_insert_free_buffer(proc, buffer);
-}
-
-static struct binder_node *binder_get_node(struct binder_proc *proc,
- binder_uintptr_t ptr)
+static struct binder_node *binder_get_node_ilocked(struct binder_proc *proc,
+ binder_uintptr_t ptr)
{
struct rb_node *n = proc->nodes.rb_node;
struct binder_node *node;
+ BUG_ON(!spin_is_locked(&proc->inner_lock));
+
while (n) {
node = rb_entry(n, struct binder_node, rb_node);
@@ -984,21 +954,45 @@ static struct binder_node *binder_get_node(struct binder_proc *proc,
n = n->rb_left;
else if (ptr > node->ptr)
n = n->rb_right;
- else
+ else {
+ /*
+ * take an implicit weak reference
+ * to ensure node stays alive until
+ * call to binder_put_node()
+ */
+ binder_inc_node_tmpref_ilocked(node);
return node;
+ }
}
return NULL;
}
-static struct binder_node *binder_new_node(struct binder_proc *proc,
- binder_uintptr_t ptr,
- binder_uintptr_t cookie)
+static struct binder_node *binder_get_node(struct binder_proc *proc,
+ binder_uintptr_t ptr)
+{
+ struct binder_node *node;
+
+ binder_inner_proc_lock(proc);
+ node = binder_get_node_ilocked(proc, ptr);
+ binder_inner_proc_unlock(proc);
+ return node;
+}
+
+static struct binder_node *binder_init_node_ilocked(
+ struct binder_proc *proc,
+ struct binder_node *new_node,
+ struct flat_binder_object *fp)
{
struct rb_node **p = &proc->nodes.rb_node;
struct rb_node *parent = NULL;
struct binder_node *node;
+ binder_uintptr_t ptr = fp ? fp->binder : 0;
+ binder_uintptr_t cookie = fp ? fp->cookie : 0;
+ __u32 flags = fp ? fp->flags : 0;
+ BUG_ON(!spin_is_locked(&proc->inner_lock));
while (*p) {
+
parent = *p;
node = rb_entry(parent, struct binder_node, rb_node);
@@ -1006,33 +1000,74 @@ static struct binder_node *binder_new_node(struct binder_proc *proc,
p = &(*p)->rb_left;
else if (ptr > node->ptr)
p = &(*p)->rb_right;
- else
- return NULL;
+ else {
+ /*
+ * A matching node is already in
+ * the rb tree. Abandon the init
+ * and return it.
+ */
+ binder_inc_node_tmpref_ilocked(node);
+ return node;
+ }
}
-
- node = kzalloc_preempt_disabled(sizeof(*node));
- if (node == NULL)
- return NULL;
+ node = new_node;
binder_stats_created(BINDER_STAT_NODE);
+ node->tmp_refs++;
rb_link_node(&node->rb_node, parent, p);
rb_insert_color(&node->rb_node, &proc->nodes);
- node->debug_id = ++binder_last_id;
+ node->debug_id = atomic_inc_return(&binder_last_id);
node->proc = proc;
node->ptr = ptr;
node->cookie = cookie;
node->work.type = BINDER_WORK_NODE;
+ node->min_priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
+ node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
+ spin_lock_init(&node->lock);
INIT_LIST_HEAD(&node->work.entry);
INIT_LIST_HEAD(&node->async_todo);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"%d:%d node %d u%016llx c%016llx created\n",
proc->pid, current->pid, node->debug_id,
(u64)node->ptr, (u64)node->cookie);
+
return node;
}
-static int binder_inc_node(struct binder_node *node, int strong, int internal,
- struct list_head *target_list)
+static struct binder_node *binder_new_node(struct binder_proc *proc,
+ struct flat_binder_object *fp)
{
+ struct binder_node *node;
+ struct binder_node *new_node = kzalloc(sizeof(*node), GFP_KERNEL);
+
+ if (!new_node)
+ return NULL;
+ binder_inner_proc_lock(proc);
+ node = binder_init_node_ilocked(proc, new_node, fp);
+ binder_inner_proc_unlock(proc);
+ if (node != new_node)
+ /*
+ * The node was already added by another thread
+ */
+ kfree(new_node);
+
+ return node;
+}
+
+static void binder_free_node(struct binder_node *node)
+{
+ kfree(node);
+ binder_stats_deleted(BINDER_STAT_NODE);
+}
+
+static int binder_inc_node_nilocked(struct binder_node *node, int strong,
+ int internal,
+ struct list_head *target_list)
+{
+ struct binder_proc *proc = node->proc;
+
+ BUG_ON(!spin_is_locked(&node->lock));
+ if (proc)
+ BUG_ON(!spin_is_locked(&proc->inner_lock));
if (strong) {
if (internal) {
if (target_list == NULL &&
@@ -1049,8 +1084,8 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal,
} else
node->local_strong_refs++;
if (!node->has_strong_ref && target_list) {
- list_del_init(&node->work.entry);
- list_add_tail(&node->work.entry, target_list);
+ binder_dequeue_work_ilocked(&node->work);
+ binder_enqueue_work_ilocked(&node->work, target_list);
}
} else {
if (!internal)
@@ -1061,58 +1096,169 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal,
node->debug_id);
return -EINVAL;
}
- list_add_tail(&node->work.entry, target_list);
+ binder_enqueue_work_ilocked(&node->work, target_list);
}
}
return 0;
}
-static int binder_dec_node(struct binder_node *node, int strong, int internal)
+static int binder_inc_node(struct binder_node *node, int strong, int internal,
+ struct list_head *target_list)
{
+ int ret;
+
+ binder_node_inner_lock(node);
+ ret = binder_inc_node_nilocked(node, strong, internal, target_list);
+ binder_node_inner_unlock(node);
+
+ return ret;
+}
+
+static bool binder_dec_node_nilocked(struct binder_node *node,
+ int strong, int internal)
+{
+ struct binder_proc *proc = node->proc;
+
+ BUG_ON(!spin_is_locked(&node->lock));
+ if (proc)
+ BUG_ON(!spin_is_locked(&proc->inner_lock));
if (strong) {
if (internal)
node->internal_strong_refs--;
else
node->local_strong_refs--;
if (node->local_strong_refs || node->internal_strong_refs)
- return 0;
+ return false;
} else {
if (!internal)
node->local_weak_refs--;
- if (node->local_weak_refs || !hlist_empty(&node->refs))
- return 0;
+ if (node->local_weak_refs || node->tmp_refs ||
+ !hlist_empty(&node->refs))
+ return false;
}
- if (node->proc && (node->has_strong_ref || node->has_weak_ref)) {
+
+ if (proc && (node->has_strong_ref || node->has_weak_ref)) {
if (list_empty(&node->work.entry)) {
- list_add_tail(&node->work.entry, &node->proc->todo);
+ binder_enqueue_work_ilocked(&node->work, &proc->todo);
wake_up_interruptible(&node->proc->wait);
}
} else {
if (hlist_empty(&node->refs) && !node->local_strong_refs &&
- !node->local_weak_refs) {
- list_del_init(&node->work.entry);
- if (node->proc) {
- rb_erase(&node->rb_node, &node->proc->nodes);
+ !node->local_weak_refs && !node->tmp_refs) {
+ if (proc) {
+ binder_dequeue_work_ilocked(&node->work);
+ rb_erase(&node->rb_node, &proc->nodes);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"refless node %d deleted\n",
node->debug_id);
} else {
+ BUG_ON(!list_empty(&node->work.entry));
+ spin_lock(&binder_dead_nodes_lock);
+ /*
+ * tmp_refs could have changed so
+ * check it again
+ */
+ if (node->tmp_refs) {
+ spin_unlock(&binder_dead_nodes_lock);
+ return false;
+ }
hlist_del(&node->dead_node);
+ spin_unlock(&binder_dead_nodes_lock);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"dead node %d deleted\n",
node->debug_id);
}
- kfree(node);
- binder_stats_deleted(BINDER_STAT_NODE);
+ return true;
}
}
-
- return 0;
+ return false;
}
+static void binder_dec_node(struct binder_node *node, int strong, int internal)
+{
+ bool free_node;
-static struct binder_ref *binder_get_ref(struct binder_proc *proc,
- u32 desc, bool need_strong_ref)
+ binder_node_inner_lock(node);
+ free_node = binder_dec_node_nilocked(node, strong, internal);
+ binder_node_inner_unlock(node);
+ if (free_node)
+ binder_free_node(node);
+}
+
+static void binder_inc_node_tmpref_ilocked(struct binder_node *node)
+{
+ /*
+ * No call to binder_inc_node() is needed since we
+ * don't need to inform userspace of any changes to
+ * tmp_refs
+ */
+ node->tmp_refs++;
+}
+
+/**
+ * binder_inc_node_tmpref() - take a temporary reference on node
+ * @node: node to reference
+ *
+ * Take reference on node to prevent the node from being freed
+ * while referenced only by a local variable. The inner lock is
+ * needed to serialize with the node work on the queue (which
+ * isn't needed after the node is dead). If the node is dead
+ * (node->proc is NULL), use binder_dead_nodes_lock to protect
+ * node->tmp_refs against dead-node-only cases where the node
+ * lock cannot be acquired (eg traversing the dead node list to
+ * print nodes)
+ */
+static void binder_inc_node_tmpref(struct binder_node *node)
+{
+ binder_node_lock(node);
+ if (node->proc)
+ binder_inner_proc_lock(node->proc);
+ else
+ spin_lock(&binder_dead_nodes_lock);
+ binder_inc_node_tmpref_ilocked(node);
+ if (node->proc)
+ binder_inner_proc_unlock(node->proc);
+ else
+ spin_unlock(&binder_dead_nodes_lock);
+ binder_node_unlock(node);
+}
+
+/**
+ * binder_dec_node_tmpref() - remove a temporary reference on node
+ * @node: node to reference
+ *
+ * Release temporary reference on node taken via binder_inc_node_tmpref()
+ */
+static void binder_dec_node_tmpref(struct binder_node *node)
+{
+ bool free_node;
+
+ binder_node_inner_lock(node);
+ if (!node->proc)
+ spin_lock(&binder_dead_nodes_lock);
+ node->tmp_refs--;
+ BUG_ON(node->tmp_refs < 0);
+ if (!node->proc)
+ spin_unlock(&binder_dead_nodes_lock);
+ /*
+ * Call binder_dec_node() to check if all refcounts are 0
+ * and cleanup is needed. Calling with strong=0 and internal=1
+ * causes no actual reference to be released in binder_dec_node().
+ * If that changes, a change is needed here too.
+ */
+ free_node = binder_dec_node_nilocked(node, 0, 1);
+ binder_node_inner_unlock(node);
+ if (free_node)
+ binder_free_node(node);
+}
+
+static void binder_put_node(struct binder_node *node)
+{
+ binder_dec_node_tmpref(node);
+}
+
+static struct binder_ref *binder_get_ref_olocked(struct binder_proc *proc,
+ u32 desc, bool need_strong_ref)
{
struct rb_node *n = proc->refs_by_desc.rb_node;
struct binder_ref *ref;
@@ -1120,11 +1266,11 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc,
while (n) {
ref = rb_entry(n, struct binder_ref, rb_node_desc);
- if (desc < ref->desc) {
+ if (desc < ref->data.desc) {
n = n->rb_left;
- } else if (desc > ref->desc) {
+ } else if (desc > ref->data.desc) {
n = n->rb_right;
- } else if (need_strong_ref && !ref->strong) {
+ } else if (need_strong_ref && !ref->data.strong) {
binder_user_error("tried to use weak ref as strong ref\n");
return NULL;
} else {
@@ -1134,14 +1280,34 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc,
return NULL;
}
-static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
- struct binder_node *node)
+/**
+ * binder_get_ref_for_node_olocked() - get the ref associated with given node
+ * @proc: binder_proc that owns the ref
+ * @node: binder_node of target
+ * @new_ref: newly allocated binder_ref to be initialized or %NULL
+ *
+ * Look up the ref for the given node and return it if it exists
+ *
+ * If it doesn't exist and the caller provides a newly allocated
+ * ref, initialize the fields of the newly allocated ref and insert
+ * into the given proc rb_trees and node refs list.
+ *
+ * Return: the ref for node. It is possible that another thread
+ * allocated/initialized the ref first in which case the
+ * returned ref would be different than the passed-in
+ * new_ref. new_ref must be kfree'd by the caller in
+ * this case.
+ */
+static struct binder_ref *binder_get_ref_for_node_olocked(
+ struct binder_proc *proc,
+ struct binder_node *node,
+ struct binder_ref *new_ref)
{
- struct rb_node *n;
+ struct binder_context *context = proc->context;
struct rb_node **p = &proc->refs_by_node.rb_node;
struct rb_node *parent = NULL;
- struct binder_ref *ref, *new_ref;
- struct binder_context *context = proc->context;
+ struct binder_ref *ref;
+ struct rb_node *n;
while (*p) {
parent = *p;
@@ -1154,22 +1320,22 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
else
return ref;
}
- new_ref = kzalloc_preempt_disabled(sizeof(*ref));
- if (new_ref == NULL)
+ if (!new_ref)
return NULL;
+
binder_stats_created(BINDER_STAT_REF);
- new_ref->debug_id = ++binder_last_id;
+ new_ref->data.debug_id = atomic_inc_return(&binder_last_id);
new_ref->proc = proc;
new_ref->node = node;
rb_link_node(&new_ref->rb_node_node, parent, p);
rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node);
- new_ref->desc = (node == context->binder_context_mgr_node) ? 0 : 1;
+ new_ref->data.desc = (node == context->binder_context_mgr_node) ? 0 : 1;
for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) {
ref = rb_entry(n, struct binder_ref, rb_node_desc);
- if (ref->desc > new_ref->desc)
+ if (ref->data.desc > new_ref->data.desc)
break;
- new_ref->desc = ref->desc + 1;
+ new_ref->data.desc = ref->data.desc + 1;
}
p = &proc->refs_by_desc.rb_node;
@@ -1177,121 +1343,423 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
parent = *p;
ref = rb_entry(parent, struct binder_ref, rb_node_desc);
- if (new_ref->desc < ref->desc)
+ if (new_ref->data.desc < ref->data.desc)
p = &(*p)->rb_left;
- else if (new_ref->desc > ref->desc)
+ else if (new_ref->data.desc > ref->data.desc)
p = &(*p)->rb_right;
else
BUG();
}
rb_link_node(&new_ref->rb_node_desc, parent, p);
rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc);
- if (node) {
- hlist_add_head(&new_ref->node_entry, &node->refs);
- binder_debug(BINDER_DEBUG_INTERNAL_REFS,
- "%d new ref %d desc %d for node %d\n",
- proc->pid, new_ref->debug_id, new_ref->desc,
- node->debug_id);
- } else {
- binder_debug(BINDER_DEBUG_INTERNAL_REFS,
- "%d new ref %d desc %d for dead node\n",
- proc->pid, new_ref->debug_id, new_ref->desc);
- }
+ binder_node_lock(node);
+ hlist_add_head(&new_ref->node_entry, &node->refs);
+
+ binder_debug(BINDER_DEBUG_INTERNAL_REFS,
+ "%d new ref %d desc %d for node %d\n",
+ proc->pid, new_ref->data.debug_id, new_ref->data.desc,
+ node->debug_id);
+ binder_node_unlock(node);
return new_ref;
}
-static void binder_delete_ref(struct binder_ref *ref)
+static void binder_cleanup_ref_olocked(struct binder_ref *ref)
{
+ bool delete_node = false;
+
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"%d delete ref %d desc %d for node %d\n",
- ref->proc->pid, ref->debug_id, ref->desc,
+ ref->proc->pid, ref->data.debug_id, ref->data.desc,
ref->node->debug_id);
rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc);
rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node);
- if (ref->strong)
- binder_dec_node(ref->node, 1, 1);
+
+ binder_node_inner_lock(ref->node);
+ if (ref->data.strong)
+ binder_dec_node_nilocked(ref->node, 1, 1);
+
hlist_del(&ref->node_entry);
- binder_dec_node(ref->node, 0, 1);
+ delete_node = binder_dec_node_nilocked(ref->node, 0, 1);
+ binder_node_inner_unlock(ref->node);
+ /*
+ * Clear ref->node unless we want the caller to free the node
+ */
+ if (!delete_node) {
+ /*
+ * The caller uses ref->node to determine
+ * whether the node needs to be freed. Clear
+ * it since the node is still alive.
+ */
+ ref->node = NULL;
+ }
+
if (ref->death) {
binder_debug(BINDER_DEBUG_DEAD_BINDER,
"%d delete ref %d desc %d has death notification\n",
- ref->proc->pid, ref->debug_id, ref->desc);
- list_del(&ref->death->work.entry);
- kfree(ref->death);
+ ref->proc->pid, ref->data.debug_id,
+ ref->data.desc);
+ binder_dequeue_work(ref->proc, &ref->death->work);
binder_stats_deleted(BINDER_STAT_DEATH);
}
- kfree(ref);
binder_stats_deleted(BINDER_STAT_REF);
}
-static int binder_inc_ref(struct binder_ref *ref, int strong,
- struct list_head *target_list)
+/**
+ * binder_inc_ref_olocked() - increment the ref for given handle
+ * @ref: ref to be incremented
+ * @strong: if true, strong increment, else weak
+ * @target_list: list to queue node work on
+ *
+ * Increment the ref. @ref->proc->outer_lock must be held on entry
+ *
+ * Return: 0, if successful, else errno
+ */
+static int binder_inc_ref_olocked(struct binder_ref *ref, int strong,
+ struct list_head *target_list)
{
int ret;
if (strong) {
- if (ref->strong == 0) {
+ if (ref->data.strong == 0) {
ret = binder_inc_node(ref->node, 1, 1, target_list);
if (ret)
return ret;
}
- ref->strong++;
+ ref->data.strong++;
} else {
- if (ref->weak == 0) {
+ if (ref->data.weak == 0) {
ret = binder_inc_node(ref->node, 0, 1, target_list);
if (ret)
return ret;
}
- ref->weak++;
+ ref->data.weak++;
}
return 0;
}
-
-static int binder_dec_ref(struct binder_ref *ref, int strong)
+/**
+ * binder_dec_ref() - dec the ref for given handle
+ * @ref: ref to be decremented
+ * @strong: if true, strong decrement, else weak
+ *
+ * Decrement the ref.
+ *
+ * Return: true if ref is cleaned up and ready to be freed
+ */
+static bool binder_dec_ref_olocked(struct binder_ref *ref, int strong)
{
if (strong) {
- if (ref->strong == 0) {
+ if (ref->data.strong == 0) {
binder_user_error("%d invalid dec strong, ref %d desc %d s %d w %d\n",
- ref->proc->pid, ref->debug_id,
- ref->desc, ref->strong, ref->weak);
- return -EINVAL;
+ ref->proc->pid, ref->data.debug_id,
+ ref->data.desc, ref->data.strong,
+ ref->data.weak);
+ return false;
}
- ref->strong--;
- if (ref->strong == 0) {
- int ret;
-
- ret = binder_dec_node(ref->node, strong, 1);
- if (ret)
- return ret;
- }
+ ref->data.strong--;
+ if (ref->data.strong == 0)
+ binder_dec_node(ref->node, strong, 1);
} else {
- if (ref->weak == 0) {
+ if (ref->data.weak == 0) {
binder_user_error("%d invalid dec weak, ref %d desc %d s %d w %d\n",
- ref->proc->pid, ref->debug_id,
- ref->desc, ref->strong, ref->weak);
- return -EINVAL;
+ ref->proc->pid, ref->data.debug_id,
+ ref->data.desc, ref->data.strong,
+ ref->data.weak);
+ return false;
}
- ref->weak--;
+ ref->data.weak--;
}
- if (ref->strong == 0 && ref->weak == 0)
- binder_delete_ref(ref);
- return 0;
+ if (ref->data.strong == 0 && ref->data.weak == 0) {
+ binder_cleanup_ref_olocked(ref);
+ return true;
+ }
+ return false;
}
-static void binder_pop_transaction(struct binder_thread *target_thread,
- struct binder_transaction *t)
+/**
+ * binder_get_node_from_ref() - get the node from the given proc/desc
+ * @proc: proc containing the ref
+ * @desc: the handle associated with the ref
+ * @need_strong_ref: if true, only return node if ref is strong
+ * @rdata: the id/refcount data for the ref
+ *
+ * Given a proc and ref handle, return the associated binder_node
+ *
+ * Return: a binder_node or NULL if not found or not strong when strong required
+ */
+static struct binder_node *binder_get_node_from_ref(
+ struct binder_proc *proc,
+ u32 desc, bool need_strong_ref,
+ struct binder_ref_data *rdata)
{
- if (target_thread) {
- BUG_ON(target_thread->transaction_stack != t);
- BUG_ON(target_thread->transaction_stack->from != target_thread);
- target_thread->transaction_stack =
- target_thread->transaction_stack->from_parent;
- t->from = NULL;
+ struct binder_node *node;
+ struct binder_ref *ref;
+
+ binder_proc_lock(proc);
+ ref = binder_get_ref_olocked(proc, desc, need_strong_ref);
+ if (!ref)
+ goto err_no_ref;
+ node = ref->node;
+ /*
+ * Take an implicit reference on the node to ensure
+ * it stays alive until the call to binder_put_node()
+ */
+ binder_inc_node_tmpref(node);
+ if (rdata)
+ *rdata = ref->data;
+ binder_proc_unlock(proc);
+
+ return node;
+
+err_no_ref:
+ binder_proc_unlock(proc);
+ return NULL;
+}
+
+/**
+ * binder_free_ref() - free the binder_ref
+ * @ref: ref to free
+ *
+ * Free the binder_ref. Free the binder_node indicated by ref->node
+ * (if non-NULL) and the binder_ref_death indicated by ref->death.
+ */
+static void binder_free_ref(struct binder_ref *ref)
+{
+ if (ref->node)
+ binder_free_node(ref->node);
+ kfree(ref->death);
+ kfree(ref);
+}
+
+/**
+ * binder_update_ref_for_handle() - inc/dec the ref for given handle
+ * @proc: proc containing the ref
+ * @desc: the handle associated with the ref
+ * @increment: true=inc reference, false=dec reference
+ * @strong: true=strong reference, false=weak reference
+ * @rdata: the id/refcount data for the ref
+ *
+ * Given a proc and ref handle, increment or decrement the ref
+ * according to "increment" arg.
+ *
+ * Return: 0 if successful, else errno
+ */
+static int binder_update_ref_for_handle(struct binder_proc *proc,
+ uint32_t desc, bool increment, bool strong,
+ struct binder_ref_data *rdata)
+{
+ int ret = 0;
+ struct binder_ref *ref;
+ bool delete_ref = false;
+
+ binder_proc_lock(proc);
+ ref = binder_get_ref_olocked(proc, desc, strong);
+ if (!ref) {
+ ret = -EINVAL;
+ goto err_no_ref;
}
- t->need_reply = 0;
+ if (increment)
+ ret = binder_inc_ref_olocked(ref, strong, NULL);
+ else
+ delete_ref = binder_dec_ref_olocked(ref, strong);
+
+ if (rdata)
+ *rdata = ref->data;
+ binder_proc_unlock(proc);
+
+ if (delete_ref)
+ binder_free_ref(ref);
+ return ret;
+
+err_no_ref:
+ binder_proc_unlock(proc);
+ return ret;
+}
+
+/**
+ * binder_dec_ref_for_handle() - dec the ref for given handle
+ * @proc: proc containing the ref
+ * @desc: the handle associated with the ref
+ * @strong: true=strong reference, false=weak reference
+ * @rdata: the id/refcount data for the ref
+ *
+ * Just calls binder_update_ref_for_handle() to decrement the ref.
+ *
+ * Return: 0 if successful, else errno
+ */
+static int binder_dec_ref_for_handle(struct binder_proc *proc,
+ uint32_t desc, bool strong, struct binder_ref_data *rdata)
+{
+ return binder_update_ref_for_handle(proc, desc, false, strong, rdata);
+}
+
+
+/**
+ * binder_inc_ref_for_node() - increment the ref for given proc/node
+ * @proc: proc containing the ref
+ * @node: target node
+ * @strong: true=strong reference, false=weak reference
+ * @target_list: worklist to use if node is incremented
+ * @rdata: the id/refcount data for the ref
+ *
+ * Given a proc and node, increment the ref. Create the ref if it
+ * doesn't already exist
+ *
+ * Return: 0 if successful, else errno
+ */
+static int binder_inc_ref_for_node(struct binder_proc *proc,
+ struct binder_node *node,
+ bool strong,
+ struct list_head *target_list,
+ struct binder_ref_data *rdata)
+{
+ struct binder_ref *ref;
+ struct binder_ref *new_ref = NULL;
+ int ret = 0;
+
+ binder_proc_lock(proc);
+ ref = binder_get_ref_for_node_olocked(proc, node, NULL);
+ if (!ref) {
+ binder_proc_unlock(proc);
+ new_ref = kzalloc(sizeof(*ref), GFP_KERNEL);
+ if (!new_ref)
+ return -ENOMEM;
+ binder_proc_lock(proc);
+ ref = binder_get_ref_for_node_olocked(proc, node, new_ref);
+ }
+ ret = binder_inc_ref_olocked(ref, strong, target_list);
+ *rdata = ref->data;
+ binder_proc_unlock(proc);
+ if (new_ref && ref != new_ref)
+ /*
+ * Another thread created the ref first so
+ * free the one we allocated
+ */
+ kfree(new_ref);
+ return ret;
+}
+
+static void binder_pop_transaction_ilocked(struct binder_thread *target_thread,
+ struct binder_transaction *t)
+{
+ BUG_ON(!target_thread);
+ BUG_ON(!spin_is_locked(&target_thread->proc->inner_lock));
+ BUG_ON(target_thread->transaction_stack != t);
+ BUG_ON(target_thread->transaction_stack->from != target_thread);
+ target_thread->transaction_stack =
+ target_thread->transaction_stack->from_parent;
+ t->from = NULL;
+}
+
+/**
+ * binder_thread_dec_tmpref() - decrement thread->tmp_ref
+ * @thread: thread to decrement
+ *
+ * A thread needs to be kept alive while being used to create or
+ * handle a transaction. binder_get_txn_from() is used to safely
+ * extract t->from from a binder_transaction and keep the thread
+ * indicated by t->from from being freed. When done with that
+ * binder_thread, this function is called to decrement the
+ * tmp_ref and free if appropriate (thread has been released
+ * and no transaction being processed by the driver)
+ */
+static void binder_thread_dec_tmpref(struct binder_thread *thread)
+{
+ /*
+ * atomic is used to protect the counter value while
+ * it cannot reach zero or thread->is_dead is false
+ */
+ binder_inner_proc_lock(thread->proc);
+ atomic_dec(&thread->tmp_ref);
+ if (thread->is_dead && !atomic_read(&thread->tmp_ref)) {
+ binder_inner_proc_unlock(thread->proc);
+ binder_free_thread(thread);
+ return;
+ }
+ binder_inner_proc_unlock(thread->proc);
+}
+
+/**
+ * binder_proc_dec_tmpref() - decrement proc->tmp_ref
+ * @proc: proc to decrement
+ *
+ * A binder_proc needs to be kept alive while being used to create or
+ * handle a transaction. proc->tmp_ref is incremented when
+ * creating a new transaction or the binder_proc is currently in-use
+ * by threads that are being released. When done with the binder_proc,
+ * this function is called to decrement the counter and free the
+ * proc if appropriate (proc has been released, all threads have
+ * been released and not currenly in-use to process a transaction).
+ */
+static void binder_proc_dec_tmpref(struct binder_proc *proc)
+{
+ binder_inner_proc_lock(proc);
+ proc->tmp_ref--;
+ if (proc->is_dead && RB_EMPTY_ROOT(&proc->threads) &&
+ !proc->tmp_ref) {
+ binder_inner_proc_unlock(proc);
+ binder_free_proc(proc);
+ return;
+ }
+ binder_inner_proc_unlock(proc);
+}
+
+/**
+ * binder_get_txn_from() - safely extract the "from" thread in transaction
+ * @t: binder transaction for t->from
+ *
+ * Atomically return the "from" thread and increment the tmp_ref
+ * count for the thread to ensure it stays alive until
+ * binder_thread_dec_tmpref() is called.
+ *
+ * Return: the value of t->from
+ */
+static struct binder_thread *binder_get_txn_from(
+ struct binder_transaction *t)
+{
+ struct binder_thread *from;
+
+ spin_lock(&t->lock);
+ from = t->from;
+ if (from)
+ atomic_inc(&from->tmp_ref);
+ spin_unlock(&t->lock);
+ return from;
+}
+
+/**
+ * binder_get_txn_from_and_acq_inner() - get t->from and acquire inner lock
+ * @t: binder transaction for t->from
+ *
+ * Same as binder_get_txn_from() except it also acquires the proc->inner_lock
+ * to guarantee that the thread cannot be released while operating on it.
+ * The caller must call binder_inner_proc_unlock() to release the inner lock
+ * as well as call binder_dec_thread_txn() to release the reference.
+ *
+ * Return: the value of t->from
+ */
+static struct binder_thread *binder_get_txn_from_and_acq_inner(
+ struct binder_transaction *t)
+{
+ struct binder_thread *from;
+
+ from = binder_get_txn_from(t);
+ if (!from)
+ return NULL;
+ binder_inner_proc_lock(from->proc);
+ if (t->from) {
+ BUG_ON(from != t->from);
+ return from;
+ }
+ binder_inner_proc_unlock(from->proc);
+ binder_thread_dec_tmpref(from);
+ return NULL;
+}
+
+static void binder_free_transaction(struct binder_transaction *t)
+{
if (t->buffer)
t->buffer->transaction = NULL;
kfree(t);
@@ -1306,30 +1774,28 @@ static void binder_send_failed_reply(struct binder_transaction *t,
BUG_ON(t->flags & TF_ONE_WAY);
while (1) {
- target_thread = t->from;
+ target_thread = binder_get_txn_from_and_acq_inner(t);
if (target_thread) {
- if (target_thread->return_error != BR_OK &&
- target_thread->return_error2 == BR_OK) {
- target_thread->return_error2 =
- target_thread->return_error;
- target_thread->return_error = BR_OK;
- }
- if (target_thread->return_error == BR_OK) {
- binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
- "send failed reply for transaction %d to %d:%d\n",
- t->debug_id,
- target_thread->proc->pid,
- target_thread->pid);
+ binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
+ "send failed reply for transaction %d to %d:%d\n",
+ t->debug_id,
+ target_thread->proc->pid,
+ target_thread->pid);
- binder_pop_transaction(target_thread, t);
- target_thread->return_error = error_code;
+ binder_pop_transaction_ilocked(target_thread, t);
+ if (target_thread->reply_error.cmd == BR_OK) {
+ target_thread->reply_error.cmd = error_code;
+ binder_enqueue_work_ilocked(
+ &target_thread->reply_error.work,
+ &target_thread->todo);
wake_up_interruptible(&target_thread->wait);
} else {
- pr_err("reply failed, target thread, %d:%d, has error code %d already\n",
- target_thread->proc->pid,
- target_thread->pid,
- target_thread->return_error);
+ WARN(1, "Unexpected reply error: %u\n",
+ target_thread->reply_error.cmd);
}
+ binder_inner_proc_unlock(target_thread->proc);
+ binder_thread_dec_tmpref(target_thread);
+ binder_free_transaction(t);
return;
}
next = t->from_parent;
@@ -1338,7 +1804,7 @@ static void binder_send_failed_reply(struct binder_transaction *t,
"send failed reply for transaction %d, target dead\n",
t->debug_id);
- binder_pop_transaction(target_thread, t);
+ binder_free_transaction(t);
if (next == NULL) {
binder_debug(BINDER_DEBUG_DEAD_BINDER,
"reply failed, no target thread at root\n");
@@ -1547,24 +2013,26 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
node->debug_id, (u64)node->ptr);
binder_dec_node(node, hdr->type == BINDER_TYPE_BINDER,
0);
+ binder_put_node(node);
} break;
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
struct flat_binder_object *fp;
- struct binder_ref *ref;
+ struct binder_ref_data rdata;
+ int ret;
fp = to_flat_binder_object(hdr);
- ref = binder_get_ref(proc, fp->handle,
- hdr->type == BINDER_TYPE_HANDLE);
- if (ref == NULL) {
- pr_err("transaction release %d bad handle %d\n",
- debug_id, fp->handle);
+ ret = binder_dec_ref_for_handle(proc, fp->handle,
+ hdr->type == BINDER_TYPE_HANDLE, &rdata);
+
+ if (ret) {
+ pr_err("transaction release %d bad handle %d, ret = %d\n",
+ debug_id, fp->handle, ret);
break;
}
binder_debug(BINDER_DEBUG_TRANSACTION,
- " ref %d desc %d (node %d)\n",
- ref->debug_id, ref->desc, ref->node->debug_id);
- binder_dec_ref(ref, hdr->type == BINDER_TYPE_HANDLE);
+ " ref %d desc %d\n",
+ rdata.debug_id, rdata.desc);
} break;
case BINDER_TYPE_FD: {
@@ -1603,7 +2071,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
* back to kernel address space to access it
*/
parent_buffer = parent->buffer -
- proc->user_buffer_offset;
+ binder_alloc_get_user_buffer_offset(
+ &proc->alloc);
fd_buf_size = sizeof(u32) * fda->num_fds;
if (fda->num_fds >= SIZE_MAX / sizeof(u32)) {
@@ -1635,102 +2104,122 @@ static int binder_translate_binder(struct flat_binder_object *fp,
struct binder_thread *thread)
{
struct binder_node *node;
- struct binder_ref *ref;
struct binder_proc *proc = thread->proc;
struct binder_proc *target_proc = t->to_proc;
+ struct binder_ref_data rdata;
+ int ret = 0;
node = binder_get_node(proc, fp->binder);
if (!node) {
- node = binder_new_node(proc, fp->binder, fp->cookie);
+ node = binder_new_node(proc, fp);
if (!node)
return -ENOMEM;
-
- node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
- node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
}
if (fp->cookie != node->cookie) {
binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n",
proc->pid, thread->pid, (u64)fp->binder,
node->debug_id, (u64)fp->cookie,
(u64)node->cookie);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
- if (security_binder_transfer_binder(proc->tsk, target_proc->tsk))
- return -EPERM;
+ if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+ ret = -EPERM;
+ goto done;
+ }
- ref = binder_get_ref_for_node(target_proc, node);
- if (!ref)
- return -EINVAL;
+ ret = binder_inc_ref_for_node(target_proc, node,
+ fp->hdr.type == BINDER_TYPE_BINDER,
+ &thread->todo, &rdata);
+ if (ret)
+ goto done;
if (fp->hdr.type == BINDER_TYPE_BINDER)
fp->hdr.type = BINDER_TYPE_HANDLE;
else
fp->hdr.type = BINDER_TYPE_WEAK_HANDLE;
fp->binder = 0;
- fp->handle = ref->desc;
+ fp->handle = rdata.desc;
fp->cookie = 0;
- binder_inc_ref(ref, fp->hdr.type == BINDER_TYPE_HANDLE, &thread->todo);
- trace_binder_transaction_node_to_ref(t, node, ref);
+ trace_binder_transaction_node_to_ref(t, node, &rdata);
binder_debug(BINDER_DEBUG_TRANSACTION,
" node %d u%016llx -> ref %d desc %d\n",
node->debug_id, (u64)node->ptr,
- ref->debug_id, ref->desc);
-
- return 0;
+ rdata.debug_id, rdata.desc);
+done:
+ binder_put_node(node);
+ return ret;
}
static int binder_translate_handle(struct flat_binder_object *fp,
struct binder_transaction *t,
struct binder_thread *thread)
{
- struct binder_ref *ref;
struct binder_proc *proc = thread->proc;
struct binder_proc *target_proc = t->to_proc;
+ struct binder_node *node;
+ struct binder_ref_data src_rdata;
+ int ret = 0;
- ref = binder_get_ref(proc, fp->handle,
- fp->hdr.type == BINDER_TYPE_HANDLE);
- if (!ref) {
+ node = binder_get_node_from_ref(proc, fp->handle,
+ fp->hdr.type == BINDER_TYPE_HANDLE, &src_rdata);
+ if (!node) {
binder_user_error("%d:%d got transaction with invalid handle, %d\n",
proc->pid, thread->pid, fp->handle);
return -EINVAL;
}
- if (security_binder_transfer_binder(proc->tsk, target_proc->tsk))
- return -EPERM;
+ if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+ ret = -EPERM;
+ goto done;
+ }
- if (ref->node->proc == target_proc) {
+ binder_node_lock(node);
+ if (node->proc == target_proc) {
if (fp->hdr.type == BINDER_TYPE_HANDLE)
fp->hdr.type = BINDER_TYPE_BINDER;
else
fp->hdr.type = BINDER_TYPE_WEAK_BINDER;
- fp->binder = ref->node->ptr;
- fp->cookie = ref->node->cookie;
- binder_inc_node(ref->node, fp->hdr.type == BINDER_TYPE_BINDER,
- 0, NULL);
- trace_binder_transaction_ref_to_node(t, ref);
+ fp->binder = node->ptr;
+ fp->cookie = node->cookie;
+ if (node->proc)
+ binder_inner_proc_lock(node->proc);
+ binder_inc_node_nilocked(node,
+ fp->hdr.type == BINDER_TYPE_BINDER,
+ 0, NULL);
+ if (node->proc)
+ binder_inner_proc_unlock(node->proc);
+ trace_binder_transaction_ref_to_node(t, node, &src_rdata);
binder_debug(BINDER_DEBUG_TRANSACTION,
" ref %d desc %d -> node %d u%016llx\n",
- ref->debug_id, ref->desc, ref->node->debug_id,
- (u64)ref->node->ptr);
+ src_rdata.debug_id, src_rdata.desc, node->debug_id,
+ (u64)node->ptr);
+ binder_node_unlock(node);
} else {
- struct binder_ref *new_ref;
+ int ret;
+ struct binder_ref_data dest_rdata;
- new_ref = binder_get_ref_for_node(target_proc, ref->node);
- if (!new_ref)
- return -EINVAL;
+ binder_node_unlock(node);
+ ret = binder_inc_ref_for_node(target_proc, node,
+ fp->hdr.type == BINDER_TYPE_HANDLE,
+ NULL, &dest_rdata);
+ if (ret)
+ goto done;
fp->binder = 0;
- fp->handle = new_ref->desc;
+ fp->handle = dest_rdata.desc;
fp->cookie = 0;
- binder_inc_ref(new_ref, fp->hdr.type == BINDER_TYPE_HANDLE,
- NULL);
- trace_binder_transaction_ref_to_ref(t, ref, new_ref);
+ trace_binder_transaction_ref_to_ref(t, node, &src_rdata,
+ &dest_rdata);
binder_debug(BINDER_DEBUG_TRANSACTION,
" ref %d desc %d -> ref %d desc %d (node %d)\n",
- ref->debug_id, ref->desc, new_ref->debug_id,
- new_ref->desc, ref->node->debug_id);
+ src_rdata.debug_id, src_rdata.desc,
+ dest_rdata.debug_id, dest_rdata.desc,
+ node->debug_id);
}
- return 0;
+done:
+ binder_put_node(node);
+ return ret;
}
static int binder_translate_fd(int fd,
@@ -1765,9 +2254,7 @@ static int binder_translate_fd(int fd,
ret = -EBADF;
goto err_fget;
}
- preempt_enable_no_resched();
ret = security_binder_transfer_file(proc->tsk, target_proc->tsk, file);
- preempt_disable();
if (ret < 0) {
ret = -EPERM;
goto err_security;
@@ -1823,7 +2310,8 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda,
* Since the parent was already fixed up, convert it
* back to the kernel address space to access it
*/
- parent_buffer = parent->buffer - target_proc->user_buffer_offset;
+ parent_buffer = parent->buffer -
+ binder_alloc_get_user_buffer_offset(&target_proc->alloc);
fd_array = (u32 *)(parent_buffer + fda->parent_offset);
if (!IS_ALIGNED((unsigned long)fd_array, sizeof(u32))) {
binder_user_error("%d:%d parent offset not aligned correctly.\n",
@@ -1891,7 +2379,8 @@ static int binder_fixup_parent(struct binder_transaction *t,
return -EINVAL;
}
parent_buffer = (u8 *)(parent->buffer -
- target_proc->user_buffer_offset);
+ binder_alloc_get_user_buffer_offset(
+ &target_proc->alloc));
*(binder_uintptr_t *)(parent_buffer + bp->parent_offset) = bp->buffer;
return 0;
@@ -1908,19 +2397,23 @@ static void binder_transaction(struct binder_proc *proc,
binder_size_t *offp, *off_end, *off_start;
binder_size_t off_min;
u8 *sg_bufp, *sg_buf_end;
- struct binder_proc *target_proc;
+ struct binder_proc *target_proc = NULL;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
struct list_head *target_list;
wait_queue_head_t *target_wait;
struct binder_transaction *in_reply_to = NULL;
struct binder_transaction_log_entry *e;
- uint32_t return_error;
+ uint32_t return_error = 0;
+ uint32_t return_error_param = 0;
+ uint32_t return_error_line = 0;
struct binder_buffer_object *last_fixup_obj = NULL;
binder_size_t last_fixup_min_off = 0;
struct binder_context *context = proc->context;
+ int t_debug_id = atomic_inc_return(&binder_last_id);
e = binder_transaction_log_add(&binder_transaction_log);
+ e->debug_id = t_debug_id;
e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY);
e->from_proc = proc->pid;
e->from_thread = thread->pid;
@@ -1930,29 +2423,40 @@ static void binder_transaction(struct binder_proc *proc,
e->context_name = proc->context->name;
if (reply) {
+ binder_inner_proc_lock(proc);
in_reply_to = thread->transaction_stack;
if (in_reply_to == NULL) {
+ binder_inner_proc_unlock(proc);
binder_user_error("%d:%d got reply transaction with no transaction stack\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EPROTO;
+ return_error_line = __LINE__;
goto err_empty_call_stack;
}
- binder_set_nice(in_reply_to->saved_priority);
if (in_reply_to->to_thread != thread) {
+ spin_lock(&in_reply_to->lock);
binder_user_error("%d:%d got reply transaction with bad transaction stack, transaction %d has target %d:%d\n",
proc->pid, thread->pid, in_reply_to->debug_id,
in_reply_to->to_proc ?
in_reply_to->to_proc->pid : 0,
in_reply_to->to_thread ?
in_reply_to->to_thread->pid : 0);
+ spin_unlock(&in_reply_to->lock);
+ binder_inner_proc_unlock(proc);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EPROTO;
+ return_error_line = __LINE__;
in_reply_to = NULL;
goto err_bad_call_stack;
}
thread->transaction_stack = in_reply_to->to_parent;
- target_thread = in_reply_to->from;
+ binder_inner_proc_unlock(proc);
+ binder_set_nice(in_reply_to->saved_priority);
+ target_thread = binder_get_txn_from_and_acq_inner(in_reply_to);
if (target_thread == NULL) {
return_error = BR_DEAD_REPLY;
+ return_error_line = __LINE__;
goto err_dead_binder;
}
if (target_thread->transaction_stack != in_reply_to) {
@@ -1961,61 +2465,111 @@ static void binder_transaction(struct binder_proc *proc,
target_thread->transaction_stack ?
target_thread->transaction_stack->debug_id : 0,
in_reply_to->debug_id);
+ binder_inner_proc_unlock(target_thread->proc);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EPROTO;
+ return_error_line = __LINE__;
in_reply_to = NULL;
target_thread = NULL;
goto err_dead_binder;
}
target_proc = target_thread->proc;
+ target_proc->tmp_ref++;
+ binder_inner_proc_unlock(target_thread->proc);
} else {
if (tr->target.handle) {
struct binder_ref *ref;
- ref = binder_get_ref(proc, tr->target.handle, true);
- if (ref == NULL) {
+ /*
+ * There must already be a strong ref
+ * on this node. If so, do a strong
+ * increment on the node to ensure it
+ * stays alive until the transaction is
+ * done.
+ */
+ binder_proc_lock(proc);
+ ref = binder_get_ref_olocked(proc, tr->target.handle,
+ true);
+ if (ref) {
+ binder_inc_node(ref->node, 1, 0, NULL);
+ target_node = ref->node;
+ }
+ binder_proc_unlock(proc);
+ if (target_node == NULL) {
binder_user_error("%d:%d got transaction to invalid handle\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EINVAL;
+ return_error_line = __LINE__;
goto err_invalid_target_handle;
}
- target_node = ref->node;
} else {
+ mutex_lock(&context->context_mgr_node_lock);
target_node = context->binder_context_mgr_node;
if (target_node == NULL) {
return_error = BR_DEAD_REPLY;
+ mutex_unlock(&context->context_mgr_node_lock);
+ return_error_line = __LINE__;
goto err_no_context_mgr_node;
}
+ binder_inc_node(target_node, 1, 0, NULL);
+ mutex_unlock(&context->context_mgr_node_lock);
}
e->to_node = target_node->debug_id;
+ binder_node_lock(target_node);
target_proc = target_node->proc;
if (target_proc == NULL) {
+ binder_node_unlock(target_node);
return_error = BR_DEAD_REPLY;
+ return_error_line = __LINE__;
goto err_dead_binder;
}
+ binder_inner_proc_lock(target_proc);
+ target_proc->tmp_ref++;
+ binder_inner_proc_unlock(target_proc);
+ binder_node_unlock(target_node);
if (security_binder_transaction(proc->tsk,
target_proc->tsk) < 0) {
return_error = BR_FAILED_REPLY;
+ return_error_param = -EPERM;
+ return_error_line = __LINE__;
goto err_invalid_target_handle;
}
+ binder_inner_proc_lock(proc);
if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
struct binder_transaction *tmp;
tmp = thread->transaction_stack;
if (tmp->to_thread != thread) {
+ spin_lock(&tmp->lock);
binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n",
proc->pid, thread->pid, tmp->debug_id,
tmp->to_proc ? tmp->to_proc->pid : 0,
tmp->to_thread ?
tmp->to_thread->pid : 0);
+ spin_unlock(&tmp->lock);
+ binder_inner_proc_unlock(proc);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EPROTO;
+ return_error_line = __LINE__;
goto err_bad_call_stack;
}
while (tmp) {
- if (tmp->from && tmp->from->proc == target_proc)
- target_thread = tmp->from;
+ struct binder_thread *from;
+
+ spin_lock(&tmp->lock);
+ from = tmp->from;
+ if (from && from->proc == target_proc) {
+ atomic_inc(&from->tmp_ref);
+ target_thread = from;
+ spin_unlock(&tmp->lock);
+ break;
+ }
+ spin_unlock(&tmp->lock);
tmp = tmp->from_parent;
}
}
+ binder_inner_proc_unlock(proc);
}
if (target_thread) {
e->to_thread = target_thread->pid;
@@ -2028,22 +2582,26 @@ static void binder_transaction(struct binder_proc *proc,
e->to_proc = target_proc->pid;
/* TODO: reuse incoming transaction for reply */
- t = kzalloc_preempt_disabled(sizeof(*t));
+ t = kzalloc(sizeof(*t), GFP_KERNEL);
if (t == NULL) {
return_error = BR_FAILED_REPLY;
+ return_error_param = -ENOMEM;
+ return_error_line = __LINE__;
goto err_alloc_t_failed;
}
binder_stats_created(BINDER_STAT_TRANSACTION);
+ spin_lock_init(&t->lock);
- tcomplete = kzalloc_preempt_disabled(sizeof(*tcomplete));
+ tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
if (tcomplete == NULL) {
return_error = BR_FAILED_REPLY;
+ return_error_param = -ENOMEM;
+ return_error_line = __LINE__;
goto err_alloc_tcomplete_failed;
}
binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
- t->debug_id = ++binder_last_id;
- e->debug_id = t->debug_id;
+ t->debug_id = t_debug_id;
if (reply)
binder_debug(BINDER_DEBUG_TRANSACTION,
@@ -2077,11 +2635,18 @@ static void binder_transaction(struct binder_proc *proc,
trace_binder_transaction(reply, t, target_node);
- t->buffer = binder_alloc_buf(target_proc, tr->data_size,
+ t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
tr->offsets_size, extra_buffers_size,
!reply && (t->flags & TF_ONE_WAY));
- if (t->buffer == NULL) {
- return_error = BR_FAILED_REPLY;
+ if (IS_ERR(t->buffer)) {
+ /*
+ * -ESRCH indicates VMA cleared. The target is dying.
+ */
+ return_error_param = PTR_ERR(t->buffer);
+ return_error = return_error_param == -ESRCH ?
+ BR_DEAD_REPLY : BR_FAILED_REPLY;
+ return_error_line = __LINE__;
+ t->buffer = NULL;
goto err_binder_alloc_buf_failed;
}
t->buffer->allow_user_free = 0;
@@ -2089,31 +2654,34 @@ static void binder_transaction(struct binder_proc *proc,
t->buffer->transaction = t;
t->buffer->target_node = target_node;
trace_binder_transaction_alloc_buf(t->buffer);
- if (target_node)
- binder_inc_node(target_node, 1, 0, NULL);
-
off_start = (binder_size_t *)(t->buffer->data +
ALIGN(tr->data_size, sizeof(void *)));
offp = off_start;
- if (copy_from_user_preempt_disabled(t->buffer->data, (const void __user *)(uintptr_t)
+ if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
tr->data.ptr.buffer, tr->data_size)) {
binder_user_error("%d:%d got transaction with invalid data ptr\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EFAULT;
+ return_error_line = __LINE__;
goto err_copy_data_failed;
}
- if (copy_from_user_preempt_disabled(offp, (const void __user *)(uintptr_t)
+ if (copy_from_user(offp, (const void __user *)(uintptr_t)
tr->data.ptr.offsets, tr->offsets_size)) {
binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EFAULT;
+ return_error_line = __LINE__;
goto err_copy_data_failed;
}
if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) {
binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n",
proc->pid, thread->pid, (u64)tr->offsets_size);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EINVAL;
+ return_error_line = __LINE__;
goto err_bad_offset;
}
if (!IS_ALIGNED(extra_buffers_size, sizeof(u64))) {
@@ -2121,6 +2689,8 @@ static void binder_transaction(struct binder_proc *proc,
proc->pid, thread->pid,
(u64)extra_buffers_size);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EINVAL;
+ return_error_line = __LINE__;
goto err_bad_offset;
}
off_end = (void *)off_start + tr->offsets_size;
@@ -2137,6 +2707,8 @@ static void binder_transaction(struct binder_proc *proc,
(u64)off_min,
(u64)t->buffer->data_size);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EINVAL;
+ return_error_line = __LINE__;
goto err_bad_offset;
}
@@ -2151,6 +2723,8 @@ static void binder_transaction(struct binder_proc *proc,
ret = binder_translate_binder(fp, t, thread);
if (ret < 0) {
return_error = BR_FAILED_REPLY;
+ return_error_param = ret;
+ return_error_line = __LINE__;
goto err_translate_failed;
}
} break;
@@ -2162,6 +2736,8 @@ static void binder_transaction(struct binder_proc *proc,
ret = binder_translate_handle(fp, t, thread);
if (ret < 0) {
return_error = BR_FAILED_REPLY;
+ return_error_param = ret;
+ return_error_line = __LINE__;
goto err_translate_failed;
}
} break;
@@ -2173,6 +2749,8 @@ static void binder_transaction(struct binder_proc *proc,
if (target_fd < 0) {
return_error = BR_FAILED_REPLY;
+ return_error_param = target_fd;
+ return_error_line = __LINE__;
goto err_translate_failed;
}
fp->pad_binder = 0;
@@ -2189,6 +2767,8 @@ static void binder_transaction(struct binder_proc *proc,
binder_user_error("%d:%d got transaction with invalid parent offset or type\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EINVAL;
+ return_error_line = __LINE__;
goto err_bad_parent;
}
if (!binder_validate_fixup(t->buffer, off_start,
@@ -2198,12 +2778,16 @@ static void binder_transaction(struct binder_proc *proc,
binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EINVAL;
+ return_error_line = __LINE__;
goto err_bad_parent;
}
ret = binder_translate_fd_array(fda, parent, t, thread,
in_reply_to);
if (ret < 0) {
return_error = BR_FAILED_REPLY;
+ return_error_param = ret;
+ return_error_line = __LINE__;
goto err_translate_failed;
}
last_fixup_obj = parent;
@@ -2219,20 +2803,24 @@ static void binder_transaction(struct binder_proc *proc,
binder_user_error("%d:%d got transaction with too large buffer\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EINVAL;
+ return_error_line = __LINE__;
goto err_bad_offset;
}
- if (copy_from_user_preempt_disabled(
- sg_bufp,
- (const void __user *)(uintptr_t)
- bp->buffer, bp->length)) {
+ if (copy_from_user(sg_bufp,
+ (const void __user *)(uintptr_t)
+ bp->buffer, bp->length)) {
binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
proc->pid, thread->pid);
+ return_error_param = -EFAULT;
return_error = BR_FAILED_REPLY;
+ return_error_line = __LINE__;
goto err_copy_data_failed;
}
/* Fixup buffer pointer to target proc address space */
bp->buffer = (uintptr_t)sg_bufp +
- target_proc->user_buffer_offset;
+ binder_alloc_get_user_buffer_offset(
+ &target_proc->alloc);
sg_bufp += ALIGN(bp->length, sizeof(u64));
ret = binder_fixup_parent(t, thread, bp, off_start,
@@ -2241,6 +2829,8 @@ static void binder_transaction(struct binder_proc *proc,
last_fixup_min_off);
if (ret < 0) {
return_error = BR_FAILED_REPLY;
+ return_error_param = ret;
+ return_error_line = __LINE__;
goto err_translate_failed;
}
last_fixup_obj = bp;
@@ -2250,34 +2840,89 @@ static void binder_transaction(struct binder_proc *proc,
binder_user_error("%d:%d got transaction with invalid object type, %x\n",
proc->pid, thread->pid, hdr->type);
return_error = BR_FAILED_REPLY;
+ return_error_param = -EINVAL;
+ return_error_line = __LINE__;
goto err_bad_object_type;
}
}
+ tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
+ binder_enqueue_work(proc, tcomplete, &thread->todo);
+ t->work.type = BINDER_WORK_TRANSACTION;
+
if (reply) {
+ binder_inner_proc_lock(target_proc);
+ if (target_thread->is_dead) {
+ binder_inner_proc_unlock(target_proc);
+ goto err_dead_proc_or_thread;
+ }
BUG_ON(t->buffer->async_transaction != 0);
- binder_pop_transaction(target_thread, in_reply_to);
+ binder_pop_transaction_ilocked(target_thread, in_reply_to);
+ binder_enqueue_work_ilocked(&t->work, target_list);
+ binder_inner_proc_unlock(target_proc);
+ binder_free_transaction(in_reply_to);
} else if (!(t->flags & TF_ONE_WAY)) {
BUG_ON(t->buffer->async_transaction != 0);
+ binder_inner_proc_lock(proc);
t->need_reply = 1;
t->from_parent = thread->transaction_stack;
thread->transaction_stack = t;
+ binder_inner_proc_unlock(proc);
+ binder_inner_proc_lock(target_proc);
+ if (target_proc->is_dead ||
+ (target_thread && target_thread->is_dead)) {
+ binder_inner_proc_unlock(target_proc);
+ binder_inner_proc_lock(proc);
+ binder_pop_transaction_ilocked(thread, t);
+ binder_inner_proc_unlock(proc);
+ goto err_dead_proc_or_thread;
+ }
+ binder_enqueue_work_ilocked(&t->work, target_list);
+ binder_inner_proc_unlock(target_proc);
} else {
BUG_ON(target_node == NULL);
BUG_ON(t->buffer->async_transaction != 1);
+ binder_node_lock(target_node);
if (target_node->has_async_transaction) {
target_list = &target_node->async_todo;
target_wait = NULL;
} else
target_node->has_async_transaction = 1;
+ /*
+ * Test/set of has_async_transaction
+ * must be atomic with enqueue on
+ * async_todo
+ */
+ binder_inner_proc_lock(target_proc);
+ if (target_proc->is_dead ||
+ (target_thread && target_thread->is_dead)) {
+ binder_inner_proc_unlock(target_proc);
+ binder_node_unlock(target_node);
+ goto err_dead_proc_or_thread;
+ }
+ binder_enqueue_work_ilocked(&t->work, target_list);
+ binder_inner_proc_unlock(target_proc);
+ binder_node_unlock(target_node);
}
- t->work.type = BINDER_WORK_TRANSACTION;
- list_add_tail(&t->work.entry, target_list);
- tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
- list_add_tail(&tcomplete->entry, &thread->todo);
- if (target_wait)
- wake_up_interruptible(target_wait);
+ if (target_wait) {
+ if (reply || !(tr->flags & TF_ONE_WAY))
+ wake_up_interruptible_sync(target_wait);
+ else
+ wake_up_interruptible(target_wait);
+ }
+ if (target_thread)
+ binder_thread_dec_tmpref(target_thread);
+ binder_proc_dec_tmpref(target_proc);
+ /*
+ * write barrier to synchronize with initialization
+ * of log entry
+ */
+ smp_wmb();
+ WRITE_ONCE(e->debug_id_done, t_debug_id);
return;
+err_dead_proc_or_thread:
+ return_error = BR_DEAD_REPLY;
+ return_error_line = __LINE__;
err_translate_failed:
err_bad_object_type:
err_bad_offset:
@@ -2285,8 +2930,9 @@ static void binder_transaction(struct binder_proc *proc,
err_copy_data_failed:
trace_binder_transaction_failed_buffer_release(t->buffer);
binder_transaction_buffer_release(target_proc, t->buffer, offp);
+ target_node = NULL;
t->buffer->transaction = NULL;
- binder_free_buf(target_proc, t->buffer);
+ binder_alloc_free_buf(&target_proc->alloc, t->buffer);
err_binder_alloc_buf_failed:
kfree(tcomplete);
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
@@ -2299,24 +2945,49 @@ static void binder_transaction(struct binder_proc *proc,
err_dead_binder:
err_invalid_target_handle:
err_no_context_mgr_node:
+ if (target_thread)
+ binder_thread_dec_tmpref(target_thread);
+ if (target_proc)
+ binder_proc_dec_tmpref(target_proc);
+ if (target_node)
+ binder_dec_node(target_node, 1, 0);
+
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
- "%d:%d transaction failed %d, size %lld-%lld\n",
- proc->pid, thread->pid, return_error,
- (u64)tr->data_size, (u64)tr->offsets_size);
+ "%d:%d transaction failed %d/%d, size %lld-%lld line %d\n",
+ proc->pid, thread->pid, return_error, return_error_param,
+ (u64)tr->data_size, (u64)tr->offsets_size,
+ return_error_line);
{
struct binder_transaction_log_entry *fe;
+ e->return_error = return_error;
+ e->return_error_param = return_error_param;
+ e->return_error_line = return_error_line;
fe = binder_transaction_log_add(&binder_transaction_log_failed);
*fe = *e;
+ /*
+ * write barrier to synchronize with initialization
+ * of log entry
+ */
+ smp_wmb();
+ WRITE_ONCE(e->debug_id_done, t_debug_id);
+ WRITE_ONCE(fe->debug_id_done, t_debug_id);
}
- BUG_ON(thread->return_error != BR_OK);
+ BUG_ON(thread->return_error.cmd != BR_OK);
if (in_reply_to) {
- thread->return_error = BR_TRANSACTION_COMPLETE;
+ thread->return_error.cmd = BR_TRANSACTION_COMPLETE;
+ binder_enqueue_work(thread->proc,
+ &thread->return_error.work,
+ &thread->todo);
binder_send_failed_reply(in_reply_to, return_error);
- } else
- thread->return_error = return_error;
+ } else {
+ thread->return_error.cmd = return_error;
+ binder_enqueue_work(thread->proc,
+ &thread->return_error.work,
+ &thread->todo);
+ }
}
static int binder_thread_write(struct binder_proc *proc,
@@ -2330,15 +3001,17 @@ static int binder_thread_write(struct binder_proc *proc,
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
- while (ptr < end && thread->return_error == BR_OK) {
- if (get_user_preempt_disabled(cmd, (uint32_t __user *)ptr))
+ while (ptr < end && thread->return_error.cmd == BR_OK) {
+ int ret;
+
+ if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
- binder_stats.bc[_IOC_NR(cmd)]++;
- proc->stats.bc[_IOC_NR(cmd)]++;
- thread->stats.bc[_IOC_NR(cmd)]++;
+ atomic_inc(&binder_stats.bc[_IOC_NR(cmd)]);
+ atomic_inc(&proc->stats.bc[_IOC_NR(cmd)]);
+ atomic_inc(&thread->stats.bc[_IOC_NR(cmd)]);
}
switch (cmd) {
case BC_INCREFS:
@@ -2346,53 +3019,61 @@ static int binder_thread_write(struct binder_proc *proc,
case BC_RELEASE:
case BC_DECREFS: {
uint32_t target;
- struct binder_ref *ref;
const char *debug_string;
+ bool strong = cmd == BC_ACQUIRE || cmd == BC_RELEASE;
+ bool increment = cmd == BC_INCREFS || cmd == BC_ACQUIRE;
+ struct binder_ref_data rdata;
- if (get_user_preempt_disabled(target, (uint32_t __user *)ptr))
+ if (get_user(target, (uint32_t __user *)ptr))
return -EFAULT;
+
ptr += sizeof(uint32_t);
- if (target == 0 && context->binder_context_mgr_node &&
- (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {
- ref = binder_get_ref_for_node(proc,
- context->binder_context_mgr_node);
- if (ref->desc != target) {
- binder_user_error("%d:%d tried to acquire reference to desc 0, got %d instead\n",
- proc->pid, thread->pid,
- ref->desc);
- }
- } else
- ref = binder_get_ref(proc, target,
- cmd == BC_ACQUIRE ||
- cmd == BC_RELEASE);
- if (ref == NULL) {
- binder_user_error("%d:%d refcount change on invalid ref %d\n",
- proc->pid, thread->pid, target);
- break;
+ ret = -1;
+ if (increment && !target) {
+ struct binder_node *ctx_mgr_node;
+ mutex_lock(&context->context_mgr_node_lock);
+ ctx_mgr_node = context->binder_context_mgr_node;
+ if (ctx_mgr_node)
+ ret = binder_inc_ref_for_node(
+ proc, ctx_mgr_node,
+ strong, NULL, &rdata);
+ mutex_unlock(&context->context_mgr_node_lock);
+ }
+ if (ret)
+ ret = binder_update_ref_for_handle(
+ proc, target, increment, strong,
+ &rdata);
+ if (!ret && rdata.desc != target) {
+ binder_user_error("%d:%d tried to acquire reference to desc %d, got %d instead\n",
+ proc->pid, thread->pid,
+ target, rdata.desc);
}
switch (cmd) {
case BC_INCREFS:
debug_string = "IncRefs";
- binder_inc_ref(ref, 0, NULL);
break;
case BC_ACQUIRE:
debug_string = "Acquire";
- binder_inc_ref(ref, 1, NULL);
break;
case BC_RELEASE:
debug_string = "Release";
- binder_dec_ref(ref, 1);
break;
case BC_DECREFS:
default:
debug_string = "DecRefs";
- binder_dec_ref(ref, 0);
+ break;
+ }
+ if (ret) {
+ binder_user_error("%d:%d %s %d refcount change on invalid ref %d ret %d\n",
+ proc->pid, thread->pid, debug_string,
+ strong, target, ret);
break;
}
binder_debug(BINDER_DEBUG_USER_REFS,
- "%d:%d %s ref %d desc %d s %d w %d for node %d\n",
- proc->pid, thread->pid, debug_string, ref->debug_id,
- ref->desc, ref->strong, ref->weak, ref->node->debug_id);
+ "%d:%d %s ref %d desc %d s %d w %d\n",
+ proc->pid, thread->pid, debug_string,
+ rdata.debug_id, rdata.desc, rdata.strong,
+ rdata.weak);
break;
}
case BC_INCREFS_DONE:
@@ -2400,11 +3081,12 @@ static int binder_thread_write(struct binder_proc *proc,
binder_uintptr_t node_ptr;
binder_uintptr_t cookie;
struct binder_node *node;
+ bool free_node;
- if (get_user_preempt_disabled(node_ptr, (binder_uintptr_t __user *)ptr))
+ if (get_user(node_ptr, (binder_uintptr_t __user *)ptr))
return -EFAULT;
ptr += sizeof(binder_uintptr_t);
- if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr))
+ if (get_user(cookie, (binder_uintptr_t __user *)ptr))
return -EFAULT;
ptr += sizeof(binder_uintptr_t);
node = binder_get_node(proc, node_ptr);
@@ -2424,13 +3106,17 @@ static int binder_thread_write(struct binder_proc *proc,
"BC_INCREFS_DONE" : "BC_ACQUIRE_DONE",
(u64)node_ptr, node->debug_id,
(u64)cookie, (u64)node->cookie);
+ binder_put_node(node);
break;
}
+ binder_node_inner_lock(node);
if (cmd == BC_ACQUIRE_DONE) {
if (node->pending_strong_ref == 0) {
binder_user_error("%d:%d BC_ACQUIRE_DONE node %d has no pending acquire request\n",
proc->pid, thread->pid,
node->debug_id);
+ binder_node_inner_unlock(node);
+ binder_put_node(node);
break;
}
node->pending_strong_ref = 0;
@@ -2439,16 +3125,23 @@ static int binder_thread_write(struct binder_proc *proc,
binder_user_error("%d:%d BC_INCREFS_DONE node %d has no pending increfs request\n",
proc->pid, thread->pid,
node->debug_id);
+ binder_node_inner_unlock(node);
+ binder_put_node(node);
break;
}
node->pending_weak_ref = 0;
}
- binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0);
+ free_node = binder_dec_node_nilocked(node,
+ cmd == BC_ACQUIRE_DONE, 0);
+ WARN_ON(free_node);
binder_debug(BINDER_DEBUG_USER_REFS,
- "%d:%d %s node %d ls %d lw %d\n",
+ "%d:%d %s node %d ls %d lw %d tr %d\n",
proc->pid, thread->pid,
cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE",
- node->debug_id, node->local_strong_refs, node->local_weak_refs);
+ node->debug_id, node->local_strong_refs,
+ node->local_weak_refs, node->tmp_refs);
+ binder_node_inner_unlock(node);
+ binder_put_node(node);
break;
}
case BC_ATTEMPT_ACQUIRE:
@@ -2462,11 +3155,12 @@ static int binder_thread_write(struct binder_proc *proc,
binder_uintptr_t data_ptr;
struct binder_buffer *buffer;
- if (get_user_preempt_disabled(data_ptr, (binder_uintptr_t __user *)ptr))
+ if (get_user(data_ptr, (binder_uintptr_t __user *)ptr))
return -EFAULT;
ptr += sizeof(binder_uintptr_t);
- buffer = binder_buffer_lookup(proc, data_ptr);
+ buffer = binder_alloc_prepare_to_free(&proc->alloc,
+ data_ptr);
if (buffer == NULL) {
binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n",
proc->pid, thread->pid, (u64)data_ptr);
@@ -2488,15 +3182,25 @@ static int binder_thread_write(struct binder_proc *proc,
buffer->transaction = NULL;
}
if (buffer->async_transaction && buffer->target_node) {
- BUG_ON(!buffer->target_node->has_async_transaction);
- if (list_empty(&buffer->target_node->async_todo))
- buffer->target_node->has_async_transaction = 0;
+ struct binder_node *buf_node;
+ struct binder_work *w;
+
+ buf_node = buffer->target_node;
+ binder_node_inner_lock(buf_node);
+ BUG_ON(!buf_node->has_async_transaction);
+ BUG_ON(buf_node->proc != proc);
+ w = binder_dequeue_work_head_ilocked(
+ &buf_node->async_todo);
+ if (!w)
+ buf_node->has_async_transaction = 0;
else
- list_move_tail(buffer->target_node->async_todo.next, &thread->todo);
+ binder_enqueue_work_ilocked(
+ w, &thread->todo);
+ binder_node_inner_unlock(buf_node);
}
trace_binder_transaction_buffer_release(buffer);
binder_transaction_buffer_release(proc, buffer, NULL);
- binder_free_buf(proc, buffer);
+ binder_alloc_free_buf(&proc->alloc, buffer);
break;
}
@@ -2504,8 +3208,7 @@ static int binder_thread_write(struct binder_proc *proc,
case BC_REPLY_SG: {
struct binder_transaction_data_sg tr;
- if (copy_from_user_preempt_disabled(&tr, ptr,
- sizeof(tr)))
+ if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr.transaction_data,
@@ -2516,7 +3219,7 @@ static int binder_thread_write(struct binder_proc *proc,
case BC_REPLY: {
struct binder_transaction_data tr;
- if (copy_from_user_preempt_disabled(&tr, ptr, sizeof(tr)))
+ if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr,
@@ -2528,6 +3231,7 @@ static int binder_thread_write(struct binder_proc *proc,
binder_debug(BINDER_DEBUG_THREADS,
"%d:%d BC_REGISTER_LOOPER\n",
proc->pid, thread->pid);
+ binder_inner_proc_lock(proc);
if (thread->looper & BINDER_LOOPER_STATE_ENTERED) {
thread->looper |= BINDER_LOOPER_STATE_INVALID;
binder_user_error("%d:%d ERROR: BC_REGISTER_LOOPER called after BC_ENTER_LOOPER\n",
@@ -2541,6 +3245,7 @@ static int binder_thread_write(struct binder_proc *proc,
proc->requested_threads_started++;
}
thread->looper |= BINDER_LOOPER_STATE_REGISTERED;
+ binder_inner_proc_unlock(proc);
break;
case BC_ENTER_LOOPER:
binder_debug(BINDER_DEBUG_THREADS,
@@ -2565,15 +3270,37 @@ static int binder_thread_write(struct binder_proc *proc,
uint32_t target;
binder_uintptr_t cookie;
struct binder_ref *ref;
- struct binder_ref_death *death;
+ struct binder_ref_death *death = NULL;
- if (get_user_preempt_disabled(target, (uint32_t __user *)ptr))
+ if (get_user(target, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
- if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr))
+ if (get_user(cookie, (binder_uintptr_t __user *)ptr))
return -EFAULT;
ptr += sizeof(binder_uintptr_t);
- ref = binder_get_ref(proc, target, false);
+ if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
+ /*
+ * Allocate memory for death notification
+ * before taking lock
+ */
+ death = kzalloc(sizeof(*death), GFP_KERNEL);
+ if (death == NULL) {
+ WARN_ON(thread->return_error.cmd !=
+ BR_OK);
+ thread->return_error.cmd = BR_ERROR;
+ binder_enqueue_work(
+ thread->proc,
+ &thread->return_error.work,
+ &thread->todo);
+ binder_debug(
+ BINDER_DEBUG_FAILED_TRANSACTION,
+ "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n",
+ proc->pid, thread->pid);
+ break;
+ }
+ }
+ binder_proc_lock(proc);
+ ref = binder_get_ref_olocked(proc, target, false);
if (ref == NULL) {
binder_user_error("%d:%d %s invalid ref %d\n",
proc->pid, thread->pid,
@@ -2581,6 +3308,8 @@ static int binder_thread_write(struct binder_proc *proc,
"BC_REQUEST_DEATH_NOTIFICATION" :
"BC_CLEAR_DEATH_NOTIFICATION",
target);
+ binder_proc_unlock(proc);
+ kfree(death);
break;
}
@@ -2590,21 +3319,18 @@ static int binder_thread_write(struct binder_proc *proc,
cmd == BC_REQUEST_DEATH_NOTIFICATION ?
"BC_REQUEST_DEATH_NOTIFICATION" :
"BC_CLEAR_DEATH_NOTIFICATION",
- (u64)cookie, ref->debug_id, ref->desc,
- ref->strong, ref->weak, ref->node->debug_id);
+ (u64)cookie, ref->data.debug_id,
+ ref->data.desc, ref->data.strong,
+ ref->data.weak, ref->node->debug_id);
+ binder_node_lock(ref->node);
if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
if (ref->death) {
binder_user_error("%d:%d BC_REQUEST_DEATH_NOTIFICATION death notification already set\n",
proc->pid, thread->pid);
- break;
- }
- death = kzalloc_preempt_disabled(sizeof(*death));
- if (death == NULL) {
- thread->return_error = BR_ERROR;
- binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
- "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n",
- proc->pid, thread->pid);
+ binder_node_unlock(ref->node);
+ binder_proc_unlock(proc);
+ kfree(death);
break;
}
binder_stats_created(BINDER_STAT_DEATH);
@@ -2613,17 +3339,28 @@ static int binder_thread_write(struct binder_proc *proc,
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)) {
- list_add_tail(&ref->death->work.entry, &thread->todo);
- } else {
- list_add_tail(&ref->death->work.entry, &proc->todo);
- wake_up_interruptible(&proc->wait);
+ if (thread->looper &
+ (BINDER_LOOPER_STATE_REGISTERED |
+ BINDER_LOOPER_STATE_ENTERED))
+ binder_enqueue_work(
+ proc,
+ &ref->death->work,
+ &thread->todo);
+ else {
+ binder_enqueue_work(
+ proc,
+ &ref->death->work,
+ &proc->todo);
+ wake_up_interruptible(
+ &proc->wait);
}
}
} else {
if (ref->death == NULL) {
binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification not active\n",
proc->pid, thread->pid);
+ binder_node_unlock(ref->node);
+ binder_proc_unlock(proc);
break;
}
death = ref->death;
@@ -2632,33 +3369,52 @@ static int binder_thread_write(struct binder_proc *proc,
proc->pid, thread->pid,
(u64)death->cookie,
(u64)cookie);
+ binder_node_unlock(ref->node);
+ binder_proc_unlock(proc);
break;
}
ref->death = NULL;
+ binder_inner_proc_lock(proc);
if (list_empty(&death->work.entry)) {
death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION;
- if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
- list_add_tail(&death->work.entry, &thread->todo);
- } else {
- list_add_tail(&death->work.entry, &proc->todo);
- wake_up_interruptible(&proc->wait);
+ if (thread->looper &
+ (BINDER_LOOPER_STATE_REGISTERED |
+ BINDER_LOOPER_STATE_ENTERED))
+ binder_enqueue_work_ilocked(
+ &death->work,
+ &thread->todo);
+ else {
+ binder_enqueue_work_ilocked(
+ &death->work,
+ &proc->todo);
+ wake_up_interruptible(
+ &proc->wait);
}
} else {
BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER);
death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR;
}
+ binder_inner_proc_unlock(proc);
}
+ binder_node_unlock(ref->node);
+ binder_proc_unlock(proc);
} break;
case BC_DEAD_BINDER_DONE: {
struct binder_work *w;
binder_uintptr_t cookie;
struct binder_ref_death *death = NULL;
- if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr))
+
+ if (get_user(cookie, (binder_uintptr_t __user *)ptr))
return -EFAULT;
ptr += sizeof(cookie);
- list_for_each_entry(w, &proc->delivered_death, entry) {
- struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work);
+ binder_inner_proc_lock(proc);
+ list_for_each_entry(w, &proc->delivered_death,
+ entry) {
+ struct binder_ref_death *tmp_death =
+ container_of(w,
+ struct binder_ref_death,
+ work);
if (tmp_death->cookie == cookie) {
death = tmp_death;
@@ -2672,21 +3428,26 @@ static int binder_thread_write(struct binder_proc *proc,
if (death == NULL) {
binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n",
proc->pid, thread->pid, (u64)cookie);
+ binder_inner_proc_unlock(proc);
break;
}
-
- list_del_init(&death->work.entry);
+ binder_dequeue_work_ilocked(&death->work);
if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) {
death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION;
- if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
- list_add_tail(&death->work.entry, &thread->todo);
- } else {
- list_add_tail(&death->work.entry, &proc->todo);
+ if (thread->looper &
+ (BINDER_LOOPER_STATE_REGISTERED |
+ BINDER_LOOPER_STATE_ENTERED))
+ binder_enqueue_work_ilocked(
+ &death->work, &thread->todo);
+ else {
+ binder_enqueue_work_ilocked(
+ &death->work,
+ &proc->todo);
wake_up_interruptible(&proc->wait);
}
}
- }
- break;
+ binder_inner_proc_unlock(proc);
+ } break;
default:
pr_err("%d:%d unknown command %d\n",
@@ -2703,23 +3464,54 @@ static void binder_stat_br(struct binder_proc *proc,
{
trace_binder_return(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) {
- binder_stats.br[_IOC_NR(cmd)]++;
- proc->stats.br[_IOC_NR(cmd)]++;
- thread->stats.br[_IOC_NR(cmd)]++;
+ atomic_inc(&binder_stats.br[_IOC_NR(cmd)]);
+ atomic_inc(&proc->stats.br[_IOC_NR(cmd)]);
+ atomic_inc(&thread->stats.br[_IOC_NR(cmd)]);
}
}
static int binder_has_proc_work(struct binder_proc *proc,
struct binder_thread *thread)
{
- return !list_empty(&proc->todo) ||
- (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN);
+ return !binder_worklist_empty(proc, &proc->todo) ||
+ thread->looper_need_return;
}
static int binder_has_thread_work(struct binder_thread *thread)
{
- return !list_empty(&thread->todo) || thread->return_error != BR_OK ||
- (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN);
+ 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,
+ binder_uintptr_t node_ptr,
+ binder_uintptr_t node_cookie,
+ int node_debug_id,
+ uint32_t cmd, const char *cmd_name)
+{
+ void __user *ptr = *ptrp;
+
+ if (put_user(cmd, (uint32_t __user *)ptr))
+ return -EFAULT;
+ ptr += sizeof(uint32_t);
+
+ if (put_user(node_ptr, (binder_uintptr_t __user *)ptr))
+ return -EFAULT;
+ ptr += sizeof(binder_uintptr_t);
+
+ if (put_user(node_cookie, (binder_uintptr_t __user *)ptr))
+ return -EFAULT;
+ ptr += sizeof(binder_uintptr_t);
+
+ binder_stat_br(proc, thread, cmd);
+ binder_debug(BINDER_DEBUG_USER_REFS, "%d:%d %s %d u%016llx c%016llx\n",
+ proc->pid, thread->pid, cmd_name, node_debug_id,
+ (u64)node_ptr, (u64)node_cookie);
+
+ *ptrp = ptr;
+ return 0;
}
static int binder_thread_read(struct binder_proc *proc,
@@ -2735,43 +3527,24 @@ static int binder_thread_read(struct binder_proc *proc,
int wait_for_proc_work;
if (*consumed == 0) {
- if (put_user_preempt_disabled(BR_NOOP, (uint32_t __user *)ptr))
+ if (put_user(BR_NOOP, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
}
retry:
+ binder_inner_proc_lock(proc);
wait_for_proc_work = thread->transaction_stack == NULL &&
- list_empty(&thread->todo);
-
- if (thread->return_error != BR_OK && ptr < end) {
- if (thread->return_error2 != BR_OK) {
- if (put_user_preempt_disabled(thread->return_error2, (uint32_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
- binder_stat_br(proc, thread, thread->return_error2);
- if (ptr == end)
- goto done;
- thread->return_error2 = BR_OK;
- }
- if (put_user_preempt_disabled(thread->return_error, (uint32_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
- binder_stat_br(proc, thread, thread->return_error);
- thread->return_error = BR_OK;
- goto done;
- }
-
-
- thread->looper |= BINDER_LOOPER_STATE_WAITING;
+ binder_worklist_empty_ilocked(&thread->todo);
if (wait_for_proc_work)
proc->ready_threads++;
+ binder_inner_proc_unlock(proc);
- binder_unlock(__func__);
+ thread->looper |= BINDER_LOOPER_STATE_WAITING;
trace_binder_wait_for_work(wait_for_proc_work,
!!thread->transaction_stack,
- !list_empty(&thread->todo));
+ !binder_worklist_empty(proc, &thread->todo));
if (wait_for_proc_work) {
if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
@@ -2794,10 +3567,10 @@ static int binder_thread_read(struct binder_proc *proc,
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
}
- binder_lock(__func__);
-
+ binder_inner_proc_lock(proc);
if (wait_for_proc_work)
proc->ready_threads--;
+ binder_inner_proc_unlock(proc);
thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
if (ret)
@@ -2806,33 +3579,54 @@ static int binder_thread_read(struct binder_proc *proc,
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
- struct binder_work *w;
+ struct binder_work *w = NULL;
+ struct list_head *list = NULL;
struct binder_transaction *t = NULL;
+ struct binder_thread *t_from;
- if (!list_empty(&thread->todo)) {
- w = list_first_entry(&thread->todo, struct binder_work,
- entry);
- } else if (!list_empty(&proc->todo) && wait_for_proc_work) {
- w = list_first_entry(&proc->todo, struct binder_work,
- entry);
- } else {
+ binder_inner_proc_lock(proc);
+ if (!binder_worklist_empty_ilocked(&thread->todo))
+ list = &thread->todo;
+ else if (!binder_worklist_empty_ilocked(&proc->todo) &&
+ wait_for_proc_work)
+ list = &proc->todo;
+ else {
+ binder_inner_proc_unlock(proc);
+
/* no data added */
- if (ptr - buffer == 4 &&
- !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
+ if (ptr - buffer == 4 && !thread->looper_need_return)
goto retry;
break;
}
- if (end - ptr < sizeof(tr) + 4)
+ if (end - ptr < sizeof(tr) + 4) {
+ binder_inner_proc_unlock(proc);
break;
+ }
+ w = binder_dequeue_work_head_ilocked(list);
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
+ binder_inner_proc_unlock(proc);
t = container_of(w, struct binder_transaction, work);
} break;
+ case BINDER_WORK_RETURN_ERROR: {
+ struct binder_error *e = container_of(
+ w, struct binder_error, work);
+
+ WARN_ON(e->cmd == BR_OK);
+ binder_inner_proc_unlock(proc);
+ if (put_user(e->cmd, (uint32_t __user *)ptr))
+ return -EFAULT;
+ e->cmd = BR_OK;
+ ptr += sizeof(uint32_t);
+
+ binder_stat_br(proc, thread, cmd);
+ } break;
case BINDER_WORK_TRANSACTION_COMPLETE: {
+ binder_inner_proc_unlock(proc);
cmd = BR_TRANSACTION_COMPLETE;
- if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
+ if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
@@ -2840,112 +3634,134 @@ static int binder_thread_read(struct binder_proc *proc,
binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE,
"%d:%d BR_TRANSACTION_COMPLETE\n",
proc->pid, thread->pid);
-
- list_del(&w->entry);
kfree(w);
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
} break;
case BINDER_WORK_NODE: {
struct binder_node *node = container_of(w, struct binder_node, work);
- uint32_t cmd = BR_NOOP;
- const char *cmd_name;
- int strong = node->internal_strong_refs || node->local_strong_refs;
- int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong;
+ int strong, weak;
+ binder_uintptr_t node_ptr = node->ptr;
+ binder_uintptr_t node_cookie = node->cookie;
+ int node_debug_id = node->debug_id;
+ int has_weak_ref;
+ int has_strong_ref;
+ void __user *orig_ptr = ptr;
- if (weak && !node->has_weak_ref) {
- cmd = BR_INCREFS;
- cmd_name = "BR_INCREFS";
+ BUG_ON(proc != node->proc);
+ strong = node->internal_strong_refs ||
+ node->local_strong_refs;
+ weak = !hlist_empty(&node->refs) ||
+ node->local_weak_refs ||
+ node->tmp_refs || strong;
+ has_strong_ref = node->has_strong_ref;
+ has_weak_ref = node->has_weak_ref;
+
+ if (weak && !has_weak_ref) {
node->has_weak_ref = 1;
node->pending_weak_ref = 1;
node->local_weak_refs++;
- } else if (strong && !node->has_strong_ref) {
- cmd = BR_ACQUIRE;
- cmd_name = "BR_ACQUIRE";
+ }
+ if (strong && !has_strong_ref) {
node->has_strong_ref = 1;
node->pending_strong_ref = 1;
node->local_strong_refs++;
- } else if (!strong && node->has_strong_ref) {
- cmd = BR_RELEASE;
- cmd_name = "BR_RELEASE";
+ }
+ if (!strong && has_strong_ref)
node->has_strong_ref = 0;
- } else if (!weak && node->has_weak_ref) {
- cmd = BR_DECREFS;
- cmd_name = "BR_DECREFS";
+ if (!weak && has_weak_ref)
node->has_weak_ref = 0;
- }
- if (cmd != BR_NOOP) {
- if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
- if (put_user_preempt_disabled(node->ptr, (binder_uintptr_t __user *)
- (binder_uintptr_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(binder_uintptr_t);
- if (put_user_preempt_disabled(node->cookie, (binder_uintptr_t __user *)
- (binder_uintptr_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(binder_uintptr_t);
+ if (!weak && !strong) {
+ binder_debug(BINDER_DEBUG_INTERNAL_REFS,
+ "%d:%d node %d u%016llx c%016llx deleted\n",
+ proc->pid, thread->pid,
+ node_debug_id,
+ (u64)node_ptr,
+ (u64)node_cookie);
+ rb_erase(&node->rb_node, &proc->nodes);
+ binder_inner_proc_unlock(proc);
+ binder_node_lock(node);
+ /*
+ * Acquire the node lock before freeing the
+ * node to serialize with other threads that
+ * may have been holding the node lock while
+ * decrementing this node (avoids race where
+ * this thread frees while the other thread
+ * is unlocking the node after the final
+ * decrement)
+ */
+ binder_node_unlock(node);
+ binder_free_node(node);
+ } else
+ binder_inner_proc_unlock(proc);
- binder_stat_br(proc, thread, cmd);
- binder_debug(BINDER_DEBUG_USER_REFS,
- "%d:%d %s %d u%016llx c%016llx\n",
- proc->pid, thread->pid, cmd_name,
- node->debug_id,
- (u64)node->ptr, (u64)node->cookie);
- } else {
- list_del_init(&w->entry);
- if (!weak && !strong) {
- binder_debug(BINDER_DEBUG_INTERNAL_REFS,
- "%d:%d node %d u%016llx c%016llx deleted\n",
- proc->pid, thread->pid,
- node->debug_id,
- (u64)node->ptr,
- (u64)node->cookie);
- rb_erase(&node->rb_node, &proc->nodes);
- kfree(node);
- binder_stats_deleted(BINDER_STAT_NODE);
- } else {
- binder_debug(BINDER_DEBUG_INTERNAL_REFS,
- "%d:%d node %d u%016llx c%016llx state unchanged\n",
- proc->pid, thread->pid,
- node->debug_id,
- (u64)node->ptr,
- (u64)node->cookie);
- }
- }
+ if (weak && !has_weak_ref)
+ ret = binder_put_node_cmd(
+ proc, thread, &ptr, node_ptr,
+ node_cookie, node_debug_id,
+ BR_INCREFS, "BR_INCREFS");
+ if (!ret && strong && !has_strong_ref)
+ ret = binder_put_node_cmd(
+ proc, thread, &ptr, node_ptr,
+ node_cookie, node_debug_id,
+ BR_ACQUIRE, "BR_ACQUIRE");
+ if (!ret && !strong && has_strong_ref)
+ ret = binder_put_node_cmd(
+ proc, thread, &ptr, node_ptr,
+ node_cookie, node_debug_id,
+ BR_RELEASE, "BR_RELEASE");
+ if (!ret && !weak && has_weak_ref)
+ ret = binder_put_node_cmd(
+ proc, thread, &ptr, node_ptr,
+ node_cookie, node_debug_id,
+ BR_DECREFS, "BR_DECREFS");
+ if (orig_ptr == ptr)
+ binder_debug(BINDER_DEBUG_INTERNAL_REFS,
+ "%d:%d node %d u%016llx c%016llx state unchanged\n",
+ proc->pid, thread->pid,
+ node_debug_id,
+ (u64)node_ptr,
+ (u64)node_cookie);
+ if (ret)
+ return ret;
} break;
case BINDER_WORK_DEAD_BINDER:
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
struct binder_ref_death *death;
uint32_t cmd;
+ binder_uintptr_t cookie;
death = container_of(w, struct binder_ref_death, work);
if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
else
cmd = BR_DEAD_BINDER;
- if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
- if (put_user_preempt_disabled(death->cookie, (binder_uintptr_t __user *) ptr))
- return -EFAULT;
- ptr += sizeof(binder_uintptr_t);
- binder_stat_br(proc, thread, cmd);
+ cookie = death->cookie;
+
binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,
"%d:%d %s %016llx\n",
proc->pid, thread->pid,
cmd == BR_DEAD_BINDER ?
"BR_DEAD_BINDER" :
"BR_CLEAR_DEATH_NOTIFICATION_DONE",
- (u64)death->cookie);
-
+ (u64)cookie);
if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
- list_del(&w->entry);
+ binder_inner_proc_unlock(proc);
kfree(death);
binder_stats_deleted(BINDER_STAT_DEATH);
- } else
- list_move(&w->entry, &proc->delivered_death);
+ } else {
+ binder_enqueue_work_ilocked(
+ w, &proc->delivered_death);
+ binder_inner_proc_unlock(proc);
+ }
+ if (put_user(cmd, (uint32_t __user *)ptr))
+ return -EFAULT;
+ ptr += sizeof(uint32_t);
+ if (put_user(cookie,
+ (binder_uintptr_t __user *)ptr))
+ return -EFAULT;
+ ptr += sizeof(binder_uintptr_t);
+ binder_stat_br(proc, thread, cmd);
if (cmd == BR_DEAD_BINDER)
goto done; /* DEAD_BINDER notifications can cause transactions */
} break;
@@ -2977,8 +3793,9 @@ static int binder_thread_read(struct binder_proc *proc,
tr.flags = t->flags;
tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);
- if (t->from) {
- struct task_struct *sender = t->from->proc->tsk;
+ t_from = binder_get_txn_from(t);
+ if (t_from) {
+ struct task_struct *sender = t_from->proc->tsk;
tr.sender_pid = task_tgid_nr_ns(sender,
task_active_pid_ns(current));
@@ -2988,18 +3805,24 @@ static int binder_thread_read(struct binder_proc *proc,
tr.data_size = t->buffer->data_size;
tr.offsets_size = t->buffer->offsets_size;
- tr.data.ptr.buffer = (binder_uintptr_t)(
- (uintptr_t)t->buffer->data +
- proc->user_buffer_offset);
+ tr.data.ptr.buffer = (binder_uintptr_t)
+ ((uintptr_t)t->buffer->data +
+ binder_alloc_get_user_buffer_offset(&proc->alloc));
tr.data.ptr.offsets = tr.data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *));
- if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
+ if (put_user(cmd, (uint32_t __user *)ptr)) {
+ if (t_from)
+ binder_thread_dec_tmpref(t_from);
return -EFAULT;
+ }
ptr += sizeof(uint32_t);
- if (copy_to_user_preempt_disabled(ptr, &tr, sizeof(tr)))
+ if (copy_to_user(ptr, &tr, sizeof(tr))) {
+ if (t_from)
+ binder_thread_dec_tmpref(t_from);
return -EFAULT;
+ }
ptr += sizeof(tr);
trace_binder_transaction_received(t);
@@ -3009,21 +3832,22 @@ static int binder_thread_read(struct binder_proc *proc,
proc->pid, thread->pid,
(cmd == BR_TRANSACTION) ? "BR_TRANSACTION" :
"BR_REPLY",
- t->debug_id, t->from ? t->from->proc->pid : 0,
- t->from ? t->from->pid : 0, cmd,
+ t->debug_id, t_from ? t_from->proc->pid : 0,
+ t_from ? t_from->pid : 0, cmd,
t->buffer->data_size, t->buffer->offsets_size,
(u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets);
- list_del(&t->work.entry);
+ if (t_from)
+ binder_thread_dec_tmpref(t_from);
t->buffer->allow_user_free = 1;
if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
+ binder_inner_proc_lock(thread->proc);
t->to_parent = thread->transaction_stack;
t->to_thread = thread;
thread->transaction_stack = t;
+ binder_inner_proc_unlock(thread->proc);
} else {
- t->buffer->transaction = NULL;
- kfree(t);
- binder_stats_deleted(BINDER_STAT_TRANSACTION);
+ binder_free_transaction(t);
}
break;
}
@@ -3031,29 +3855,35 @@ static int binder_thread_read(struct binder_proc *proc,
done:
*consumed = ptr - buffer;
+ binder_inner_proc_lock(proc);
if (proc->requested_threads + proc->ready_threads == 0 &&
proc->requested_threads_started < proc->max_threads &&
(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
/*spawn a new thread if we leave this out */) {
proc->requested_threads++;
+ binder_inner_proc_unlock(proc);
binder_debug(BINDER_DEBUG_THREADS,
"%d:%d BR_SPAWN_LOOPER\n",
proc->pid, thread->pid);
- if (put_user_preempt_disabled(BR_SPAWN_LOOPER, (uint32_t __user *) buffer))
+ if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
return -EFAULT;
binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
- }
+ } else
+ binder_inner_proc_unlock(proc);
return 0;
}
-static void binder_release_work(struct list_head *list)
+static void binder_release_work(struct binder_proc *proc,
+ struct list_head *list)
{
struct binder_work *w;
- while (!list_empty(list)) {
- w = list_first_entry(list, struct binder_work, entry);
- list_del_init(&w->entry);
+ while (1) {
+ w = binder_dequeue_work_head(proc, list);
+ if (!w)
+ return;
+
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
struct binder_transaction *t;
@@ -3066,11 +3896,17 @@ static void binder_release_work(struct list_head *list)
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
"undelivered transaction %d\n",
t->debug_id);
- t->buffer->transaction = NULL;
- kfree(t);
- binder_stats_deleted(BINDER_STAT_TRANSACTION);
+ binder_free_transaction(t);
}
} break;
+ case BINDER_WORK_RETURN_ERROR: {
+ struct binder_error *e = container_of(
+ w, struct binder_error, work);
+
+ binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
+ "undelivered TRANSACTION_ERROR: %u\n",
+ e->cmd);
+ } break;
case BINDER_WORK_TRANSACTION_COMPLETE: {
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
"undelivered TRANSACTION_COMPLETE\n");
@@ -3097,7 +3933,8 @@ static void binder_release_work(struct list_head *list)
}
-static struct binder_thread *binder_get_thread(struct binder_proc *proc)
+static struct binder_thread *binder_get_thread_ilocked(
+ struct binder_proc *proc, struct binder_thread *new_thread)
{
struct binder_thread *thread = NULL;
struct rb_node *parent = NULL;
@@ -3112,38 +3949,99 @@ static struct binder_thread *binder_get_thread(struct binder_proc *proc)
else if (current->pid > thread->pid)
p = &(*p)->rb_right;
else
- break;
+ return thread;
}
- if (*p == NULL) {
- thread = kzalloc_preempt_disabled(sizeof(*thread));
- if (thread == NULL)
+ if (!new_thread)
+ return NULL;
+ thread = new_thread;
+ binder_stats_created(BINDER_STAT_THREAD);
+ thread->proc = proc;
+ thread->pid = current->pid;
+ atomic_set(&thread->tmp_ref, 0);
+ init_waitqueue_head(&thread->wait);
+ INIT_LIST_HEAD(&thread->todo);
+ rb_link_node(&thread->rb_node, parent, p);
+ rb_insert_color(&thread->rb_node, &proc->threads);
+ thread->looper_need_return = true;
+ thread->return_error.work.type = BINDER_WORK_RETURN_ERROR;
+ thread->return_error.cmd = BR_OK;
+ thread->reply_error.work.type = BINDER_WORK_RETURN_ERROR;
+ thread->reply_error.cmd = BR_OK;
+
+ return thread;
+}
+
+static struct binder_thread *binder_get_thread(struct binder_proc *proc)
+{
+ struct binder_thread *thread;
+ struct binder_thread *new_thread;
+
+ binder_inner_proc_lock(proc);
+ thread = binder_get_thread_ilocked(proc, NULL);
+ binder_inner_proc_unlock(proc);
+ if (!thread) {
+ new_thread = kzalloc(sizeof(*thread), GFP_KERNEL);
+ if (new_thread == NULL)
return NULL;
- binder_stats_created(BINDER_STAT_THREAD);
- thread->proc = proc;
- thread->pid = current->pid;
- init_waitqueue_head(&thread->wait);
- INIT_LIST_HEAD(&thread->todo);
- rb_link_node(&thread->rb_node, parent, p);
- rb_insert_color(&thread->rb_node, &proc->threads);
- thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;
- thread->return_error = BR_OK;
- thread->return_error2 = BR_OK;
+ binder_inner_proc_lock(proc);
+ thread = binder_get_thread_ilocked(proc, new_thread);
+ binder_inner_proc_unlock(proc);
+ if (thread != new_thread)
+ kfree(new_thread);
}
return thread;
}
-static int binder_free_thread(struct binder_proc *proc,
- struct binder_thread *thread)
+static void binder_free_proc(struct binder_proc *proc)
+{
+ BUG_ON(!list_empty(&proc->todo));
+ BUG_ON(!list_empty(&proc->delivered_death));
+ binder_alloc_deferred_release(&proc->alloc);
+ put_task_struct(proc->tsk);
+ binder_stats_deleted(BINDER_STAT_PROC);
+ kfree(proc);
+}
+
+static void binder_free_thread(struct binder_thread *thread)
+{
+ BUG_ON(!list_empty(&thread->todo));
+ binder_stats_deleted(BINDER_STAT_THREAD);
+ binder_proc_dec_tmpref(thread->proc);
+ kfree(thread);
+}
+
+static int binder_thread_release(struct binder_proc *proc,
+ struct binder_thread *thread)
{
struct binder_transaction *t;
struct binder_transaction *send_reply = NULL;
int active_transactions = 0;
+ struct binder_transaction *last_t = NULL;
+ binder_inner_proc_lock(thread->proc);
+ /*
+ * take a ref on the proc so it survives
+ * after we remove this thread from proc->threads.
+ * The corresponding dec is when we actually
+ * free the thread in binder_free_thread()
+ */
+ proc->tmp_ref++;
+ /*
+ * take a ref on this thread to ensure it
+ * survives while we are releasing it
+ */
+ atomic_inc(&thread->tmp_ref);
rb_erase(&thread->rb_node, &proc->threads);
t = thread->transaction_stack;
- if (t && t->to_thread == thread)
- send_reply = t;
+ if (t) {
+ spin_lock(&t->lock);
+ if (t->to_thread == thread)
+ send_reply = t;
+ }
+ thread->is_dead = true;
+
while (t) {
+ last_t = t;
active_transactions++;
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
"release %d:%d transaction %d %s, still active\n",
@@ -3164,12 +4062,16 @@ static int binder_free_thread(struct binder_proc *proc,
t = t->from_parent;
} else
BUG();
+ spin_unlock(&last_t->lock);
+ if (t)
+ spin_lock(&t->lock);
}
+ binder_inner_proc_unlock(thread->proc);
+
if (send_reply)
binder_send_failed_reply(send_reply, BR_DEAD_REPLY);
- binder_release_work(&thread->todo);
- kfree(thread);
- binder_stats_deleted(BINDER_STAT_THREAD);
+ binder_release_work(proc, &thread->todo);
+ binder_thread_dec_tmpref(thread);
return active_transactions;
}
@@ -3180,14 +4082,12 @@ static unsigned int binder_poll(struct file *filp,
struct binder_thread *thread = NULL;
int wait_for_proc_work;
- binder_lock(__func__);
-
thread = binder_get_thread(proc);
+ binder_inner_proc_lock(thread->proc);
wait_for_proc_work = thread->transaction_stack == NULL &&
- list_empty(&thread->todo) && thread->return_error == BR_OK;
-
- binder_unlock(__func__);
+ binder_worklist_empty_ilocked(&thread->todo);
+ binder_inner_proc_unlock(thread->proc);
if (wait_for_proc_work) {
if (binder_has_proc_work(proc, thread))
@@ -3219,7 +4119,7 @@ static int binder_ioctl_write_read(struct file *filp,
ret = -EINVAL;
goto out;
}
- if (copy_from_user_preempt_disabled(&bwr, ubuf, sizeof(bwr))) {
+ if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
@@ -3237,7 +4137,7 @@ static int binder_ioctl_write_read(struct file *filp,
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
- if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr)))
+ if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
@@ -3248,10 +4148,10 @@ static int binder_ioctl_write_read(struct file *filp,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
trace_binder_read_done(ret);
- if (!list_empty(&proc->todo))
+ if (!binder_worklist_empty(proc, &proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
- if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr)))
+ if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
@@ -3261,7 +4161,7 @@ static int binder_ioctl_write_read(struct file *filp,
proc->pid, thread->pid,
(u64)bwr.write_consumed, (u64)bwr.write_size,
(u64)bwr.read_consumed, (u64)bwr.read_size);
- if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr))) {
+ if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
@@ -3274,9 +4174,10 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp)
int ret = 0;
struct binder_proc *proc = filp->private_data;
struct binder_context *context = proc->context;
-
+ struct binder_node *new_node;
kuid_t curr_euid = current_euid();
+ mutex_lock(&context->context_mgr_node_lock);
if (context->binder_context_mgr_node) {
pr_err("BINDER_SET_CONTEXT_MGR already set\n");
ret = -EBUSY;
@@ -3297,16 +4198,21 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp)
} else {
context->binder_context_mgr_uid = curr_euid;
}
- context->binder_context_mgr_node = binder_new_node(proc, 0, 0);
- if (!context->binder_context_mgr_node) {
+ new_node = binder_new_node(proc, NULL);
+ if (!new_node) {
ret = -ENOMEM;
goto out;
}
- context->binder_context_mgr_node->local_weak_refs++;
- context->binder_context_mgr_node->local_strong_refs++;
- context->binder_context_mgr_node->has_strong_ref = 1;
- context->binder_context_mgr_node->has_weak_ref = 1;
+ binder_node_lock(new_node);
+ new_node->local_weak_refs++;
+ new_node->local_strong_refs++;
+ new_node->has_strong_ref = 1;
+ new_node->has_weak_ref = 1;
+ context->binder_context_mgr_node = new_node;
+ binder_node_unlock(new_node);
+ binder_put_node(new_node);
out:
+ mutex_unlock(&context->context_mgr_node_lock);
return ret;
}
@@ -3321,17 +4227,12 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
/*pr_info("binder_ioctl: %d:%d %x %lx\n",
proc->pid, current->pid, cmd, arg);*/
- if (unlikely(current->mm != proc->vma_vm_mm)) {
- pr_err("current mm mismatch proc mm\n");
- return -EINVAL;
- }
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret)
goto err_unlocked;
- binder_lock(__func__);
thread = binder_get_thread(proc);
if (thread == NULL) {
ret = -ENOMEM;
@@ -3344,12 +4245,19 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (ret)
goto err;
break;
- case BINDER_SET_MAX_THREADS:
- if (copy_from_user_preempt_disabled(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
+ case BINDER_SET_MAX_THREADS: {
+ int max_threads;
+
+ if (copy_from_user(&max_threads, ubuf,
+ sizeof(max_threads))) {
ret = -EINVAL;
goto err;
}
+ binder_inner_proc_lock(proc);
+ proc->max_threads = max_threads;
+ binder_inner_proc_unlock(proc);
break;
+ }
case BINDER_SET_CONTEXT_MGR:
ret = binder_ioctl_set_ctx_mgr(filp);
if (ret)
@@ -3358,7 +4266,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
case BINDER_THREAD_EXIT:
binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n",
proc->pid, thread->pid);
- binder_free_thread(proc, thread);
+ binder_thread_release(proc, thread);
thread = NULL;
break;
case BINDER_VERSION: {
@@ -3368,8 +4276,9 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
ret = -EINVAL;
goto err;
}
- if (put_user_preempt_disabled(BINDER_CURRENT_PROTOCOL_VERSION, &ver->protocol_version)) {
- ret = -EINVAL;
+ if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
+ &ver->protocol_version)) {
+ ret = -EINVAL;
goto err;
}
break;
@@ -3381,8 +4290,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
ret = 0;
err:
if (thread)
- thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
- binder_unlock(__func__);
+ thread->looper_need_return = false;
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
@@ -3411,8 +4319,7 @@ static void binder_vma_close(struct vm_area_struct *vma)
proc->pid, vma->vm_start, vma->vm_end,
(vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
(unsigned long)pgprot_val(vma->vm_page_prot));
- proc->vma = NULL;
- proc->vma_vm_mm = NULL;
+ binder_alloc_vma_close(&proc->alloc);
binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES);
}
@@ -3430,11 +4337,8 @@ static const struct vm_operations_struct binder_vm_ops = {
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret;
-
- struct vm_struct *area;
struct binder_proc *proc = filp->private_data;
const char *failure_string;
- struct binder_buffer *buffer;
if (proc->tsk != current->group_leader)
return -EINVAL;
@@ -3443,8 +4347,8 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_end = vma->vm_start + SZ_4M;
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
- "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n",
- proc->pid, vma->vm_start, vma->vm_end,
+ "%s: %d %lx-%lx (%ld K) vma %lx pagep %lx\n",
+ __func__, proc->pid, vma->vm_start, vma->vm_end,
(vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
(unsigned long)pgprot_val(vma->vm_page_prot));
@@ -3454,77 +4358,15 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
goto err_bad_arg;
}
vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;
-
- mutex_lock(&binder_mmap_lock);
- if (proc->buffer) {
- ret = -EBUSY;
- failure_string = "already mapped";
- goto err_already_mapped;
- }
-
- area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
- if (area == NULL) {
- ret = -ENOMEM;
- failure_string = "get_vm_area";
- goto err_get_vm_area_failed;
- }
- proc->buffer = area->addr;
- proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;
- mutex_unlock(&binder_mmap_lock);
-
-#ifdef CONFIG_CPU_CACHE_VIPT
- if (cache_is_vipt_aliasing()) {
- while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) {
- pr_info("binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);
- vma->vm_start += PAGE_SIZE;
- }
- }
-#endif
- proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);
- if (proc->pages == NULL) {
- ret = -ENOMEM;
- failure_string = "alloc page array";
- goto err_alloc_pages_failed;
- }
- proc->buffer_size = vma->vm_end - vma->vm_start;
-
vma->vm_ops = &binder_vm_ops;
vma->vm_private_data = proc;
- /* binder_update_page_range assumes preemption is disabled */
- preempt_disable();
- ret = binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma);
- preempt_enable_no_resched();
- if (ret) {
- ret = -ENOMEM;
- failure_string = "alloc small buf";
- goto err_alloc_small_buf_failed;
- }
- buffer = proc->buffer;
- INIT_LIST_HEAD(&proc->buffers);
- list_add(&buffer->entry, &proc->buffers);
- buffer->free = 1;
- binder_insert_free_buffer(proc, buffer);
- proc->free_async_space = proc->buffer_size / 2;
- barrier();
+ ret = binder_alloc_mmap_handler(&proc->alloc, vma);
+ if (ret)
+ return ret;
proc->files = get_files_struct(current);
- proc->vma = vma;
- proc->vma_vm_mm = vma->vm_mm;
-
- /*pr_info("binder_mmap: %d %lx-%lx maps %p\n",
- proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/
return 0;
-err_alloc_small_buf_failed:
- kfree(proc->pages);
- proc->pages = NULL;
-err_alloc_pages_failed:
- mutex_lock(&binder_mmap_lock);
- vfree(proc->buffer);
- proc->buffer = NULL;
-err_get_vm_area_failed:
-err_already_mapped:
- mutex_unlock(&binder_mmap_lock);
err_bad_arg:
pr_err("binder_mmap: %d %lx-%lx %s failed %d\n",
proc->pid, vma->vm_start, vma->vm_end, failure_string, ret);
@@ -3542,25 +4384,26 @@ static int binder_open(struct inode *nodp, struct file *filp)
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
if (proc == NULL)
return -ENOMEM;
+ spin_lock_init(&proc->inner_lock);
+ spin_lock_init(&proc->outer_lock);
get_task_struct(current->group_leader);
proc->tsk = current->group_leader;
- proc->vma_vm_mm = current->group_leader->mm;
INIT_LIST_HEAD(&proc->todo);
init_waitqueue_head(&proc->wait);
proc->default_priority = task_nice(current);
binder_dev = container_of(filp->private_data, struct binder_device,
miscdev);
proc->context = &binder_dev->context;
-
- binder_lock(__func__);
+ binder_alloc_init(&proc->alloc);
binder_stats_created(BINDER_STAT_PROC);
- hlist_add_head(&proc->proc_node, &binder_procs);
proc->pid = current->group_leader->pid;
INIT_LIST_HEAD(&proc->delivered_death);
filp->private_data = proc;
- binder_unlock(__func__);
+ mutex_lock(&binder_procs_lock);
+ hlist_add_head(&proc->proc_node, &binder_procs);
+ mutex_unlock(&binder_procs_lock);
if (binder_debugfs_dir_entry_proc) {
char strbuf[11];
@@ -3596,15 +4439,17 @@ static void binder_deferred_flush(struct binder_proc *proc)
struct rb_node *n;
int wake_count = 0;
+ binder_inner_proc_lock(proc);
for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) {
struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node);
- thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;
+ thread->looper_need_return = true;
if (thread->looper & BINDER_LOOPER_STATE_WAITING) {
wake_up_interruptible(&thread->wait);
wake_count++;
}
}
+ binder_inner_proc_unlock(proc);
wake_up_interruptible_all(&proc->wait);
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
@@ -3626,13 +4471,21 @@ static int binder_node_release(struct binder_node *node, int refs)
{
struct binder_ref *ref;
int death = 0;
+ struct binder_proc *proc = node->proc;
- list_del_init(&node->work.entry);
- binder_release_work(&node->async_todo);
+ binder_release_work(proc, &node->async_todo);
- if (hlist_empty(&node->refs)) {
- kfree(node);
- binder_stats_deleted(BINDER_STAT_NODE);
+ binder_node_lock(node);
+ binder_inner_proc_lock(proc);
+ binder_dequeue_work_ilocked(&node->work);
+ /*
+ * The caller must have taken a temporary ref on the node,
+ */
+ BUG_ON(!node->tmp_refs);
+ if (hlist_empty(&node->refs) && node->tmp_refs == 1) {
+ binder_inner_proc_unlock(proc);
+ binder_node_unlock(node);
+ binder_free_node(node);
return refs;
}
@@ -3640,45 +4493,58 @@ static int binder_node_release(struct binder_node *node, int refs)
node->proc = NULL;
node->local_strong_refs = 0;
node->local_weak_refs = 0;
+ binder_inner_proc_unlock(proc);
+
+ spin_lock(&binder_dead_nodes_lock);
hlist_add_head(&node->dead_node, &binder_dead_nodes);
+ spin_unlock(&binder_dead_nodes_lock);
hlist_for_each_entry(ref, &node->refs, node_entry) {
refs++;
-
- if (!ref->death)
+ /*
+ * Need the node lock to synchronize
+ * with new notification requests and the
+ * inner lock to synchronize with queued
+ * death notifications.
+ */
+ binder_inner_proc_lock(ref->proc);
+ if (!ref->death) {
+ binder_inner_proc_unlock(ref->proc);
continue;
+ }
death++;
- if (list_empty(&ref->death->work.entry)) {
- ref->death->work.type = BINDER_WORK_DEAD_BINDER;
- list_add_tail(&ref->death->work.entry,
- &ref->proc->todo);
- wake_up_interruptible(&ref->proc->wait);
- } else
- BUG();
+ BUG_ON(!list_empty(&ref->death->work.entry));
+ ref->death->work.type = BINDER_WORK_DEAD_BINDER;
+ binder_enqueue_work_ilocked(&ref->death->work,
+ &ref->proc->todo);
+ wake_up_interruptible(&ref->proc->wait);
+ binder_inner_proc_unlock(ref->proc);
}
binder_debug(BINDER_DEBUG_DEAD_BINDER,
"node %d now dead, refs %d, death %d\n",
node->debug_id, refs, death);
+ binder_node_unlock(node);
+ binder_put_node(node);
return refs;
}
static void binder_deferred_release(struct binder_proc *proc)
{
- struct binder_transaction *t;
struct binder_context *context = proc->context;
struct rb_node *n;
- int threads, nodes, incoming_refs, outgoing_refs, buffers,
- active_transactions, page_count;
+ int threads, nodes, incoming_refs, outgoing_refs, active_transactions;
- BUG_ON(proc->vma);
BUG_ON(proc->files);
+ mutex_lock(&binder_procs_lock);
hlist_del(&proc->proc_node);
+ mutex_unlock(&binder_procs_lock);
+ mutex_lock(&context->context_mgr_node_lock);
if (context->binder_context_mgr_node &&
context->binder_context_mgr_node->proc == proc) {
binder_debug(BINDER_DEBUG_DEAD_BINDER,
@@ -3686,15 +4552,25 @@ static void binder_deferred_release(struct binder_proc *proc)
__func__, proc->pid);
context->binder_context_mgr_node = NULL;
}
+ mutex_unlock(&context->context_mgr_node_lock);
+ binder_inner_proc_lock(proc);
+ /*
+ * Make sure proc stays alive after we
+ * remove all the threads
+ */
+ proc->tmp_ref++;
+ proc->is_dead = true;
threads = 0;
active_transactions = 0;
while ((n = rb_first(&proc->threads))) {
struct binder_thread *thread;
thread = rb_entry(n, struct binder_thread, rb_node);
+ binder_inner_proc_unlock(proc);
threads++;
- active_transactions += binder_free_thread(proc, thread);
+ active_transactions += binder_thread_release(proc, thread);
+ binder_inner_proc_lock(proc);
}
nodes = 0;
@@ -3704,73 +4580,42 @@ static void binder_deferred_release(struct binder_proc *proc)
node = rb_entry(n, struct binder_node, rb_node);
nodes++;
+ /*
+ * take a temporary ref on the node before
+ * calling binder_node_release() which will either
+ * kfree() the node or call binder_put_node()
+ */
+ binder_inc_node_tmpref_ilocked(node);
rb_erase(&node->rb_node, &proc->nodes);
+ binder_inner_proc_unlock(proc);
incoming_refs = binder_node_release(node, incoming_refs);
+ binder_inner_proc_lock(proc);
}
+ binder_inner_proc_unlock(proc);
outgoing_refs = 0;
+ binder_proc_lock(proc);
while ((n = rb_first(&proc->refs_by_desc))) {
struct binder_ref *ref;
ref = rb_entry(n, struct binder_ref, rb_node_desc);
outgoing_refs++;
- binder_delete_ref(ref);
+ binder_cleanup_ref_olocked(ref);
+ binder_proc_unlock(proc);
+ binder_free_ref(ref);
+ binder_proc_lock(proc);
}
+ binder_proc_unlock(proc);
- binder_release_work(&proc->todo);
- binder_release_work(&proc->delivered_death);
-
- buffers = 0;
- while ((n = rb_first(&proc->allocated_buffers))) {
- struct binder_buffer *buffer;
-
- buffer = rb_entry(n, struct binder_buffer, rb_node);
-
- t = buffer->transaction;
- if (t) {
- t->buffer = NULL;
- buffer->transaction = NULL;
- pr_err("release proc %d, transaction %d, not freed\n",
- proc->pid, t->debug_id);
- /*BUG();*/
- }
-
- binder_free_buf(proc, buffer);
- buffers++;
- }
-
- binder_stats_deleted(BINDER_STAT_PROC);
-
- page_count = 0;
- if (proc->pages) {
- int i;
-
- for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) {
- void *page_addr;
-
- if (!proc->pages[i])
- continue;
-
- page_addr = proc->buffer + i * PAGE_SIZE;
- binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%s: %d: page %d at %p not freed\n",
- __func__, proc->pid, i, page_addr);
- unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
- __free_page(proc->pages[i]);
- page_count++;
- }
- kfree(proc->pages);
- vfree(proc->buffer);
- }
-
- put_task_struct(proc->tsk);
+ binder_release_work(proc, &proc->todo);
+ binder_release_work(proc, &proc->delivered_death);
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
- "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n",
+ "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d\n",
__func__, proc->pid, threads, nodes, incoming_refs,
- outgoing_refs, active_transactions, buffers, page_count);
+ outgoing_refs, active_transactions);
- kfree(proc);
+ binder_proc_dec_tmpref(proc);
}
static void binder_deferred_func(struct work_struct *work)
@@ -3781,12 +4626,7 @@ static void binder_deferred_func(struct work_struct *work)
int defer;
do {
- trace_binder_lock(__func__);
- mutex_lock(&binder_main_lock);
- trace_binder_locked(__func__);
-
mutex_lock(&binder_deferred_lock);
- preempt_disable();
if (!hlist_empty(&binder_deferred_list)) {
proc = hlist_entry(binder_deferred_list.first,
struct binder_proc, deferred_work_node);
@@ -3812,9 +4652,6 @@ static void binder_deferred_func(struct work_struct *work)
if (defer & BINDER_DEFERRED_RELEASE)
binder_deferred_release(proc); /* frees proc */
- trace_binder_unlock(__func__);
- mutex_unlock(&binder_main_lock);
- preempt_enable_no_resched();
if (files)
put_files_struct(files);
} while (proc);
@@ -3834,41 +4671,52 @@ binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer)
mutex_unlock(&binder_deferred_lock);
}
-static void print_binder_transaction(struct seq_file *m, const char *prefix,
- struct binder_transaction *t)
+static void print_binder_transaction_ilocked(struct seq_file *m,
+ struct binder_proc *proc,
+ const char *prefix,
+ struct binder_transaction *t)
{
+ struct binder_proc *to_proc;
+ struct binder_buffer *buffer = t->buffer;
+
+ WARN_ON(!spin_is_locked(&proc->inner_lock));
+ spin_lock(&t->lock);
+ to_proc = t->to_proc;
seq_printf(m,
"%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d",
prefix, t->debug_id, t,
t->from ? t->from->proc->pid : 0,
t->from ? t->from->pid : 0,
- t->to_proc ? t->to_proc->pid : 0,
+ to_proc ? to_proc->pid : 0,
t->to_thread ? t->to_thread->pid : 0,
t->code, t->flags, t->priority, t->need_reply);
- if (t->buffer == NULL) {
+ spin_unlock(&t->lock);
+
+ if (proc != to_proc) {
+ /*
+ * Can only safely deref buffer if we are holding the
+ * correct proc inner lock for this node
+ */
+ seq_puts(m, "\n");
+ return;
+ }
+
+ if (buffer == NULL) {
seq_puts(m, " buffer free\n");
return;
}
- if (t->buffer->target_node)
- seq_printf(m, " node %d",
- t->buffer->target_node->debug_id);
+ if (buffer->target_node)
+ seq_printf(m, " node %d", buffer->target_node->debug_id);
seq_printf(m, " size %zd:%zd data %p\n",
- t->buffer->data_size, t->buffer->offsets_size,
- t->buffer->data);
-}
-
-static void print_binder_buffer(struct seq_file *m, const char *prefix,
- struct binder_buffer *buffer)
-{
- seq_printf(m, "%s %d: %p size %zd:%zd %s\n",
- prefix, buffer->debug_id, buffer->data,
buffer->data_size, buffer->offsets_size,
- buffer->transaction ? "active" : "delivered");
+ buffer->data);
}
-static void print_binder_work(struct seq_file *m, const char *prefix,
- const char *transaction_prefix,
- struct binder_work *w)
+static void print_binder_work_ilocked(struct seq_file *m,
+ struct binder_proc *proc,
+ const char *prefix,
+ const char *transaction_prefix,
+ struct binder_work *w)
{
struct binder_node *node;
struct binder_transaction *t;
@@ -3876,8 +4724,16 @@ static void print_binder_work(struct seq_file *m, const char *prefix,
switch (w->type) {
case BINDER_WORK_TRANSACTION:
t = container_of(w, struct binder_transaction, work);
- print_binder_transaction(m, transaction_prefix, t);
+ print_binder_transaction_ilocked(
+ m, proc, transaction_prefix, t);
break;
+ case BINDER_WORK_RETURN_ERROR: {
+ struct binder_error *e = container_of(
+ w, struct binder_error, work);
+
+ seq_printf(m, "%stransaction error: %u\n",
+ prefix, e->cmd);
+ } break;
case BINDER_WORK_TRANSACTION_COMPLETE:
seq_printf(m, "%stransaction complete\n", prefix);
break;
@@ -3902,70 +4758,89 @@ static void print_binder_work(struct seq_file *m, const char *prefix,
}
}
-static void print_binder_thread(struct seq_file *m,
- struct binder_thread *thread,
- int print_always)
+static void print_binder_thread_ilocked(struct seq_file *m,
+ struct binder_thread *thread,
+ int print_always)
{
struct binder_transaction *t;
struct binder_work *w;
size_t start_pos = m->count;
size_t header_pos;
- seq_printf(m, " thread %d: l %02x\n", thread->pid, thread->looper);
+ WARN_ON(!spin_is_locked(&thread->proc->inner_lock));
+ seq_printf(m, " thread %d: l %02x need_return %d tr %d\n",
+ thread->pid, thread->looper,
+ thread->looper_need_return,
+ atomic_read(&thread->tmp_ref));
header_pos = m->count;
t = thread->transaction_stack;
while (t) {
if (t->from == thread) {
- print_binder_transaction(m,
- " outgoing transaction", t);
+ print_binder_transaction_ilocked(m, thread->proc,
+ " outgoing transaction", t);
t = t->from_parent;
} else if (t->to_thread == thread) {
- print_binder_transaction(m,
+ print_binder_transaction_ilocked(m, thread->proc,
" incoming transaction", t);
t = t->to_parent;
} else {
- print_binder_transaction(m, " bad transaction", t);
+ print_binder_transaction_ilocked(m, thread->proc,
+ " bad transaction", t);
t = NULL;
}
}
list_for_each_entry(w, &thread->todo, entry) {
- print_binder_work(m, " ", " pending transaction", w);
+ print_binder_work_ilocked(m, thread->proc, " ",
+ " pending transaction", w);
}
if (!print_always && m->count == header_pos)
m->count = start_pos;
}
-static void print_binder_node(struct seq_file *m, struct binder_node *node)
+static void print_binder_node_nilocked(struct seq_file *m,
+ struct binder_node *node)
{
struct binder_ref *ref;
struct binder_work *w;
int count;
+ WARN_ON(!spin_is_locked(&node->lock));
+ if (node->proc)
+ WARN_ON(!spin_is_locked(&node->proc->inner_lock));
+
count = 0;
hlist_for_each_entry(ref, &node->refs, node_entry)
count++;
- seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d",
+ seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d tr %d",
node->debug_id, (u64)node->ptr, (u64)node->cookie,
node->has_strong_ref, node->has_weak_ref,
node->local_strong_refs, node->local_weak_refs,
- node->internal_strong_refs, count);
+ node->internal_strong_refs, count, node->tmp_refs);
if (count) {
seq_puts(m, " proc");
hlist_for_each_entry(ref, &node->refs, node_entry)
seq_printf(m, " %d", ref->proc->pid);
}
seq_puts(m, "\n");
- list_for_each_entry(w, &node->async_todo, entry)
- print_binder_work(m, " ",
- " pending async transaction", w);
+ if (node->proc) {
+ list_for_each_entry(w, &node->async_todo, entry)
+ print_binder_work_ilocked(m, node->proc, " ",
+ " pending async transaction", w);
+ }
}
-static void print_binder_ref(struct seq_file *m, struct binder_ref *ref)
+static void print_binder_ref_olocked(struct seq_file *m,
+ struct binder_ref *ref)
{
- seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %p\n",
- ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ",
- ref->node->debug_id, ref->strong, ref->weak, ref->death);
+ WARN_ON(!spin_is_locked(&ref->proc->outer_lock));
+ binder_node_lock(ref->node);
+ seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %pK\n",
+ ref->data.debug_id, ref->data.desc,
+ ref->node->proc ? "" : "dead ",
+ ref->node->debug_id, ref->data.strong,
+ ref->data.weak, ref->death);
+ binder_node_unlock(ref->node);
}
static void print_binder_proc(struct seq_file *m,
@@ -3975,36 +4850,60 @@ static void print_binder_proc(struct seq_file *m,
struct rb_node *n;
size_t start_pos = m->count;
size_t header_pos;
+ struct binder_node *last_node = NULL;
seq_printf(m, "proc %d\n", proc->pid);
seq_printf(m, "context %s\n", proc->context->name);
header_pos = m->count;
+ binder_inner_proc_lock(proc);
for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n))
- print_binder_thread(m, rb_entry(n, struct binder_thread,
+ print_binder_thread_ilocked(m, rb_entry(n, struct binder_thread,
rb_node), print_all);
+
for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) {
struct binder_node *node = rb_entry(n, struct binder_node,
rb_node);
- if (print_all || node->has_async_transaction)
- print_binder_node(m, node);
+ /*
+ * take a temporary reference on the node so it
+ * survives and isn't removed from the tree
+ * while we print it.
+ */
+ binder_inc_node_tmpref_ilocked(node);
+ /* Need to drop inner lock to take node lock */
+ binder_inner_proc_unlock(proc);
+ if (last_node)
+ binder_put_node(last_node);
+ binder_node_inner_lock(node);
+ print_binder_node_nilocked(m, node);
+ binder_node_inner_unlock(node);
+ last_node = node;
+ binder_inner_proc_lock(proc);
}
+ binder_inner_proc_unlock(proc);
+ if (last_node)
+ binder_put_node(last_node);
+
if (print_all) {
+ binder_proc_lock(proc);
for (n = rb_first(&proc->refs_by_desc);
n != NULL;
n = rb_next(n))
- print_binder_ref(m, rb_entry(n, struct binder_ref,
- rb_node_desc));
+ print_binder_ref_olocked(m, rb_entry(n,
+ struct binder_ref,
+ rb_node_desc));
+ binder_proc_unlock(proc);
}
- for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n))
- print_binder_buffer(m, " buffer",
- rb_entry(n, struct binder_buffer, rb_node));
+ binder_alloc_print_allocated(m, &proc->alloc);
+ binder_inner_proc_lock(proc);
list_for_each_entry(w, &proc->todo, entry)
- print_binder_work(m, " ", " pending transaction", w);
+ print_binder_work_ilocked(m, proc, " ",
+ " pending transaction", w);
list_for_each_entry(w, &proc->delivered_death, entry) {
seq_puts(m, " has delivered dead binder\n");
break;
}
+ binder_inner_proc_unlock(proc);
if (!print_all && m->count == header_pos)
m->count = start_pos;
}
@@ -4070,17 +4969,21 @@ static void print_binder_stats(struct seq_file *m, const char *prefix,
BUILD_BUG_ON(ARRAY_SIZE(stats->bc) !=
ARRAY_SIZE(binder_command_strings));
for (i = 0; i < ARRAY_SIZE(stats->bc); i++) {
- if (stats->bc[i])
+ int temp = atomic_read(&stats->bc[i]);
+
+ if (temp)
seq_printf(m, "%s%s: %d\n", prefix,
- binder_command_strings[i], stats->bc[i]);
+ binder_command_strings[i], temp);
}
BUILD_BUG_ON(ARRAY_SIZE(stats->br) !=
ARRAY_SIZE(binder_return_strings));
for (i = 0; i < ARRAY_SIZE(stats->br); i++) {
- if (stats->br[i])
+ int temp = atomic_read(&stats->br[i]);
+
+ if (temp)
seq_printf(m, "%s%s: %d\n", prefix,
- binder_return_strings[i], stats->br[i]);
+ binder_return_strings[i], temp);
}
BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) !=
@@ -4088,11 +4991,15 @@ static void print_binder_stats(struct seq_file *m, const char *prefix,
BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) !=
ARRAY_SIZE(stats->obj_deleted));
for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) {
- if (stats->obj_created[i] || stats->obj_deleted[i])
- seq_printf(m, "%s%s: active %d total %d\n", prefix,
+ int created = atomic_read(&stats->obj_created[i]);
+ int deleted = atomic_read(&stats->obj_deleted[i]);
+
+ if (created || deleted)
+ seq_printf(m, "%s%s: active %d total %d\n",
+ prefix,
binder_objstat_strings[i],
- stats->obj_created[i] - stats->obj_deleted[i],
- stats->obj_created[i]);
+ created - deleted,
+ created);
}
}
@@ -4102,10 +5009,13 @@ static void print_binder_proc_stats(struct seq_file *m,
struct binder_work *w;
struct rb_node *n;
int count, strong, weak;
+ size_t free_async_space =
+ binder_alloc_get_free_async_space(&proc->alloc);
seq_printf(m, "proc %d\n", proc->pid);
seq_printf(m, "context %s\n", proc->context->name);
count = 0;
+ binder_inner_proc_lock(proc);
for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n))
count++;
seq_printf(m, " threads: %d\n", count);
@@ -4113,38 +5023,37 @@ static void print_binder_proc_stats(struct seq_file *m,
" ready threads %d\n"
" free async space %zd\n", proc->requested_threads,
proc->requested_threads_started, proc->max_threads,
- proc->ready_threads, proc->free_async_space);
+ proc->ready_threads,
+ free_async_space);
count = 0;
for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n))
count++;
+ binder_inner_proc_unlock(proc);
seq_printf(m, " nodes: %d\n", count);
count = 0;
strong = 0;
weak = 0;
+ binder_proc_lock(proc);
for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) {
struct binder_ref *ref = rb_entry(n, struct binder_ref,
rb_node_desc);
count++;
- strong += ref->strong;
- weak += ref->weak;
+ strong += ref->data.strong;
+ weak += ref->data.weak;
}
+ binder_proc_unlock(proc);
seq_printf(m, " refs: %d s %d w %d\n", count, strong, weak);
- count = 0;
- for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n))
- count++;
+ count = binder_alloc_get_allocated_count(&proc->alloc);
seq_printf(m, " buffers: %d\n", count);
count = 0;
+ binder_inner_proc_lock(proc);
list_for_each_entry(w, &proc->todo, entry) {
- switch (w->type) {
- case BINDER_WORK_TRANSACTION:
+ if (w->type == BINDER_WORK_TRANSACTION)
count++;
- break;
- default:
- break;
- }
}
+ binder_inner_proc_unlock(proc);
seq_printf(m, " pending transactions: %d\n", count);
print_binder_stats(m, " ", &proc->stats);
@@ -4155,57 +5064,67 @@ static int binder_state_show(struct seq_file *m, void *unused)
{
struct binder_proc *proc;
struct binder_node *node;
- int do_lock = !binder_debug_no_lock;
-
- if (do_lock)
- binder_lock(__func__);
+ struct binder_node *last_node = NULL;
seq_puts(m, "binder state:\n");
+ spin_lock(&binder_dead_nodes_lock);
if (!hlist_empty(&binder_dead_nodes))
seq_puts(m, "dead nodes:\n");
- hlist_for_each_entry(node, &binder_dead_nodes, dead_node)
- print_binder_node(m, node);
+ hlist_for_each_entry(node, &binder_dead_nodes, dead_node) {
+ /*
+ * take a temporary reference on the node so it
+ * survives and isn't removed from the list
+ * while we print it.
+ */
+ node->tmp_refs++;
+ spin_unlock(&binder_dead_nodes_lock);
+ if (last_node)
+ binder_put_node(last_node);
+ binder_node_lock(node);
+ print_binder_node_nilocked(m, node);
+ binder_node_unlock(node);
+ last_node = node;
+ spin_lock(&binder_dead_nodes_lock);
+ }
+ spin_unlock(&binder_dead_nodes_lock);
+ if (last_node)
+ binder_put_node(last_node);
+ mutex_lock(&binder_procs_lock);
hlist_for_each_entry(proc, &binder_procs, proc_node)
print_binder_proc(m, proc, 1);
- if (do_lock)
- binder_unlock(__func__);
+ mutex_unlock(&binder_procs_lock);
+
return 0;
}
static int binder_stats_show(struct seq_file *m, void *unused)
{
struct binder_proc *proc;
- int do_lock = !binder_debug_no_lock;
-
- if (do_lock)
- binder_lock(__func__);
seq_puts(m, "binder stats:\n");
print_binder_stats(m, "", &binder_stats);
+ mutex_lock(&binder_procs_lock);
hlist_for_each_entry(proc, &binder_procs, proc_node)
print_binder_proc_stats(m, proc);
- if (do_lock)
- binder_unlock(__func__);
+ mutex_unlock(&binder_procs_lock);
+
return 0;
}
static int binder_transactions_show(struct seq_file *m, void *unused)
{
struct binder_proc *proc;
- int do_lock = !binder_debug_no_lock;
-
- if (do_lock)
- binder_lock(__func__);
seq_puts(m, "binder transactions:\n");
+ mutex_lock(&binder_procs_lock);
hlist_for_each_entry(proc, &binder_procs, proc_node)
print_binder_proc(m, proc, 0);
- if (do_lock)
- binder_unlock(__func__);
+ mutex_unlock(&binder_procs_lock);
+
return 0;
}
@@ -4213,44 +5132,63 @@ static int binder_proc_show(struct seq_file *m, void *unused)
{
struct binder_proc *itr;
int pid = (unsigned long)m->private;
- int do_lock = !binder_debug_no_lock;
- if (do_lock)
- binder_lock(__func__);
-
+ mutex_lock(&binder_procs_lock);
hlist_for_each_entry(itr, &binder_procs, proc_node) {
if (itr->pid == pid) {
seq_puts(m, "binder proc state:\n");
print_binder_proc(m, itr, 1);
}
}
- if (do_lock)
- binder_unlock(__func__);
+ mutex_unlock(&binder_procs_lock);
+
return 0;
}
static void print_binder_transaction_log_entry(struct seq_file *m,
struct binder_transaction_log_entry *e)
{
+ int debug_id = READ_ONCE(e->debug_id_done);
+ /*
+ * read barrier to guarantee debug_id_done read before
+ * we print the log values
+ */
+ smp_rmb();
seq_printf(m,
- "%d: %s from %d:%d to %d:%d context %s node %d handle %d size %d:%d\n",
+ "%d: %s from %d:%d to %d:%d context %s node %d handle %d size %d:%d ret %d/%d l=%d",
e->debug_id, (e->call_type == 2) ? "reply" :
((e->call_type == 1) ? "async" : "call "), e->from_proc,
e->from_thread, e->to_proc, e->to_thread, e->context_name,
- e->to_node, e->target_handle, e->data_size, e->offsets_size);
+ e->to_node, e->target_handle, e->data_size, e->offsets_size,
+ e->return_error, e->return_error_param,
+ e->return_error_line);
+ /*
+ * read-barrier to guarantee read of debug_id_done after
+ * done printing the fields of the entry
+ */
+ smp_rmb();
+ seq_printf(m, debug_id && debug_id == READ_ONCE(e->debug_id_done) ?
+ "\n" : " (incomplete)\n");
}
static int binder_transaction_log_show(struct seq_file *m, void *unused)
{
struct binder_transaction_log *log = m->private;
+ unsigned int log_cur = atomic_read(&log->cur);
+ unsigned int count;
+ unsigned int cur;
int i;
- if (log->full) {
- for (i = log->next; i < ARRAY_SIZE(log->entry); i++)
- print_binder_transaction_log_entry(m, &log->entry[i]);
+ count = log_cur + 1;
+ cur = count < ARRAY_SIZE(log->entry) && !log->full ?
+ 0 : count % ARRAY_SIZE(log->entry);
+ if (count > ARRAY_SIZE(log->entry) || log->full)
+ count = ARRAY_SIZE(log->entry);
+ for (i = 0; i < count; i++) {
+ unsigned int index = cur++ % ARRAY_SIZE(log->entry);
+
+ print_binder_transaction_log_entry(m, &log->entry[index]);
}
- for (i = 0; i < log->next; i++)
- print_binder_transaction_log_entry(m, &log->entry[i]);
return 0;
}
@@ -4285,6 +5223,7 @@ static int __init init_binder_device(const char *name)
binder_device->context.binder_context_mgr_uid = INVALID_UID;
binder_device->context.name = name;
+ mutex_init(&binder_device->context.context_mgr_node_lock);
ret = misc_register(&binder_device->miscdev);
if (ret < 0) {
@@ -4304,6 +5243,9 @@ static int __init binder_init(void)
struct binder_device *device;
struct hlist_node *tmp;
+ atomic_set(&binder_transaction_log.cur, ~0U);
+ atomic_set(&binder_transaction_log_failed.cur, ~0U);
+
binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
if (binder_debugfs_dir_entry_root)
binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
new file mode 100644
index 0000000..b90222a
--- /dev/null
+++ b/drivers/android/binder_alloc.c
@@ -0,0 +1,802 @@
+/* binder_alloc.c
+ *
+ * Android IPC Subsystem
+ *
+ * Copyright (C) 2007-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 <asm/cacheflush.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/rtmutex.h>
+#include <linux/rbtree.h>
+#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include "binder_alloc.h"
+#include "binder_trace.h"
+
+static DEFINE_MUTEX(binder_alloc_mmap_lock);
+
+enum {
+ BINDER_DEBUG_OPEN_CLOSE = 1U << 1,
+ BINDER_DEBUG_BUFFER_ALLOC = 1U << 2,
+ BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 3,
+};
+static uint32_t binder_alloc_debug_mask;
+
+module_param_named(debug_mask, binder_alloc_debug_mask,
+ uint, 0644);
+
+#define binder_alloc_debug(mask, x...) \
+ do { \
+ if (binder_alloc_debug_mask & mask) \
+ pr_info(x); \
+ } while (0)
+
+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;
+}
+
+static void binder_insert_free_buffer(struct binder_alloc *alloc,
+ struct binder_buffer *new_buffer)
+{
+ struct rb_node **p = &alloc->free_buffers.rb_node;
+ struct rb_node *parent = NULL;
+ struct binder_buffer *buffer;
+ size_t buffer_size;
+ size_t new_buffer_size;
+
+ BUG_ON(!new_buffer->free);
+
+ new_buffer_size = binder_alloc_buffer_size(alloc, new_buffer);
+
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%d: add free buffer, size %zd, at %pK\n",
+ alloc->pid, new_buffer_size, new_buffer);
+
+ while (*p) {
+ parent = *p;
+ buffer = rb_entry(parent, struct binder_buffer, rb_node);
+ BUG_ON(!buffer->free);
+
+ buffer_size = binder_alloc_buffer_size(alloc, buffer);
+
+ if (new_buffer_size < buffer_size)
+ p = &parent->rb_left;
+ else
+ p = &parent->rb_right;
+ }
+ rb_link_node(&new_buffer->rb_node, parent, p);
+ rb_insert_color(&new_buffer->rb_node, &alloc->free_buffers);
+}
+
+static void binder_insert_allocated_buffer_locked(
+ struct binder_alloc *alloc, struct binder_buffer *new_buffer)
+{
+ struct rb_node **p = &alloc->allocated_buffers.rb_node;
+ struct rb_node *parent = NULL;
+ struct binder_buffer *buffer;
+
+ BUG_ON(new_buffer->free);
+
+ while (*p) {
+ parent = *p;
+ buffer = rb_entry(parent, struct binder_buffer, rb_node);
+ BUG_ON(buffer->free);
+
+ if (new_buffer < buffer)
+ p = &parent->rb_left;
+ else if (new_buffer > buffer)
+ p = &parent->rb_right;
+ else
+ BUG();
+ }
+ rb_link_node(&new_buffer->rb_node, parent, p);
+ rb_insert_color(&new_buffer->rb_node, &alloc->allocated_buffers);
+}
+
+static struct binder_buffer *binder_alloc_prepare_to_free_locked(
+ struct binder_alloc *alloc,
+ uintptr_t user_ptr)
+{
+ struct rb_node *n = alloc->allocated_buffers.rb_node;
+ struct binder_buffer *buffer;
+ struct binder_buffer *kern_ptr;
+
+ kern_ptr = (struct binder_buffer *)(user_ptr - alloc->user_buffer_offset
+ - offsetof(struct binder_buffer, data));
+
+ while (n) {
+ buffer = rb_entry(n, struct binder_buffer, rb_node);
+ BUG_ON(buffer->free);
+
+ if (kern_ptr < buffer)
+ n = n->rb_left;
+ else if (kern_ptr > buffer)
+ n = n->rb_right;
+ else {
+ /*
+ * Guard against user threads attempting to
+ * free the buffer twice
+ */
+ if (buffer->free_in_progress) {
+ pr_err("%d:%d FREE_BUFFER u%016llx user freed buffer twice\n",
+ alloc->pid, current->pid, (u64)user_ptr);
+ return NULL;
+ }
+ buffer->free_in_progress = 1;
+ return buffer;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * binder_alloc_buffer_lookup() - get buffer given user ptr
+ * @alloc: binder_alloc for this proc
+ * @user_ptr: User pointer to buffer data
+ *
+ * Validate userspace pointer to buffer data and return buffer corresponding to
+ * that user pointer. Search the rb tree for buffer that matches user data
+ * pointer.
+ *
+ * Return: Pointer to buffer or NULL
+ */
+struct binder_buffer *binder_alloc_prepare_to_free(struct binder_alloc *alloc,
+ uintptr_t user_ptr)
+{
+ struct binder_buffer *buffer;
+
+ mutex_lock(&alloc->mutex);
+ buffer = binder_alloc_prepare_to_free_locked(alloc, user_ptr);
+ mutex_unlock(&alloc->mutex);
+ return buffer;
+}
+
+static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
+ void *start, void *end,
+ struct vm_area_struct *vma)
+{
+ void *page_addr;
+ unsigned long user_page_addr;
+ struct page **page;
+ struct mm_struct *mm;
+
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%d: %s pages %pK-%pK\n", alloc->pid,
+ allocate ? "allocate" : "free", start, end);
+
+ if (end <= start)
+ return 0;
+
+ trace_binder_update_page_range(alloc, allocate, start, end);
+
+ if (vma)
+ mm = NULL;
+ else
+ mm = get_task_mm(alloc->tsk);
+
+ if (mm) {
+ down_write(&mm->mmap_sem);
+ vma = alloc->vma;
+ if (vma && mm != alloc->vma_vm_mm) {
+ pr_err("%d: vma mm and task mm mismatch\n",
+ alloc->pid);
+ vma = NULL;
+ }
+ }
+
+ if (allocate == 0)
+ goto free_range;
+
+ if (vma == NULL) {
+ pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n",
+ alloc->pid);
+ goto err_no_vma;
+ }
+
+ for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
+ int ret;
+
+ page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
+
+ BUG_ON(*page);
+ *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
+ if (*page == NULL) {
+ pr_err("%d: binder_alloc_buf failed for page at %pK\n",
+ alloc->pid, page_addr);
+ goto err_alloc_page_failed;
+ }
+ ret = map_kernel_range_noflush((unsigned long)page_addr,
+ PAGE_SIZE, PAGE_KERNEL, page);
+ flush_cache_vmap((unsigned long)page_addr,
+ (unsigned long)page_addr + PAGE_SIZE);
+ if (ret != 1) {
+ pr_err("%d: binder_alloc_buf failed to map page at %pK in kernel\n",
+ alloc->pid, page_addr);
+ goto err_map_kernel_failed;
+ }
+ user_page_addr =
+ (uintptr_t)page_addr + alloc->user_buffer_offset;
+ ret = vm_insert_page(vma, user_page_addr, page[0]);
+ 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;
+ }
+ /* vm_insert_page does not seem to increment the refcount */
+ }
+ if (mm) {
+ up_write(&mm->mmap_sem);
+ mmput(mm);
+ }
+ return 0;
+
+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);
+err_vm_insert_page_failed:
+ unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
+err_map_kernel_failed:
+ __free_page(*page);
+ *page = NULL;
+err_alloc_page_failed:
+ ;
+ }
+err_no_vma:
+ if (mm) {
+ up_write(&mm->mmap_sem);
+ mmput(mm);
+ }
+ return vma ? -ENOMEM : -ESRCH;
+}
+
+struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc,
+ size_t data_size,
+ size_t offsets_size,
+ size_t extra_buffers_size,
+ int is_async)
+{
+ struct rb_node *n = alloc->free_buffers.rb_node;
+ struct binder_buffer *buffer;
+ size_t buffer_size;
+ struct rb_node *best_fit = NULL;
+ void *has_page_addr;
+ void *end_page_addr;
+ size_t size, data_offsets_size;
+ int ret;
+
+ if (alloc->vma == NULL) {
+ pr_err("%d: binder_alloc_buf, no vma\n",
+ alloc->pid);
+ return ERR_PTR(-ESRCH);
+ }
+
+ data_offsets_size = ALIGN(data_size, sizeof(void *)) +
+ ALIGN(offsets_size, sizeof(void *));
+
+ if (data_offsets_size < data_size || data_offsets_size < offsets_size) {
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%d: got transaction with invalid size %zd-%zd\n",
+ alloc->pid, data_size, offsets_size);
+ return ERR_PTR(-EINVAL);
+ }
+ size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *));
+ if (size < data_offsets_size || size < extra_buffers_size) {
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%d: got transaction with invalid extra_buffers_size %zd\n",
+ alloc->pid, extra_buffers_size);
+ return ERR_PTR(-EINVAL);
+ }
+ if (is_async &&
+ alloc->free_async_space < size + sizeof(struct binder_buffer)) {
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%d: binder_alloc_buf size %zd failed, no async space left\n",
+ alloc->pid, size);
+ return ERR_PTR(-ENOSPC);
+ }
+
+ while (n) {
+ buffer = rb_entry(n, struct binder_buffer, rb_node);
+ BUG_ON(!buffer->free);
+ buffer_size = binder_alloc_buffer_size(alloc, buffer);
+
+ if (size < buffer_size) {
+ best_fit = n;
+ n = n->rb_left;
+ } else if (size > buffer_size)
+ n = n->rb_right;
+ else {
+ best_fit = n;
+ break;
+ }
+ }
+ if (best_fit == NULL) {
+ size_t allocated_buffers = 0;
+ size_t largest_alloc_size = 0;
+ size_t total_alloc_size = 0;
+ size_t free_buffers = 0;
+ size_t largest_free_size = 0;
+ size_t total_free_size = 0;
+
+ for (n = rb_first(&alloc->allocated_buffers); n != NULL;
+ n = rb_next(n)) {
+ buffer = rb_entry(n, struct binder_buffer, rb_node);
+ buffer_size = binder_alloc_buffer_size(alloc, buffer);
+ allocated_buffers++;
+ total_alloc_size += buffer_size;
+ if (buffer_size > largest_alloc_size)
+ largest_alloc_size = buffer_size;
+ }
+ for (n = rb_first(&alloc->free_buffers); n != NULL;
+ n = rb_next(n)) {
+ buffer = rb_entry(n, struct binder_buffer, rb_node);
+ buffer_size = binder_alloc_buffer_size(alloc, buffer);
+ free_buffers++;
+ total_free_size += buffer_size;
+ if (buffer_size > largest_free_size)
+ largest_free_size = buffer_size;
+ }
+ pr_err("%d: binder_alloc_buf size %zd failed, no address space\n",
+ alloc->pid, size);
+ pr_err("allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n",
+ total_alloc_size, allocated_buffers, largest_alloc_size,
+ total_free_size, free_buffers, largest_free_size);
+ return ERR_PTR(-ENOSPC);
+ }
+ if (n == NULL) {
+ buffer = rb_entry(best_fit, struct binder_buffer, rb_node);
+ buffer_size = binder_alloc_buffer_size(alloc, buffer);
+ }
+
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%d: binder_alloc_buf size %zd got buffer %pK size %zd\n",
+ alloc->pid, size, buffer, buffer_size);
+
+ 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);
+ }
+ end_page_addr =
+ (void *)PAGE_ALIGN((uintptr_t)buffer->data + buffer_size);
+ if (end_page_addr > has_page_addr)
+ end_page_addr = has_page_addr;
+ ret = binder_update_page_range(alloc, 1,
+ (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL);
+ 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;
+
+ list_add(&new_buffer->entry, &buffer->entry);
+ new_buffer->free = 1;
+ binder_insert_free_buffer(alloc, new_buffer);
+ }
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%d: binder_alloc_buf size %zd got %pK\n",
+ alloc->pid, size, buffer);
+ buffer->data_size = data_size;
+ buffer->offsets_size = offsets_size;
+ buffer->async_transaction = is_async;
+ buffer->extra_buffers_size = extra_buffers_size;
+ if (is_async) {
+ alloc->free_async_space -= size + sizeof(struct binder_buffer);
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
+ "%d: binder_alloc_buf size %zd async free %zd\n",
+ alloc->pid, size, alloc->free_async_space);
+ }
+ return buffer;
+}
+
+/**
+ * binder_alloc_new_buf() - Allocate a new binder buffer
+ * @alloc: binder_alloc for this proc
+ * @data_size: size of user data buffer
+ * @offsets_size: user specified buffer offset
+ * @extra_buffers_size: size of extra space for meta-data (eg, security context)
+ * @is_async: buffer for async transaction
+ *
+ * Allocate a new buffer given the requested sizes. Returns
+ * the kernel version of the buffer pointer. The size allocated
+ * is the sum of the three given sizes (each rounded up to
+ * pointer-sized boundary)
+ *
+ * Return: The allocated buffer or %NULL if error
+ */
+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)
+{
+ struct binder_buffer *buffer;
+
+ mutex_lock(&alloc->mutex);
+ buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size,
+ extra_buffers_size, is_async);
+ mutex_unlock(&alloc->mutex);
+ return buffer;
+}
+
+static void *buffer_start_page(struct binder_buffer *buffer)
+{
+ return (void *)((uintptr_t)buffer & PAGE_MASK);
+}
+
+static void *buffer_end_page(struct binder_buffer *buffer)
+{
+ return (void *)(((uintptr_t)(buffer + 1) - 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;
+
+ BUG_ON(alloc->buffers.next == &buffer->entry);
+ prev = list_entry(buffer->entry.prev, struct binder_buffer, entry);
+ 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;
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%d: merge free, buffer %pK share page with %pK\n",
+ alloc->pid, buffer, prev);
+ }
+
+ 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;
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%d: merge free, buffer %pK share page with %pK\n",
+ alloc->pid, buffer, prev);
+ }
+ }
+ list_del(&buffer->entry);
+ if (free_page_start || free_page_end) {
+ 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);
+ }
+}
+
+static void binder_free_buf_locked(struct binder_alloc *alloc,
+ struct binder_buffer *buffer)
+{
+ size_t size, buffer_size;
+
+ buffer_size = binder_alloc_buffer_size(alloc, buffer);
+
+ size = ALIGN(buffer->data_size, sizeof(void *)) +
+ ALIGN(buffer->offsets_size, sizeof(void *)) +
+ ALIGN(buffer->extra_buffers_size, sizeof(void *));
+
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%d: binder_free_buf %pK size %zd buffer_size %zd\n",
+ alloc->pid, buffer, size, buffer_size);
+
+ 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);
+
+ if (buffer->async_transaction) {
+ alloc->free_async_space += size + sizeof(struct binder_buffer);
+
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
+ "%d: binder_free_buf size %zd async free %zd\n",
+ alloc->pid, size, alloc->free_async_space);
+ }
+
+ binder_update_page_range(alloc, 0,
+ (void *)PAGE_ALIGN((uintptr_t)buffer->data),
+ (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK),
+ NULL);
+
+ 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);
+
+ if (next->free) {
+ rb_erase(&next->rb_node, &alloc->free_buffers);
+ binder_delete_free_buffer(alloc, next);
+ }
+ }
+ if (alloc->buffers.next != &buffer->entry) {
+ struct binder_buffer *prev = list_entry(buffer->entry.prev,
+ struct binder_buffer, entry);
+
+ if (prev->free) {
+ binder_delete_free_buffer(alloc, buffer);
+ rb_erase(&prev->rb_node, &alloc->free_buffers);
+ buffer = prev;
+ }
+ }
+ binder_insert_free_buffer(alloc, buffer);
+}
+
+/**
+ * binder_alloc_free_buf() - free a binder buffer
+ * @alloc: binder_alloc for this proc
+ * @buffer: kernel pointer to buffer
+ *
+ * Free the buffer allocated via binder_alloc_new_buffer()
+ */
+void binder_alloc_free_buf(struct binder_alloc *alloc,
+ struct binder_buffer *buffer)
+{
+ mutex_lock(&alloc->mutex);
+ binder_free_buf_locked(alloc, buffer);
+ mutex_unlock(&alloc->mutex);
+}
+
+/**
+ * binder_alloc_mmap_handler() - map virtual address space for proc
+ * @alloc: alloc structure for this proc
+ * @vma: vma passed to mmap()
+ *
+ * Called by binder_mmap() to initialize the space specified in
+ * vma for allocating binder buffers
+ *
+ * Return:
+ * 0 = success
+ * -EBUSY = address space already mapped
+ * -ENOMEM = failed to map memory to given address space
+ */
+int binder_alloc_mmap_handler(struct binder_alloc *alloc,
+ struct vm_area_struct *vma)
+{
+ int ret;
+ struct vm_struct *area;
+ const char *failure_string;
+ struct binder_buffer *buffer;
+
+ mutex_lock(&binder_alloc_mmap_lock);
+ if (alloc->buffer) {
+ ret = -EBUSY;
+ failure_string = "already mapped";
+ goto err_already_mapped;
+ }
+
+ area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
+ if (area == NULL) {
+ ret = -ENOMEM;
+ failure_string = "get_vm_area";
+ goto err_get_vm_area_failed;
+ }
+ alloc->buffer = area->addr;
+ alloc->user_buffer_offset =
+ vma->vm_start - (uintptr_t)alloc->buffer;
+ mutex_unlock(&binder_alloc_mmap_lock);
+
+#ifdef CONFIG_CPU_CACHE_VIPT
+ if (cache_is_vipt_aliasing()) {
+ while (CACHE_COLOUR(
+ (vma->vm_start ^ (uint32_t)alloc->buffer))) {
+ pr_info("%s: %d %lx-%lx maps %pK bad alignment\n",
+ __func__, alloc->pid, vma->vm_start,
+ vma->vm_end, alloc->buffer);
+ vma->vm_start += PAGE_SIZE;
+ }
+ }
+#endif
+ alloc->pages = kzalloc(sizeof(alloc->pages[0]) *
+ ((vma->vm_end - vma->vm_start) / PAGE_SIZE),
+ GFP_KERNEL);
+ if (alloc->pages == NULL) {
+ ret = -ENOMEM;
+ failure_string = "alloc page array";
+ goto err_alloc_pages_failed;
+ }
+ alloc->buffer_size = vma->vm_end - vma->vm_start;
+
+ if (binder_update_page_range(alloc, 1, alloc->buffer,
+ alloc->buffer + PAGE_SIZE, vma)) {
+ ret = -ENOMEM;
+ failure_string = "alloc small buf";
+ goto err_alloc_small_buf_failed;
+ }
+ buffer = alloc->buffer;
+ INIT_LIST_HEAD(&alloc->buffers);
+ list_add(&buffer->entry, &alloc->buffers);
+ buffer->free = 1;
+ binder_insert_free_buffer(alloc, buffer);
+ alloc->free_async_space = alloc->buffer_size / 2;
+ barrier();
+ alloc->vma = vma;
+ alloc->vma_vm_mm = vma->vm_mm;
+
+ return 0;
+
+err_alloc_small_buf_failed:
+ kfree(alloc->pages);
+ alloc->pages = NULL;
+err_alloc_pages_failed:
+ mutex_lock(&binder_alloc_mmap_lock);
+ vfree(alloc->buffer);
+ alloc->buffer = NULL;
+err_get_vm_area_failed:
+err_already_mapped:
+ mutex_unlock(&binder_alloc_mmap_lock);
+ pr_err("%s: %d %lx-%lx %s failed %d\n", __func__,
+ alloc->pid, vma->vm_start, vma->vm_end, failure_string, ret);
+ return ret;
+}
+
+
+void binder_alloc_deferred_release(struct binder_alloc *alloc)
+{
+ struct rb_node *n;
+ int buffers, page_count;
+
+ 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 */
+ BUG_ON(buffer->transaction);
+
+ binder_free_buf_locked(alloc, buffer);
+ buffers++;
+ }
+
+ page_count = 0;
+ if (alloc->pages) {
+ int i;
+
+ for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
+ void *page_addr;
+
+ if (!alloc->pages[i])
+ continue;
+
+ 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);
+ unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
+ __free_page(alloc->pages[i]);
+ page_count++;
+ }
+ kfree(alloc->pages);
+ vfree(alloc->buffer);
+ }
+ mutex_unlock(&alloc->mutex);
+
+ binder_alloc_debug(BINDER_DEBUG_OPEN_CLOSE,
+ "%s: %d buffers %d, pages %d\n",
+ __func__, alloc->pid, buffers, page_count);
+}
+
+static void print_binder_buffer(struct seq_file *m, const char *prefix,
+ struct binder_buffer *buffer)
+{
+ seq_printf(m, "%s %d: %pK size %zd:%zd:%zd %s\n",
+ prefix, buffer->debug_id, buffer->data,
+ buffer->data_size, buffer->offsets_size,
+ buffer->extra_buffers_size,
+ buffer->transaction ? "active" : "delivered");
+}
+
+/**
+ * binder_alloc_print_allocated() - print buffer info
+ * @m: seq_file for output via seq_printf()
+ * @alloc: binder_alloc for this proc
+ *
+ * Prints information about every buffer associated with
+ * the binder_alloc state to the given seq_file
+ */
+void binder_alloc_print_allocated(struct seq_file *m,
+ struct binder_alloc *alloc)
+{
+ struct rb_node *n;
+
+ mutex_lock(&alloc->mutex);
+ for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n))
+ print_binder_buffer(m, " buffer",
+ rb_entry(n, struct binder_buffer, rb_node));
+ mutex_unlock(&alloc->mutex);
+}
+
+/**
+ * binder_alloc_get_allocated_count() - return count of buffers
+ * @alloc: binder_alloc for this proc
+ *
+ * Return: count of allocated buffers
+ */
+int binder_alloc_get_allocated_count(struct binder_alloc *alloc)
+{
+ struct rb_node *n;
+ int count = 0;
+
+ mutex_lock(&alloc->mutex);
+ for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n))
+ count++;
+ mutex_unlock(&alloc->mutex);
+ return count;
+}
+
+
+/**
+ * binder_alloc_vma_close() - invalidate address space
+ * @alloc: binder_alloc for this proc
+ *
+ * Called from binder_vma_close() when releasing address space.
+ * Clears alloc->vma to prevent new incoming transactions from
+ * allocating more buffers.
+ */
+void binder_alloc_vma_close(struct binder_alloc *alloc)
+{
+ WRITE_ONCE(alloc->vma, NULL);
+ WRITE_ONCE(alloc->vma_vm_mm, NULL);
+}
+
+/**
+ * binder_alloc_init() - called by binder_open() for per-proc initialization
+ * @alloc: binder_alloc for this proc
+ *
+ * Called from binder_open() to initialize binder_alloc fields for
+ * new binder proc
+ */
+void binder_alloc_init(struct binder_alloc *alloc)
+{
+ alloc->tsk = current->group_leader;
+ alloc->pid = current->group_leader->pid;
+ mutex_init(&alloc->mutex);
+}
+
diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h
new file mode 100644
index 0000000..088e4ff
--- /dev/null
+++ b/drivers/android/binder_alloc.h
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef _LINUX_BINDER_ALLOC_H
+#define _LINUX_BINDER_ALLOC_H
+
+#include <linux/rbtree.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/rtmutex.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+
+struct binder_transaction;
+
+/**
+ * struct binder_buffer - buffer used for binder transactions
+ * @entry: entry alloc->buffers
+ * @rb_node: node for allocated_buffers/free_buffers rb trees
+ * @free: true if buffer is free
+ * @allow_user_free: describe the second member of struct blah,
+ * @async_transaction: describe the second member of struct blah,
+ * @debug_id: describe the second member of struct blah,
+ * @transaction: describe the second member of struct blah,
+ * @target_node: describe the second member of struct blah,
+ * @data_size: describe the second member of struct blah,
+ * @offsets_size: describe the second member of struct blah,
+ * @extra_buffers_size: describe the second member of struct blah,
+ * @data:i describe the second member of struct blah,
+ *
+ * Bookkeeping structure for binder transaction buffers
+ */
+struct binder_buffer {
+ struct list_head entry; /* free and allocated entries by address */
+ struct rb_node rb_node; /* free entry by size or allocated entry */
+ /* by address */
+ unsigned free:1;
+ unsigned allow_user_free:1;
+ unsigned async_transaction:1;
+ unsigned free_in_progress:1;
+ unsigned debug_id:28;
+
+ struct binder_transaction *transaction;
+
+ struct binder_node *target_node;
+ size_t data_size;
+ size_t offsets_size;
+ size_t extra_buffers_size;
+ uint8_t data[0];
+};
+
+/**
+ * struct binder_alloc - per-binder proc state for binder allocator
+ * @vma: vm_area_struct passed to mmap_handler
+ * (invarient after mmap)
+ * @tsk: tid for task that called init for this proc
+ * (invariant after init)
+ * @vma_vm_mm: copy of vma->vm_mm (invarient after mmap)
+ * @buffer: base of per-proc address space mapped via mmap
+ * @user_buffer_offset: offset between user and kernel VAs for buffer
+ * @buffers: list of all buffers for this proc
+ * @free_buffers: rb tree of buffers available for allocation
+ * sorted by size
+ * @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
+ * @buffer_size: size of address space specified via mmap
+ * @pid: pid for associated binder_proc (invariant after init)
+ *
+ * Bookkeeping structure for per-proc address space management for binder
+ * buffers. It is normally initialized during binder_init() and binder_mmap()
+ * calls. The address space is used for both user-visible buffers and for
+ * struct binder_buffer objects used to track the user buffers
+ */
+struct binder_alloc {
+ struct mutex mutex;
+ struct task_struct *tsk;
+ struct vm_area_struct *vma;
+ struct mm_struct *vma_vm_mm;
+ void *buffer;
+ ptrdiff_t user_buffer_offset;
+ struct list_head buffers;
+ struct rb_root free_buffers;
+ struct rb_root allocated_buffers;
+ size_t free_async_space;
+ struct page **pages;
+ size_t buffer_size;
+ uint32_t buffer_free;
+ int pid;
+};
+
+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);
+extern void binder_alloc_vma_close(struct binder_alloc *alloc);
+extern struct binder_buffer *
+binder_alloc_prepare_to_free(struct binder_alloc *alloc,
+ uintptr_t user_ptr);
+extern void binder_alloc_free_buf(struct binder_alloc *alloc,
+ struct binder_buffer *buffer);
+extern int binder_alloc_mmap_handler(struct binder_alloc *alloc,
+ struct vm_area_struct *vma);
+extern void binder_alloc_deferred_release(struct binder_alloc *alloc);
+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);
+
+/**
+ * binder_alloc_get_free_async_space() - get free space available for async
+ * @alloc: binder_alloc for this proc
+ *
+ * Return: the bytes remaining in the address-space for async transactions
+ */
+static inline size_t
+binder_alloc_get_free_async_space(struct binder_alloc *alloc)
+{
+ size_t free_async_space;
+
+ mutex_lock(&alloc->mutex);
+ free_async_space = alloc->free_async_space;
+ mutex_unlock(&alloc->mutex);
+ return free_async_space;
+}
+
+/**
+ * binder_alloc_get_user_buffer_offset() - get offset between kernel/user addrs
+ * @alloc: binder_alloc for this proc
+ *
+ * Return: the offset between kernel and user-space addresses to use for
+ * virtual address conversion
+ */
+static inline ptrdiff_t
+binder_alloc_get_user_buffer_offset(struct binder_alloc *alloc)
+{
+ /*
+ * user_buffer_offset is constant if vma is set and
+ * undefined if vma is not set. It is possible to
+ * get here with !alloc->vma if the target process
+ * is dying while a transaction is being initiated.
+ * Returning the old value is ok in this case and
+ * the transaction will fail.
+ */
+ return alloc->user_buffer_offset;
+}
+
+#endif /* _LINUX_BINDER_ALLOC_H */
+
diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h
index 7f20f3d..7967db1 100644
--- a/drivers/android/binder_trace.h
+++ b/drivers/android/binder_trace.h
@@ -23,7 +23,8 @@
struct binder_buffer;
struct binder_node;
struct binder_proc;
-struct binder_ref;
+struct binder_alloc;
+struct binder_ref_data;
struct binder_thread;
struct binder_transaction;
@@ -146,8 +147,8 @@ TRACE_EVENT(binder_transaction_received,
TRACE_EVENT(binder_transaction_node_to_ref,
TP_PROTO(struct binder_transaction *t, struct binder_node *node,
- struct binder_ref *ref),
- TP_ARGS(t, node, ref),
+ struct binder_ref_data *rdata),
+ TP_ARGS(t, node, rdata),
TP_STRUCT__entry(
__field(int, debug_id)
@@ -160,8 +161,8 @@ TRACE_EVENT(binder_transaction_node_to_ref,
__entry->debug_id = t->debug_id;
__entry->node_debug_id = node->debug_id;
__entry->node_ptr = node->ptr;
- __entry->ref_debug_id = ref->debug_id;
- __entry->ref_desc = ref->desc;
+ __entry->ref_debug_id = rdata->debug_id;
+ __entry->ref_desc = rdata->desc;
),
TP_printk("transaction=%d node=%d src_ptr=0x%016llx ==> dest_ref=%d dest_desc=%d",
__entry->debug_id, __entry->node_debug_id,
@@ -170,8 +171,9 @@ TRACE_EVENT(binder_transaction_node_to_ref,
);
TRACE_EVENT(binder_transaction_ref_to_node,
- TP_PROTO(struct binder_transaction *t, struct binder_ref *ref),
- TP_ARGS(t, ref),
+ TP_PROTO(struct binder_transaction *t, struct binder_node *node,
+ struct binder_ref_data *rdata),
+ TP_ARGS(t, node, rdata),
TP_STRUCT__entry(
__field(int, debug_id)
@@ -182,10 +184,10 @@ TRACE_EVENT(binder_transaction_ref_to_node,
),
TP_fast_assign(
__entry->debug_id = t->debug_id;
- __entry->ref_debug_id = ref->debug_id;
- __entry->ref_desc = ref->desc;
- __entry->node_debug_id = ref->node->debug_id;
- __entry->node_ptr = ref->node->ptr;
+ __entry->ref_debug_id = rdata->debug_id;
+ __entry->ref_desc = rdata->desc;
+ __entry->node_debug_id = node->debug_id;
+ __entry->node_ptr = node->ptr;
),
TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%016llx",
__entry->debug_id, __entry->node_debug_id,
@@ -194,9 +196,10 @@ TRACE_EVENT(binder_transaction_ref_to_node,
);
TRACE_EVENT(binder_transaction_ref_to_ref,
- TP_PROTO(struct binder_transaction *t, struct binder_ref *src_ref,
- struct binder_ref *dest_ref),
- TP_ARGS(t, src_ref, dest_ref),
+ TP_PROTO(struct binder_transaction *t, struct binder_node *node,
+ struct binder_ref_data *src_ref,
+ struct binder_ref_data *dest_ref),
+ TP_ARGS(t, node, src_ref, dest_ref),
TP_STRUCT__entry(
__field(int, debug_id)
@@ -208,7 +211,7 @@ TRACE_EVENT(binder_transaction_ref_to_ref,
),
TP_fast_assign(
__entry->debug_id = t->debug_id;
- __entry->node_debug_id = src_ref->node->debug_id;
+ __entry->node_debug_id = node->debug_id;
__entry->src_ref_debug_id = src_ref->debug_id;
__entry->src_ref_desc = src_ref->desc;
__entry->dest_ref_debug_id = dest_ref->debug_id;
@@ -268,9 +271,9 @@ DEFINE_EVENT(binder_buffer_class, binder_transaction_failed_buffer_release,
TP_ARGS(buffer));
TRACE_EVENT(binder_update_page_range,
- TP_PROTO(struct binder_proc *proc, bool allocate,
+ TP_PROTO(struct binder_alloc *alloc, bool allocate,
void *start, void *end),
- TP_ARGS(proc, allocate, start, end),
+ TP_ARGS(alloc, allocate, start, end),
TP_STRUCT__entry(
__field(int, proc)
__field(bool, allocate)
@@ -278,9 +281,9 @@ TRACE_EVENT(binder_update_page_range,
__field(size_t, size)
),
TP_fast_assign(
- __entry->proc = proc->pid;
+ __entry->proc = alloc->pid;
__entry->allocate = allocate;
- __entry->offset = start - proc->buffer;
+ __entry->offset = start - alloc->buffer;
__entry->size = end - start;
),
TP_printk("proc=%d allocate=%d offset=%zu size=%zu",
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 5ba619a..35ab4d5 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2106,7 +2106,11 @@ void device_shutdown(void)
pm_runtime_get_noresume(dev);
pm_runtime_barrier(dev);
- if (dev->bus && dev->bus->shutdown) {
+ if (dev->class && dev->class->shutdown) {
+ if (initcall_debug)
+ dev_info(dev, "shutdown\n");
+ dev->class->shutdown(dev);
+ } else if (dev->bus && dev->bus->shutdown) {
if (initcall_debug)
dev_info(dev, "shutdown\n");
dev->bus->shutdown(dev);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 624f069..55687b8 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -208,145 +208,10 @@ static struct attribute_group cpu_isolated_attr_group = {
#endif
-#ifdef CONFIG_SCHED_HMP
-
-static ssize_t show_sched_static_cpu_pwr_cost(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct cpu *cpu = container_of(dev, struct cpu, dev);
- ssize_t rc;
- int cpuid = cpu->dev.id;
- unsigned int pwr_cost;
-
- pwr_cost = sched_get_static_cpu_pwr_cost(cpuid);
-
- rc = snprintf(buf, PAGE_SIZE-2, "%d\n", pwr_cost);
-
- return rc;
-}
-
-static ssize_t __ref store_sched_static_cpu_pwr_cost(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct cpu *cpu = container_of(dev, struct cpu, dev);
- int err;
- int cpuid = cpu->dev.id;
- unsigned int pwr_cost;
-
- err = kstrtouint(strstrip((char *)buf), 0, &pwr_cost);
- if (err)
- return err;
-
- err = sched_set_static_cpu_pwr_cost(cpuid, pwr_cost);
-
- if (err >= 0)
- err = count;
-
- return err;
-}
-
-static ssize_t show_sched_static_cluster_pwr_cost(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct cpu *cpu = container_of(dev, struct cpu, dev);
- ssize_t rc;
- int cpuid = cpu->dev.id;
- unsigned int pwr_cost;
-
- pwr_cost = sched_get_static_cluster_pwr_cost(cpuid);
-
- rc = snprintf(buf, PAGE_SIZE-2, "%d\n", pwr_cost);
-
- return rc;
-}
-
-static ssize_t __ref store_sched_static_cluster_pwr_cost(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct cpu *cpu = container_of(dev, struct cpu, dev);
- int err;
- int cpuid = cpu->dev.id;
- unsigned int pwr_cost;
-
- err = kstrtouint(strstrip((char *)buf), 0, &pwr_cost);
- if (err)
- return err;
-
- err = sched_set_static_cluster_pwr_cost(cpuid, pwr_cost);
-
- if (err >= 0)
- err = count;
-
- return err;
-}
-
-static ssize_t show_sched_cluser_wake_idle(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct cpu *cpu = container_of(dev, struct cpu, dev);
- ssize_t rc;
- int cpuid = cpu->dev.id;
- unsigned int wake_up_idle;
-
- wake_up_idle = sched_get_cluster_wake_idle(cpuid);
-
- rc = scnprintf(buf, PAGE_SIZE-2, "%d\n", wake_up_idle);
-
- return rc;
-}
-
-static ssize_t __ref store_sched_cluster_wake_idle(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct cpu *cpu = container_of(dev, struct cpu, dev);
- int err;
- int cpuid = cpu->dev.id;
- unsigned int wake_up_idle;
-
- err = kstrtouint(strstrip((char *)buf), 0, &wake_up_idle);
- if (err)
- return err;
-
- err = sched_set_cluster_wake_idle(cpuid, wake_up_idle);
-
- if (err >= 0)
- err = count;
-
- return err;
-}
-
-static DEVICE_ATTR(sched_static_cpu_pwr_cost, 0644,
- show_sched_static_cpu_pwr_cost,
- store_sched_static_cpu_pwr_cost);
-static DEVICE_ATTR(sched_static_cluster_pwr_cost, 0644,
- show_sched_static_cluster_pwr_cost,
- store_sched_static_cluster_pwr_cost);
-static DEVICE_ATTR(sched_cluster_wake_up_idle, 0644,
- show_sched_cluser_wake_idle,
- store_sched_cluster_wake_idle);
-
-static struct attribute *hmp_sched_cpu_attrs[] = {
- &dev_attr_sched_static_cpu_pwr_cost.attr,
- &dev_attr_sched_static_cluster_pwr_cost.attr,
- &dev_attr_sched_cluster_wake_up_idle.attr,
- NULL
-};
-
-static struct attribute_group sched_hmp_cpu_attr_group = {
- .attrs = hmp_sched_cpu_attrs,
-};
-
-#endif /* CONFIG_SCHED_HMP */
static const struct attribute_group *common_cpu_attr_groups[] = {
#ifdef CONFIG_KEXEC
&crash_note_cpu_attr_group,
#endif
-#ifdef CONFIG_SCHED_HMP
- &sched_hmp_cpu_attr_group,
-#endif
#ifdef CONFIG_HOTPLUG_CPU
&cpu_isolated_attr_group,
#endif
@@ -357,9 +222,6 @@ static const struct attribute_group *hotplugable_cpu_attr_groups[] = {
#ifdef CONFIG_KEXEC
&crash_note_cpu_attr_group,
#endif
-#ifdef CONFIG_SCHED_HMP
- &sched_hmp_cpu_attr_group,
-#endif
#ifdef CONFIG_HOTPLUG_CPU
&cpu_isolated_attr_group,
#endif
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index c4af003..5eba478 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -856,7 +856,7 @@ static ssize_t driver_override_store(struct device *dev,
const char *buf, size_t count)
{
struct platform_device *pdev = to_platform_device(dev);
- char *driver_override, *old = pdev->driver_override, *cp;
+ char *driver_override, *old, *cp;
if (count > PATH_MAX)
return -EINVAL;
@@ -869,12 +869,15 @@ static ssize_t driver_override_store(struct device *dev,
if (cp)
*cp = '\0';
+ device_lock(dev);
+ old = pdev->driver_override;
if (strlen(driver_override)) {
pdev->driver_override = driver_override;
} else {
kfree(driver_override);
pdev->driver_override = NULL;
}
+ device_unlock(dev);
kfree(old);
@@ -885,8 +888,12 @@ static ssize_t driver_override_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
+ ssize_t len;
- return sprintf(buf, "%s\n", pdev->driver_override);
+ device_lock(dev);
+ len = sprintf(buf, "%s\n", pdev->driver_override);
+ device_unlock(dev);
+ return len;
}
static DEVICE_ATTR_RW(driver_override);
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index c9914d65..3868665 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1271,6 +1271,7 @@ static int zram_add(void)
zram->disk->private_data = zram;
snprintf(zram->disk->disk_name, 16, "zram%d", device_id);
+ __set_bit(QUEUE_FLAG_FAST, &zram->disk->queue->queue_flags);
/* Actual capacity set using syfs (/sys/block/zram<id>/disksize */
set_capacity(zram->disk, 0);
/* zram devices sort of resembles non-rotational disks */
diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c
index bfc3648..f927756 100644
--- a/drivers/bluetooth/bluetooth-power.c
+++ b/drivers/bluetooth/bluetooth-power.c
@@ -708,6 +708,7 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
} else {
BT_PWR_ERR("BT chip state is already :%d no change d\n"
, pwr_state);
+ ret = 0;
}
break;
default:
diff --git a/drivers/bluetooth/btfm_slim.h b/drivers/bluetooth/btfm_slim.h
index 161be78..ed3a743 100644
--- a/drivers/bluetooth/btfm_slim.h
+++ b/drivers/bluetooth/btfm_slim.h
@@ -13,7 +13,7 @@
#define BTFM_SLIM_H
#include <linux/slimbus/slimbus.h>
-#define BTFMSLIM_DBG(fmt, arg...) pr_debug(fmt "\n", ## arg)
+#define BTFMSLIM_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg)
#define BTFMSLIM_INFO(fmt, arg...) pr_info("%s: " fmt "\n", __func__, ## arg)
#define BTFMSLIM_ERR(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg)
@@ -68,6 +68,7 @@ struct btfmslim {
uint32_t num_rx_port;
uint32_t num_tx_port;
+ uint32_t sample_rate;
struct btfmslim_ch *rx_chs;
struct btfmslim_ch *tx_chs;
diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c
index 73a789c..791ea29 100644
--- a/drivers/bluetooth/btfm_slim_codec.c
+++ b/drivers/bluetooth/btfm_slim_codec.c
@@ -54,7 +54,7 @@ static int btfm_slim_dai_startup(struct snd_pcm_substream *substream,
int ret;
struct btfmslim *btfmslim = dai->dev->platform_data;
- BTFMSLIM_DBG("substream = %s stream = %d dai name = %s",
+ BTFMSLIM_DBG("substream = %s stream = %d dai->name = %s",
substream->name, substream->stream, dai->name);
ret = btfm_slim_hw_init(btfmslim);
return ret;
@@ -63,10 +63,52 @@ static int btfm_slim_dai_startup(struct snd_pcm_substream *substream,
static void btfm_slim_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ int i;
struct btfmslim *btfmslim = dai->dev->platform_data;
+ struct btfmslim_ch *ch;
+ uint8_t rxport, grp = false, nchan = 1;
- BTFMSLIM_DBG("substream = %s stream = %d dai name = %s",
- substream->name, substream->stream, dai->name);
+ BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name,
+ dai->id, dai->rate);
+
+ switch (dai->id) {
+ case BTFM_FM_SLIM_TX:
+ grp = true; nchan = 2;
+ ch = btfmslim->tx_chs;
+ rxport = 0;
+ break;
+ case BTFM_BT_SCO_SLIM_TX:
+ ch = btfmslim->tx_chs;
+ rxport = 0;
+ break;
+ case BTFM_BT_SCO_A2DP_SLIM_RX:
+ case BTFM_BT_SPLIT_A2DP_SLIM_RX:
+ ch = btfmslim->rx_chs;
+ rxport = 1;
+ break;
+ case BTFM_SLIM_NUM_CODEC_DAIS:
+ default:
+ BTFMSLIM_ERR("dai->id is invalid:%d", dai->id);
+ return;
+ }
+
+ if (dai->id == BTFM_FM_SLIM_TX)
+ goto out;
+
+ /* Search for dai->id matched port handler */
+ for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) &&
+ (ch->id != BTFM_SLIM_NUM_CODEC_DAIS) &&
+ (ch->id != dai->id); ch++, i++)
+ ;
+
+ if ((ch->port == BTFM_SLIM_PGD_PORT_LAST) ||
+ (ch->id == BTFM_SLIM_NUM_CODEC_DAIS)) {
+ BTFMSLIM_ERR("ch is invalid!!");
+ return;
+ }
+
+ btfm_slim_disable_ch(btfmslim, ch, rxport, grp, nchan);
+out:
btfm_slim_hw_deinit(btfmslim);
}
@@ -74,14 +116,14 @@ static int btfm_slim_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- BTFMSLIM_DBG("dai name = %s DAI-ID %x rate %d num_ch %d",
+ BTFMSLIM_DBG("dai->name = %s DAI-ID %x rate %d num_ch %d",
dai->name, dai->id, params_rate(params),
params_channels(params));
return 0;
}
-int btfm_slim_dai_prepare(struct snd_pcm_substream *substream,
+static int btfm_slim_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
int i, ret = -EINVAL;
@@ -89,9 +131,12 @@ int btfm_slim_dai_prepare(struct snd_pcm_substream *substream,
struct btfmslim_ch *ch;
uint8_t rxport, grp = false, nchan = 1;
- BTFMSLIM_DBG("dai name: %s, dai->id: %d, dai->rate: %d", dai->name,
+ BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name,
dai->id, dai->rate);
+ /* save sample rate */
+ btfmslim->sample_rate = dai->rate;
+
switch (dai->id) {
case BTFM_FM_SLIM_TX:
grp = true; nchan = 2;
@@ -129,15 +174,15 @@ int btfm_slim_dai_prepare(struct snd_pcm_substream *substream,
return ret;
}
-int btfm_slim_dai_hw_free(struct snd_pcm_substream *substream,
+static int btfm_slim_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- int i, ret = -EINVAL;
+ int ret = -EINVAL, i;
struct btfmslim *btfmslim = dai->dev->platform_data;
struct btfmslim_ch *ch;
uint8_t rxport, grp = false, nchan = 1;
- BTFMSLIM_DBG("dai name: %s, dai->id: %d, dai->rate: %d", dai->name,
+ BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name,
dai->id, dai->rate);
switch (dai->id) {
@@ -158,7 +203,12 @@ int btfm_slim_dai_hw_free(struct snd_pcm_substream *substream,
case BTFM_SLIM_NUM_CODEC_DAIS:
default:
BTFMSLIM_ERR("dai->id is invalid:%d", dai->id);
- return ret;
+ goto out;
+ }
+
+ if (dai->id != BTFM_FM_SLIM_TX) {
+ ret = 0;
+ goto out;
}
/* Search for dai->id matched port handler */
@@ -170,9 +220,12 @@ int btfm_slim_dai_hw_free(struct snd_pcm_substream *substream,
if ((ch->port == BTFM_SLIM_PGD_PORT_LAST) ||
(ch->id == BTFM_SLIM_NUM_CODEC_DAIS)) {
BTFMSLIM_ERR("ch is invalid!!");
- return ret;
+ goto out;
}
- ret = btfm_slim_disable_ch(btfmslim, ch, rxport, grp, nchan);
+
+ btfm_slim_disable_ch(btfmslim, ch, rxport, grp, nchan);
+
+out:
return ret;
}
@@ -282,6 +335,9 @@ static int btfm_slim_dai_get_channel_map(struct snd_soc_dai *dai,
*tx_num = 0;
*rx_num = num;
break;
+ default:
+ BTFMSLIM_ERR("Unsupported DAI %d", dai->id);
+ return -EINVAL;
}
do {
diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c
index 72e28da..77e2973 100644
--- a/drivers/bluetooth/btfm_slim_wcn3990.c
+++ b/drivers/bluetooth/btfm_slim_wcn3990.c
@@ -39,6 +39,7 @@ int btfm_slim_chrk_hw_init(struct btfmslim *btfmslim)
{
int ret = 0;
uint8_t reg_val;
+ uint16_t reg;
BTFMSLIM_DBG("");
@@ -46,20 +47,20 @@ int btfm_slim_chrk_hw_init(struct btfmslim *btfmslim)
return -EINVAL;
/* Get SB_SLAVE_HW_REV_MSB value*/
- ret = btfm_slim_read(btfmslim, CHRK_SB_SLAVE_HW_REV_MSB, 1,
- ®_val, IFD);
+ reg = CHRK_SB_SLAVE_HW_REV_MSB;
+ ret = btfm_slim_read(btfmslim, reg, 1, ®_val, IFD);
if (ret) {
- BTFMSLIM_ERR("failed to read (%d)", ret);
+ BTFMSLIM_ERR("failed to read (%d) reg 0x%x", ret, reg);
goto error;
}
BTFMSLIM_DBG("Major Rev: 0x%x, Minor Rev: 0x%x",
(reg_val & 0xF0) >> 4, (reg_val & 0x0F));
/* Get SB_SLAVE_HW_REV_LSB value*/
- ret = btfm_slim_read(btfmslim, CHRK_SB_SLAVE_HW_REV_LSB, 1,
- ®_val, IFD);
+ reg = CHRK_SB_SLAVE_HW_REV_LSB;
+ ret = btfm_slim_read(btfmslim, reg, 1, ®_val, IFD);
if (ret) {
- BTFMSLIM_ERR("failed to read (%d)", ret);
+ BTFMSLIM_ERR("failed to read (%d) reg 0x%x", ret, reg);
goto error;
}
BTFMSLIM_DBG("Step Rev: 0x%x", reg_val);
@@ -68,62 +69,87 @@ int btfm_slim_chrk_hw_init(struct btfmslim *btfmslim)
return ret;
}
+static inline int is_fm_port(uint8_t port_num)
+{
+ if (port_num == CHRK_SB_PGD_PORT_TX1_FM ||
+ port_num == CHRK_SB_PGD_PORT_TX2_FM)
+ return 1;
+ else
+ return 0;
+}
int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num,
uint8_t rxport, uint8_t enable)
{
int ret = 0;
uint8_t reg_val = 0;
+ uint8_t port_bit = 0;
uint16_t reg;
BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable);
if (rxport) {
- /* Port enable */
- reg = CHRK_SB_PGD_PORT_RX_CFGN(port_num - 0x10);
- } else { /* txport */
- /* Multiple Channel Setting - only FM Tx will be multiple
- * channel
- */
- if (enable && (port_num == CHRK_SB_PGD_PORT_TX1_FM ||
- port_num == CHRK_SB_PGD_PORT_TX2_FM)) {
-
- reg_val = (0x1 << CHRK_SB_PGD_PORT_TX1_FM) |
- (0x1 << CHRK_SB_PGD_PORT_TX2_FM);
- reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num);
+ if (enable && btfmslim->sample_rate == 48000) {
+ /* For A2DP Rx */
+ reg_val = 0x1;
+ port_bit = port_num - 0x10;
+ reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_0(port_bit);
+ BTFMSLIM_DBG("writing reg_val (%d) to reg(%x) for A2DP",
+ reg_val, reg);
ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
if (ret) {
- BTFMSLIM_ERR("failed to write (%d)", ret);
+ BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
+ ret, reg);
goto error;
}
}
+ /* Port enable */
+ reg = CHRK_SB_PGD_PORT_RX_CFGN(port_num - 0x10);
+ goto enable_disable_rxport;
+ }
+ if (!enable)
+ goto enable_disable_txport;
- /* Enable Tx port hw auto recovery for underrun or
- * overrun error
- */
- reg_val = (enable) ? (CHRK_ENABLE_OVERRUN_AUTO_RECOVERY |
- CHRK_ENABLE_UNDERRUN_AUTO_RECOVERY) : 0x0;
-
- ret = btfm_slim_write(btfmslim,
- CHRK_SB_PGD_PORT_TX_OR_UR_CFGN(port_num), 1,
- ®_val, IFD);
+ /* txport */
+ /* Multiple Channel Setting */
+ if (is_fm_port(port_num)) {
+ reg_val = (0x1 << CHRK_SB_PGD_PORT_TX1_FM) |
+ (0x1 << CHRK_SB_PGD_PORT_TX2_FM);
+ reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num);
+ ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
if (ret) {
- BTFMSLIM_ERR("failed to write (%d)", ret);
+ BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
goto error;
}
-
- /* Port enable */
- reg = CHRK_SB_PGD_PORT_TX_CFGN(port_num);
}
- if (enable)
- /* Set water mark to 1 and enable the port */
- reg_val = CHRK_SB_PGD_PORT_ENABLE | CHRK_SB_PGD_PORT_WM_LB;
- else
+ /* Enable Tx port hw auto recovery for underrun or overrun error */
+ reg_val = (CHRK_ENABLE_OVERRUN_AUTO_RECOVERY |
+ CHRK_ENABLE_UNDERRUN_AUTO_RECOVERY);
+ reg = CHRK_SB_PGD_PORT_TX_OR_UR_CFGN(port_num);
+ ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
+ if (ret) {
+ BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
+ goto error;
+ }
+
+enable_disable_txport:
+ /* Port enable */
+ reg = CHRK_SB_PGD_PORT_TX_CFGN(port_num);
+
+enable_disable_rxport:
+ if (enable) {
+ if (is_fm_port(port_num))
+ reg_val = CHRK_SB_PGD_PORT_ENABLE |
+ CHRK_SB_PGD_PORT_WM_L3;
+ else
+ reg_val = CHRK_SB_PGD_PORT_ENABLE |
+ CHRK_SB_PGD_PORT_WM_LB;
+ } else
reg_val = CHRK_SB_PGD_PORT_DISABLE;
ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
if (ret)
- BTFMSLIM_ERR("failed to write (%d)", ret);
+ BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
error:
return ret;
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 13fac71..7bc263c 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -211,6 +211,7 @@ struct fastrpc_channel_ctx {
struct device *dev;
struct fastrpc_session_ctx session[NUM_SESSIONS];
struct completion work;
+ struct completion workport;
struct notifier_block nb;
struct kref kref;
int sesscount;
@@ -1378,6 +1379,7 @@ static void fastrpc_init(struct fastrpc_apps *me)
me->channel = &gcinfo[0];
for (i = 0; i < NUM_CHANNELS; i++) {
init_completion(&me->channel[i].work);
+ init_completion(&me->channel[i].workport);
me->channel[i].sesscount = 0;
}
}
@@ -1828,7 +1830,7 @@ void fastrpc_glink_notify_state(void *handle, const void *priv,
switch (event) {
case GLINK_CONNECTED:
link->port_state = FASTRPC_LINK_CONNECTED;
- complete(&me->channel[cid].work);
+ complete(&me->channel[cid].workport);
break;
case GLINK_LOCAL_DISCONNECTED:
link->port_state = FASTRPC_LINK_DISCONNECTED;
@@ -1978,8 +1980,7 @@ static void fastrpc_glink_close(void *chan, int cid)
return;
link = &gfa.channel[cid].link;
- if (link->port_state == FASTRPC_LINK_CONNECTED ||
- link->port_state == FASTRPC_LINK_CONNECTING) {
+ if (link->port_state == FASTRPC_LINK_CONNECTED) {
link->port_state = FASTRPC_LINK_DISCONNECTING;
glink_close(chan);
}
@@ -2161,7 +2162,8 @@ static int fastrpc_channel_open(struct fastrpc_file *fl)
if (err)
goto bail;
- VERIFY(err, wait_for_completion_timeout(&me->channel[cid].work,
+ VERIFY(err,
+ wait_for_completion_timeout(&me->channel[cid].workport,
RPC_TIMEOUT));
if (err) {
me->channel[cid].chan = 0;
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 8f0597f..e2d39e7 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -2208,11 +2208,28 @@ struct diag_dci_client_tbl *dci_lookup_client_entry_pid(int tgid)
{
struct list_head *start, *temp;
struct diag_dci_client_tbl *entry = NULL;
+ struct pid *pid_struct = NULL;
+ struct task_struct *task_s = NULL;
list_for_each_safe(start, temp, &driver->dci_client_list) {
entry = list_entry(start, struct diag_dci_client_tbl, track);
- if (entry->client->tgid == tgid)
- return entry;
+ pid_struct = find_get_pid(entry->tgid);
+ if (!pid_struct) {
+ DIAG_LOG(DIAG_DEBUG_DCI,
+ "diag: valid pid doesn't exist for pid = %d\n",
+ entry->tgid);
+ continue;
+ }
+ task_s = get_pid_task(pid_struct, PIDTYPE_PID);
+ if (!task_s) {
+ DIAG_LOG(DIAG_DEBUG_DCI,
+ "diag: valid task doesn't exist for pid = %d\n",
+ entry->tgid);
+ continue;
+ }
+ if (task_s == entry->client)
+ if (entry->client->tgid == tgid)
+ return entry;
}
return NULL;
}
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index b5a594a..8aefb5a1 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -113,10 +113,12 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id)
else
mask_info = &log_mask;
- if (!mask_info)
+ if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
mask = (struct diag_log_mask_t *)mask_info->ptr;
+ if (!mask->ptr)
+ return;
buf = mask_info->update_buf;
switch (mask_info->status) {
@@ -225,7 +227,7 @@ static void diag_send_event_mask_update(uint8_t peripheral)
else
mask_info = &event_mask;
- if (!mask_info)
+ if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
buf = mask_info->update_buf;
@@ -289,6 +291,7 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last)
struct diag_mask_info *mask_info = NULL;
struct diag_msg_mask_t *mask = NULL;
struct diag_ctrl_msg_mask header;
+ uint8_t msg_mask_tbl_count_local;
if (peripheral >= NUM_PERIPHERALS)
return;
@@ -306,11 +309,17 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last)
else
mask_info = &msg_mask;
- if (!mask_info)
+ if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
-
+ mutex_lock(&driver->msg_mask_lock);
mask = (struct diag_msg_mask_t *)mask_info->ptr;
+ if (!mask->ptr) {
+ mutex_unlock(&driver->msg_mask_lock);
+ return;
+ }
buf = mask_info->update_buf;
+ msg_mask_tbl_count_local = driver->msg_mask_tbl_count;
+ mutex_unlock(&driver->msg_mask_lock);
mutex_lock(&mask_info->lock);
switch (mask_info->status) {
case DIAG_CTRL_MASK_ALL_DISABLED:
@@ -327,9 +336,11 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last)
goto err;
}
- for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
- if (((first < mask->ssid_first) ||
- (last > mask->ssid_last_tools)) && first != ALL_SSID) {
+ for (i = 0; i < msg_mask_tbl_count_local; i++, mask++) {
+ mutex_lock(&driver->msg_mask_lock);
+ if (((mask->ssid_first > first) ||
+ (mask->ssid_last_tools < last)) && first != ALL_SSID) {
+ mutex_unlock(&driver->msg_mask_lock);
continue;
}
@@ -370,12 +381,13 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last)
if (mask_size > 0)
memcpy(buf + header_len, mask->ptr, mask_size);
mutex_unlock(&mask->lock);
+ mutex_unlock(&driver->msg_mask_lock);
err = diagfwd_write(peripheral, TYPE_CNTL, buf,
header_len + mask_size);
if (err && err != -ENODEV)
- pr_err_ratelimited("diag: Unable to send msg masks to peripheral %d\n",
- peripheral);
+ pr_err_ratelimited("diag: Unable to send msg masks to peripheral %d, error = %d\n",
+ peripheral, err);
if (first != ALL_SSID)
break;
@@ -495,7 +507,7 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len,
if (!diag_apps_responds())
return 0;
-
+ mutex_lock(&driver->msg_mask_lock);
rsp.cmd_code = DIAG_CMD_MSG_CONFIG;
rsp.sub_cmd = DIAG_CMD_OP_GET_SSID_RANGE;
rsp.status = MSG_STATUS_SUCCESS;
@@ -503,7 +515,6 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len,
rsp.count = driver->msg_mask_tbl_count;
memcpy(dest_buf, &rsp, sizeof(rsp));
write_len += sizeof(rsp);
-
mask_ptr = (struct diag_msg_mask_t *)mask_info->ptr;
for (i = 0; i < driver->msg_mask_tbl_count; i++, mask_ptr++) {
if (write_len + sizeof(ssid_range) > dest_len) {
@@ -516,7 +527,7 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len,
memcpy(dest_buf + write_len, &ssid_range, sizeof(ssid_range));
write_len += sizeof(ssid_range);
}
-
+ mutex_unlock(&driver->msg_mask_lock);
return write_len;
}
@@ -540,7 +551,7 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len,
if (!diag_apps_responds())
return 0;
-
+ mutex_lock(&driver->msg_mask_lock);
req = (struct diag_build_mask_req_t *)src_buf;
rsp.cmd_code = DIAG_CMD_MSG_CONFIG;
rsp.sub_cmd = DIAG_CMD_OP_GET_BUILD_MASK;
@@ -548,9 +559,8 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len,
rsp.ssid_last = req->ssid_last;
rsp.status = MSG_STATUS_FAIL;
rsp.padding = 0;
-
build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr;
- for (i = 0; i < driver->msg_mask_tbl_count; i++, build_mask++) {
+ for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) {
if (build_mask->ssid_first != req->ssid_first)
continue;
num_entries = req->ssid_last - req->ssid_first + 1;
@@ -571,7 +581,7 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len,
}
memcpy(dest_buf, &rsp, sizeof(rsp));
write_len += sizeof(rsp);
-
+ mutex_unlock(&driver->msg_mask_lock);
return write_len;
}
@@ -599,6 +609,7 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len,
if (!diag_apps_responds())
return 0;
+ mutex_lock(&driver->msg_mask_lock);
req = (struct diag_build_mask_req_t *)src_buf;
rsp.cmd_code = DIAG_CMD_MSG_CONFIG;
rsp.sub_cmd = DIAG_CMD_OP_GET_MSG_MASK;
@@ -606,7 +617,6 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len,
rsp.ssid_last = req->ssid_last;
rsp.status = MSG_STATUS_FAIL;
rsp.padding = 0;
-
mask = (struct diag_msg_mask_t *)mask_info->ptr;
for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
if ((req->ssid_first < mask->ssid_first) ||
@@ -624,7 +634,7 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len,
}
memcpy(dest_buf, &rsp, sizeof(rsp));
write_len += sizeof(rsp);
-
+ mutex_unlock(&driver->msg_mask_lock);
return write_len;
}
@@ -655,8 +665,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len,
}
req = (struct diag_msg_build_mask_t *)src_buf;
-
mutex_lock(&mask_info->lock);
+ mutex_lock(&driver->msg_mask_lock);
mask = (struct diag_msg_mask_t *)mask_info->ptr;
for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
if (i < (driver->msg_mask_tbl_count - 1)) {
@@ -696,6 +706,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len,
pr_err_ratelimited("diag: In %s, unable to allocate memory for msg mask ptr, mask_size: %d\n",
__func__, mask_size);
mutex_unlock(&mask->lock);
+ mutex_unlock(&driver->msg_mask_lock);
+ mutex_unlock(&mask_info->lock);
return -ENOMEM;
}
mask->ptr = temp;
@@ -714,8 +726,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len,
mask_info->status = DIAG_CTRL_MASK_VALID;
break;
}
+ mutex_unlock(&driver->msg_mask_lock);
mutex_unlock(&mask_info->lock);
-
if (diag_check_update(APPS_DATA))
diag_update_userspace_clients(MSG_MASKS_TYPE);
@@ -740,7 +752,9 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len,
for (i = 0; i < NUM_PERIPHERALS; i++) {
if (!diag_check_update(i))
continue;
+ mutex_lock(&driver->md_session_lock);
diag_send_msg_mask_update(i, req->ssid_first, req->ssid_last);
+ mutex_unlock(&driver->md_session_lock);
}
end:
return write_len;
@@ -769,8 +783,10 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len,
req = (struct diag_msg_config_rsp_t *)src_buf;
- mask = (struct diag_msg_mask_t *)mask_info->ptr;
mutex_lock(&mask_info->lock);
+ mutex_lock(&driver->msg_mask_lock);
+
+ mask = (struct diag_msg_mask_t *)mask_info->ptr;
mask_info->status = (req->rt_mask) ? DIAG_CTRL_MASK_ALL_ENABLED :
DIAG_CTRL_MASK_ALL_DISABLED;
for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
@@ -779,6 +795,7 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len,
mask->range * sizeof(uint32_t));
mutex_unlock(&mask->lock);
}
+ mutex_unlock(&driver->msg_mask_lock);
mutex_unlock(&mask_info->lock);
if (diag_check_update(APPS_DATA))
@@ -799,7 +816,9 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len,
for (i = 0; i < NUM_PERIPHERALS; i++) {
if (!diag_check_update(i))
continue;
+ mutex_lock(&driver->md_session_lock);
diag_send_msg_mask_update(i, ALL_SSID, ALL_SSID);
+ mutex_unlock(&driver->md_session_lock);
}
return write_len;
@@ -893,7 +912,9 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len,
for (i = 0; i < NUM_PERIPHERALS; i++) {
if (!diag_check_update(i))
continue;
+ mutex_lock(&driver->md_session_lock);
diag_send_event_mask_update(i);
+ mutex_unlock(&driver->md_session_lock);
}
return write_len;
@@ -940,7 +961,9 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len,
for (i = 0; i < NUM_PERIPHERALS; i++) {
if (!diag_check_update(i))
continue;
+ mutex_lock(&driver->md_session_lock);
diag_send_event_mask_update(i);
+ mutex_unlock(&driver->md_session_lock);
}
memcpy(dest_buf, &header, sizeof(header));
write_len += sizeof(header);
@@ -1194,7 +1217,9 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len,
for (i = 0; i < NUM_PERIPHERALS; i++) {
if (!diag_check_update(i))
continue;
+ mutex_lock(&driver->md_session_lock);
diag_send_log_mask_update(i, req->equip_id);
+ mutex_unlock(&driver->md_session_lock);
}
end:
return write_len;
@@ -1245,7 +1270,9 @@ static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len,
for (i = 0; i < NUM_PERIPHERALS; i++) {
if (!diag_check_update(i))
continue;
+ mutex_lock(&driver->md_session_lock);
diag_send_log_mask_update(i, ALL_EQUIP_ID);
+ mutex_unlock(&driver->md_session_lock);
}
return write_len;
@@ -1284,6 +1311,7 @@ static int diag_create_msg_mask_table(void)
struct diag_ssid_range_t range;
mutex_lock(&msg_mask.lock);
+ mutex_lock(&driver->msg_mask_lock);
driver->msg_mask_tbl_count = MSG_MASK_TBL_CNT;
for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
range.ssid_first = msg_mask_tbl[i].ssid_first;
@@ -1292,6 +1320,7 @@ static int diag_create_msg_mask_table(void)
if (err)
break;
}
+ mutex_unlock(&driver->msg_mask_lock);
mutex_unlock(&msg_mask.lock);
return err;
}
@@ -1306,8 +1335,10 @@ static int diag_create_build_time_mask(void)
struct diag_ssid_range_t range;
mutex_lock(&msg_bt_mask.lock);
+ mutex_lock(&driver->msg_mask_lock);
+ driver->bt_msg_mask_tbl_count = MSG_MASK_TBL_CNT;
build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr;
- for (i = 0; i < driver->msg_mask_tbl_count; i++, build_mask++) {
+ for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) {
range.ssid_first = msg_mask_tbl[i].ssid_first;
range.ssid_last = msg_mask_tbl[i].ssid_last;
err = diag_create_msg_mask_table_entry(build_mask, &range);
@@ -1417,8 +1448,8 @@ static int diag_create_build_time_mask(void)
}
memcpy(build_mask->ptr, tbl, tbl_size);
}
+ mutex_unlock(&driver->msg_mask_lock);
mutex_unlock(&msg_bt_mask.lock);
-
return err;
}
@@ -1565,10 +1596,11 @@ static int diag_msg_mask_init(void)
pr_err("diag: Unable to create msg masks, err: %d\n", err);
return err;
}
+ mutex_lock(&driver->msg_mask_lock);
driver->msg_mask = &msg_mask;
-
for (i = 0; i < NUM_PERIPHERALS; i++)
driver->max_ssid_count[i] = 0;
+ mutex_unlock(&driver->msg_mask_lock);
return 0;
}
@@ -1587,8 +1619,8 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src)
err = __diag_mask_init(dest, MSG_MASK_SIZE, APPS_BUF_SIZE);
if (err)
return err;
-
mutex_lock(&dest->lock);
+ mutex_lock(&driver->msg_mask_lock);
src_mask = (struct diag_msg_mask_t *)src->ptr;
dest_mask = (struct diag_msg_mask_t *)dest->ptr;
@@ -1605,8 +1637,8 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src)
src_mask++;
dest_mask++;
}
+ mutex_unlock(&driver->msg_mask_lock);
mutex_unlock(&dest->lock);
-
return err;
}
@@ -1617,15 +1649,15 @@ void diag_msg_mask_free(struct diag_mask_info *mask_info)
if (!mask_info)
return;
-
mutex_lock(&mask_info->lock);
+ mutex_lock(&driver->msg_mask_lock);
mask = (struct diag_msg_mask_t *)mask_info->ptr;
for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
kfree(mask->ptr);
mask->ptr = NULL;
}
+ mutex_unlock(&driver->msg_mask_lock);
mutex_unlock(&mask_info->lock);
-
__diag_mask_exit(mask_info);
}
@@ -1633,15 +1665,17 @@ static void diag_msg_mask_exit(void)
{
int i;
struct diag_msg_mask_t *mask = NULL;
-
+ mutex_lock(&driver->msg_mask_lock);
mask = (struct diag_msg_mask_t *)(msg_mask.ptr);
if (mask) {
for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++)
kfree(mask->ptr);
kfree(msg_mask.ptr);
+ msg_mask.ptr = NULL;
}
-
kfree(msg_mask.update_buf);
+ msg_mask.update_buf = NULL;
+ mutex_unlock(&driver->msg_mask_lock);
}
static int diag_build_time_mask_init(void)
@@ -1666,13 +1700,15 @@ static void diag_build_time_mask_exit(void)
{
int i;
struct diag_msg_mask_t *mask = NULL;
-
+ mutex_lock(&driver->msg_mask_lock);
mask = (struct diag_msg_mask_t *)(msg_bt_mask.ptr);
if (mask) {
- for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++)
+ for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, mask++)
kfree(mask->ptr);
- kfree(msg_mask.ptr);
+ kfree(msg_bt_mask.ptr);
+ msg_bt_mask.ptr = NULL;
}
+ mutex_unlock(&driver->msg_mask_lock);
}
static int diag_log_mask_init(void)
@@ -1790,8 +1826,9 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count,
return -EIO;
}
mutex_unlock(&driver->diag_maskclear_mutex);
-
mutex_lock(&mask_info->lock);
+ mutex_lock(&driver->msg_mask_lock);
+
mask = (struct diag_msg_mask_t *)(mask_info->ptr);
for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
ptr = mask_info->update_buf;
@@ -1828,8 +1865,8 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count,
}
total_len += len;
}
+ mutex_unlock(&driver->msg_mask_lock);
mutex_unlock(&mask_info->lock);
-
return err ? err : total_len;
}
@@ -1898,9 +1935,11 @@ void diag_send_updates_peripheral(uint8_t peripheral)
diag_send_feature_mask_update(peripheral);
if (driver->time_sync_enabled)
diag_send_time_sync_update(peripheral);
+ mutex_lock(&driver->md_session_lock);
diag_send_msg_mask_update(peripheral, ALL_SSID, ALL_SSID);
diag_send_log_mask_update(peripheral, ALL_EQUIP_ID);
diag_send_event_mask_update(peripheral);
+ mutex_unlock(&driver->md_session_lock);
diag_send_real_time_update(peripheral,
driver->real_time_mode[DIAG_LOCAL_PROC]);
diag_send_peripheral_buffering_mode(
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index d3dde50..26e91f9 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -625,8 +625,10 @@ struct diagchar_dev {
struct diag_mask_info *event_mask;
struct diag_mask_info *build_time_mask;
uint8_t msg_mask_tbl_count;
+ uint8_t bt_msg_mask_tbl_count;
uint16_t event_mask_size;
uint16_t last_event_id;
+ struct mutex msg_mask_lock;
/* Variables for Mask Centralization */
uint16_t num_event_id[NUM_PERIPHERALS];
uint32_t num_equip_id[NUM_PERIPHERALS];
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 128d6ce..5b507df 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1713,14 +1713,18 @@ static int diag_ioctl_lsm_deinit(void)
{
int i;
+ mutex_lock(&driver->diagchar_mutex);
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
break;
- if (i == driver->num_clients)
+ if (i == driver->num_clients) {
+ mutex_unlock(&driver->diagchar_mutex);
return -EINVAL;
+ }
driver->data_ready[i] |= DEINIT_TYPE;
+ mutex_unlock(&driver->diagchar_mutex);
wake_up_interruptible(&driver->wait_q);
return 1;
@@ -3463,6 +3467,7 @@ static int __init diagchar_init(void)
mutex_init(&driver->diag_file_mutex);
mutex_init(&driver->delayed_rsp_mutex);
mutex_init(&apps_data_mutex);
+ mutex_init(&driver->msg_mask_lock);
for (i = 0; i < NUM_PERIPHERALS; i++)
mutex_init(&driver->diagfwd_channel_mutex[i]);
init_waitqueue_head(&driver->wait_q);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index e13871e..c975654 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -511,6 +511,7 @@ static void process_ssid_range_report(uint8_t *buf, uint32_t len,
/* Don't account for pkt_id and length */
read_len += header_len - (2 * sizeof(uint32_t));
+ mutex_lock(&driver->msg_mask_lock);
driver->max_ssid_count[peripheral] = header->count;
for (i = 0; i < header->count && read_len < len; i++) {
ssid_range = (struct diag_ssid_range_t *)ptr;
@@ -554,6 +555,7 @@ static void process_ssid_range_report(uint8_t *buf, uint32_t len,
}
driver->msg_mask_tbl_count += 1;
}
+ mutex_unlock(&driver->msg_mask_lock);
}
static void diag_build_time_mask_update(uint8_t *buf,
@@ -578,11 +580,11 @@ static void diag_build_time_mask_update(uint8_t *buf,
__func__, range->ssid_first, range->ssid_last);
return;
}
-
+ mutex_lock(&driver->msg_mask_lock);
build_mask = (struct diag_msg_mask_t *)(driver->build_time_mask->ptr);
num_items = range->ssid_last - range->ssid_first + 1;
- for (i = 0; i < driver->msg_mask_tbl_count; i++, build_mask++) {
+ for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) {
if (build_mask->ssid_first != range->ssid_first)
continue;
found = 1;
@@ -601,7 +603,7 @@ static void diag_build_time_mask_update(uint8_t *buf,
if (found)
goto end;
- new_size = (driver->msg_mask_tbl_count + 1) *
+ new_size = (driver->bt_msg_mask_tbl_count + 1) *
sizeof(struct diag_msg_mask_t);
temp = krealloc(driver->build_time_mask->ptr, new_size, GFP_KERNEL);
if (!temp) {
@@ -616,8 +618,9 @@ static void diag_build_time_mask_update(uint8_t *buf,
__func__, err);
goto end;
}
- driver->msg_mask_tbl_count += 1;
+ driver->bt_msg_mask_tbl_count += 1;
end:
+ mutex_unlock(&driver->msg_mask_lock);
return;
}
diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c
index ebc37f6..6476684 100644
--- a/drivers/char/diag/diagfwd_glink.c
+++ b/drivers/char/diag/diagfwd_glink.c
@@ -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
@@ -361,13 +361,41 @@ static void diag_glink_read_work_fn(struct work_struct *work)
diagfwd_channel_read(glink_info->fwd_ctxt);
}
+struct diag_glink_read_work {
+ struct diag_glink_info *glink_info;
+ const void *ptr_read_done;
+ const void *ptr_rx_done;
+ size_t ptr_read_size;
+ struct work_struct work;
+};
+
+static void diag_glink_notify_rx_work_fn(struct work_struct *work)
+{
+ struct diag_glink_read_work *read_work = container_of(work,
+ struct diag_glink_read_work, work);
+ struct diag_glink_info *glink_info = read_work->glink_info;
+
+ if (!glink_info || !glink_info->hdl)
+ return;
+
+ diagfwd_channel_read_done(glink_info->fwd_ctxt,
+ (unsigned char *)(read_work->ptr_read_done),
+ read_work->ptr_read_size);
+
+ glink_rx_done(glink_info->hdl, read_work->ptr_rx_done, false);
+
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: Rx done for packet %pK of len: %d periph: %d ch: %d\n",
+ read_work->ptr_rx_done, (int)read_work->ptr_read_size,
+ glink_info->peripheral, glink_info->type);
+}
static void diag_glink_notify_rx(void *hdl, const void *priv,
const void *pkt_priv, const void *ptr,
size_t size)
{
struct diag_glink_info *glink_info = (struct diag_glink_info *)priv;
- int err = 0;
+ struct diag_glink_read_work *read_work;
if (!glink_info || !glink_info->hdl || !ptr || !pkt_priv || !hdl)
return;
@@ -379,12 +407,24 @@ static void diag_glink_notify_rx(void *hdl, const void *priv,
"diag: received a packet %pK of len:%d from periph:%d ch:%d\n",
ptr, (int)size, glink_info->peripheral, glink_info->type);
+ read_work = kmalloc(sizeof(*read_work), GFP_ATOMIC);
+ if (!read_work) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: Could not allocate read_work\n");
+ return;
+ }
+
memcpy((void *)pkt_priv, ptr, size);
- err = diagfwd_channel_read_done(glink_info->fwd_ctxt,
- (unsigned char *)pkt_priv, size);
- glink_rx_done(glink_info->hdl, ptr, false);
+
+ read_work->glink_info = glink_info;
+ read_work->ptr_read_done = pkt_priv;
+ read_work->ptr_rx_done = ptr;
+ read_work->ptr_read_size = size;
+ INIT_WORK(&read_work->work, diag_glink_notify_rx_work_fn);
+ queue_work(glink_info->wq, &read_work->work);
+
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
- "diag: Rx done for packet %pK of len:%d periph:%d ch:%d\n",
+ "diag: Rx queued for packet %pK of len: %d periph: %d ch: %d\n",
ptr, (int)size, glink_info->peripheral, glink_info->type);
}
@@ -462,6 +502,45 @@ static int diag_glink_write(void *ctxt, unsigned char *buf, int len)
return err;
}
+
+static void diag_glink_connect_work_fn(struct work_struct *work)
+{
+ struct diag_glink_info *glink_info = container_of(work,
+ struct diag_glink_info,
+ connect_work);
+ if (!glink_info || !glink_info->hdl)
+ return;
+ atomic_set(&glink_info->opened, 1);
+ diagfwd_channel_open(glink_info->fwd_ctxt);
+ diagfwd_late_open(glink_info->fwd_ctxt);
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "glink channel open: p: %d t: %d\n",
+ glink_info->peripheral, glink_info->type);
+}
+
+static void diag_glink_remote_disconnect_work_fn(struct work_struct *work)
+{
+ struct diag_glink_info *glink_info = container_of(work,
+ struct diag_glink_info,
+ remote_disconnect_work);
+ if (!glink_info || !glink_info->hdl)
+ return;
+ atomic_set(&glink_info->opened, 0);
+ diagfwd_channel_close(glink_info->fwd_ctxt);
+ atomic_set(&glink_info->tx_intent_ready, 0);
+}
+
+static void diag_glink_late_init_work_fn(struct work_struct *work)
+{
+ struct diag_glink_info *glink_info = container_of(work,
+ struct diag_glink_info,
+ late_init_work);
+ if (!glink_info || !glink_info->hdl)
+ return;
+ diagfwd_channel_open(glink_info->fwd_ctxt);
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "glink late init p: %d t: %d\n",
+ glink_info->peripheral, glink_info->type);
+}
+
static void diag_glink_transport_notify_state(void *handle, const void *priv,
unsigned int event)
{
@@ -475,9 +554,7 @@ static void diag_glink_transport_notify_state(void *handle, const void *priv,
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
"%s received channel connect for periph:%d\n",
glink_info->name, glink_info->peripheral);
- atomic_set(&glink_info->opened, 1);
- diagfwd_channel_open(glink_info->fwd_ctxt);
- diagfwd_late_open(glink_info->fwd_ctxt);
+ queue_work(glink_info->wq, &glink_info->connect_work);
break;
case GLINK_LOCAL_DISCONNECTED:
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
@@ -489,9 +566,7 @@ static void diag_glink_transport_notify_state(void *handle, const void *priv,
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
"%s received channel remote disconnect for periph:%d\n",
glink_info->name, glink_info->peripheral);
- atomic_set(&glink_info->opened, 0);
- diagfwd_channel_close(glink_info->fwd_ctxt);
- atomic_set(&glink_info->tx_intent_ready, 0);
+ queue_work(glink_info->wq, &glink_info->remote_disconnect_work);
break;
default:
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
@@ -596,7 +671,7 @@ static void glink_late_init(struct diag_glink_info *glink_info)
glink_info->inited = 1;
if (atomic_read(&glink_info->opened))
- diagfwd_channel_open(glink_info->fwd_ctxt);
+ queue_work(glink_info->wq, &(glink_info->late_init_work));
DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n",
glink_info->name);
@@ -641,6 +716,10 @@ static void __diag_glink_init(struct diag_glink_info *glink_info)
INIT_WORK(&(glink_info->open_work), diag_glink_open_work_fn);
INIT_WORK(&(glink_info->close_work), diag_glink_close_work_fn);
INIT_WORK(&(glink_info->read_work), diag_glink_read_work_fn);
+ INIT_WORK(&(glink_info->connect_work), diag_glink_connect_work_fn);
+ INIT_WORK(&(glink_info->remote_disconnect_work),
+ diag_glink_remote_disconnect_work_fn);
+ INIT_WORK(&(glink_info->late_init_work), diag_glink_late_init_work_fn);
link_info.glink_link_state_notif_cb = diag_glink_notify_cb;
link_info.transport = NULL;
link_info.edge = glink_info->edge;
@@ -681,6 +760,8 @@ int diag_glink_init(void)
struct diag_glink_info *glink_info = NULL;
for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
+ if (peripheral != PERIPHERAL_WDSP)
+ continue;
glink_info = &glink_cntl[peripheral];
__diag_glink_init(glink_info);
diagfwd_cntl_register(TRANSPORT_GLINK, glink_info->peripheral,
@@ -719,6 +800,8 @@ void diag_glink_early_exit(void)
int peripheral = 0;
for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
+ if (peripheral != PERIPHERAL_WDSP)
+ continue;
__diag_glink_exit(&glink_cntl[peripheral]);
glink_unregister_link_state_cb(&glink_cntl[peripheral].hdl);
}
@@ -729,6 +812,8 @@ void diag_glink_exit(void)
int peripheral = 0;
for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
+ if (peripheral != PERIPHERAL_WDSP)
+ continue;
__diag_glink_exit(&glink_data[peripheral]);
__diag_glink_exit(&glink_cmd[peripheral]);
__diag_glink_exit(&glink_dci[peripheral]);
diff --git a/drivers/char/diag/diagfwd_glink.h b/drivers/char/diag/diagfwd_glink.h
index 73f2fe8..6cad445 100644
--- a/drivers/char/diag/diagfwd_glink.h
+++ b/drivers/char/diag/diagfwd_glink.h
@@ -35,6 +35,9 @@ struct diag_glink_info {
struct work_struct open_work;
struct work_struct close_work;
struct work_struct read_work;
+ struct work_struct connect_work;
+ struct work_struct remote_disconnect_work;
+ struct work_struct late_init_work;
struct diagfwd_info *fwd_ctxt;
};
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 119f5ac..3b8203f 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -668,7 +668,16 @@ void diagfwd_close_transport(uint8_t transport, uint8_t peripheral)
dest_info->buf_ptr[i] = fwd_info->buf_ptr[i];
if (!check_channel_state(dest_info->ctxt))
diagfwd_late_open(dest_info);
- diagfwd_cntl_open(dest_info);
+
+ /*
+ * Open control channel to update masks after buffers are
+ * initialized for peripherals that have transport other than
+ * GLINK. GLINK supported peripheral mask update will
+ * happen after glink buffers are initialized.
+ */
+
+ if (dest_info->transport != TRANSPORT_GLINK)
+ diagfwd_cntl_open(dest_info);
init_fn(peripheral);
mutex_unlock(&driver->diagfwd_channel_mutex[peripheral]);
diagfwd_queue_read(&peripheral_info[TYPE_DATA][peripheral]);
@@ -851,7 +860,18 @@ int diagfwd_channel_open(struct diagfwd_info *fwd_info)
mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
fwd_info->ch_open = 1;
diagfwd_buffers_init(fwd_info);
- diagfwd_write_buffers_init(fwd_info);
+
+ /*
+ * Initialize buffers for glink supported
+ * peripherals only. Open control channel to update
+ * masks after buffers are initialized.
+ */
+ if (fwd_info->transport == TRANSPORT_GLINK) {
+ diagfwd_write_buffers_init(fwd_info);
+ if (fwd_info->type == TYPE_CNTL)
+ diagfwd_cntl_open(fwd_info);
+ }
+
if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->open)
fwd_info->c_ops->open(fwd_info);
for (i = 0; i < NUM_WRITE_BUFFERS; i++) {
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index a7511a1..8069b36 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -59,7 +59,7 @@ static DEFINE_MUTEX(misc_mtx);
/*
* Assigned numbers, used for dynamic minors
*/
-#define DYNAMIC_MINORS 75 /* like dynamic majors */
+#define DYNAMIC_MINORS 64 /* like dynamic majors */
static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);
#ifdef CONFIG_PROC_FS
diff --git a/drivers/char/rdbg.c b/drivers/char/rdbg.c
index 92d9399..8612112 100644
--- a/drivers/char/rdbg.c
+++ b/drivers/char/rdbg.c
@@ -22,7 +22,7 @@
#include <linux/uaccess.h>
#include <linux/interrupt.h>
-#define SMP2P_NUM_PROCS 8
+#define SMP2P_NUM_PROCS 16
#define MAX_RETRIES 20
#define SM_VERSION 1
@@ -146,9 +146,17 @@ static struct processor_specific_info proc_info[SMP2P_NUM_PROCS] = {
{"rdbg_adsp", SMEM_LC_DEBUGGER, 16*1024}, /*ADSP*/
{0}, /*SMP2P_RESERVED_PROC_1*/
{"rdbg_wcnss", 0, 0}, /*WCNSS*/
- {0}, /*SMP2P_RESERVED_PROC_2*/
- {0}, /*SMP2P_POWER_PROC*/
- {0} /*SMP2P_REMOTE_MOCK_PROC*/
+ {"rdbg_cdsp", SMEM_LC_DEBUGGER, 16*1024}, /*CDSP*/
+ {NULL}, /*SMP2P_POWER_PROC*/
+ {NULL}, /*SMP2P_TZ_PROC*/
+ {NULL}, /*EMPTY*/
+ {NULL}, /*EMPTY*/
+ {NULL}, /*EMPTY*/
+ {NULL}, /*EMPTY*/
+ {NULL}, /*EMPTY*/
+ {NULL}, /*EMPTY*/
+ {NULL}, /*EMPTY*/
+ {NULL} /*SMP2P_REMOTE_MOCK_PROC*/
};
static int smq_blockmap_get(struct smq_block_map *block_map,
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index a017ccd..9ff8532 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -130,6 +130,41 @@ static void tpm_dev_release(struct device *dev)
kfree(chip);
}
+
+/**
+ * tpm_class_shutdown() - prepare the TPM device for loss of power.
+ * @dev: device to which the chip is associated.
+ *
+ * Issues a TPM2_Shutdown command prior to loss of power, as required by the
+ * TPM 2.0 spec.
+ * Then, calls bus- and device- specific shutdown code.
+ *
+ * XXX: This codepath relies on the fact that sysfs is not enabled for
+ * TPM2: sysfs uses an implicit lock on chip->ops, so this could race if TPM2
+ * has sysfs support enabled before TPM sysfs's implicit locking is fixed.
+ */
+static int tpm_class_shutdown(struct device *dev)
+{
+ struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
+
+ if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+ down_write(&chip->ops_sem);
+ tpm2_shutdown(chip, TPM2_SU_CLEAR);
+ chip->ops = NULL;
+ up_write(&chip->ops_sem);
+ }
+ /* Allow bus- and device-specific code to run. Note: since chip->ops
+ * is NULL, more-specific shutdown code will not be able to issue TPM
+ * commands.
+ */
+ if (dev->bus && dev->bus->shutdown)
+ dev->bus->shutdown(dev);
+ else if (dev->driver && dev->driver->shutdown)
+ dev->driver->shutdown(dev);
+ return 0;
+}
+
+
/**
* tpm_chip_alloc() - allocate a new struct tpm_chip instance
* @pdev: device to which the chip is associated
@@ -168,6 +203,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
device_initialize(&chip->dev);
chip->dev.class = tpm_class;
+ chip->dev.class->shutdown = tpm_class_shutdown;
chip->dev.release = tpm_dev_release;
chip->dev.parent = pdev;
chip->dev.groups = chip->groups;
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index a76ab4a..edf8c59 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -35,9 +35,10 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
ssize_t err;
int i, rc;
char *str = buf;
-
struct tpm_chip *chip = to_tpm_chip(dev);
+ memset(&tpm_cmd, 0, sizeof(tpm_cmd));
+
tpm_cmd.header.in = tpm_readpubek_header;
err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, 0,
"attempting to read the PUBEK");
@@ -284,6 +285,11 @@ static const struct attribute_group tpm_dev_group = {
void tpm_sysfs_add_device(struct tpm_chip *chip)
{
+ /* XXX: If you wish to remove this restriction, you must first update
+ * tpm_sysfs to explicitly lock chip->ops.
+ */
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
+ return;
/* The sysfs routines rely on an implicit tpm_try_get_ops, device_del
* is called before ops is null'd and the sysfs core synchronizes this
* removal so that no callbacks are running or can run again
diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c
index 3ca8e1c..46ced08 100644
--- a/drivers/clk/qcom/clk-branch.c
+++ b/drivers/clk/qcom/clk-branch.c
@@ -92,7 +92,7 @@ static int clk_branch_wait(const struct clk_branch *br, bool enabling,
} else if (br->halt_check == BRANCH_HALT_ENABLE ||
br->halt_check == BRANCH_HALT ||
(enabling && voted)) {
- int count = 200;
+ int count = 500;
while (count-- > 0) {
if (check_halt(br, enabling))
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index f12f03d..1d63a86 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -150,12 +150,17 @@
#define DATA_MEM(n) (0x400 + (n) * 4)
-#define DCVS_PERF_STATE_DESIRED_REG_0 0x780
-#define DCVS_PERF_STATE_DESIRED_REG(n) (DCVS_PERF_STATE_DESIRED_REG_0 + \
- (4 * n))
-#define OSM_CYCLE_COUNTER_STATUS_REG_0 0x7d0
-#define OSM_CYCLE_COUNTER_STATUS_REG(n) (OSM_CYCLE_COUNTER_STATUS_REG_0 + \
- (4 * n))
+#define DCVS_PERF_STATE_DESIRED_REG_0_V1 0x780
+#define DCVS_PERF_STATE_DESIRED_REG_0_V2 0x920
+#define DCVS_PERF_STATE_DESIRED_REG(n, v2) \
+ (((v2) ? DCVS_PERF_STATE_DESIRED_REG_0_V2 \
+ : DCVS_PERF_STATE_DESIRED_REG_0_V1) + 4 * (n))
+
+#define OSM_CYCLE_COUNTER_STATUS_REG_0_V1 0x7d0
+#define OSM_CYCLE_COUNTER_STATUS_REG_0_V2 0x9c0
+#define OSM_CYCLE_COUNTER_STATUS_REG(n, v2) \
+ (((v2) ? OSM_CYCLE_COUNTER_STATUS_REG_0_V2 \
+ : OSM_CYCLE_COUNTER_STATUS_REG_0_V1) + 4 * (n))
/* ACD registers */
#define ACD_HW_VERSION 0x0
@@ -444,6 +449,8 @@ static int clk_osm_acd_auto_local_write_reg(struct clk_osm *c, u32 mask)
return 0;
}
+static bool is_v2;
+
static inline struct clk_osm *to_clk_osm(struct clk_hw *_hw)
{
return container_of(_hw, struct clk_osm, hw);
@@ -604,8 +611,8 @@ static int l3_clk_set_rate(struct clk_hw *hw, unsigned long rate,
}
pr_debug("rate: %lu --> index %d\n", rate, index);
- clk_osm_write_reg(cpuclk, index, DCVS_PERF_STATE_DESIRED_REG_0,
- OSM_BASE);
+ clk_osm_write_reg(cpuclk, index, DCVS_PERF_STATE_DESIRED_REG(0, is_v2),
+ OSM_BASE);
/* Make sure the write goes through before proceeding */
clk_osm_mb(cpuclk, OSM_BASE);
@@ -622,7 +629,7 @@ static unsigned long l3_clk_recalc_rate(struct clk_hw *hw,
if (!cpuclk)
return -EINVAL;
- index = clk_osm_read_reg(cpuclk, DCVS_PERF_STATE_DESIRED_REG_0);
+ index = clk_osm_read_reg(cpuclk, DCVS_PERF_STATE_DESIRED_REG(0, is_v2));
pr_debug("%s: Index %d, freq %ld\n", __func__, index,
cpuclk->osm_table[index].frequency);
@@ -890,7 +897,8 @@ static struct clk_osm *osm_configure_policy(struct cpufreq_policy *policy)
static void
osm_set_index(struct clk_osm *c, unsigned int index, unsigned int num)
{
- clk_osm_write_reg(c, index, DCVS_PERF_STATE_DESIRED_REG(num), OSM_BASE);
+ clk_osm_write_reg(c, index, DCVS_PERF_STATE_DESIRED_REG(num, is_v2),
+ OSM_BASE);
/* Make sure the write goes through before proceeding */
clk_osm_mb(c, OSM_BASE);
@@ -915,8 +923,8 @@ static unsigned int osm_cpufreq_get(unsigned int cpu)
return 0;
c = policy->driver_data;
- index = clk_osm_read_reg(c, DCVS_PERF_STATE_DESIRED_REG(c->core_num));
-
+ index = clk_osm_read_reg(c,
+ DCVS_PERF_STATE_DESIRED_REG(c->core_num, is_v2));
return policy->freq_table[index].frequency;
}
@@ -1872,6 +1880,7 @@ static void populate_opp_table(struct platform_device *pdev)
static u64 clk_osm_get_cpu_cycle_counter(int cpu)
{
u32 val;
+ int core_num;
unsigned long flags;
struct clk_osm *parent, *c = logical_cpu_to_clk(cpu);
@@ -1887,12 +1896,9 @@ static u64 clk_osm_get_cpu_cycle_counter(int cpu)
* Use core 0's copy as proxy for the whole cluster when per
* core DCVS is disabled.
*/
- if (parent->per_core_dcvs)
- val = clk_osm_read_reg_no_log(parent,
- OSM_CYCLE_COUNTER_STATUS_REG(c->core_num));
- else
- val = clk_osm_read_reg_no_log(parent,
- OSM_CYCLE_COUNTER_STATUS_REG(0));
+ core_num = parent->per_core_dcvs ? c->core_num : 0;
+ val = clk_osm_read_reg_no_log(parent,
+ OSM_CYCLE_COUNTER_STATUS_REG(core_num, is_v2));
if (val < c->prev_cycle_counter) {
/* Handle counter overflow */
@@ -2061,6 +2067,10 @@ static int clk_osm_get_lut(struct platform_device *pdev,
c->osm_table[j].override_data,
c->osm_table[j].mem_acc_level);
+ data = (array[i + FREQ_DATA] & GENMASK(29, 28)) >> 28;
+ if (j && !c->min_cpr_vc && !data)
+ c->min_cpr_vc = c->osm_table[j].virtual_corner;
+
data = (array[i + FREQ_DATA] & GENMASK(18, 16)) >> 16;
if (!last_entry && data == MAX_CORE_COUNT) {
fmax_temp[k] = array[i];
@@ -2243,9 +2253,6 @@ static int clk_osm_parse_dt_configs(struct platform_device *pdev)
u32 *array;
int rc = 0;
struct resource *res;
- char l3_min_cpr_vc_str[] = "qcom,l3-min-cpr-vc-bin0";
- char pwrcl_min_cpr_vc_str[] = "qcom,pwrcl-min-cpr-vc-bin0";
- char perfcl_min_cpr_vc_str[] = "qcom,perfcl-min-cpr-vc-bin0";
array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32),
GFP_KERNEL);
@@ -2463,35 +2470,6 @@ static int clk_osm_parse_dt_configs(struct platform_device *pdev)
return -ENOMEM;
}
- snprintf(l3_min_cpr_vc_str, ARRAY_SIZE(l3_min_cpr_vc_str),
- "qcom,l3-min-cpr-vc-bin%d", l3_clk.speedbin);
- rc = of_property_read_u32(of, l3_min_cpr_vc_str, &l3_clk.min_cpr_vc);
- if (rc) {
- dev_err(&pdev->dev, "unable to find %s property, rc=%d\n",
- l3_min_cpr_vc_str, rc);
- return -EINVAL;
- }
-
- snprintf(pwrcl_min_cpr_vc_str, ARRAY_SIZE(pwrcl_min_cpr_vc_str),
- "qcom,pwrcl-min-cpr-vc-bin%d", pwrcl_clk.speedbin);
- rc = of_property_read_u32(of, pwrcl_min_cpr_vc_str,
- &pwrcl_clk.min_cpr_vc);
- if (rc) {
- dev_err(&pdev->dev, "unable to find %s property, rc=%d\n",
- pwrcl_min_cpr_vc_str, rc);
- return -EINVAL;
- }
-
- snprintf(perfcl_min_cpr_vc_str, ARRAY_SIZE(perfcl_min_cpr_vc_str),
- "qcom,perfcl-min-cpr-vc-bin%d", perfcl_clk.speedbin);
- rc = of_property_read_u32(of, perfcl_min_cpr_vc_str,
- &perfcl_clk.min_cpr_vc);
- if (rc) {
- dev_err(&pdev->dev, "unable to find %s property, rc=%d\n",
- perfcl_min_cpr_vc_str, rc);
- return -EINVAL;
- }
-
l3_clk.secure_init = perfcl_clk.secure_init = pwrcl_clk.secure_init =
of_property_read_bool(pdev->dev.of_node, "qcom,osm-no-tz");
@@ -3025,6 +3003,9 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
return PTR_ERR(ext_xo_clk);
}
+ is_v2 = of_device_is_compatible(pdev->dev.of_node,
+ "qcom,clk-cpu-osm-v2");
+
clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
GFP_KERNEL);
if (!clk_data)
@@ -3037,33 +3018,6 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
clk_data->clk_num = num_clks;
- rc = clk_osm_parse_dt_configs(pdev);
- if (rc) {
- dev_err(&pdev->dev, "Unable to parse OSM device tree configurations\n");
- return rc;
- }
-
- rc = clk_osm_parse_acd_dt_configs(pdev);
- if (rc) {
- dev_err(&pdev->dev, "Unable to parse ACD device tree configurations\n");
- return rc;
- }
-
- rc = clk_osm_resources_init(pdev);
- if (rc) {
- if (rc != -EPROBE_DEFER)
- dev_err(&pdev->dev, "OSM resources init failed, rc=%d\n",
- rc);
- return rc;
- }
-
- rc = clk_osm_acd_resources_init(pdev);
- if (rc) {
- dev_err(&pdev->dev, "ACD resources init failed, rc=%d\n",
- rc);
- return rc;
- }
-
if (l3_clk.vbases[EFUSE_BASE]) {
/* Multiple speed-bins are supported */
pte_efuse = readl_relaxed(l3_clk.vbases[EFUSE_BASE]);
@@ -3123,6 +3077,33 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
return rc;
}
+ rc = clk_osm_parse_dt_configs(pdev);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to parse OSM device tree configurations\n");
+ return rc;
+ }
+
+ rc = clk_osm_parse_acd_dt_configs(pdev);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to parse ACD device tree configurations\n");
+ return rc;
+ }
+
+ rc = clk_osm_resources_init(pdev);
+ if (rc) {
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "OSM resources init failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = clk_osm_acd_resources_init(pdev);
+ if (rc) {
+ dev_err(&pdev->dev, "ACD resources init failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
rc = clk_osm_resolve_open_loop_voltages(&l3_clk);
if (rc) {
if (rc == -EPROBE_DEFER)
@@ -3313,8 +3294,10 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
rc);
goto provider_err;
}
- WARN(clk_prepare_enable(l3_clk.hw.clk),
- "clk: Failed to enable clock for L3\n");
+ WARN(clk_prepare_enable(l3_cluster0_vote_clk.hw.clk),
+ "clk: Failed to enable cluster0 clock for L3\n");
+ WARN(clk_prepare_enable(l3_cluster1_vote_clk.hw.clk),
+ "clk: Failed to enable cluster1 clock for L3\n");
udelay(300);
/* Configure default rate to lowest frequency */
@@ -3352,6 +3335,7 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
static const struct of_device_id match_table[] = {
{ .compatible = "qcom,clk-cpu-osm" },
+ { .compatible = "qcom,clk-cpu-osm-v2" },
{}
};
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index b63c3c3..fd2a8bd 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -934,10 +934,11 @@ const struct clk_ops clk_byte2_ops = {
EXPORT_SYMBOL_GPL(clk_byte2_ops);
static const struct frac_entry frac_table_pixel[] = {
+ { 1, 1 },
+ { 2, 3 },
+ { 4, 9 },
{ 3, 8 },
{ 2, 9 },
- { 4, 9 },
- { 1, 1 },
{ }
};
diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c
index 5348491..c314d2c 100644
--- a/drivers/clk/qcom/clk-regmap-divider.c
+++ b/drivers/clk/qcom/clk-regmap-divider.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -28,8 +28,10 @@ static long div_round_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_regmap_div *divider = to_clk_regmap_div(hw);
- return divider_round_rate(hw, rate, prate, NULL, divider->width,
- CLK_DIVIDER_ROUND_CLOSEST);
+ return divider_round_rate(hw, rate, prate, divider->table,
+ divider->width,
+ CLK_DIVIDER_ROUND_CLOSEST |
+ divider->flags);
}
static int div_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -39,8 +41,9 @@ static int div_set_rate(struct clk_hw *hw, unsigned long rate,
struct clk_regmap *clkr = ÷r->clkr;
u32 div;
- div = divider_get_val(rate, parent_rate, NULL, divider->width,
- CLK_DIVIDER_ROUND_CLOSEST);
+ div = divider_get_val(rate, parent_rate, divider->table,
+ divider->width, CLK_DIVIDER_ROUND_CLOSEST |
+ divider->flags);
return regmap_update_bits(clkr->regmap, divider->reg,
(BIT(divider->width) - 1) << divider->shift,
@@ -58,8 +61,8 @@ static unsigned long div_recalc_rate(struct clk_hw *hw,
div >>= divider->shift;
div &= BIT(divider->width) - 1;
- return divider_recalc_rate(hw, parent_rate, div, NULL,
- CLK_DIVIDER_ROUND_CLOSEST);
+ return divider_recalc_rate(hw, parent_rate, div, divider->table,
+ CLK_DIVIDER_ROUND_CLOSEST | divider->flags);
}
const struct clk_ops clk_regmap_div_ops = {
diff --git a/drivers/clk/qcom/clk-regmap-divider.h b/drivers/clk/qcom/clk-regmap-divider.h
index fc4492e..1c5e087 100644
--- a/drivers/clk/qcom/clk-regmap-divider.h
+++ b/drivers/clk/qcom/clk-regmap-divider.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -18,10 +18,12 @@
#include "clk-regmap.h"
struct clk_regmap_div {
- u32 reg;
- u32 shift;
- u32 width;
- struct clk_regmap clkr;
+ u32 reg;
+ u32 shift;
+ u32 width;
+ u32 flags;
+ const struct clk_div_table *table;
+ struct clk_regmap clkr;
};
extern const struct clk_ops clk_regmap_div_ops;
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 25f9d62..1450b91 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -53,7 +53,9 @@ enum {
P_CORE_BI_PLL_TEST_SE,
P_GPLL0_OUT_EVEN,
P_GPLL0_OUT_MAIN,
+ P_GPLL1_OUT_MAIN,
P_GPLL4_OUT_MAIN,
+ P_GPLL6_OUT_MAIN,
P_SLEEP_CLK,
};
@@ -166,6 +168,20 @@ static const char * const gcc_parent_names_8[] = {
"core_bi_pll_test_se",
};
+static const struct parent_map gcc_parent_map_9[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL1_OUT_MAIN, 4 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_9[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll1",
+ "core_bi_pll_test_se",
+};
+
static struct clk_dummy measure_only_snoc_clk = {
.rrate = 1000,
.hw.init = &(struct clk_init_data){
@@ -1224,6 +1240,49 @@ static struct clk_rcg2 gcc_usb3_sec_phy_aux_clk_src = {
},
};
+static struct clk_rcg2 gcc_vs_ctrl_clk_src = {
+ .cmd_rcgr = 0x7a030,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_vs_ctrl_clk_src",
+ .parent_names = gcc_parent_names_3,
+ .num_parents = 3,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ VDD_CX_FMAX_MAP1(
+ MIN, 19200000),
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_vsensor_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+ F(600000000, P_GPLL0_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_vsensor_clk_src = {
+ .cmd_rcgr = 0x7a018,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_9,
+ .freq_tbl = ftbl_gcc_vsensor_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_vsensor_clk_src",
+ .parent_names = gcc_parent_names_9,
+ .num_parents = 4,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ VDD_CX_FMAX_MAP3(
+ MIN, 19200000,
+ LOW, 300000000,
+ LOW_L1, 600000000),
+ },
+};
+
static struct clk_branch gcc_aggre_noc_pcie_tbu_clk = {
.halt_reg = 0x90014,
.halt_check = BRANCH_HALT,
@@ -1347,6 +1406,24 @@ static struct clk_branch gcc_aggre_usb3_sec_axi_clk = {
},
};
+static struct clk_branch gcc_apc_vs_clk = {
+ .halt_reg = 0x7a050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7a050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_apc_vs_clk",
+ .parent_names = (const char *[]){
+ "gcc_vsensor_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_boot_rom_ahb_clk = {
.halt_reg = 0x38004,
.halt_check = BRANCH_HALT_VOTED,
@@ -1774,6 +1851,24 @@ static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = {
},
};
+static struct clk_branch gcc_gpu_vs_clk = {
+ .halt_reg = 0x7a04c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7a04c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_vs_clk",
+ .parent_names = (const char *[]){
+ "gcc_vsensor_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_mss_axis2_clk = {
.halt_reg = 0x8a008,
.halt_check = BRANCH_HALT,
@@ -1855,6 +1950,24 @@ static struct clk_branch gcc_mss_snoc_axi_clk = {
},
};
+static struct clk_branch gcc_mss_vs_clk = {
+ .halt_reg = 0x7a048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7a048,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_vs_clk",
+ .parent_names = (const char *[]){
+ "gcc_vsensor_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_pcie_0_aux_clk = {
.halt_reg = 0x6b01c,
.halt_check = BRANCH_HALT_VOTED,
@@ -1914,14 +2027,15 @@ static struct clk_branch gcc_pcie_0_mstr_axi_clk = {
},
};
-static struct clk_gate2 gcc_pcie_0_pipe_clk = {
- .udelay = 500,
+static struct clk_branch gcc_pcie_0_pipe_clk = {
+ .halt_reg = 0x6b020,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x5200c,
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_pipe_clk",
- .ops = &clk_gate2_ops,
+ .ops = &clk_branch2_ops,
},
},
};
@@ -2013,14 +2127,15 @@ static struct clk_branch gcc_pcie_1_mstr_axi_clk = {
},
};
-static struct clk_gate2 gcc_pcie_1_pipe_clk = {
- .udelay = 500,
+static struct clk_branch gcc_pcie_1_pipe_clk = {
+ .halt_reg = 0x8d020,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x52004,
.enable_mask = BIT(30),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_pipe_clk",
- .ops = &clk_gate2_ops,
+ .ops = &clk_branch2_ops,
},
},
};
@@ -3322,6 +3437,60 @@ static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = {
},
};
+static struct clk_branch gcc_vdda_vs_clk = {
+ .halt_reg = 0x7a00c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7a00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_vdda_vs_clk",
+ .parent_names = (const char *[]){
+ "gcc_vsensor_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_vddcx_vs_clk = {
+ .halt_reg = 0x7a004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_vddcx_vs_clk",
+ .parent_names = (const char *[]){
+ "gcc_vsensor_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_vddmx_vs_clk = {
+ .halt_reg = 0x7a008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7a008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_vddmx_vs_clk",
+ .parent_names = (const char *[]){
+ "gcc_vsensor_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_video_ahb_clk = {
.halt_reg = 0xb004,
.halt_check = BRANCH_HALT,
@@ -3363,6 +3532,39 @@ static struct clk_branch gcc_video_xo_clk = {
},
};
+static struct clk_branch gcc_vs_ctrl_ahb_clk = {
+ .halt_reg = 0x7a014,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x7a014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7a014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_vs_ctrl_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_vs_ctrl_clk = {
+ .halt_reg = 0x7a010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7a010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_vs_ctrl_clk",
+ .parent_names = (const char *[]){
+ "gcc_vs_ctrl_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
struct clk_hw *gcc_sdm845_hws[] = {
[MEASURE_ONLY_SNOC_CLK] = &measure_only_snoc_clk.hw,
[MEASURE_ONLY_CNOC_CLK] = &measure_only_cnoc_clk.hw,
@@ -3380,6 +3582,7 @@ static struct clk_regmap *gcc_sdm845_clocks[] = {
&gcc_aggre_ufs_phy_axi_hw_ctl_clk.clkr,
[GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr,
[GCC_AGGRE_USB3_SEC_AXI_CLK] = &gcc_aggre_usb3_sec_axi_clk.clkr,
+ [GCC_APC_VS_CLK] = &gcc_apc_vs_clk.clkr,
[GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
[GCC_CAMERA_AHB_CLK] = &gcc_camera_ahb_clk.clkr,
[GCC_CAMERA_AXI_CLK] = &gcc_camera_axi_clk.clkr,
@@ -3413,12 +3616,14 @@ static struct clk_regmap *gcc_sdm845_clocks[] = {
[GCC_GPU_IREF_CLK] = &gcc_gpu_iref_clk.clkr,
[GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr,
[GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr,
+ [GCC_GPU_VS_CLK] = &gcc_gpu_vs_clk.clkr,
[GCC_MSS_AXIS2_CLK] = &gcc_mss_axis2_clk.clkr,
[GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr,
[GCC_MSS_GPLL0_DIV_CLK_SRC] = &gcc_mss_gpll0_div_clk_src.clkr,
[GCC_MSS_MFAB_AXIS_CLK] = &gcc_mss_mfab_axis_clk.clkr,
[GCC_MSS_Q6_MEMNOC_AXI_CLK] = &gcc_mss_q6_memnoc_axi_clk.clkr,
[GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr,
+ [GCC_MSS_VS_CLK] = &gcc_mss_vs_clk.clkr,
[GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr,
[GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr,
[GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr,
@@ -3558,9 +3763,16 @@ static struct clk_regmap *gcc_sdm845_clocks[] = {
[GCC_USB3_SEC_PHY_COM_AUX_CLK] = &gcc_usb3_sec_phy_com_aux_clk.clkr,
[GCC_USB3_SEC_PHY_PIPE_CLK] = &gcc_usb3_sec_phy_pipe_clk.clkr,
[GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr,
+ [GCC_VDDA_VS_CLK] = &gcc_vdda_vs_clk.clkr,
+ [GCC_VDDCX_VS_CLK] = &gcc_vddcx_vs_clk.clkr,
+ [GCC_VDDMX_VS_CLK] = &gcc_vddmx_vs_clk.clkr,
[GCC_VIDEO_AHB_CLK] = &gcc_video_ahb_clk.clkr,
[GCC_VIDEO_AXI_CLK] = &gcc_video_axi_clk.clkr,
[GCC_VIDEO_XO_CLK] = &gcc_video_xo_clk.clkr,
+ [GCC_VS_CTRL_AHB_CLK] = &gcc_vs_ctrl_ahb_clk.clkr,
+ [GCC_VS_CTRL_CLK] = &gcc_vs_ctrl_clk.clkr,
+ [GCC_VS_CTRL_CLK_SRC] = &gcc_vs_ctrl_clk_src.clkr,
+ [GCC_VSENSOR_CLK_SRC] = &gcc_vsensor_clk_src.clkr,
[GPLL0] = &gpll0.clkr,
[GPLL0_OUT_EVEN] = &gpll0_out_even.clkr,
};
diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c
index b2f6a3c..5f1b1ef 100644
--- a/drivers/clk/qcom/gpucc-sdm845.c
+++ b/drivers/clk/qcom/gpucc-sdm845.c
@@ -36,6 +36,11 @@
#include "clk-alpha-pll.h"
#include "vdd-level-sdm845.h"
+#define CX_GMU_CBCR_SLEEP_MASK 0xF
+#define CX_GMU_CBCR_SLEEP_SHIFT 4
+#define CX_GMU_CBCR_WAKE_MASK 0xF
+#define CX_GMU_CBCR_WAKE_SHIFT 8
+
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
static int vdd_gx_corner[] = {
@@ -648,6 +653,7 @@ static int gpu_cc_sdm845_probe(struct platform_device *pdev)
{
struct regmap *regmap;
int ret = 0;
+ unsigned int value, mask;
regmap = qcom_cc_map(pdev, &gpu_cc_sdm845_desc);
if (IS_ERR(regmap))
@@ -668,6 +674,12 @@ static int gpu_cc_sdm845_probe(struct platform_device *pdev)
return ret;
}
+ mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT;
+ mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT;
+ value = 0xF << CX_GMU_CBCR_WAKE_SHIFT | 0xF << CX_GMU_CBCR_SLEEP_SHIFT;
+ regmap_update_bits(regmap, gpu_cc_cx_gmu_clk.clkr.enable_reg,
+ mask, value);
+
dev_info(&pdev->dev, "Registered GPU CC clocks\n");
return ret;
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index 93ad1b0..eb6c658 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -94,7 +94,6 @@ enum {
struct dsi_pll_regs {
u32 pll_prop_gain_rate;
- u32 pll_outdiv_rate;
u32 pll_lockdet_rate;
u32 decimal_div_start;
u32 frac_div_start_low;
@@ -134,6 +133,165 @@ struct dsi_pll_10nm {
struct dsi_pll_regs reg_setup;
};
+static inline int pll_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc) {
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ return rc;
+ }
+
+ *val = MDSS_PLL_REG_R(rsc->pll_base, reg);
+ (void)mdss_pll_resource_enable(rsc, false);
+
+ return rc;
+}
+
+static inline int pll_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc) {
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ return rc;
+ }
+
+ MDSS_PLL_REG_W(rsc->pll_base, reg, val);
+ (void)mdss_pll_resource_enable(rsc, false);
+
+ return rc;
+}
+
+static inline int phy_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc) {
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ return rc;
+ }
+
+ *val = MDSS_PLL_REG_R(rsc->phy_base, reg);
+ (void)mdss_pll_resource_enable(rsc, false);
+
+ return rc;
+}
+
+static inline int phy_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc) {
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ return rc;
+ }
+
+ MDSS_PLL_REG_W(rsc->phy_base, reg, val);
+ (void)mdss_pll_resource_enable(rsc, false);
+
+ return rc;
+}
+
+static inline int phy_reg_update_bits_sub(struct mdss_pll_resources *rsc,
+ unsigned int reg, unsigned int mask, unsigned int val)
+{
+ u32 reg_val;
+ int rc = 0;
+
+ reg_val = MDSS_PLL_REG_R(rsc->phy_base, reg);
+ reg_val &= ~mask;
+ reg_val |= (val & mask);
+ MDSS_PLL_REG_W(rsc->phy_base, reg, reg_val);
+
+ return rc;
+}
+
+static inline int phy_reg_update_bits(void *context, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc) {
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = phy_reg_update_bits_sub(rsc, reg, mask, val);
+ if (!rc && rsc->slave)
+ rc = phy_reg_update_bits_sub(rsc->slave, reg, mask, val);
+ (void)mdss_pll_resource_enable(rsc, false);
+
+ return rc;
+}
+
+static inline int pclk_mux_read_sel(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc)
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ else
+ *val = (MDSS_PLL_REG_R(rsc->pll_base, reg) & 0x3);
+
+ (void)mdss_pll_resource_enable(rsc, false);
+ return rc;
+}
+
+
+static inline int pclk_mux_write_sel_sub(struct mdss_pll_resources *rsc,
+ unsigned int reg, unsigned int val)
+{
+ u32 reg_val;
+ int rc = 0;
+
+ reg_val = MDSS_PLL_REG_R(rsc->phy_base, reg);
+ reg_val &= ~0x03;
+ reg_val |= val;
+
+ MDSS_PLL_REG_W(rsc->phy_base, reg, reg_val);
+
+ return rc;
+}
+
+static inline int pclk_mux_write_sel(void *context, unsigned int reg,
+ unsigned int val)
+{
+ int rc = 0;
+ struct mdss_pll_resources *rsc = context;
+
+ rc = mdss_pll_resource_enable(rsc, true);
+ if (rc) {
+ pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = pclk_mux_write_sel_sub(rsc, reg, val);
+ if (!rc && rsc->slave)
+ rc = pclk_mux_write_sel_sub(rsc->slave, reg, val);
+
+ (void)mdss_pll_resource_enable(rsc, false);
+
+ return rc;
+}
+
static struct mdss_pll_resources *pll_rsc_db[DSI_PLL_MAX];
static struct dsi_pll_10nm plls[DSI_PLL_MAX];
@@ -203,54 +361,14 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll,
{
struct dsi_pll_config *config = &pll->pll_configuration;
struct dsi_pll_regs *regs = &pll->reg_setup;
- u64 target_freq;
u64 fref = rsc->vco_ref_clk_rate;
- u32 computed_output_div, div_log = 0;
u64 pll_freq;
u64 divider;
u64 dec, dec_multiple;
u32 frac;
u64 multiplier;
- u32 i;
- target_freq = rsc->vco_current_rate;
- pr_debug("target_freq = %llu\n", target_freq);
-
- if (config->div_override) {
- computed_output_div = config->output_div;
-
- /*
- * Computed_output_div = 2 ^ div_log
- * To get div_log from output div just get the index of the
- * 1 bit in the value.
- * div_log ranges from 0-3. so check the 4 lsbs
- */
-
- for (i = 0; i < 4; i++) {
- if (computed_output_div & (1 << i)) {
- div_log = i;
- break;
- }
- }
-
- } else {
- if (target_freq < MHZ_250) {
- computed_output_div = 8;
- div_log = 3;
- } else if (target_freq < MHZ_500) {
- computed_output_div = 4;
- div_log = 2;
- } else if (target_freq < MHZ_1000) {
- computed_output_div = 2;
- div_log = 1;
- } else {
- computed_output_div = 1;
- div_log = 0;
- }
- }
- pr_debug("computed_output_div = %d\n", computed_output_div);
-
- pll_freq = target_freq * computed_output_div;
+ pll_freq = rsc->vco_current_rate;
if (config->disable_prescaler)
divider = fref;
@@ -274,7 +392,6 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll,
else
regs->pll_clock_inverters = 0;
- regs->pll_outdiv_rate = div_log;
regs->pll_lockdet_rate = config->lock_timer;
regs->decimal_div_start = dec;
regs->frac_div_start_low = (frac & 0xff);
@@ -394,7 +511,6 @@ static void dsi_pll_commit(struct dsi_pll_10nm *pll,
MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_HIGH_1,
reg->frac_div_start_high);
MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0x40);
- MDSS_PLL_REG_W(pll_base, PLL_PLL_OUTDIV_RATE, reg->pll_outdiv_rate);
MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x06);
MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x10);
MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, reg->pll_clock_inverters);
@@ -605,7 +721,9 @@ static void vco_10nm_unprepare(struct clk_hw *hw)
}
pll->cached_cfg0 = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
pll->cached_cfg1 = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
- pr_debug("cfg0=%d,cfg1=%d\n", pll->cached_cfg0, pll->cached_cfg1);
+ pll->cached_outdiv = MDSS_PLL_REG_R(pll->pll_base, PLL_PLL_OUTDIV_RATE);
+ pr_debug("cfg0=%d,cfg1=%d, outdiv=%d\n", pll->cached_cfg0,
+ pll->cached_cfg1, pll->cached_outdiv);
pll->vco_cached_rate = clk_hw_get_rate(hw);
dsi_pll_disable(vco);
@@ -646,6 +764,8 @@ static int vco_10nm_prepare(struct clk_hw *hw)
pll->cached_cfg0);
MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG1,
pll->cached_cfg1);
+ MDSS_PLL_REG_W(pll->pll_base, PLL_PLL_OUTDIV_RATE,
+ pll->cached_outdiv);
}
rc = dsi_pll_enable(vco);
@@ -855,176 +975,6 @@ static int bit_clk_set_div(void *context, unsigned int reg, unsigned int div)
return rc;
}
-static int post_vco_clk_get_div(void *context, unsigned int reg,
- unsigned int *div)
-{
- int rc;
- struct mdss_pll_resources *pll = context;
- u32 reg_val;
-
- rc = mdss_pll_resource_enable(pll, true);
- if (rc) {
- pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
- return rc;
- }
-
- reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
- reg_val &= 0x3;
-
- if (reg_val == 2)
- *div = 1;
- else if (reg_val == 3)
- *div = 4;
- else
- *div = 1;
-
- /**
- *Common clock framework the divider value is interpreted as one less
- * hence we return one less for all dividers except when zero
- */
- if (*div != 0)
- *div -= 1;
-
- (void)mdss_pll_resource_enable(pll, false);
-
- return rc;
-}
-
-static int post_vco_clk_set_div_sub(struct mdss_pll_resources *pll, int div)
-{
- u32 reg_val;
- int rc = 0;
-
- reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
- reg_val &= ~0x03;
- if (div == 1) {
- reg_val |= 0x2;
- } else if (div == 4) {
- reg_val |= 0x3;
- } else {
- rc = -EINVAL;
- pr_err("unsupported divider %d\n", div);
- goto error;
- }
-
- MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG1, reg_val);
-
-error:
- return rc;
-}
-
-static int post_vco_clk_set_div(void *context, unsigned int reg,
- unsigned int div)
-{
- int rc = 0;
- struct mdss_pll_resources *pll = context;
-
- rc = mdss_pll_resource_enable(pll, true);
- if (rc) {
- pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
- return rc;
- }
-
- /**
- * In common clock framework the divider value provided is one less and
- * and hence adjusting the divider value by one prior to writing it to
- * hardware
- */
- div++;
- rc = post_vco_clk_set_div_sub(pll, div);
- if (!rc && pll->slave)
- rc = post_vco_clk_set_div_sub(pll->slave, div);
-
- (void)mdss_pll_resource_enable(pll, false);
-
- return rc;
-}
-
-static int post_bit_clk_get_div(void *context, unsigned int reg,
- unsigned int *div)
-{
- int rc;
- struct mdss_pll_resources *pll = context;
- u32 reg_val;
-
- rc = mdss_pll_resource_enable(pll, true);
- if (rc) {
- pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
- return rc;
- }
-
- reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
- reg_val &= 0x3;
-
- if (reg_val == 0)
- *div = 1;
- else if (reg_val == 1)
- *div = 2;
- else
- *div = 1;
-
- /**
- *Common clock framework the divider value is interpreted as one less
- * hence we return one less for all dividers except when zero
- */
- if (*div != 0)
- *div -= 1;
-
- (void)mdss_pll_resource_enable(pll, false);
-
- return rc;
-}
-
-static int post_bit_clk_set_div_sub(struct mdss_pll_resources *pll, int div)
-{
- int rc = 0;
- u32 reg_val;
-
- reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
- reg_val &= ~0x03;
- if (div == 1) {
- reg_val |= 0x0;
- } else if (div == 2) {
- reg_val |= 0x1;
- } else {
- rc = -EINVAL;
- pr_err("unsupported divider %d\n", div);
- goto error;
- }
-
- MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG1, reg_val);
-
-error:
- return rc;
-}
-
-static int post_bit_clk_set_div(void *context, unsigned int reg,
- unsigned int div)
-{
- int rc = 0;
- struct mdss_pll_resources *pll = context;
-
- rc = mdss_pll_resource_enable(pll, true);
- if (rc) {
- pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
- return rc;
- }
-
- /**
- * In common clock framework the divider value provided is one less and
- * and hence adjusting the divider value by one prior to writing it to
- * hardware
- */
- div++;
- rc = post_bit_clk_set_div_sub(pll, div);
- if (!rc && pll->slave)
- rc = post_bit_clk_set_div_sub(pll->slave, div);
-
- (void)mdss_pll_resource_enable(pll, false);
-
- return rc;
-}
-
static struct regmap_config dsi_pll_10nm_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -1032,14 +982,14 @@ static struct regmap_config dsi_pll_10nm_config = {
.max_register = 0x7c0,
};
-static struct regmap_bus post_vco_regmap_bus = {
- .reg_write = post_vco_clk_set_div,
- .reg_read = post_vco_clk_get_div,
+static struct regmap_bus pll_regmap_bus = {
+ .reg_write = pll_reg_write,
+ .reg_read = pll_reg_read,
};
-static struct regmap_bus post_bit_regmap_bus = {
- .reg_write = post_bit_clk_set_div,
- .reg_read = post_bit_clk_get_div,
+static struct regmap_bus pclk_mux_regmap_bus = {
+ .reg_read = phy_reg_read,
+ .reg_write = pclk_mux_write_sel,
};
static struct regmap_bus pclk_src_regmap_bus = {
@@ -1073,23 +1023,30 @@ static struct regmap_bus mdss_mux_regmap_bus = {
* | vco_clk |
* +-------+-------+
* |
- * +--------------------------------------+
- * | |
- * +-------v-------+ |
- * | bitclk_src | |
- * | DIV(1..15) | |
- * +-------+-------+ |
- * | |
- * +--------------------+ |
- * Shadow Path | | |
- * + +-------v-------+ +------v------+ +------v-------+
- * | | byteclk_src | |post_bit_div | |post_vco_div |
- * | | DIV(8) | |DIV(1,2) | |DIV(1,4) |
- * | +-------+-------+ +------+------+ +------+-------+
- * | | | |
- * | | +------+ +----+
- * | +--------+ | |
- * | | +----v-----v------+
+ * |
+ * +---------------+
+ * | pll_out_div |
+ * | DIV(1,2,4,8) |
+ * +-------+-------+
+ * |
+ * +-----------------------------+--------+
+ * | | |
+ * +-------v-------+ | |
+ * | bitclk_src | | |
+ * | DIV(1..15) | | |
+ * +-------+-------+ | |
+ * | | |
+ * +----------+---------+ | |
+ * Shadow Path | | | | |
+ * + +-------v-------+ | +------v------+ | +------v-------+
+ * | | byteclk_src | | |post_bit_div | | |post_vco_div |
+ * | | DIV(8) | | |DIV (2) | | |DIV(4) |
+ * | +-------+-------+ | +------+------+ | +------+-------+
+ * | | | | | | |
+ * | | | +------+ | |
+ * | | +-------------+ | | +----+
+ * | +--------+ | | | |
+ * | | +-v--v-v---v------+
* +-v---------v----+ \ pclk_src_mux /
* \ byteclk_mux / \ /
* \ / +-----+-----+
@@ -1140,13 +1097,45 @@ static struct dsi_pll_vco_clk dsi1pll_vco_clk = {
},
};
+static struct clk_regmap_div dsi0pll_pll_out_div = {
+ .reg = PLL_PLL_OUTDIV_RATE,
+ .shift = 0,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_pll_out_div",
+ .parent_names = (const char *[]){"dsi0pll_vco_clk"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div dsi1pll_pll_out_div = {
+ .reg = PLL_PLL_OUTDIV_RATE,
+ .shift = 0,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_pll_out_div",
+ .parent_names = (const char *[]){"dsi1pll_vco_clk"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
static struct clk_regmap_div dsi0pll_bitclk_src = {
.shift = 0,
.width = 4,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi0pll_bitclk_src",
- .parent_names = (const char *[]){"dsi0pll_vco_clk"},
+ .parent_names = (const char *[]){"dsi0pll_pll_out_div"},
.num_parents = 1,
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
.ops = &clk_regmap_div_ops,
@@ -1160,7 +1149,7 @@ static struct clk_regmap_div dsi1pll_bitclk_src = {
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi1pll_bitclk_src",
- .parent_names = (const char *[]){"dsi1pll_vco_clk"},
+ .parent_names = (const char *[]){"dsi1pll_pll_out_div"},
.num_parents = 1,
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
.ops = &clk_regmap_div_ops,
@@ -1168,31 +1157,27 @@ static struct clk_regmap_div dsi1pll_bitclk_src = {
},
};
-static struct clk_regmap_div dsi0pll_post_vco_div = {
- .shift = 0,
- .width = 2,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi0pll_post_vco_div",
- .parent_names = (const char *[]){"dsi0pll_vco_clk"},
- .num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
- .ops = &clk_regmap_div_ops,
- },
+static struct clk_fixed_factor dsi0pll_post_vco_div = {
+ .div = 4,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_post_vco_div",
+ .parent_names = (const char *[]){"dsi0pll_pll_out_div"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
},
};
-static struct clk_regmap_div dsi1pll_post_vco_div = {
- .shift = 0,
- .width = 2,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi1pll_post_vco_div",
- .parent_names = (const char *[]){"dsi1pll_vco_clk"},
- .num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
- .ops = &clk_regmap_div_ops,
- },
+static struct clk_fixed_factor dsi1pll_post_vco_div = {
+ .div = 4,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_post_vco_div",
+ .parent_names = (const char *[]){"dsi1pll_pll_out_div"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
},
};
@@ -1220,31 +1205,27 @@ static struct clk_fixed_factor dsi1pll_byteclk_src = {
},
};
-static struct clk_regmap_div dsi0pll_post_bit_div = {
- .shift = 0,
- .width = 1,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi0pll_post_bit_div",
- .parent_names = (const char *[]){"dsi0pll_bitclk_src"},
- .num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
- .ops = &clk_regmap_div_ops,
- },
+static struct clk_fixed_factor dsi0pll_post_bit_div = {
+ .div = 2,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_post_bit_div",
+ .parent_names = (const char *[]){"dsi0pll_bitclk_src"},
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_fixed_factor_ops,
},
};
-static struct clk_regmap_div dsi1pll_post_bit_div = {
- .shift = 0,
- .width = 1,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi1pll_post_bit_div",
- .parent_names = (const char *[]){"dsi1pll_bitclk_src"},
- .num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
- .ops = &clk_regmap_div_ops,
- },
+static struct clk_fixed_factor dsi1pll_post_bit_div = {
+ .div = 2,
+ .mult = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_post_bit_div",
+ .parent_names = (const char *[]){"dsi1pll_bitclk_src"},
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_fixed_factor_ops,
},
};
@@ -1277,30 +1258,36 @@ static struct clk_regmap_mux dsi1pll_byteclk_mux = {
};
static struct clk_regmap_mux dsi0pll_pclk_src_mux = {
+ .reg = PHY_CMN_CLK_CFG1,
.shift = 0,
- .width = 1,
+ .width = 2,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi0pll_pclk_src_mux",
- .parent_names = (const char *[]){"dsi0pll_post_bit_div",
- "dsi0pll_post_vco_div"},
- .num_parents = 2,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .parent_names = (const char *[]){"dsi0pll_bitclk_src",
+ "dsi0pll_post_bit_div",
+ "dsi0pll_pll_out_div",
+ "dsi0pll_post_vco_div"},
+ .num_parents = 4,
+ .flags = CLK_GET_RATE_NOCACHE,
.ops = &clk_regmap_mux_closest_ops,
},
},
};
static struct clk_regmap_mux dsi1pll_pclk_src_mux = {
+ .reg = PHY_CMN_CLK_CFG1,
.shift = 0,
- .width = 1,
+ .width = 2,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi1pll_pclk_src_mux",
- .parent_names = (const char *[]){"dsi1pll_post_bit_div",
- "dsi1pll_post_vco_div"},
- .num_parents = 2,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .parent_names = (const char *[]){"dsi1pll_bitclk_src",
+ "dsi1pll_post_bit_div",
+ "dsi1pll_pll_out_div",
+ "dsi1pll_post_vco_div"},
+ .num_parents = 4,
+ .flags = CLK_GET_RATE_NOCACHE,
.ops = &clk_regmap_mux_closest_ops,
},
},
@@ -1366,24 +1353,25 @@ static struct clk_regmap_mux dsi1pll_pclk_mux = {
static struct clk_hw *mdss_dsi_pllcc_10nm[] = {
[VCO_CLK_0] = &dsi0pll_vco_clk.hw,
+ [PLL_OUT_DIV_0_CLK] = &dsi0pll_pll_out_div.clkr.hw,
[BITCLK_SRC_0_CLK] = &dsi0pll_bitclk_src.clkr.hw,
[BYTECLK_SRC_0_CLK] = &dsi0pll_byteclk_src.hw,
- [POST_BIT_DIV_0_CLK] = &dsi0pll_post_bit_div.clkr.hw,
- [POST_VCO_DIV_0_CLK] = &dsi0pll_post_vco_div.clkr.hw,
+ [POST_BIT_DIV_0_CLK] = &dsi0pll_post_bit_div.hw,
+ [POST_VCO_DIV_0_CLK] = &dsi0pll_post_vco_div.hw,
[BYTECLK_MUX_0_CLK] = &dsi0pll_byteclk_mux.clkr.hw,
[PCLK_SRC_MUX_0_CLK] = &dsi0pll_pclk_src_mux.clkr.hw,
[PCLK_SRC_0_CLK] = &dsi0pll_pclk_src.clkr.hw,
[PCLK_MUX_0_CLK] = &dsi0pll_pclk_mux.clkr.hw,
[VCO_CLK_1] = &dsi1pll_vco_clk.hw,
+ [PLL_OUT_DIV_1_CLK] = &dsi1pll_pll_out_div.clkr.hw,
[BITCLK_SRC_1_CLK] = &dsi1pll_bitclk_src.clkr.hw,
[BYTECLK_SRC_1_CLK] = &dsi1pll_byteclk_src.hw,
- [POST_BIT_DIV_1_CLK] = &dsi1pll_post_bit_div.clkr.hw,
- [POST_VCO_DIV_1_CLK] = &dsi1pll_post_vco_div.clkr.hw,
+ [POST_BIT_DIV_1_CLK] = &dsi1pll_post_bit_div.hw,
+ [POST_VCO_DIV_1_CLK] = &dsi1pll_post_vco_div.hw,
[BYTECLK_MUX_1_CLK] = &dsi1pll_byteclk_mux.clkr.hw,
[PCLK_SRC_MUX_1_CLK] = &dsi1pll_pclk_src_mux.clkr.hw,
[PCLK_SRC_1_CLK] = &dsi1pll_pclk_src.clkr.hw,
[PCLK_MUX_1_CLK] = &dsi1pll_pclk_mux.clkr.hw,
-
};
int dsi_pll_clock_register_10nm(struct platform_device *pdev,
@@ -1428,13 +1416,10 @@ int dsi_pll_clock_register_10nm(struct platform_device *pdev,
/* Establish client data */
if (ndx == 0) {
- rmap = devm_regmap_init(&pdev->dev, &post_vco_regmap_bus,
- pll_res, &dsi_pll_10nm_config);
- dsi0pll_post_vco_div.clkr.regmap = rmap;
- rmap = devm_regmap_init(&pdev->dev, &post_bit_regmap_bus,
+ rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus,
pll_res, &dsi_pll_10nm_config);
- dsi0pll_post_bit_div.clkr.regmap = rmap;
+ dsi0pll_pll_out_div.clkr.regmap = rmap;
rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus,
pll_res, &dsi_pll_10nm_config);
@@ -1448,10 +1433,9 @@ int dsi_pll_clock_register_10nm(struct platform_device *pdev,
pll_res, &dsi_pll_10nm_config);
dsi0pll_pclk_mux.clkr.regmap = rmap;
- rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
+ rmap = devm_regmap_init(&pdev->dev, &pclk_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi0pll_pclk_src_mux.clkr.regmap = rmap;
-
rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi0pll_byteclk_mux.clkr.regmap = rmap;
@@ -1475,13 +1459,9 @@ int dsi_pll_clock_register_10nm(struct platform_device *pdev,
} else {
- rmap = devm_regmap_init(&pdev->dev, &post_vco_regmap_bus,
+ rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus,
pll_res, &dsi_pll_10nm_config);
- dsi1pll_post_vco_div.clkr.regmap = rmap;
-
- rmap = devm_regmap_init(&pdev->dev, &post_bit_regmap_bus,
- pll_res, &dsi_pll_10nm_config);
- dsi1pll_post_bit_div.clkr.regmap = rmap;
+ dsi1pll_pll_out_div.clkr.regmap = rmap;
rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus,
pll_res, &dsi_pll_10nm_config);
@@ -1491,14 +1471,13 @@ int dsi_pll_clock_register_10nm(struct platform_device *pdev,
pll_res, &dsi_pll_10nm_config);
dsi1pll_pclk_src.clkr.regmap = rmap;
- rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
+ rmap = devm_regmap_init(&pdev->dev, &pclk_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi1pll_pclk_mux.clkr.regmap = rmap;
rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi1pll_pclk_src_mux.clkr.regmap = rmap;
-
rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi1pll_byteclk_mux.clkr.regmap = rmap;
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index 033462d..2f92270 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -99,6 +99,7 @@ struct mdss_pll_resources {
unsigned long vco_cached_rate;
u32 cached_cfg0;
u32 cached_cfg1;
+ u32 cached_outdiv;
/* dsi/edp/hmdi pll interface type */
u32 pll_interface_type;
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index 12eb6d8..a6edf2f 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -699,7 +699,8 @@ static void cpufreq_interactive_timer(int data)
spin_lock_irqsave(&speedchange_cpumask_lock, flags);
cpumask_set_cpu(max_cpu, &speedchange_cpumask);
spin_unlock_irqrestore(&speedchange_cpumask_lock, flags);
- wake_up_process_no_notif(speedchange_task);
+
+ wake_up_process(speedchange_task);
rearm:
cpufreq_interactive_timer_resched(data, false);
@@ -814,7 +815,7 @@ static void cpufreq_interactive_boost(struct cpufreq_interactive_tunables *tunab
spin_unlock_irqrestore(&speedchange_cpumask_lock, flags[0]);
if (anyboost)
- wake_up_process_no_notif(speedchange_task);
+ wake_up_process(speedchange_task);
}
static int load_change_callback(struct notifier_block *nb, unsigned long val,
@@ -1926,7 +1927,7 @@ static int __init cpufreq_interactive_gov_init(void)
get_task_struct(speedchange_task);
/* NB: wake up so the thread does not look hung to the freezer */
- wake_up_process_no_notif(speedchange_task);
+ wake_up_process(speedchange_task);
return cpufreq_register_governor(CPU_FREQ_GOV_INTERACTIVE);
}
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 827ee8f..e11ea50 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -66,7 +66,8 @@ enum debug_event {
CPU_EXIT,
CLUSTER_ENTER,
CLUSTER_EXIT,
- PRE_PC_CB,
+ CPU_HP_STARTING,
+ CPU_HP_DYING,
};
struct lpm_debug {
@@ -324,6 +325,9 @@ static int lpm_dying_cpu(unsigned int cpu)
{
struct lpm_cluster *cluster = per_cpu(cpu_lpm, cpu)->parent;
+ update_debug_pc_event(CPU_HP_DYING, cpu,
+ cluster->num_children_in_sync.bits[0],
+ cluster->child_cpus.bits[0], false);
cluster_prepare(cluster, get_cpu_mask(cpu), NR_LPM_LEVELS, false, 0);
return 0;
}
@@ -332,6 +336,9 @@ static int lpm_starting_cpu(unsigned int cpu)
{
struct lpm_cluster *cluster = per_cpu(cpu_lpm, cpu)->parent;
+ update_debug_pc_event(CPU_HP_STARTING, cpu,
+ cluster->num_children_in_sync.bits[0],
+ cluster->child_cpus.bits[0], false);
cluster_unprepare(cluster, get_cpu_mask(cpu), NR_LPM_LEVELS, false, 0);
return 0;
}
@@ -568,7 +575,7 @@ static void update_history(struct cpuidle_device *dev, int idx);
static int cpu_power_select(struct cpuidle_device *dev,
struct lpm_cpu *cpu)
{
- int best_level = -1;
+ int best_level = 0;
uint32_t latency_us = pm_qos_request_for_cpu(PM_QOS_CPU_DMA_LATENCY,
dev->cpu);
s64 sleep_us = ktime_to_us(tick_nohz_get_sleep_length());
@@ -582,10 +589,7 @@ static int cpu_power_select(struct cpuidle_device *dev,
uint32_t *min_residency = get_per_cpu_min_residency(dev->cpu);
uint32_t *max_residency = get_per_cpu_max_residency(dev->cpu);
- if (!cpu)
- return -EINVAL;
-
- if (sleep_disabled || sleep_us < 0)
+ if ((sleep_disabled && !cpu_isolated(dev->cpu)) || sleep_us < 0)
return 0;
idx_restrict = cpu->nlevels + 1;
@@ -626,8 +630,8 @@ static int cpu_power_select(struct cpuidle_device *dev,
if (next_wakeup_us > max_residency[i]) {
predicted = lpm_cpuidle_predict(dev, cpu,
&idx_restrict, &idx_restrict_time);
- if (predicted < min_residency[i])
- predicted = 0;
+ if (predicted && (predicted < min_residency[i]))
+ predicted = min_residency[i];
} else
invalidate_predict_history(dev);
}
@@ -957,8 +961,9 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle,
best_level = i;
- if (predicted ? (pred_us <= pwr_params->max_residency)
- : (sleep_us <= pwr_params->max_residency))
+ if (from_idle &&
+ (predicted ? (pred_us <= pwr_params->max_residency)
+ : (sleep_us <= pwr_params->max_residency)))
break;
}
@@ -1292,17 +1297,11 @@ static int lpm_cpuidle_select(struct cpuidle_driver *drv,
struct cpuidle_device *dev)
{
struct lpm_cpu *cpu = per_cpu(cpu_lpm, dev->cpu);
- int idx;
if (!cpu)
return 0;
- idx = cpu_power_select(dev, cpu);
-
- if (idx < 0)
- return 0;
-
- return idx;
+ return cpu_power_select(dev, cpu);
}
static void update_history(struct cpuidle_device *dev, int idx)
@@ -1357,7 +1356,7 @@ static int lpm_cpuidle_enter(struct cpuidle_device *dev,
trace_cpu_idle_enter(idx);
lpm_stats_cpu_enter(idx, start_time);
- if (need_resched() || (idx < 0))
+ if (need_resched())
goto exit;
success = psci_enter_sleep(cpu, idx, true);
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index c310318..3bda6e5 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -2601,8 +2601,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
struct device *jrdev = ctx->jrdev;
- gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG |
- CRYPTO_TFM_REQ_MAY_SLEEP)) ?
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
GFP_KERNEL : GFP_ATOMIC;
int src_nents, dst_nents = 0, sec4_sg_bytes;
struct ablkcipher_edesc *edesc;
diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
index 6e6f28f..3cc035c 100644
--- a/drivers/dma/qcom/gpi.c
+++ b/drivers/dma/qcom/gpi.c
@@ -2564,7 +2564,7 @@ static void gpi_setup_debug(struct gpi_dev *gpi_dev)
static int gpi_smmu_init(struct gpi_dev *gpi_dev)
{
- u64 size = U64_MAX;
+ u64 size = PAGE_SIZE;
dma_addr_t base = 0x0;
struct dma_iommu_mapping *map;
int attr, ret;
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c
index 7c1e3a7..0e1d428 100644
--- a/drivers/extcon/extcon.c
+++ b/drivers/extcon/extcon.c
@@ -482,6 +482,21 @@ int extcon_sync(struct extcon_dev *edev, unsigned int id)
}
EXPORT_SYMBOL_GPL(extcon_sync);
+int extcon_blocking_sync(struct extcon_dev *edev, unsigned int id, bool val)
+{
+ int index;
+
+ if (!edev)
+ return -EINVAL;
+
+ index = find_cable_index_by_id(edev, id);
+ if (index < 0)
+ return index;
+
+ return blocking_notifier_call_chain(&edev->bnh[index], val, edev);
+}
+EXPORT_SYMBOL(extcon_blocking_sync);
+
/**
* extcon_get_state() - Get the state of a external connector.
* @edev: the extcon device that has the cable.
@@ -940,6 +955,38 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
}
EXPORT_SYMBOL_GPL(extcon_register_notifier);
+int extcon_register_blocking_notifier(struct extcon_dev *edev, unsigned int id,
+ struct notifier_block *nb)
+{
+ int idx = -EINVAL;
+
+ if (!edev || !nb)
+ return -EINVAL;
+
+ idx = find_cable_index_by_id(edev, id);
+ if (idx < 0)
+ return idx;
+
+ return blocking_notifier_chain_register(&edev->bnh[idx], nb);
+}
+EXPORT_SYMBOL(extcon_register_blocking_notifier);
+
+int extcon_unregister_blocking_notifier(struct extcon_dev *edev,
+ unsigned int id, struct notifier_block *nb)
+{
+ int idx;
+
+ if (!edev || !nb)
+ return -EINVAL;
+
+ idx = find_cable_index_by_id(edev, id);
+ if (idx < 0)
+ return idx;
+
+ return blocking_notifier_chain_unregister(&edev->bnh[idx], nb);
+}
+EXPORT_SYMBOL(extcon_unregister_blocking_notifier);
+
/**
* extcon_unregister_notifier() - Unregister a notifiee from the extcon device.
* @edev: the extcon device that has the external connecotr.
@@ -1222,6 +1269,13 @@ int extcon_dev_register(struct extcon_dev *edev)
goto err_dev;
}
+ edev->bnh = devm_kzalloc(&edev->dev,
+ sizeof(*edev->bnh) * edev->max_supported, GFP_KERNEL);
+ if (!edev->bnh) {
+ ret = -ENOMEM;
+ goto err_dev;
+ }
+
for (index = 0; index < edev->max_supported; index++)
RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]);
diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c
index 471476c..9c1c81b 100644
--- a/drivers/firmware/qcom/tz_log.c
+++ b/drivers/firmware/qcom/tz_log.c
@@ -960,7 +960,7 @@ static int tzdbgfs_init(struct platform_device *pdev)
for (i = 0; i < TZDBG_STATS_MAX; i++) {
tzdbg.debug_tz[i] = i;
- dent = debugfs_create_file(tzdbg.stat[i].name,
+ dent = debugfs_create_file_unsafe(tzdbg.stat[i].name,
0444, dent_dir,
&tzdbg.debug_tz[i], &tzdbg_fops);
if (dent == NULL) {
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 70b47ca..eeb7c49 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -28,16 +28,28 @@
config DRM_MSM_HDMI_HDCP
bool "Enable HDMI HDCP support in MSM DRM driver"
depends on DRM_MSM && QCOM_SCM
- default y
+ default n
help
- Choose this option to enable HDCP state machine
+ Compile in support for logging register reads/writes in a format
+ that can be parsed by envytools demsm tool. If enabled, register
+ logging can be switched on via msm.reglog=y module param.
+
+config DRM_MSM_HDMI
+ bool "Enable HDMI support in MSM DRM driver"
+ depends on DRM_MSM
+ default n
+ help
+ Compile in support for HDMI driver in msm drm
+ driver. HDMI external display support is enabled
+ through this config option. It can be primary or
+ secondary display on device.
config DRM_MSM_DSI
bool "Enable DSI support in MSM DRM driver"
depends on DRM_MSM
select DRM_PANEL
select DRM_MIPI_DSI
- default y
+ default n
help
Choose this option if you have a need for MIPI DSI connector
support.
@@ -83,6 +95,17 @@
help
Choose this option if the 28nm DSI PHY 8960 variant is used on the
platform.
+
+config DRM_MSM_MDP5
+ tristate "MSM MDP5 DRM driver"
+ depends on DRM_MSM
+ default n
+ help
+ Choose this option if MSM MDP5 revision support is
+ needed in DRM/KMS. This is not required if sde/mdp4
+ only target enabled. MDP5 supports DSI and HDMI
+ displays.
+
config DRM_MSM_MDP4
tristate "MSM MDP4 DRM driver"
depends on DRM_MSM
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 1ac5c6c..b698b65 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -15,32 +15,6 @@
dp/dp_ctrl.o \
dp/dp_display.o \
dp/dp_drm.o \
- hdmi/hdmi.o \
- hdmi/hdmi_audio.o \
- hdmi/hdmi_bridge.o \
- hdmi/hdmi_connector.o \
- hdmi/hdmi_i2c.o \
- hdmi/hdmi_phy.o \
- hdmi/hdmi_phy_8960.o \
- hdmi/hdmi_phy_8x60.o \
- hdmi/hdmi_phy_8x74.o \
- edp/edp.o \
- edp/edp_aux.o \
- edp/edp_bridge.o \
- edp/edp_connector.o \
- edp/edp_ctrl.o \
- edp/edp_phy.o \
- mdp/mdp_format.o \
- mdp/mdp_kms.o \
- mdp/mdp5/mdp5_cfg.o \
- mdp/mdp5/mdp5_ctl.o \
- mdp/mdp5/mdp5_crtc.o \
- mdp/mdp5/mdp5_encoder.o \
- mdp/mdp5/mdp5_irq.o \
- mdp/mdp5/mdp5_mdss.o \
- mdp/mdp5/mdp5_kms.o \
- mdp/mdp5/mdp5_plane.o \
- mdp/mdp5/mdp5_smp.o \
sde/sde_crtc.o \
sde/sde_encoder.o \
sde/sde_encoder_phys_vid.o \
@@ -61,7 +35,36 @@
sde/sde_hw_reg_dma_v1_color_proc.o \
sde/sde_hw_color_proc_v4.o \
sde/sde_hw_ad4.o \
- sde_edid_parser.o
+ sde_edid_parser.o \
+
+msm_drm-$(CONFIG_DRM_MSM_HDMI) += hdmi/hdmi.o \
+ hdmi/hdmi_audio.o \
+ hdmi/hdmi_bridge.o \
+ hdmi/hdmi_connector.o \
+ hdmi/hdmi_i2c.o \
+ hdmi/hdmi_phy.o \
+ hdmi/hdmi_phy_8960.o \
+ hdmi/hdmi_phy_8x60.o \
+ hdmi/hdmi_phy_8x74.o \
+
+msm_drm-$(CONFIG_DRM_MSM_EDP) += edp/edp.o \
+ edp/edp_aux.o \
+ edp/edp_bridge.o \
+ edp/edp_connector.o \
+ edp/edp_ctrl.o \
+ edp/edp_phy.o \
+
+msm_drm-$(CONFIG_DRM_MSM_MDP5) += mdp/mdp_format.o \
+ mdp/mdp_kms.o \
+ mdp/mdp5/mdp5_cfg.o \
+ mdp/mdp5/mdp5_ctl.o \
+ mdp/mdp5/mdp5_crtc.o \
+ mdp/mdp5/mdp5_encoder.o \
+ mdp/mdp5/mdp5_irq.o \
+ mdp/mdp5/mdp5_mdss.o \
+ mdp/mdp5/mdp5_kms.o \
+ mdp/mdp5/mdp5_plane.o \
+ mdp/mdp5/mdp5_smp.o \
msm_drm-$(CONFIG_DRM_SDE_RSC) += sde_rsc.o \
sde_rsc_hw.o \
@@ -85,9 +88,9 @@
msm_drm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
msm_drm-$(CONFIG_SYNC_FILE) += sde/sde_fence.o
-msm_drm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o
-msm_drm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_pll_8960.o
-msm_drm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_phy_8996.o
+msm_drm-$(CONFIG_DRM_MSM_MDP4) += mdp/mdp4/mdp4_lvds_pll.o
+msm_drm-$(CONFIG_DRM_MSM_HDMI) += hdmi/hdmi_pll_8960.o
+msm_drm-$(CONFIG_DRM_MSM_HDMI) += hdmi/hdmi_phy_8996.o
msm_drm-$(CONFIG_DRM_MSM_HDMI_HDCP) += hdmi/hdmi_hdcp.o
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index 2beac0d..7e3d81f 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -211,7 +211,7 @@ static char *dp_link_get_audio_sample_rate(u32 rate)
static int dp_link_get_period(struct dp_link_private *link, int const addr)
{
int ret = 0;
- u8 *bp;
+ u8 bp;
u8 data;
u32 const param_len = 0x1;
u32 const max_audio_period = 0xA;
@@ -224,7 +224,7 @@ static int dp_link_get_period(struct dp_link_private *link, int const addr)
goto exit;
}
- data = *bp;
+ data = bp;
/* Period - Bits 3:0 */
data = data & 0xF;
@@ -322,7 +322,7 @@ static int dp_link_parse_audio_channel_period(struct dp_link_private *link)
static int dp_link_parse_audio_pattern_type(struct dp_link_private *link)
{
int ret = 0;
- u8 *bp;
+ u8 bp;
u8 data;
int rlen;
int const param_len = 0x1;
@@ -337,7 +337,7 @@ static int dp_link_parse_audio_pattern_type(struct dp_link_private *link)
ret = -EINVAL;
goto exit;
}
- data = *bp;
+ data = bp;
/* Audio Pattern Type - Bits 7:0 */
if ((int)data > max_audio_pattern_type) {
@@ -356,7 +356,7 @@ static int dp_link_parse_audio_pattern_type(struct dp_link_private *link)
static int dp_link_parse_audio_mode(struct dp_link_private *link)
{
int ret = 0;
- u8 *bp;
+ u8 bp;
u8 data;
int rlen;
int const param_len = 0x1;
@@ -374,7 +374,7 @@ static int dp_link_parse_audio_mode(struct dp_link_private *link)
ret = -EINVAL;
goto exit;
}
- data = *bp;
+ data = bp;
/* Sampling Rate - Bits 3:0 */
sampling_rate = data & 0xF;
@@ -528,14 +528,14 @@ static char *dp_link_bit_depth_to_string(u32 tbd)
static int dp_link_parse_timing_params1(struct dp_link_private *link,
int const addr, int const len, u32 *val)
{
- u8 *bp;
+ u8 bp[2];
int rlen;
if (len < 2)
return -EINVAL;
/* Read the requested video link pattern (Byte 0x221). */
- rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, len);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, bp, len);
if (rlen < len) {
pr_err("failed to read 0x%x\n", addr);
return -EINVAL;
@@ -549,14 +549,14 @@ static int dp_link_parse_timing_params1(struct dp_link_private *link,
static int dp_link_parse_timing_params2(struct dp_link_private *link,
int const addr, int const len, u32 *val1, u32 *val2)
{
- u8 *bp;
+ u8 bp[2];
int rlen;
if (len < 2)
return -EINVAL;
/* Read the requested video link pattern (Byte 0x221). */
- rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, len);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, bp, len);
if (rlen < len) {
pr_err("failed to read 0x%x\n", addr);
return -EINVAL;
@@ -571,7 +571,7 @@ static int dp_link_parse_timing_params2(struct dp_link_private *link,
static int dp_link_parse_timing_params3(struct dp_link_private *link,
int const addr, u32 *val)
{
- u8 *bp;
+ u8 bp;
u32 len = 1;
int rlen;
@@ -581,7 +581,7 @@ static int dp_link_parse_timing_params3(struct dp_link_private *link,
pr_err("failed to read 0x%x\n", addr);
return -EINVAL;
}
- *val = bp[0];
+ *val = bp;
return 0;
}
@@ -597,7 +597,7 @@ static int dp_link_parse_video_pattern_params(struct dp_link_private *link)
{
int ret = 0;
int rlen;
- u8 *bp;
+ u8 bp;
u8 data;
u32 dyn_range;
int const param_len = 0x1;
@@ -612,7 +612,7 @@ static int dp_link_parse_video_pattern_params(struct dp_link_private *link)
ret = -EINVAL;
goto exit;
}
- data = *bp;
+ data = bp;
if (!dp_link_is_video_pattern_valid(data)) {
pr_err("invalid link video pattern = 0x%x\n", data);
@@ -634,7 +634,7 @@ static int dp_link_parse_video_pattern_params(struct dp_link_private *link)
ret = -EINVAL;
goto exit;
}
- data = *bp;
+ data = bp;
/* Dynamic Range */
dyn_range = (data & BIT(3)) >> 3;
@@ -789,7 +789,7 @@ static bool dp_link_is_lane_count_valid(u32 lane_count)
*/
static int dp_link_parse_link_training_params(struct dp_link_private *link)
{
- u8 *bp;
+ u8 bp;
u8 data;
int ret = 0;
int rlen;
@@ -803,7 +803,7 @@ static int dp_link_parse_link_training_params(struct dp_link_private *link)
ret = -EINVAL;
goto exit;
}
- data = *bp;
+ data = bp;
if (!dp_link_is_link_rate_valid(data)) {
pr_err("invalid link rate = 0x%x\n", data);
@@ -822,7 +822,7 @@ static int dp_link_parse_link_training_params(struct dp_link_private *link)
ret = -EINVAL;
goto exit;
}
- data = *bp;
+ data = bp;
data &= 0x1F;
if (!dp_link_is_lane_count_valid(data)) {
@@ -861,7 +861,7 @@ static bool dp_link_is_phy_test_pattern_supported(u32 phy_test_pattern_sel)
*/
static int dp_link_parse_phy_test_params(struct dp_link_private *link)
{
- u8 *bp;
+ u8 bp;
u8 data;
int rlen;
int const param_len = 0x1;
@@ -876,7 +876,7 @@ static int dp_link_parse_phy_test_params(struct dp_link_private *link)
goto end;
}
- data = *bp;
+ data = bp;
link->request.phy_test_pattern_sel = data;
@@ -939,7 +939,7 @@ static bool dp_link_is_test_supported(u32 test_requested)
static int dp_link_parse_request(struct dp_link_private *link)
{
int ret = 0;
- u8 *bp;
+ u8 bp;
u8 data;
int rlen;
u32 const param_len = 0x1;
@@ -957,12 +957,12 @@ static int dp_link_parse_request(struct dp_link_private *link)
goto end;
}
- data = *bp;
+ data = bp;
pr_debug("device service irq vector = 0x%x\n", data);
if (!(data & BIT(1))) {
- pr_debug("no link requested\n");
+ pr_debug("no test requested\n");
goto end;
}
@@ -978,7 +978,7 @@ static int dp_link_parse_request(struct dp_link_private *link)
goto end;
}
- data = *bp;
+ data = bp;
if (!dp_link_is_test_supported(data)) {
pr_debug("link 0x%x not supported\n", data);
@@ -1032,7 +1032,7 @@ static int dp_link_parse_request(struct dp_link_private *link)
*/
static void dp_link_parse_sink_count(struct dp_link_private *link)
{
- u8 *bp;
+ u8 bp;
u8 data;
int rlen;
int const param_len = 0x1;
@@ -1044,7 +1044,7 @@ static void dp_link_parse_sink_count(struct dp_link_private *link)
return;
}
- data = *bp;
+ data = bp;
/* BIT 7, BIT 5:0 */
link->sink_count.count = (data & BIT(7)) << 6 | (data & 0x63);
@@ -1109,7 +1109,7 @@ static bool dp_link_phy_pattern_requested(struct dp_link *dp_link)
static int dp_link_parse_vx_px(struct dp_link_private *link)
{
- u8 *bp;
+ u8 bp;
u8 data;
int const param_len = 0x1;
int const addr1 = 0x206;
@@ -1127,7 +1127,7 @@ static int dp_link_parse_vx_px(struct dp_link_private *link)
goto end;
}
- data = *bp;
+ data = bp;
pr_debug("lanes 0/1 (Byte 0x206): 0x%x\n", data);
@@ -1148,7 +1148,7 @@ static int dp_link_parse_vx_px(struct dp_link_private *link)
goto end;
}
- data = *bp;
+ data = bp;
pr_debug("lanes 2/3 (Byte 0x207): 0x%x\n", data);
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c
index c6ed918..7bc1433 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.c
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c
@@ -345,6 +345,9 @@ static void dp_usbpd_response_cb(struct usbpd_svid_handler *hdlr, u8 cmd,
pd->vdo = *vdos;
dp_usbpd_get_status(pd);
+ if (pd->dp_cb && pd->dp_cb->attention)
+ pd->dp_cb->attention(pd->dev);
+
if (!pd->dp_usbpd.alt_mode_cfg_done)
dp_usbpd_send_event(pd, DP_USBPD_EVT_CONFIGURE);
break;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index 3625ed0..5e76ce7 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -56,6 +56,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
dsi_ctrl_hw_cmn_trigger_cmd_test_pattern;
ctrl->ops.clear_phy0_ln_err = dsi_ctrl_hw_dln0_phy_err;
ctrl->ops.phy_reset_config = dsi_ctrl_hw_cmn_phy_reset_config;
+ ctrl->ops.setup_misr = dsi_ctrl_hw_cmn_setup_misr;
+ ctrl->ops.collect_misr = dsi_ctrl_hw_cmn_collect_misr;
switch (version) {
case DSI_CTRL_VERSION_1_4:
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index 2d7b174..e8a6ab4 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -147,6 +147,12 @@ void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl,
void dsi_ctrl_hw_cmn_phy_sw_reset(struct dsi_ctrl_hw *ctrl);
void dsi_ctrl_hw_cmn_soft_reset(struct dsi_ctrl_hw *ctrl);
+void dsi_ctrl_hw_cmn_setup_misr(struct dsi_ctrl_hw *ctrl,
+ enum dsi_op_mode panel_mode,
+ bool enable, u32 frame_count);
+u32 dsi_ctrl_hw_cmn_collect_misr(struct dsi_ctrl_hw *ctrl,
+ enum dsi_op_mode panel_mode);
+
void dsi_ctrl_hw_cmn_kickoff_command(struct dsi_ctrl_hw *ctrl,
struct dsi_ctrl_cmd_dma_info *cmd,
u32 flags);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index b2aef9c..21ef811 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -2258,6 +2258,28 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags)
}
/**
+ * _dsi_ctrl_cache_misr - Cache frame MISR value
+ * @dsi_ctrl: Pointer to associated dsi_ctrl structure
+ */
+static void _dsi_ctrl_cache_misr(struct dsi_ctrl *dsi_ctrl)
+{
+ u32 misr;
+
+ if (!dsi_ctrl || !dsi_ctrl->hw.ops.collect_misr)
+ return;
+
+ misr = dsi_ctrl->hw.ops.collect_misr(&dsi_ctrl->hw,
+ dsi_ctrl->host_config.panel_mode);
+
+ if (misr)
+ dsi_ctrl->misr_cache = misr;
+
+ pr_debug("DSI_%d misr_cache = %x\n", dsi_ctrl->cell_index,
+ dsi_ctrl->misr_cache);
+
+}
+
+/**
* dsi_ctrl_set_power_state() - set power state for dsi controller
* @dsi_ctrl: DSI controller handle.
* @state: Power state.
@@ -2295,6 +2317,9 @@ int dsi_ctrl_set_power_state(struct dsi_ctrl *dsi_ctrl,
goto error;
}
} else if (state == DSI_CTRL_POWER_VREG_OFF) {
+ if (dsi_ctrl->misr_enable)
+ _dsi_ctrl_cache_misr(dsi_ctrl);
+
rc = dsi_ctrl_enable_supplies(dsi_ctrl, false);
if (rc) {
pr_err("[%d]failed to disable vreg supplies, rc=%d\n",
@@ -2609,6 +2634,59 @@ int dsi_ctrl_set_clock_source(struct dsi_ctrl *dsi_ctrl,
}
/**
+ * dsi_ctrl_setup_misr() - Setup frame MISR
+ * @dsi_ctrl: DSI controller handle.
+ * @enable: enable/disable MISR.
+ * @frame_count: Number of frames to accumulate MISR.
+ *
+ * Return: error code.
+ */
+int dsi_ctrl_setup_misr(struct dsi_ctrl *dsi_ctrl,
+ bool enable,
+ u32 frame_count)
+{
+ if (!dsi_ctrl) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ if (!dsi_ctrl->hw.ops.setup_misr)
+ return 0;
+
+ mutex_lock(&dsi_ctrl->ctrl_lock);
+ dsi_ctrl->misr_enable = enable;
+ dsi_ctrl->hw.ops.setup_misr(&dsi_ctrl->hw,
+ dsi_ctrl->host_config.panel_mode,
+ enable, frame_count);
+ mutex_unlock(&dsi_ctrl->ctrl_lock);
+ return 0;
+}
+
+/**
+ * dsi_ctrl_collect_misr() - Read frame MISR
+ * @dsi_ctrl: DSI controller handle.
+ *
+ * Return: MISR value.
+ */
+u32 dsi_ctrl_collect_misr(struct dsi_ctrl *dsi_ctrl)
+{
+ u32 misr;
+
+ if (!dsi_ctrl || !dsi_ctrl->hw.ops.collect_misr)
+ return 0;
+
+ misr = dsi_ctrl->hw.ops.collect_misr(&dsi_ctrl->hw,
+ dsi_ctrl->host_config.panel_mode);
+ if (!misr)
+ misr = dsi_ctrl->misr_cache;
+
+ pr_debug("DSI_%d cached misr = %x, final = %x\n",
+ dsi_ctrl->cell_index, dsi_ctrl->misr_cache, misr);
+
+ return misr;
+}
+
+/**
* dsi_ctrl_drv_register() - register platform driver for dsi controller
*/
void dsi_ctrl_drv_register(void)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index ec535ce11..95dac1c 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -188,6 +188,8 @@ struct dsi_ctrl_interrupts {
* @vaddr: CPU virtual address of cmd buffer.
* @cmd_buffer_size: Size of command buffer.
* @debugfs_root: Root for debugfs entries.
+ * @misr_enable: Frame MISR enable/disable
+ * @misr_cache: Cached Frame MISR value
*/
struct dsi_ctrl {
struct platform_device *pdev;
@@ -226,6 +228,10 @@ struct dsi_ctrl {
/* Debug Information */
struct dentry *debugfs_root;
+ /* MISR */
+ bool misr_enable;
+ u32 misr_cache;
+
};
/**
@@ -571,6 +577,26 @@ void dsi_ctrl_disable_status_interrupt(
struct dsi_ctrl *dsi_ctrl, uint32_t intr_idx);
/**
+ * dsi_ctrl_setup_misr() - Setup frame MISR
+ * @dsi_ctrl: DSI controller handle.
+ * @enable: enable/disable MISR.
+ * @frame_count: Number of frames to accumulate MISR.
+ *
+ * Return: error code.
+ */
+int dsi_ctrl_setup_misr(struct dsi_ctrl *dsi_ctrl,
+ bool enable,
+ u32 frame_count);
+
+/**
+ * dsi_ctrl_collect_misr() - Read frame MISR
+ * @dsi_ctrl: DSI controller handle.
+ *
+ * Return: MISR value.
+ */
+u32 dsi_ctrl_collect_misr(struct dsi_ctrl *dsi_ctrl);
+
+/**
* dsi_ctrl_drv_register() - register platform driver for dsi controller
*/
void dsi_ctrl_drv_register(void);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index 74be279..2130144 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -675,6 +675,26 @@ struct dsi_ctrl_hw_ops {
ssize_t (*reg_dump_to_buffer)(struct dsi_ctrl_hw *ctrl,
char *buf,
u32 size);
+
+ /**
+ * setup_misr() - Setup frame MISR
+ * @ctrl: Pointer to the controller host hardware.
+ * @panel_mode: CMD or VIDEO mode indicator
+ * @enable: Enable/disable MISR.
+ * @frame_count: Number of frames to accumulate MISR.
+ */
+ void (*setup_misr)(struct dsi_ctrl_hw *ctrl,
+ enum dsi_op_mode panel_mode,
+ bool enable, u32 frame_count);
+
+ /**
+ * collect_misr() - Read frame MISR
+ * @ctrl: Pointer to the controller host hardware.
+ * @panel_mode: CMD or VIDEO mode indicator
+ */
+ u32 (*collect_misr)(struct dsi_ctrl_hw *ctrl,
+ enum dsi_op_mode panel_mode);
+
};
/*
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_0.c
index c22849a..6421dc2 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_0.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_0.c
@@ -157,6 +157,10 @@ ssize_t dsi_ctrl_hw_20_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl,
len += snprintf((buf + len), (size - len),
DUMP_REG_VALUE(DSI_RESET_SW_TRIGGER));
len += snprintf((buf + len), (size - len),
+ DUMP_REG_VALUE(DSI_MISR_CMD_CTRL));
+ len += snprintf((buf + len), (size - len),
+ DUMP_REG_VALUE(DSI_MISR_VIDEO_CTRL));
+ len += snprintf((buf + len), (size - len),
DUMP_REG_VALUE(DSI_LANE_STATUS));
len += snprintf((buf + len), (size - len),
DUMP_REG_VALUE(DSI_LANE_CTRL));
@@ -193,6 +197,12 @@ ssize_t dsi_ctrl_hw_20_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl,
len += snprintf((buf + len), (size - len),
DUMP_REG_VALUE(DSI_AXI2AHB_CTRL));
len += snprintf((buf + len), (size - len),
+ DUMP_REG_VALUE(DSI_MISR_CMD_MDP0_32BIT));
+ len += snprintf((buf + len), (size - len),
+ DUMP_REG_VALUE(DSI_MISR_CMD_MDP1_32BIT));
+ len += snprintf((buf + len), (size - len),
+ DUMP_REG_VALUE(DSI_MISR_VIDEO_32BIT));
+ len += snprintf((buf + len), (size - len),
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_CTRL2));
len += snprintf((buf + len), (size - len),
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM2_CTRL));
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
index 0af6f25..8e8e353 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
@@ -20,9 +20,12 @@
#include "dsi_ctrl_reg.h"
#include "dsi_hw.h"
#include "dsi_panel.h"
+#include "dsi_catalog.h"
#define MMSS_MISC_CLAMP_REG_OFF 0x0014
#define DSI_CTRL_DYNAMIC_FORCE_ON (0x23F|BIT(8)|BIT(9)|BIT(11)|BIT(21))
+#define DSI_CTRL_CMD_MISR_ENABLE BIT(28)
+#define DSI_CTRL_VIDEO_MISR_ENABLE BIT(16)
/* Unsupported formats default to RGB888 */
static const u8 cmd_mode_format_map[DSI_PIXEL_FORMAT_MAX] = {
@@ -149,6 +152,70 @@ void dsi_ctrl_hw_cmn_soft_reset(struct dsi_ctrl_hw *ctrl)
}
/**
+ * setup_misr() - Setup frame MISR
+ * @ctrl: Pointer to the controller host hardware.
+ * @panel_mode: CMD or VIDEO mode indicator
+ * @enable: Enable/disable MISR.
+ * @frame_count: Number of frames to accumulate MISR.
+ */
+void dsi_ctrl_hw_cmn_setup_misr(struct dsi_ctrl_hw *ctrl,
+ enum dsi_op_mode panel_mode,
+ bool enable,
+ u32 frame_count)
+{
+ u32 addr;
+ u32 config = 0;
+
+ if (panel_mode == DSI_OP_CMD_MODE) {
+ addr = DSI_MISR_CMD_CTRL;
+ if (enable)
+ config = DSI_CTRL_CMD_MISR_ENABLE;
+ } else {
+ addr = DSI_MISR_VIDEO_CTRL;
+ if (enable)
+ config = DSI_CTRL_VIDEO_MISR_ENABLE;
+ if (frame_count > 255)
+ frame_count = 255;
+ config |= frame_count << 8;
+ }
+
+ pr_debug("[DSI_%d] MISR ctrl: 0x%x\n", ctrl->index,
+ config);
+ DSI_W32(ctrl, addr, config);
+ wmb(); /* make sure MISR is configured */
+}
+
+/**
+ * collect_misr() - Read frame MISR
+ * @ctrl: Pointer to the controller host hardware.
+ * @panel_mode: CMD or VIDEO mode indicator
+ */
+u32 dsi_ctrl_hw_cmn_collect_misr(struct dsi_ctrl_hw *ctrl,
+ enum dsi_op_mode panel_mode)
+{
+ u32 addr;
+ u32 enabled;
+ u32 misr = 0;
+
+ if (panel_mode == DSI_OP_CMD_MODE) {
+ addr = DSI_MISR_CMD_MDP0_32BIT;
+ enabled = DSI_R32(ctrl, DSI_MISR_CMD_CTRL) &
+ DSI_CTRL_CMD_MISR_ENABLE;
+ } else {
+ addr = DSI_MISR_VIDEO_32BIT;
+ enabled = DSI_R32(ctrl, DSI_MISR_VIDEO_CTRL) &
+ DSI_CTRL_VIDEO_MISR_ENABLE;
+ }
+
+ if (enabled)
+ misr = DSI_R32(ctrl, addr);
+
+ pr_debug("[DSI_%d] MISR enabled %x value: 0x%x\n", ctrl->index,
+ enabled, misr);
+ return misr;
+}
+
+/**
* set_video_timing() - set up the timing for video frame
* @ctrl: Pointer to controller host hardware.
* @mode: Video mode information.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 6f6c559..c0c6698 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -32,6 +32,8 @@
#define to_dsi_display(x) container_of(x, struct dsi_display, host)
#define INT_BASE_10 10
+#define MISR_BUFF_SIZE 256
+
static DEFINE_MUTEX(dsi_display_list_lock);
static LIST_HEAD(dsi_display_list);
static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN];
@@ -128,9 +130,20 @@ enum dsi_pixel_format dsi_display_get_dst_format(void *display)
return format;
}
+static void _dsi_display_setup_misr(struct dsi_display *display)
+{
+ int i;
+
+ for (i = 0; i < display->ctrl_count; i++) {
+ dsi_ctrl_setup_misr(display->ctrl[i].ctrl,
+ display->misr_enable,
+ display->misr_frame_count);
+ }
+}
+
static ssize_t debugfs_dump_info_read(struct file *file,
- char __user *buff,
- size_t count,
+ char __user *user_buf,
+ size_t user_len,
loff_t *ppos)
{
struct dsi_display *display = file->private_data;
@@ -168,7 +181,7 @@ static ssize_t debugfs_dump_info_read(struct file *file,
"\tClock master = %s\n",
display->ctrl[display->clk_master_idx].ctrl->name);
- if (copy_to_user(buff, buf, len)) {
+ if (copy_to_user(user_buf, buf, len)) {
kfree(buf);
return -EFAULT;
}
@@ -179,16 +192,151 @@ static ssize_t debugfs_dump_info_read(struct file *file,
return len;
}
+static ssize_t debugfs_misr_setup(struct file *file,
+ const char __user *user_buf,
+ size_t user_len,
+ loff_t *ppos)
+{
+ struct dsi_display *display = file->private_data;
+ char *buf;
+ int rc = 0;
+ size_t len;
+ u32 enable, frame_count;
+
+ if (!display)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ buf = kzalloc(MISR_BUFF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ /* leave room for termination char */
+ len = min_t(size_t, user_len, MISR_BUFF_SIZE - 1);
+ if (copy_from_user(buf, user_buf, len)) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ buf[len] = '\0'; /* terminate the string */
+
+ if (sscanf(buf, "%u %u", &enable, &frame_count) != 2) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ display->misr_enable = enable;
+ display->misr_frame_count = frame_count;
+
+ mutex_lock(&display->display_lock);
+ rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
+ DSI_CORE_CLK, DSI_CLK_ON);
+ if (rc) {
+ pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
+ display->name, rc);
+ goto unlock;
+ }
+
+ _dsi_display_setup_misr(display);
+
+ rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
+ DSI_CORE_CLK, DSI_CLK_OFF);
+ if (rc) {
+ pr_err("[%s] failed to disable DSI core clocks, rc=%d\n",
+ display->name, rc);
+ goto unlock;
+ }
+
+ rc = user_len;
+unlock:
+ mutex_unlock(&display->display_lock);
+error:
+ kfree(buf);
+ return rc;
+}
+
+static ssize_t debugfs_misr_read(struct file *file,
+ char __user *user_buf,
+ size_t user_len,
+ loff_t *ppos)
+{
+ struct dsi_display *display = file->private_data;
+ char *buf;
+ u32 len = 0;
+ int rc = 0;
+ struct dsi_ctrl *dsi_ctrl;
+ int i;
+ u32 misr;
+ size_t max_len = min_t(size_t, user_len, MISR_BUFF_SIZE);
+
+ if (!display)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ buf = kzalloc(max_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ mutex_lock(&display->display_lock);
+ rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
+ DSI_CORE_CLK, DSI_CLK_ON);
+ if (rc) {
+ pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
+ display->name, rc);
+ goto error;
+ }
+
+ for (i = 0; i < display->ctrl_count; i++) {
+ dsi_ctrl = display->ctrl[i].ctrl;
+ misr = dsi_ctrl_collect_misr(display->ctrl[i].ctrl);
+
+ len += snprintf((buf + len), max_len - len,
+ "DSI_%d MISR: 0x%x\n", dsi_ctrl->cell_index, misr);
+
+ if (len >= max_len)
+ break;
+ }
+
+ rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
+ DSI_CORE_CLK, DSI_CLK_OFF);
+ if (rc) {
+ pr_err("[%s] failed to disable DSI core clocks, rc=%d\n",
+ display->name, rc);
+ goto error;
+ }
+
+ if (copy_to_user(user_buf, buf, len)) {
+ rc = -EFAULT;
+ goto error;
+ }
+
+ *ppos += len;
+
+error:
+ mutex_unlock(&display->display_lock);
+ kfree(buf);
+ return len;
+}
static const struct file_operations dump_info_fops = {
.open = simple_open,
.read = debugfs_dump_info_read,
};
+static const struct file_operations misr_data_fops = {
+ .open = simple_open,
+ .read = debugfs_misr_read,
+ .write = debugfs_misr_setup,
+};
+
static int dsi_display_debugfs_init(struct dsi_display *display)
{
int rc = 0;
- struct dentry *dir, *dump_file;
+ struct dentry *dir, *dump_file, *misr_data;
dir = debugfs_create_dir(display->name, NULL);
if (IS_ERR_OR_NULL(dir)) {
@@ -199,13 +347,25 @@ static int dsi_display_debugfs_init(struct dsi_display *display)
}
dump_file = debugfs_create_file("dump_info",
- 0444,
+ 0400,
dir,
display,
&dump_info_fops);
if (IS_ERR_OR_NULL(dump_file)) {
rc = PTR_ERR(dump_file);
- pr_err("[%s] debugfs create file failed, rc=%d\n",
+ pr_err("[%s] debugfs create dump info file failed, rc=%d\n",
+ display->name, rc);
+ goto error_remove_dir;
+ }
+
+ misr_data = debugfs_create_file("misr_data",
+ 0600,
+ dir,
+ display,
+ &misr_data_fops);
+ if (IS_ERR_OR_NULL(misr_data)) {
+ rc = PTR_ERR(misr_data);
+ pr_err("[%s] debugfs create misr datafile failed, rc=%d\n",
display->name, rc);
goto error_remove_dir;
}
@@ -3114,7 +3274,8 @@ int dsi_display_get_info(struct msm_display_info *info, void *disp)
info->frame_rate = timing->refresh_rate;
info->vtotal = DSI_V_TOTAL(timing);
info->prefill_lines = display->panel->panel_prefill_lines;
- info->jitter = display->panel->panel_jitter;
+ info->jitter_numer = display->panel->panel_jitter_numer;
+ info->jitter_denom = display->panel->panel_jitter_denom;
info->width_mm = phy_props.panel_width_mm;
info->height_mm = phy_props.panel_height_mm;
info->max_width = 1920;
@@ -3532,6 +3693,10 @@ int dsi_display_pre_kickoff(struct dsi_display *display,
{
int rc = 0;
+ /* check and setup MISR */
+ if (display->misr_enable)
+ _dsi_display_setup_misr(display);
+
rc = dsi_display_set_roi(display, params->rois);
return rc;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index b382e4a..359e04f3 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -154,6 +154,8 @@ struct dsi_display_clk_info {
* @dsi_clk_handle: DSI clock handle.
* @mdp_clk_handle: MDP clock handle.
* @root: Debugfs root directory
+ * @misr_enable Frame MISR enable/disable
+ * @misr_frame_count Number of frames to accumulate the MISR value
*/
struct dsi_display {
struct platform_device *pdev;
@@ -201,6 +203,9 @@ struct dsi_display {
/* DEBUG FS */
struct dentry *root;
+
+ bool misr_enable;
+ u32 misr_frame_count;
};
int dsi_display_dev_probe(struct platform_device *pdev);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index b8bf7a8..8bc82f5 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -35,20 +35,66 @@
#define DEFAULT_MDP_TRANSFER_TIME 14000
-#define DEFAULT_PANEL_JITTER 5
-#define MAX_PANEL_JITTER 25
-#define DEFAULT_PANEL_PREFILL_LINES 16
+#define DEFAULT_PANEL_JITTER_NUMERATOR 2
+#define DEFAULT_PANEL_JITTER_DENOMINATOR 1
+#define DEFAULT_PANEL_JITTER_ARRAY_SIZE 2
+#define MAX_PANEL_JITTER 10
+#define DEFAULT_PANEL_PREFILL_LINES 25
+
+enum dsi_dsc_ratio_type {
+ DSC_8BPC_8BPP,
+ DSC_10BPC_8BPP,
+ DSC_12BPC_8BPP,
+ DSC_RATIO_TYPE_MAX
+};
static u32 dsi_dsc_rc_buf_thresh[] = {0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54,
0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e};
-static char dsi_dsc_rc_range_min_qp_1_1[] = {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5,
- 5, 5, 7, 13};
-static char dsi_dsc_rc_range_min_qp_1_1_scr1[] = {0, 0, 1, 1, 3, 3, 3, 3, 3, 3,
- 5, 5, 5, 9, 12};
-static char dsi_dsc_rc_range_max_qp_1_1[] = {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11,
- 12, 13, 13, 15};
-static char dsi_dsc_rc_range_max_qp_1_1_scr1[] = {4, 4, 5, 6, 7, 7, 7, 8, 9, 10,
- 11, 11, 12, 13};
+
+/*
+ * DSC 1.1
+ * Rate control - Min QP values for each ratio type in dsi_dsc_ratio_type
+ */
+static char dsi_dsc_rc_range_min_qp_1_1[][15] = {
+ {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 13},
+ {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 17},
+ {0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 21},
+ };
+
+/*
+ * DSC 1.1 SCR
+ * Rate control - Min QP values for each ratio type in dsi_dsc_ratio_type
+ */
+static char dsi_dsc_rc_range_min_qp_1_1_scr1[][15] = {
+ {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 12},
+ {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 16},
+ {0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 17, 20},
+ };
+
+/*
+ * DSC 1.1
+ * Rate control - Max QP values for each ratio type in dsi_dsc_ratio_type
+ */
+static char dsi_dsc_rc_range_max_qp_1_1[][15] = {
+ {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15},
+ {8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 15, 16, 17, 17, 19},
+ {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 19, 20, 21, 21, 23},
+ };
+
+/*
+ * DSC 1.1 SCR
+ * Rate control - Max QP values for each ratio type in dsi_dsc_ratio_type
+ */
+static char dsi_dsc_rc_range_max_qp_1_1_scr1[][15] = {
+ {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13},
+ {8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17},
+ {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21},
+ };
+
+/*
+ * DSC 1.1 and DSC 1.1 SCR
+ * Rate control - bpg offset values
+ */
static char dsi_dsc_rc_range_bpg_offset[] = {2, 0, 0, -2, -4, -6, -8, -8,
-8, -10, -10, -12, -12, -12, -12};
@@ -1579,16 +1625,24 @@ static int dsi_panel_parse_jitter_config(struct dsi_panel *panel,
struct device_node *of_node)
{
int rc;
+ u32 jitter[DEFAULT_PANEL_JITTER_ARRAY_SIZE] = {0, 0};
+ u64 jitter_val = 0;
- rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-jitter",
- &panel->panel_jitter);
+ rc = of_property_read_u32_array(of_node, "qcom,mdss-dsi-panel-jitter",
+ jitter, DEFAULT_PANEL_JITTER_ARRAY_SIZE);
if (rc) {
- pr_debug("panel jitter is not defined rc=%d\n", rc);
- panel->panel_jitter = DEFAULT_PANEL_JITTER;
- } else if (panel->panel_jitter > MAX_PANEL_JITTER) {
- pr_debug("invalid jitter config=%d setting to:%d\n",
- panel->panel_jitter, DEFAULT_PANEL_JITTER);
- panel->panel_jitter = DEFAULT_PANEL_JITTER;
+ pr_debug("panel jitter not defined rc=%d\n", rc);
+ } else {
+ jitter_val = jitter[0];
+ jitter_val = div_u64(jitter_val, jitter[1]);
+ }
+
+ if (rc || !jitter_val || (jitter_val > MAX_PANEL_JITTER)) {
+ panel->panel_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR;
+ panel->panel_jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR;
+ } else {
+ panel->panel_jitter_numer = jitter[0];
+ panel->panel_jitter_denom = jitter[1];
}
rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-prefill-lines",
@@ -1848,6 +1902,7 @@ int dsi_dsc_populate_static_param(struct msm_display_dsc_info *dsc)
int target_bpp_x16;
int data;
int final_value, final_scale;
+ int ratio_index;
dsc->version = 0x11;
dsc->scr_rev = 0;
@@ -1857,12 +1912,7 @@ int dsi_dsc_populate_static_param(struct msm_display_dsc_info *dsc)
else
dsc->first_line_bpg_offset = 12;
- dsc->min_qp_flatness = 3;
- dsc->max_qp_flatness = 12;
- dsc->line_buf_depth = 9;
dsc->edge_factor = 6;
- dsc->quant_incr_limit0 = 11;
- dsc->quant_incr_limit1 = 11;
dsc->tgt_offset_hi = 3;
dsc->tgt_offset_lo = 3;
dsc->enable_422 = 0;
@@ -1870,27 +1920,60 @@ int dsi_dsc_populate_static_param(struct msm_display_dsc_info *dsc)
dsc->vbr_enable = 0;
dsc->buf_thresh = dsi_dsc_rc_buf_thresh;
- if (dsc->version == 0x11 && dsc->scr_rev == 0x1) {
- dsc->range_min_qp = dsi_dsc_rc_range_min_qp_1_1_scr1;
- dsc->range_max_qp = dsi_dsc_rc_range_max_qp_1_1_scr1;
- } else {
- dsc->range_min_qp = dsi_dsc_rc_range_min_qp_1_1;
- dsc->range_max_qp = dsi_dsc_rc_range_max_qp_1_1;
- }
- dsc->range_bpg_offset = dsi_dsc_rc_range_bpg_offset;
bpp = dsc->bpp;
bpc = dsc->bpc;
+ if (bpc == 12)
+ ratio_index = DSC_12BPC_8BPP;
+ else if (bpc == 10)
+ ratio_index = DSC_10BPC_8BPP;
+ else
+ ratio_index = DSC_8BPC_8BPP;
+
+ if (dsc->version == 0x11 && dsc->scr_rev == 0x1) {
+ dsc->range_min_qp =
+ dsi_dsc_rc_range_min_qp_1_1_scr1[ratio_index];
+ dsc->range_max_qp =
+ dsi_dsc_rc_range_max_qp_1_1_scr1[ratio_index];
+ } else {
+ dsc->range_min_qp = dsi_dsc_rc_range_min_qp_1_1[ratio_index];
+ dsc->range_max_qp = dsi_dsc_rc_range_max_qp_1_1[ratio_index];
+ }
+ dsc->range_bpg_offset = dsi_dsc_rc_range_bpg_offset;
+
if (bpp == 8)
dsc->initial_offset = 6144;
else
dsc->initial_offset = 2048; /* bpp = 12 */
- if (bpc <= 8)
- mux_words_size = 48;
+ if (bpc == 12)
+ mux_words_size = 64;
else
- mux_words_size = 64; /* bpc == 12 */
+ mux_words_size = 48; /* bpc == 8/10 */
+
+ if (bpc == 8) {
+ dsc->line_buf_depth = 9;
+ dsc->input_10_bits = 0;
+ dsc->min_qp_flatness = 3;
+ dsc->max_qp_flatness = 12;
+ dsc->quant_incr_limit0 = 11;
+ dsc->quant_incr_limit1 = 11;
+ } else if (bpc == 10) { /* 10bpc */
+ dsc->line_buf_depth = 11;
+ dsc->input_10_bits = 1;
+ dsc->min_qp_flatness = 7;
+ dsc->max_qp_flatness = 16;
+ dsc->quant_incr_limit0 = 15;
+ dsc->quant_incr_limit1 = 15;
+ } else { /* 12 bpc */
+ dsc->line_buf_depth = 9;
+ dsc->input_10_bits = 0;
+ dsc->min_qp_flatness = 11;
+ dsc->max_qp_flatness = 20;
+ dsc->quant_incr_limit0 = 19;
+ dsc->quant_incr_limit1 = 19;
+ }
dsc->slice_last_group_size = 3 - (dsc->slice_width % 3);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 3569b5b..5380049 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -184,7 +184,8 @@ struct dsi_panel {
bool ulps_enabled;
bool allow_phy_power_off;
- u32 panel_jitter;
+ u32 panel_jitter_numer;
+ u32 panel_jitter_denom;
u32 panel_prefill_lines;
bool panel_initialized;
bool te_using_watchdog_timer;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 11f1c4f..d2ac684 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -284,7 +284,7 @@ static int vblank_ctrl_queue_work(struct msm_drm_private *priv,
list_add_tail(&vbl_ev->node, &vbl_ctrl->event_list);
spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
- kthread_queue_work(&priv->event_thread[crtc_id].worker,
+ kthread_queue_work(&priv->disp_thread[crtc_id].worker,
&vbl_ctrl->work);
return 0;
@@ -521,6 +521,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
struct msm_kms *kms;
struct sde_dbg_power_ctrl dbg_power_ctrl = { 0 };
int ret, i;
+ struct sched_param param;
ddev = drm_dev_alloc(drv, dev);
if (!ddev) {
@@ -624,6 +625,12 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
}
ddev->mode_config.funcs = &mode_config_funcs;
+ /**
+ * this priority was found during empiric testing to have appropriate
+ * realtime scheduling to process display updates and interact with
+ * other real time and normal priority task
+ */
+ param.sched_priority = 16;
for (i = 0; i < priv->num_crtcs; i++) {
/* initialize display thread */
@@ -634,6 +641,11 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
kthread_run(kthread_worker_fn,
&priv->disp_thread[i].worker,
"crtc_commit:%d", priv->disp_thread[i].crtc_id);
+ ret = sched_setscheduler(priv->disp_thread[i].thread,
+ SCHED_FIFO, ¶m);
+ if (ret)
+ pr_warn("display thread priority update failed: %d\n",
+ ret);
if (IS_ERR(priv->disp_thread[i].thread)) {
dev_err(dev, "failed to create crtc_commit kthread\n");
@@ -648,6 +660,18 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
kthread_run(kthread_worker_fn,
&priv->event_thread[i].worker,
"crtc_event:%d", priv->event_thread[i].crtc_id);
+ /**
+ * event thread should also run at same priority as disp_thread
+ * because it is handling frame_done events. A lower priority
+ * event thread and higher priority disp_thread can causes
+ * frame_pending counters beyond 2. This can lead to commit
+ * failure at crtc commit level.
+ */
+ ret = sched_setscheduler(priv->event_thread[i].thread,
+ SCHED_FIFO, ¶m);
+ if (ret)
+ pr_warn("display event thread priority update failed: %d\n",
+ ret);
if (IS_ERR(priv->event_thread[i].thread)) {
dev_err(dev, "failed to create crtc_event kthread\n");
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 7edd534..96ab883 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -413,7 +413,8 @@ struct msm_mode_info {
* @frame_rate: Display frame rate
* @prefill_lines: prefill lines based on porches.
* @vtotal: display vertical total
- * @jitter: display jitter configuration
+ * @jitter_numer: display panel jitter numerator configuration
+ * @jitter_denom: display panel jitter denominator configuration
* @comp_info: Compression supported by the display
* @roi_caps: Region of interest capability info
*/
@@ -437,7 +438,8 @@ struct msm_display_info {
uint32_t frame_rate;
uint32_t prefill_lines;
uint32_t vtotal;
- uint32_t jitter;
+ uint32_t jitter_numer;
+ uint32_t jitter_denom;
struct msm_compression_info comp_info;
struct msm_roi_caps roi_caps;
@@ -741,16 +743,34 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev);
void msm_fbdev_free(struct drm_device *dev);
struct hdmi;
+#ifdef CONFIG_DRM_MSM_HDMI
int msm_hdmi_modeset_init(struct hdmi *hdmi, struct drm_device *dev,
struct drm_encoder *encoder);
void __init msm_hdmi_register(void);
void __exit msm_hdmi_unregister(void);
+#else
+static inline void __init msm_hdmi_register(void)
+{
+}
+static inline void __exit msm_hdmi_unregister(void)
+{
+}
+#endif
struct msm_edp;
+#ifdef CONFIG_DRM_MSM_EDP
void __init msm_edp_register(void);
void __exit msm_edp_unregister(void);
int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
struct drm_encoder *encoder);
+#else
+static inline void __init msm_edp_register(void)
+{
+}
+static inline void __exit msm_edp_unregister(void)
+{
+}
+#endif
struct msm_dsi;
enum msm_dsi_encoder_id {
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index 35e6b71..7692bef 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -115,9 +115,24 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev);
static inline
struct msm_kms *mdp4_kms_init(struct drm_device *dev) { return NULL; };
#endif
-struct msm_kms *mdp5_kms_init(struct drm_device *dev);
+
+#ifdef CONFIG_DRM_MSM_MDP5
int msm_mdss_init(struct drm_device *dev);
void msm_mdss_destroy(struct drm_device *dev);
+struct msm_kms *mdp5_kms_init(struct drm_device *dev);
+#else
+static inline int msm_mdss_init(struct drm_device *dev)
+{
+ return 0;
+}
+static inline void msm_mdss_destroy(struct drm_device *dev)
+{
+}
+static inline struct msm_kms *mdp5_kms_init(struct drm_device *dev)
+{
+ return NULL;
+}
+#endif
struct msm_kms *sde_kms_init(struct drm_device *dev);
/**
diff --git a/drivers/gpu/drm/msm/msm_prop.c b/drivers/gpu/drm/msm/msm_prop.c
index f2996dd..d1991a4 100644
--- a/drivers/gpu/drm/msm/msm_prop.c
+++ b/drivers/gpu/drm/msm/msm_prop.c
@@ -21,8 +21,6 @@ void msm_property_init(struct msm_property_info *info,
uint32_t blob_count,
uint32_t state_size)
{
- int i;
-
/* prevent access if any of these are NULL */
if (!base || !dev || !property_array || !property_data) {
property_count = 0;
@@ -60,10 +58,6 @@ void msm_property_init(struct msm_property_info *info,
0,
sizeof(struct msm_property_data) *
property_count);
- INIT_LIST_HEAD(&info->dirty_list);
-
- for (i = 0; i < property_count; ++i)
- INIT_LIST_HEAD(&property_data[i].dirty_node);
}
}
@@ -72,9 +66,6 @@ void msm_property_destroy(struct msm_property_info *info)
if (!info)
return;
- /* reset dirty list */
- INIT_LIST_HEAD(&info->dirty_list);
-
/* free state cache */
while (info->state_cache_size > 0)
kfree(info->state_cache[--(info->state_cache_size)]);
@@ -82,24 +73,25 @@ void msm_property_destroy(struct msm_property_info *info)
mutex_destroy(&info->property_lock);
}
-int msm_property_pop_dirty(struct msm_property_info *info)
+int msm_property_pop_dirty(struct msm_property_info *info,
+ struct msm_property_state *property_state)
{
struct list_head *item;
int rc = 0;
- if (!info) {
- DRM_ERROR("invalid info\n");
+ if (!info || !property_state || !property_state->values) {
+ DRM_ERROR("invalid argument(s)\n");
return -EINVAL;
}
mutex_lock(&info->property_lock);
- if (list_empty(&info->dirty_list)) {
+ if (list_empty(&property_state->dirty_list)) {
rc = -EAGAIN;
} else {
- item = info->dirty_list.next;
+ item = property_state->dirty_list.next;
list_del_init(item);
- rc = container_of(item, struct msm_property_data, dirty_node)
- - info->property_data;
+ rc = container_of(item, struct msm_property_value, dirty_node)
+ - property_state->values;
DRM_DEBUG_KMS("property %d dirty\n", rc);
}
mutex_unlock(&info->property_lock);
@@ -112,26 +104,28 @@ int msm_property_pop_dirty(struct msm_property_info *info)
* This function doesn't mutex protect the
* dirty linked list.
* @info: Pointer to property info container struct
+ * @property_state: Pointer to property state container struct
* @property_idx: Property index
*/
static void _msm_property_set_dirty_no_lock(
struct msm_property_info *info,
+ struct msm_property_state *property_state,
uint32_t property_idx)
{
- if (!info || property_idx >= info->property_count) {
- DRM_ERROR("invalid argument(s), info %pK, idx %u\n",
- info, property_idx);
+ if (!info || !property_state || !property_state->values ||
+ property_idx >= info->property_count) {
+ DRM_ERROR("invalid argument(s), idx %u\n", property_idx);
return;
}
/* avoid re-inserting if already dirty */
- if (!list_empty(&info->property_data[property_idx].dirty_node)) {
+ if (!list_empty(&property_state->values[property_idx].dirty_node)) {
DRM_DEBUG_KMS("property %u already dirty\n", property_idx);
return;
}
- list_add_tail(&info->property_data[property_idx].dirty_node,
- &info->dirty_list);
+ list_add_tail(&property_state->values[property_idx].dirty_node,
+ &property_state->dirty_list);
}
/**
@@ -371,35 +365,36 @@ int msm_property_index(struct msm_property_info *info,
return rc;
}
-int msm_property_set_dirty(struct msm_property_info *info, int property_idx)
+int msm_property_set_dirty(struct msm_property_info *info,
+ struct msm_property_state *property_state,
+ int property_idx)
{
- if (!info) {
- DRM_ERROR("invalid property info\n");
+ if (!info || !property_state || !property_state->values) {
+ DRM_ERROR("invalid argument(s)\n");
return -EINVAL;
}
mutex_lock(&info->property_lock);
- _msm_property_set_dirty_no_lock(info, property_idx);
+ _msm_property_set_dirty_no_lock(info, property_state, property_idx);
mutex_unlock(&info->property_lock);
return 0;
}
int msm_property_atomic_set(struct msm_property_info *info,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
struct drm_property *property, uint64_t val)
{
struct drm_property_blob *blob;
int property_idx, rc = -EINVAL;
property_idx = msm_property_index(info, property);
- if (!info || (property_idx == -EINVAL) || !property_values) {
- DRM_DEBUG("Invalid argument(s)\n");
+ if (!info || !property_state ||
+ (property_idx == -EINVAL) || !property_state->values) {
+ DRM_DEBUG("invalid argument(s)\n");
} else {
/* extra handling for incoming properties */
mutex_lock(&info->property_lock);
if ((property->flags & DRM_MODE_PROP_BLOB) &&
- (property_idx < info->blob_count) &&
- property_blobs) {
+ (property_idx < info->blob_count)) {
/* DRM lookup also takes a reference */
blob = drm_property_lookup_blob(info->dev,
(uint32_t)val);
@@ -411,18 +406,21 @@ int msm_property_atomic_set(struct msm_property_info *info,
val = blob->base.id;
/* save blob - need to clear previous ref */
- if (property_blobs[property_idx])
+ if (property_state->values[property_idx].blob)
drm_property_unreference_blob(
- property_blobs[property_idx]);
- property_blobs[property_idx] = blob;
+ property_state->values[
+ property_idx].blob);
+ property_state->values[property_idx].blob =
+ blob;
}
}
/* update value and flag as dirty */
- if (property_values[property_idx] != val ||
+ if (property_state->values[property_idx].value != val ||
info->property_data[property_idx].force_dirty) {
- property_values[property_idx] = val;
- _msm_property_set_dirty_no_lock(info, property_idx);
+ property_state->values[property_idx].value = val;
+ _msm_property_set_dirty_no_lock(info, property_state,
+ property_idx);
DBG("%s - %lld", property->name, val);
}
@@ -434,18 +432,18 @@ int msm_property_atomic_set(struct msm_property_info *info,
}
int msm_property_atomic_get(struct msm_property_info *info,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
struct drm_property *property, uint64_t *val)
{
int property_idx, rc = -EINVAL;
property_idx = msm_property_index(info, property);
- if (!info || (property_idx == -EINVAL) || !property_values || !val) {
+ if (!info || (property_idx == -EINVAL) ||
+ !property_state->values || !val) {
DRM_DEBUG("Invalid argument(s)\n");
} else {
mutex_lock(&info->property_lock);
- *val = property_values[property_idx];
+ *val = property_state->values[property_idx].value;
mutex_unlock(&info->property_lock);
rc = 0;
}
@@ -495,8 +493,8 @@ static void _msm_property_free_state(struct msm_property_info *info, void *st)
}
void msm_property_reset_state(struct msm_property_info *info, void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs)
+ struct msm_property_state *property_state,
+ struct msm_property_value *property_values)
{
uint32_t i;
@@ -508,24 +506,29 @@ void msm_property_reset_state(struct msm_property_info *info, void *state,
if (state)
memset(state, 0, info->state_size);
+ if (property_state) {
+ property_state->property_count = info->property_count;
+ property_state->values = property_values;
+ INIT_LIST_HEAD(&property_state->dirty_list);
+ }
+
/*
* Assign default property values. This helper is mostly used
* to initialize newly created state objects.
*/
if (property_values)
- for (i = 0; i < info->property_count; ++i)
- property_values[i] =
+ for (i = 0; i < info->property_count; ++i) {
+ property_values[i].value =
info->property_data[i].default_value;
-
- if (property_blobs)
- for (i = 0; i < info->blob_count; ++i)
- property_blobs[i] = 0;
+ property_values[i].blob = NULL;
+ INIT_LIST_HEAD(&property_values[i].dirty_node);
+ }
}
void msm_property_duplicate_state(struct msm_property_info *info,
void *old_state, void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs)
+ struct msm_property_state *property_state,
+ struct msm_property_value *property_values)
{
uint32_t i;
@@ -536,17 +539,24 @@ void msm_property_duplicate_state(struct msm_property_info *info,
memcpy(state, old_state, info->state_size);
- if (property_blobs) {
- /* add ref count for blobs */
- for (i = 0; i < info->blob_count; ++i)
- if (property_blobs[i])
- drm_property_reference_blob(property_blobs[i]);
- }
+ if (!property_state)
+ return;
+
+ INIT_LIST_HEAD(&property_state->dirty_list);
+ property_state->values = property_values;
+
+ if (property_state->values)
+ /* add ref count for blobs and initialize dirty nodes */
+ for (i = 0; i < info->property_count; ++i) {
+ if (property_state->values[i].blob)
+ drm_property_reference_blob(
+ property_state->values[i].blob);
+ INIT_LIST_HEAD(&property_state->values[i].dirty_node);
+ }
}
void msm_property_destroy_state(struct msm_property_info *info, void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs)
+ struct msm_property_state *property_state)
{
uint32_t i;
@@ -554,19 +564,21 @@ void msm_property_destroy_state(struct msm_property_info *info, void *state,
DRM_ERROR("invalid argument(s)\n");
return;
}
- if (property_blobs) {
+ if (property_state && property_state->values) {
/* remove ref count for blobs */
- for (i = 0; i < info->blob_count; ++i)
- if (property_blobs[i])
+ for (i = 0; i < info->property_count; ++i)
+ if (property_state->values[i].blob) {
drm_property_unreference_blob(
- property_blobs[i]);
+ property_state->values[i].blob);
+ property_state->values[i].blob = NULL;
+ }
}
_msm_property_free_state(info, state);
}
void *msm_property_get_blob(struct msm_property_info *info,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
size_t *byte_len,
uint32_t property_idx)
{
@@ -574,10 +586,11 @@ void *msm_property_get_blob(struct msm_property_info *info,
size_t len = 0;
void *rc = 0;
- if (!info || !property_blobs || (property_idx >= info->blob_count)) {
+ if (!info || !property_state || !property_state->values ||
+ (property_idx >= info->blob_count)) {
DRM_ERROR("invalid argument(s)\n");
} else {
- blob = property_blobs[property_idx];
+ blob = property_state->values[property_idx].blob;
if (blob) {
len = blob->length;
rc = &blob->data;
@@ -636,14 +649,15 @@ int msm_property_set_blob(struct msm_property_info *info,
}
int msm_property_set_property(struct msm_property_info *info,
- uint64_t *property_values,
+ struct msm_property_state *property_state,
uint32_t property_idx,
uint64_t val)
{
int rc = -EINVAL;
if (!info || (property_idx >= info->property_count) ||
- property_idx < info->blob_count || !property_values) {
+ property_idx < info->blob_count ||
+ !property_state || !property_state->values) {
DRM_ERROR("invalid argument(s)\n");
} else {
struct drm_property *drm_prop;
@@ -651,8 +665,7 @@ int msm_property_set_property(struct msm_property_info *info,
mutex_lock(&info->property_lock);
/* update cached value */
- if (property_values)
- property_values[property_idx] = val;
+ property_state->values[property_idx].value = val;
/* update the new default value for immutables */
drm_prop = info->property_array[property_idx];
diff --git a/drivers/gpu/drm/msm/msm_prop.h b/drivers/gpu/drm/msm/msm_prop.h
index e54c796..9a53e56 100644
--- a/drivers/gpu/drm/msm/msm_prop.h
+++ b/drivers/gpu/drm/msm/msm_prop.h
@@ -22,17 +22,28 @@
* struct msm_property_data - opaque structure for tracking per
* drm-object per property stuff
* @default_value: Default property value for this drm object
- * @dirty_node: Linked list node to track if property is dirty or not
* @force_dirty: Always dirty property on incoming sets, rather than checking
* for modified values
*/
struct msm_property_data {
uint64_t default_value;
- struct list_head dirty_node;
bool force_dirty;
};
/**
+ * struct msm_property_value - opaque structure for tracking per
+ * drm-object per property stuff
+ * @value: Current property value for this drm object
+ * @blob: Pointer to associated blob data, if available
+ * @dirty_node: Linked list node to track if property is dirty or not
+ */
+struct msm_property_value {
+ uint64_t value;
+ struct drm_property_blob *blob;
+ struct list_head dirty_node;
+};
+
+/**
* struct msm_property_info: Structure for property/state helper functions
* @base: Pointer to base drm object (plane/crtc/etc.)
* @dev: Pointer to drm device object
@@ -43,8 +54,6 @@ struct msm_property_data {
* @install_request: Total number of property 'install' requests
* @install_count: Total number of successful 'install' requests
* @recent_idx: Index of property most recently accessed by set/get
- * @dirty_list: List of all properties that have been 'atomic_set' but not
- * yet cleared with 'msm_property_pop_dirty'
* @is_active: Whether or not drm component properties are 'active'
* @state_cache: Cache of local states, to prevent alloc/free thrashing
* @state_size: Size of local state structures
@@ -64,7 +73,6 @@ struct msm_property_info {
int32_t recent_idx;
- struct list_head dirty_list;
bool is_active;
void *state_cache[MSM_PROP_STATE_CACHE_SIZE];
@@ -74,6 +82,19 @@ struct msm_property_info {
};
/**
+ * struct msm_property_state - Structure for local property state information
+ * @property_count: Total number of properties
+ * @values: Pointer to array of msm_property_value objects
+ * @dirty_list: List of all properties that have been 'atomic_set' but not
+ * yet cleared with 'msm_property_pop_dirty'
+ */
+struct msm_property_state {
+ uint32_t property_count;
+ struct msm_property_value *values;
+ struct list_head dirty_list;
+};
+
+/**
* msm_property_get_default - query default value of a property
* @info: Pointer to property info container struct
* @property_idx: Property index
@@ -134,12 +155,14 @@ bool msm_property_get_is_active(struct msm_property_info *info)
* msm_property_pop_dirty - determine next dirty property and clear
* its dirty flag
* @info: Pointer to property info container struct
+ * @property_state: Pointer to property state container struct
* Returns: Valid msm property index on success,
* -EAGAIN if no dirty properties are available
* Property indicies returned from this function are similar
* to those returned by the msm_property_index function.
*/
-int msm_property_pop_dirty(struct msm_property_info *info);
+int msm_property_pop_dirty(struct msm_property_info *info,
+ struct msm_property_state *property_state);
/**
* msm_property_init - initialize property info structure
@@ -268,38 +291,37 @@ int msm_property_index(struct msm_property_info *info,
/**
* msm_property_set_dirty - forcibly flag a property as dirty
* @info: Pointer to property info container struct
+ * @property_state: Pointer to property state container struct
* @property_idx: Property index
* Returns: Zero on success
*/
-int msm_property_set_dirty(struct msm_property_info *info, int property_idx);
+int msm_property_set_dirty(struct msm_property_info *info,
+ struct msm_property_state *property_state,
+ int property_idx);
/**
* msm_property_atomic_set - helper function for atomic property set callback
* @info: Pointer to property info container struct
- * @property_values: Pointer to property values cache array
- * @property_blobs: Pointer to property blobs cache array
+ * @property_state: Pointer to local state structure
* @property: Incoming property pointer
* @val: Incoming property value
* Returns: Zero on success
*/
int msm_property_atomic_set(struct msm_property_info *info,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
struct drm_property *property,
uint64_t val);
/**
* msm_property_atomic_get - helper function for atomic property get callback
* @info: Pointer to property info container struct
- * @property_values: Pointer to property values cache array
- * @property_blobs: Pointer to property blobs cache array
+ * @property_state: Pointer to local state structure
* @property: Incoming property pointer
* @val: Pointer to variable for receiving property value
* Returns: Zero on success
*/
int msm_property_atomic_get(struct msm_property_info *info,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
struct drm_property *property,
uint64_t *val);
@@ -313,50 +335,47 @@ void *msm_property_alloc_state(struct msm_property_info *info);
* msm_property_reset_state - helper function for state reset callback
* @info: Pointer to property info container struct
* @state: Pointer to local state structure
+ * @property_state: Pointer to property state container struct
* @property_values: Pointer to property values cache array
- * @property_blobs: Pointer to property blobs cache array
*/
-void msm_property_reset_state(struct msm_property_info *info,
- void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs);
+void msm_property_reset_state(struct msm_property_info *info, void *state,
+ struct msm_property_state *property_state,
+ struct msm_property_value *property_values);
/**
* msm_property_duplicate_state - helper function for duplicate state cb
* @info: Pointer to property info container struct
* @old_state: Pointer to original state structure
* @state: Pointer to newly created state structure
+ * @property_state: Pointer to destination property state container struct
* @property_values: Pointer to property values cache array
- * @property_blobs: Pointer to property blobs cache array
*/
void msm_property_duplicate_state(struct msm_property_info *info,
void *old_state,
void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs);
+ struct msm_property_state *property_state,
+ struct msm_property_value *property_values);
/**
* msm_property_destroy_state - helper function for destroy state cb
* @info: Pointer to property info container struct
* @state: Pointer to local state structure
- * @property_values: Pointer to property values cache array
- * @property_blobs: Pointer to property blobs cache array
+ * @property_state: Pointer to property state container struct
*/
void msm_property_destroy_state(struct msm_property_info *info,
void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs);
+ struct msm_property_state *property_state);
/**
* msm_property_get_blob - obtain cached data pointer for drm blob property
* @info: Pointer to property info container struct
- * @property_blobs: Pointer to property blobs cache array
+ * @property_state: Pointer to property state container struct
* @byte_len: Optional pointer to variable for accepting blob size
* @property_idx: Property index
* Returns: Pointer to blob data
*/
void *msm_property_get_blob(struct msm_property_info *info,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
size_t *byte_len,
uint32_t property_idx);
@@ -385,13 +404,13 @@ int msm_property_set_blob(struct msm_property_info *info,
* DRM_MODE_PROP_IMMUTABLE flag set.
* Note: This function cannot be called on a blob.
* @info: Pointer to property info container struct
- * @property_values: Pointer to property values cache array
+ * @property_state: Pointer to property state container struct
* @property_idx: Property index
* @val: value of the property to set
* Returns: Zero on success
*/
int msm_property_set_property(struct msm_property_info *info,
- uint64_t *property_values,
+ struct msm_property_state *property_state,
uint32_t property_idx,
uint64_t val);
diff --git a/drivers/gpu/drm/msm/sde/sde_ad4.h b/drivers/gpu/drm/msm/sde/sde_ad4.h
index 4a664a8..5a646e9 100644
--- a/drivers/gpu/drm/msm/sde/sde_ad4.h
+++ b/drivers/gpu/drm/msm/sde/sde_ad4.h
@@ -48,6 +48,9 @@ enum ad_property {
AD_SUSPEND,
AD_ASSERTIVE,
AD_BACKLIGHT,
+ AD_IPC_SUSPEND,
+ AD_IPC_RESUME,
+ AD_IPC_RESET,
AD_PROPMAX,
};
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c
index e999a6a..9409066 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.c
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c
@@ -60,6 +60,8 @@ static void dspp_gamut_install_property(struct drm_crtc *crtc);
static void dspp_gc_install_property(struct drm_crtc *crtc);
+static void dspp_igc_install_property(struct drm_crtc *crtc);
+
typedef void (*dspp_prop_install_func_t)(struct drm_crtc *crtc);
static dspp_prop_install_func_t dspp_prop_install_func[SDE_DSPP_MAX];
@@ -72,6 +74,9 @@ static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node,
static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg);
+static void sde_cp_ad_set_prop(struct sde_crtc *sde_crtc,
+ enum ad_property ad_prop);
+
#define setup_dspp_prop_install_funcs(func) \
do { \
func[SDE_DSPP_PCC] = dspp_pcc_install_property; \
@@ -80,6 +85,7 @@ do { \
func[SDE_DSPP_VLUT] = dspp_vlut_install_property; \
func[SDE_DSPP_GAMUT] = dspp_gamut_install_property; \
func[SDE_DSPP_GC] = dspp_gc_install_property; \
+ func[SDE_DSPP_IGC] = dspp_igc_install_property; \
} while (0)
typedef void (*lm_prop_install_func_t)(struct drm_crtc *crtc);
@@ -750,6 +756,7 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
DRM_DEBUG_DRIVER("Dirty list is empty\n");
return;
}
+ sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESET);
set_dspp_flush = true;
}
@@ -1061,6 +1068,7 @@ static void dspp_pcc_install_property(struct drm_crtc *crtc)
"SDE_DSPP_PCC_V", version);
switch (version) {
case 1:
+ case 4:
sde_cp_crtc_install_blob_property(crtc, feature_name,
SDE_CP_CRTC_DSPP_PCC, sizeof(struct drm_msm_pcc));
break;
@@ -1241,6 +1249,30 @@ static void dspp_gc_install_property(struct drm_crtc *crtc)
}
}
+static void dspp_igc_install_property(struct drm_crtc *crtc)
+{
+ char feature_name[256];
+ struct sde_kms *kms = NULL;
+ struct sde_mdss_cfg *catalog = NULL;
+ u32 version;
+
+ kms = get_kms(crtc);
+ catalog = kms->catalog;
+
+ version = catalog->dspp[0].sblk->igc.version >> 16;
+ snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
+ "SDE_DSPP_IGC_V", version);
+ switch (version) {
+ case 3:
+ sde_cp_crtc_install_blob_property(crtc, feature_name,
+ SDE_CP_CRTC_DSPP_IGC, sizeof(struct drm_msm_igc_lut));
+ break;
+ default:
+ DRM_ERROR("version %d not supported\n", version);
+ break;
+ }
+}
+
static void sde_cp_update_list(struct sde_cp_node *prop_node,
struct sde_crtc *crtc, bool dirty_list)
{
@@ -1429,3 +1461,61 @@ int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en,
exit:
return ret;
}
+
+static void sde_cp_ad_set_prop(struct sde_crtc *sde_crtc,
+ enum ad_property ad_prop)
+{
+ struct sde_ad_hw_cfg ad_cfg;
+ struct sde_hw_cp_cfg hw_cfg;
+ struct sde_hw_dspp *hw_dspp = NULL;
+ struct sde_hw_mixer *hw_lm = NULL;
+ u32 num_mixers = sde_crtc->num_mixers;
+ int i = 0, ret = 0;
+
+ hw_cfg.num_of_mixers = sde_crtc->num_mixers;
+ hw_cfg.displayh = sde_crtc->base.mode.hdisplay;
+ hw_cfg.displayv = sde_crtc->base.mode.vdisplay;
+
+ for (i = 0; i < num_mixers && !ret; i++) {
+ hw_lm = sde_crtc->mixers[i].hw_lm;
+ hw_dspp = sde_crtc->mixers[i].hw_dspp;
+ if (!hw_lm || !hw_dspp || !hw_dspp->ops.validate_ad ||
+ !hw_dspp->ops.setup_ad) {
+ ret = -EINVAL;
+ continue;
+ }
+
+ hw_cfg.mixer_info = hw_lm;
+ ad_cfg.prop = ad_prop;
+ ad_cfg.hw_cfg = &hw_cfg;
+ ret = hw_dspp->ops.validate_ad(hw_dspp, (u32 *)&ad_prop);
+ if (!ret)
+ hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+ }
+}
+
+void sde_cp_crtc_pre_ipc(struct drm_crtc *drm_crtc)
+{
+ struct sde_crtc *sde_crtc;
+
+ sde_crtc = to_sde_crtc(drm_crtc);
+ if (!sde_crtc) {
+ DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
+ return;
+ }
+
+ sde_cp_ad_set_prop(sde_crtc, AD_IPC_SUSPEND);
+}
+
+void sde_cp_crtc_post_ipc(struct drm_crtc *drm_crtc)
+{
+ struct sde_crtc *sde_crtc;
+
+ sde_crtc = to_sde_crtc(drm_crtc);
+ if (!sde_crtc) {
+ DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
+ return;
+ }
+
+ sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESUME);
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.h b/drivers/gpu/drm/msm/sde/sde_color_processing.h
index e78f690..08e345d 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.h
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.h
@@ -103,4 +103,18 @@ void sde_cp_crtc_resume(struct drm_crtc *crtc);
*/
int sde_cp_ad_interrupt(struct drm_crtc *crtc, bool en,
struct sde_irq_callback *irq);
+
+/**
+ * sde_cp_crtc_pre_ipc: Handle color processing features
+ * before entering IPC
+ * @crtc: Pointer to crtc.
+ */
+void sde_cp_crtc_pre_ipc(struct drm_crtc *crtc);
+
+/**
+ * sde_cp_crtc_post_ipc: Handle color processing features
+ * after exiting IPC
+ * @crtc: Pointer to crtc.
+ */
+void sde_cp_crtc_post_ipc(struct drm_crtc *crtc);
#endif /*_SDE_COLOR_PROCESSING_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 6c9d496..fdb7d64 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -331,7 +331,7 @@ int sde_connector_get_dither_cfg(struct drm_connector *conn,
/* try to get user config data first */
*cfg = msm_property_get_blob(&c_conn->property_info,
- c_state->property_blobs,
+ &c_state->property_state,
&dither_sz,
CONNECTOR_PROP_PP_DITHER);
/* if user config data doesn't exist, use default dither blob */
@@ -459,13 +459,12 @@ static void _sde_connector_destroy_fb(struct sde_connector *c_conn,
drm_framebuffer_unreference(c_state->out_fb);
c_state->out_fb = NULL;
- if (c_conn) {
- c_state->property_values[CONNECTOR_PROP_OUT_FB] =
+ if (c_conn)
+ c_state->property_values[CONNECTOR_PROP_OUT_FB].value =
msm_property_get_default(&c_conn->property_info,
CONNECTOR_PROP_OUT_FB);
- } else {
- c_state->property_values[CONNECTOR_PROP_OUT_FB] = ~0;
- }
+ else
+ c_state->property_values[CONNECTOR_PROP_OUT_FB].value = ~0;
}
static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
@@ -496,8 +495,7 @@ static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
} else {
/* destroy value helper */
msm_property_destroy_state(&c_conn->property_info, c_state,
- c_state->property_values,
- c_state->property_blobs);
+ &c_state->property_state);
}
}
@@ -526,7 +524,8 @@ static void sde_connector_atomic_reset(struct drm_connector *connector)
/* reset value helper, zero out state structure and reset properties */
msm_property_reset_state(&c_conn->property_info, c_state,
- c_state->property_values, c_state->property_blobs);
+ &c_state->property_state,
+ c_state->property_values);
c_state->base.connector = connector;
connector->state = &c_state->base;
@@ -554,8 +553,8 @@ sde_connector_atomic_duplicate_state(struct drm_connector *connector)
/* duplicate value helper */
msm_property_duplicate_state(&c_conn->property_info,
- c_oldstate, c_state, c_state->property_values,
- c_state->property_blobs);
+ c_oldstate, c_state,
+ &c_state->property_state, c_state->property_values);
/* additional handling for drm framebuffer objects */
if (c_state->out_fb) {
@@ -755,8 +754,7 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
/* generic property handling */
rc = msm_property_atomic_set(&c_conn->property_info,
- c_state->property_values, c_state->property_blobs,
- property, val);
+ &c_state->property_state, property, val);
if (rc)
goto end;
@@ -863,8 +861,7 @@ static int sde_connector_atomic_get_property(struct drm_connector *connector,
else
/* get cached property value */
rc = msm_property_atomic_get(&c_conn->property_info,
- c_state->property_values,
- c_state->property_blobs, property, val);
+ &c_state->property_state, property, val);
/* allow for custom override */
if (c_conn->ops.get_property)
@@ -886,7 +883,8 @@ void sde_connector_prepare_fence(struct drm_connector *connector)
sde_fence_prepare(&to_sde_connector(connector)->retire_fence);
}
-void sde_connector_complete_commit(struct drm_connector *connector)
+void sde_connector_complete_commit(struct drm_connector *connector,
+ ktime_t ts)
{
if (!connector) {
SDE_ERROR("invalid connector\n");
@@ -894,7 +892,7 @@ void sde_connector_complete_commit(struct drm_connector *connector)
}
/* signal connector's retire fence */
- sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
+ sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, 0);
}
static enum drm_connector_status
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 8e46a11..1598968 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -315,6 +315,7 @@ struct sde_connector {
* @base: Base drm connector structure
* @out_fb: Pointer to output frame buffer, if applicable
* @aspace: Address space for accessing frame buffer objects, if applicable
+ * @property_state: Local storage for msm_prop properties
* @property_values: Local cache of current connector property values
* @rois: Regions of interest structure for mapping CRTC to Connector output
* @property_blobs: blob properties
@@ -323,7 +324,8 @@ struct sde_connector_state {
struct drm_connector_state base;
struct drm_framebuffer *out_fb;
struct msm_gem_address_space *aspace;
- uint64_t property_values[CONNECTOR_PROP_COUNT];
+ struct msm_property_state property_state;
+ struct msm_property_value property_values[CONNECTOR_PROP_COUNT];
struct msm_roi_list rois;
struct drm_property_blob *property_blobs[CONNECTOR_PROP_BLOBCOUNT];
@@ -346,15 +348,15 @@ struct sde_connector_state {
*/
#define sde_connector_get_property(S, X) \
((S) && ((X) < CONNECTOR_PROP_COUNT) ? \
- (to_sde_connector_state((S))->property_values[(X)]) : 0)
+ (to_sde_connector_state((S))->property_values[(X)].value) : 0)
/**
- * sde_connector_get_property_values - retrieve property values cache
+ * sde_connector_get_property_state - retrieve property state cache
* @S: Pointer to drm connector state
- * Returns: Integer value of requested property
+ * Returns: Pointer to local property state structure
*/
-#define sde_connector_get_property_values(S) \
- ((S) ? (to_sde_connector_state((S))->property_values) : 0)
+#define sde_connector_get_property_state(S) \
+ ((S) ? (&to_sde_connector_state((S))->property_state) : NULL)
/**
* sde_connector_get_out_fb - query out_fb value from sde connector state
@@ -406,8 +408,9 @@ void sde_connector_prepare_fence(struct drm_connector *connector);
/**
* sde_connector_complete_commit - signal completion of current commit
* @connector: Pointer to drm connector object
+ * @ts: timestamp to be updated in the fence signalling
*/
-void sde_connector_complete_commit(struct drm_connector *connector);
+void sde_connector_complete_commit(struct drm_connector *connector, ktime_t ts);
/**
* sde_connector_get_info - query display specific information
diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.c b/drivers/gpu/drm/msm/sde/sde_core_irq.c
index cec2b5f..dfdfc1a 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_irq.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_irq.c
@@ -34,8 +34,12 @@ static void sde_core_irq_callback_handler(void *arg, int irq_idx)
pr_debug("irq_idx=%d\n", irq_idx);
- if (list_empty(&irq_obj->irq_cb_tbl[irq_idx]))
+ if (list_empty(&irq_obj->irq_cb_tbl[irq_idx])) {
SDE_ERROR("irq_idx=%d has no registered callback\n", irq_idx);
+ SDE_EVT32_IRQ(irq_idx, atomic_read(
+ &sde_kms->irq_obj.enable_counts[irq_idx]),
+ SDE_EVTLOG_ERROR);
+ }
atomic_inc(&irq_obj->irq_counts[irq_idx]);
@@ -53,7 +57,7 @@ static void sde_core_irq_callback_handler(void *arg, int irq_idx)
* NOTE: sde_core_irq_callback_handler is protected by top-level
* spinlock, so it is safe to clear any interrupt status here.
*/
- sde_kms->hw_intr->ops.clear_interrupt_status(
+ sde_kms->hw_intr->ops.clear_intr_status_nolock(
sde_kms->hw_intr,
irq_idx);
}
@@ -94,7 +98,6 @@ static int _sde_core_irq_enable(struct sde_kms *sde_kms, int irq_idx)
SDE_DEBUG("irq_idx=%d enable_count=%d\n", irq_idx,
atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx]));
- spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags);
SDE_EVT32(irq_idx,
atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx]));
if (atomic_inc_return(&sde_kms->irq_obj.enable_counts[irq_idx]) == 1) {
@@ -107,26 +110,33 @@ static int _sde_core_irq_enable(struct sde_kms *sde_kms, int irq_idx)
SDE_DEBUG("irq_idx=%d ret=%d\n", irq_idx, ret);
+ spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags);
/* empty callback list but interrupt is enabled */
if (list_empty(&sde_kms->irq_obj.irq_cb_tbl[irq_idx]))
SDE_ERROR("irq_idx=%d enabled with no callback\n",
irq_idx);
+ spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags);
}
- spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags);
return ret;
}
int sde_core_irq_enable(struct sde_kms *sde_kms, int *irq_idxs, u32 irq_count)
{
- int i;
- int ret = 0;
+ int i, ret = 0, counts;
if (!sde_kms || !irq_idxs || !irq_count) {
SDE_ERROR("invalid params\n");
return -EINVAL;
}
+ counts = atomic_read(&sde_kms->irq_obj.enable_counts[irq_idxs[0]]);
+ if (counts) {
+ SDE_ERROR("%pS: irq_idx=%d enable_count=%d\n",
+ __builtin_return_address(0), irq_idxs[0], counts);
+ SDE_EVT32(irq_idxs[0], counts, SDE_EVTLOG_ERROR);
+ }
+
for (i = 0; (i < irq_count) && !ret; i++)
ret = _sde_core_irq_enable(sde_kms, irq_idxs[i]);
@@ -140,7 +150,6 @@ int sde_core_irq_enable(struct sde_kms *sde_kms, int *irq_idxs, u32 irq_count)
*/
static int _sde_core_irq_disable(struct sde_kms *sde_kms, int irq_idx)
{
- unsigned long irq_flags;
int ret = 0;
if (!sde_kms || !sde_kms->hw_intr || !sde_kms->irq_obj.enable_counts) {
@@ -156,7 +165,6 @@ static int _sde_core_irq_disable(struct sde_kms *sde_kms, int irq_idx)
SDE_DEBUG("irq_idx=%d enable_count=%d\n", irq_idx,
atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx]));
- spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags);
SDE_EVT32(irq_idx,
atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx]));
if (atomic_dec_return(&sde_kms->irq_obj.enable_counts[irq_idx]) == 0) {
@@ -168,27 +176,48 @@ static int _sde_core_irq_disable(struct sde_kms *sde_kms, int irq_idx)
irq_idx);
SDE_DEBUG("irq_idx=%d ret=%d\n", irq_idx, ret);
}
- spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags);
return ret;
}
int sde_core_irq_disable(struct sde_kms *sde_kms, int *irq_idxs, u32 irq_count)
{
- int i;
- int ret = 0;
+ int i, ret = 0, counts;
if (!sde_kms || !irq_idxs || !irq_count) {
SDE_ERROR("invalid params\n");
return -EINVAL;
}
+ counts = atomic_read(&sde_kms->irq_obj.enable_counts[irq_idxs[0]]);
+ if (counts == 2) {
+ SDE_ERROR("%pS: irq_idx=%d enable_count=%d\n",
+ __builtin_return_address(0), irq_idxs[0], counts);
+ SDE_EVT32(irq_idxs[0], counts, SDE_EVTLOG_ERROR);
+ }
+
for (i = 0; (i < irq_count) && !ret; i++)
ret = _sde_core_irq_disable(sde_kms, irq_idxs[i]);
return ret;
}
+u32 sde_core_irq_read_nolock(struct sde_kms *sde_kms, int irq_idx, bool clear)
+{
+ if (!sde_kms || !sde_kms->hw_intr ||
+ !sde_kms->hw_intr->ops.get_interrupt_status)
+ return 0;
+
+ if (irq_idx < 0) {
+ SDE_ERROR("[%pS] invalid irq_idx=%d\n",
+ __builtin_return_address(0), irq_idx);
+ return 0;
+ }
+
+ return sde_kms->hw_intr->ops.get_intr_status_nolock(sde_kms->hw_intr,
+ irq_idx, clear);
+}
+
u32 sde_core_irq_read(struct sde_kms *sde_kms, int irq_idx, bool clear)
{
if (!sde_kms || !sde_kms->hw_intr ||
@@ -210,12 +239,19 @@ int sde_core_irq_register_callback(struct sde_kms *sde_kms, int irq_idx,
{
unsigned long irq_flags;
- if (!sde_kms || !register_irq_cb || !register_irq_cb->func ||
- !sde_kms->irq_obj.irq_cb_tbl) {
+ if (!sde_kms || !sde_kms->irq_obj.irq_cb_tbl) {
SDE_ERROR("invalid params\n");
return -EINVAL;
}
+ if (!register_irq_cb || !register_irq_cb->func) {
+ SDE_ERROR("invalid irq_cb:%d func:%d\n",
+ register_irq_cb != NULL,
+ register_irq_cb ?
+ register_irq_cb->func != NULL : -1);
+ return -EINVAL;
+ }
+
if (irq_idx < 0 || irq_idx >= sde_kms->hw_intr->irq_idx_tbl_size) {
SDE_ERROR("invalid IRQ index: [%d]\n", irq_idx);
return -EINVAL;
@@ -238,12 +274,19 @@ int sde_core_irq_unregister_callback(struct sde_kms *sde_kms, int irq_idx,
{
unsigned long irq_flags;
- if (!sde_kms || !register_irq_cb || !register_irq_cb->func ||
- !sde_kms->irq_obj.irq_cb_tbl) {
+ if (!sde_kms || !sde_kms->irq_obj.irq_cb_tbl) {
SDE_ERROR("invalid params\n");
return -EINVAL;
}
+ if (!register_irq_cb || !register_irq_cb->func) {
+ SDE_ERROR("invalid irq_cb:%d func:%d\n",
+ register_irq_cb != NULL,
+ register_irq_cb ?
+ register_irq_cb->func != NULL : -1);
+ return -EINVAL;
+ }
+
if (irq_idx < 0 || irq_idx >= sde_kms->hw_intr->irq_idx_tbl_size) {
SDE_ERROR("invalid IRQ index: [%d]\n", irq_idx);
return -EINVAL;
diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.h b/drivers/gpu/drm/msm/sde/sde_core_irq.h
index c775f8c..c32c19c 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_irq.h
+++ b/drivers/gpu/drm/msm/sde/sde_core_irq.h
@@ -114,6 +114,18 @@ u32 sde_core_irq_read(
bool clear);
/**
+ * sde_core_irq_read - no lock version of sde_core_irq_read
+ * @sde_kms: SDE handle
+ * @irq_idx: irq index
+ * @clear: True to clear the irq after read
+ * @return: non-zero if irq detected; otherwise no irq detected
+ */
+u32 sde_core_irq_read_nolock(
+ struct sde_kms *sde_kms,
+ int irq_idx,
+ bool clear);
+
+/**
* sde_core_irq_register_callback - For registering callback function on IRQ
* interrupt
* @sde_kms: SDE handle
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.c b/drivers/gpu/drm/msm/sde/sde_core_perf.c
index 71dfc12..7243fe2 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.c
@@ -225,8 +225,17 @@ int sde_core_perf_crtc_check(struct drm_crtc *crtc,
struct sde_crtc_state *tmp_cstate =
to_sde_crtc_state(tmp_crtc->state);
- bw_sum_of_intfs +=
- tmp_cstate->new_perf.bw_ctl[i];
+ SDE_DEBUG("crtc:%d bw:%llu ctrl:%d\n",
+ tmp_crtc->base.id,
+ tmp_cstate->new_perf.bw_ctl[i],
+ tmp_cstate->bw_control);
+ /*
+ * For bw check only use the bw if the
+ * atomic property has been already set
+ */
+ if (tmp_cstate->bw_control)
+ bw_sum_of_intfs +=
+ tmp_cstate->new_perf.bw_ctl[i];
}
}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 63979dd..01e4f93 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -55,9 +55,13 @@ struct sde_crtc_custom_events {
static int sde_crtc_power_interrupt_handler(struct drm_crtc *crtc_drm,
bool en, struct sde_irq_callback *ad_irq);
+static int sde_crtc_pm_event_handler(struct drm_crtc *crtc_drm,
+ bool en, struct sde_irq_callback *noirq);
+
static struct sde_crtc_custom_events custom_events[] = {
{DRM_EVENT_AD_BACKLIGHT, sde_cp_ad_interrupt},
- {DRM_EVENT_CRTC_POWER, sde_crtc_power_interrupt_handler}
+ {DRM_EVENT_CRTC_POWER, sde_crtc_power_interrupt_handler},
+ {DRM_EVENT_SDE_POWER, sde_crtc_pm_event_handler},
};
/* default input fence timeout, in ms */
@@ -1516,6 +1520,8 @@ static void sde_crtc_frame_event_work(struct kthread_work *work)
struct sde_crtc_state *cstate;
struct sde_kms *sde_kms;
unsigned long flags;
+ bool frame_done = false;
+ int i;
if (!work) {
SDE_ERROR("invalid work handle\n");
@@ -1538,13 +1544,16 @@ static void sde_crtc_frame_event_work(struct kthread_work *work)
return;
}
priv = sde_kms->dev->dev_private;
+ SDE_ATRACE_BEGIN("crtc_frame_event");
SDE_DEBUG("crtc%d event:%u ts:%lld\n", crtc->base.id, fevent->event,
ktime_to_ns(fevent->ts));
- if (fevent->event == SDE_ENCODER_FRAME_EVENT_DONE ||
- (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR) ||
- (fevent->event & SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) {
+ SDE_EVT32_VERBOSE(DRMID(crtc), fevent->event, SDE_EVTLOG_FUNC_ENTRY);
+
+ if (fevent->event & (SDE_ENCODER_FRAME_EVENT_DONE
+ | SDE_ENCODER_FRAME_EVENT_ERROR
+ | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) {
if (atomic_read(&sde_crtc->frame_pending) < 1) {
/* this should not happen */
@@ -1567,26 +1576,39 @@ static void sde_crtc_frame_event_work(struct kthread_work *work)
SDE_EVTLOG_FUNC_CASE3);
}
- if (fevent->event == SDE_ENCODER_FRAME_EVENT_DONE ||
- (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR))
- complete_all(&sde_crtc->frame_done_comp);
-
- if (fevent->event == SDE_ENCODER_FRAME_EVENT_DONE)
+ if (fevent->event & SDE_ENCODER_FRAME_EVENT_DONE)
sde_core_perf_crtc_update(crtc, 0, false);
- } else {
- SDE_ERROR("crtc%d ts:%lld unknown event %u\n", crtc->base.id,
- ktime_to_ns(fevent->ts),
- fevent->event);
- SDE_EVT32(DRMID(crtc), fevent->event, SDE_EVTLOG_FUNC_CASE4);
+
+ if (fevent->event & (SDE_ENCODER_FRAME_EVENT_DONE
+ | SDE_ENCODER_FRAME_EVENT_ERROR))
+ frame_done = true;
+ }
+
+ if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE) {
+ SDE_ATRACE_BEGIN("signal_release_fence");
+ sde_fence_signal(&sde_crtc->output_fence, fevent->ts, 0);
+ SDE_ATRACE_END("signal_release_fence");
+ }
+
+ if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE) {
+ SDE_ATRACE_BEGIN("signal_retire_fence");
+ for (i = 0; i < cstate->num_connectors; ++i)
+ sde_connector_complete_commit(cstate->connectors[i],
+ fevent->ts);
+ SDE_ATRACE_END("signal_retire_fence");
}
if (fevent->event & SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)
SDE_ERROR("crtc%d ts:%lld received panel dead event\n",
crtc->base.id, ktime_to_ns(fevent->ts));
+ if (frame_done)
+ complete_all(&sde_crtc->frame_done_comp);
+
spin_lock_irqsave(&sde_crtc->spin_lock, flags);
list_add_tail(&fevent->list, &sde_crtc->frame_event_list);
spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
+ SDE_ATRACE_END("crtc_frame_event");
}
static void sde_crtc_frame_event_cb(void *data, u32 event)
@@ -1629,30 +1651,6 @@ static void sde_crtc_frame_event_cb(void *data, u32 event)
kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work);
}
-void sde_crtc_complete_commit(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state)
-{
- struct sde_crtc *sde_crtc;
- struct sde_crtc_state *cstate;
- int i;
-
- if (!crtc || !crtc->state) {
- SDE_ERROR("invalid crtc\n");
- return;
- }
-
- sde_crtc = to_sde_crtc(crtc);
- cstate = to_sde_crtc_state(crtc->state);
- SDE_EVT32_VERBOSE(DRMID(crtc));
-
- /* signal release fence */
- sde_fence_signal(&sde_crtc->output_fence, 0);
-
- /* signal retire fence */
- for (i = 0; i < cstate->num_connectors; ++i)
- sde_connector_complete_commit(cstate->connectors[i]);
-}
-
/**
* _sde_crtc_set_input_fence_timeout - update ns version of in fence timeout
* @cstate: Pointer to sde crtc state
@@ -2086,7 +2084,7 @@ static void sde_crtc_destroy_state(struct drm_crtc *crtc,
/* destroy value helper */
msm_property_destroy_state(&sde_crtc->property_info, cstate,
- cstate->property_values, cstate->property_blobs);
+ &cstate->property_state);
}
static int _sde_crtc_wait_for_frame_done(struct drm_crtc *crtc)
@@ -2127,6 +2125,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
struct sde_crtc_state *cstate;
+ int ret;
if (!crtc) {
SDE_ERROR("invalid argument\n");
@@ -2170,7 +2169,10 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
}
/* wait for frame_event_done completion */
- if (_sde_crtc_wait_for_frame_done(crtc)) {
+ SDE_ATRACE_BEGIN("wait_for_frame_done_event");
+ ret = _sde_crtc_wait_for_frame_done(crtc);
+ SDE_ATRACE_END("wait_for_frame_done_event");
+ if (ret) {
SDE_ERROR("crtc%d wait for frame done failed;frame_pending%d\n",
crtc->base.id,
atomic_read(&sde_crtc->frame_pending));
@@ -2301,13 +2303,13 @@ static void _sde_crtc_set_suspend(struct drm_crtc *crtc, bool enable)
}
/*
- * If the vblank refcount != 0, release a power reference on suspend
- * and take it back during resume (if it is still != 0).
+ * If the vblank is enabled, release a power reference on suspend
+ * and take it back during resume (if it is still enabled).
*/
if (sde_crtc->suspend == enable)
SDE_DEBUG("crtc%d suspend already set to %d, ignoring update\n",
crtc->base.id, enable);
- else if (atomic_read(&sde_crtc->vblank_refcount) != 0)
+ else if (sde_crtc->vblank_enable)
_sde_crtc_vblank_enable_nolock(sde_crtc, !enable);
sde_crtc->suspend = enable;
@@ -2342,7 +2344,7 @@ static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc)
/* duplicate value helper */
msm_property_duplicate_state(&sde_crtc->property_info,
old_cstate, cstate,
- cstate->property_values, cstate->property_blobs);
+ &cstate->property_state, cstate->property_values);
/* duplicate base helper */
__drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base);
@@ -2387,7 +2389,8 @@ static void sde_crtc_reset(struct drm_crtc *crtc)
/* reset value helper */
msm_property_reset_state(&sde_crtc->property_info, cstate,
- cstate->property_values, cstate->property_blobs);
+ &cstate->property_state,
+ cstate->property_values);
_sde_crtc_set_input_fence_timeout(cstate);
@@ -2402,25 +2405,15 @@ static int _sde_crtc_vblank_no_lock(struct sde_crtc *sde_crtc, bool en)
if (!sde_crtc) {
SDE_ERROR("invalid crtc\n");
return -EINVAL;
- } else if (en && atomic_inc_return(&sde_crtc->vblank_refcount) == 1) {
- SDE_DEBUG("crtc%d vblank enable\n", sde_crtc->base.base.id);
- if (!sde_crtc->suspend)
- _sde_crtc_vblank_enable_nolock(sde_crtc, true);
- } else if (!en && atomic_read(&sde_crtc->vblank_refcount) < 1) {
- SDE_ERROR("crtc%d invalid vblank disable\n",
- sde_crtc->base.base.id);
- return -EINVAL;
- } else if (!en && atomic_dec_return(&sde_crtc->vblank_refcount) == 0) {
- SDE_DEBUG("crtc%d vblank disable\n", sde_crtc->base.base.id);
- if (!sde_crtc->suspend)
- _sde_crtc_vblank_enable_nolock(sde_crtc, false);
- } else {
- SDE_DEBUG("crtc%d vblank %s refcount:%d\n",
- sde_crtc->base.base.id,
- en ? "enable" : "disable",
- atomic_read(&sde_crtc->vblank_refcount));
}
+ if (!sde_crtc->base.enabled || sde_crtc->suspend)
+ SDE_EVT32(DRMID(&sde_crtc->base), sde_crtc->base.enabled, en,
+ sde_crtc->vblank_enable, sde_crtc->suspend);
+ else if (sde_crtc->vblank_enable != en)
+ _sde_crtc_vblank_enable_nolock(sde_crtc, en);
+ sde_crtc->vblank_enable = en;
+
return 0;
}
@@ -2429,6 +2422,8 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
struct drm_crtc *crtc = arg;
struct sde_crtc *sde_crtc;
struct drm_encoder *encoder;
+ struct drm_event event;
+ u32 power_on = 0;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
@@ -2448,7 +2443,13 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
sde_encoder_virt_restore(encoder);
}
+ sde_cp_crtc_post_ipc(crtc);
+ event.type = DRM_EVENT_SDE_POWER;
+ event.length = sizeof(power_on);
+ power_on = 1;
+ msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
+ (u8 *)&power_on);
} else if (event_type == SDE_POWER_EVENT_POST_DISABLE) {
struct drm_plane *plane;
@@ -2460,6 +2461,14 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
sde_plane_set_revalidate(plane, true);
sde_cp_crtc_suspend(crtc);
+
+ event.type = DRM_EVENT_SDE_POWER;
+ event.length = sizeof(power_on);
+ power_on = 0;
+ msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
+ (u8 *)&power_on);
+ } else if (event_type == SDE_POWER_EVENT_PRE_DISABLE) {
+ sde_cp_crtc_pre_ipc(crtc);
}
mutex_unlock(&sde_crtc->crtc_lock);
@@ -2497,14 +2506,12 @@ static void sde_crtc_disable(struct drm_crtc *crtc)
crtc->base.id,
atomic_read(&sde_crtc->frame_pending));
- if (atomic_read(&sde_crtc->vblank_refcount) && !sde_crtc->suspend) {
- SDE_ERROR("crtc%d invalid vblank refcount\n",
+ if (sde_crtc->vblank_enable && !sde_crtc->suspend) {
+ SDE_DEBUG("crtc%d vblank left enabled at disable time\n",
crtc->base.id);
- SDE_EVT32(DRMID(crtc), atomic_read(&sde_crtc->vblank_refcount),
- SDE_EVTLOG_FUNC_CASE1);
- while (atomic_read(&sde_crtc->vblank_refcount))
- if (_sde_crtc_vblank_no_lock(sde_crtc, false))
- break;
+ SDE_EVT32(DRMID(crtc), sde_crtc->vblank_enable,
+ SDE_EVTLOG_FUNC_CASE1);
+ _sde_crtc_vblank_enable_nolock(sde_crtc, false);
}
if (atomic_read(&sde_crtc->frame_pending)) {
@@ -2575,6 +2582,16 @@ static void sde_crtc_enable(struct drm_crtc *crtc)
sde_crtc_frame_event_cb, (void *)crtc);
}
+ mutex_lock(&sde_crtc->crtc_lock);
+ if (sde_crtc->vblank_enable) {
+ /* honor user vblank request on crtc while it was disabled */
+ SDE_DEBUG("%s vblank found enabled at crtc enable time\n",
+ sde_crtc->name);
+ SDE_EVT32(DRMID(crtc), sde_crtc->vblank_enable);
+ _sde_crtc_vblank_enable_nolock(sde_crtc, true);
+ }
+ mutex_unlock(&sde_crtc->crtc_lock);
+
spin_lock_irqsave(&sde_crtc->spin_lock, flags);
list_for_each_entry(node, &sde_crtc->user_event_list, list) {
ret = 0;
@@ -2588,7 +2605,8 @@ static void sde_crtc_enable(struct drm_crtc *crtc)
sde_crtc->power_event = sde_power_handle_register_event(
&priv->phandle,
- SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE,
+ SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE |
+ SDE_POWER_EVENT_PRE_DISABLE,
sde_crtc_handle_power_event, crtc, sde_crtc->name);
}
@@ -2758,7 +2776,8 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
/* check dim layer stage with every plane */
for (i = 0; i < cstate->num_dim_layers; i++) {
- if (pstates[cnt].stage == cstate->dim_layer[i].stage) {
+ if (cstate->dim_layer[i].stage
+ == (pstates[cnt].stage + SDE_STAGE_0)) {
SDE_ERROR(
"plane:%d/dim_layer:%i-same stage:%d\n",
plane->base.id, i,
@@ -3178,8 +3197,7 @@ static int sde_crtc_atomic_set_property(struct drm_crtc *crtc,
sde_crtc = to_sde_crtc(crtc);
cstate = to_sde_crtc_state(state);
ret = msm_property_atomic_set(&sde_crtc->property_info,
- cstate->property_values, cstate->property_blobs,
- property, val);
+ &cstate->property_state, property, val);
if (!ret) {
idx = msm_property_index(&sde_crtc->property_info,
property);
@@ -3253,8 +3271,10 @@ static int sde_crtc_atomic_get_property(struct drm_crtc *crtc,
{
struct sde_crtc *sde_crtc;
struct sde_crtc_state *cstate;
+ struct drm_encoder *encoder;
int i, ret = -EINVAL;
bool conn_offset = 0;
+ bool is_cmd = true;
if (!crtc || !state) {
SDE_ERROR("invalid argument(s)\n");
@@ -3269,19 +3289,36 @@ static int sde_crtc_atomic_get_property(struct drm_crtc *crtc,
break;
}
+ /**
+ * set the cmd flag only when all the encoders attached
+ * to the crtc are in cmd mode. Consider all other cases
+ * as video mode.
+ */
+ drm_for_each_encoder(encoder, crtc->dev) {
+ if (encoder->crtc == crtc)
+ is_cmd &= sde_encoder_is_cmd_mode(encoder);
+ }
+
i = msm_property_index(&sde_crtc->property_info, property);
if (i == CRTC_PROP_OUTPUT_FENCE) {
uint32_t offset = sde_crtc_get_property(cstate,
CRTC_PROP_OUTPUT_FENCE_OFFSET);
+ /**
+ * set the offset to 0 only for cmd mode panels, so
+ * the release fence for the current frame can be
+ * triggered right after PP_DONE interrupt.
+ */
+ offset = is_cmd ? 0 : (offset + conn_offset);
+
ret = sde_fence_create(&sde_crtc->output_fence, val,
- offset + conn_offset);
+ offset);
if (ret)
SDE_ERROR("fence create failed\n");
} else {
ret = msm_property_atomic_get(&sde_crtc->property_info,
- cstate->property_values,
- cstate->property_blobs, property, val);
+ &cstate->property_state,
+ property, val);
if (ret)
ret = sde_cp_crtc_get_property(crtc,
property, val);
@@ -3423,8 +3460,7 @@ static int _sde_debugfs_status_show(struct seq_file *s, void *data)
sde_crtc->vblank_cb_time = ktime_set(0, 0);
}
- seq_printf(s, "vblank_refcount:%d\n",
- atomic_read(&sde_crtc->vblank_refcount));
+ seq_printf(s, "vblank_enable:%d\n", sde_crtc->vblank_enable);
mutex_unlock(&sde_crtc->crtc_lock);
@@ -3790,7 +3826,6 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane)
crtc = &sde_crtc->base;
crtc->dev = dev;
- atomic_set(&sde_crtc->vblank_refcount, 0);
mutex_init(&sde_crtc->crtc_lock);
spin_lock_init(&sde_crtc->spin_lock);
@@ -3975,3 +4010,13 @@ static int sde_crtc_power_interrupt_handler(struct drm_crtc *crtc_drm,
{
return 0;
}
+
+static int sde_crtc_pm_event_handler(struct drm_crtc *crtc, bool en,
+ struct sde_irq_callback *noirq)
+{
+ /*
+ * IRQ object noirq is not being used here since there is
+ * no crtc irq from pm event.
+ */
+ return 0;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 0d72ff1..84f9ce1 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -30,7 +30,7 @@
#define SDE_CRTC_NAME_SIZE 12
/* define the maximum number of in-flight frame events */
-#define SDE_CRTC_FRAME_EVENT_SIZE 2
+#define SDE_CRTC_FRAME_EVENT_SIZE 4
/**
* enum sde_crtc_client_type: crtc client type
@@ -123,7 +123,7 @@ struct sde_crtc_event {
* @vblank_cb_count : count of vblank callback since last reset
* @play_count : frame count between crtc enable and disable
* @vblank_cb_time : ktime at vblank count reset
- * @vblank_refcount : reference count for vblank enable request
+ * @vblank_enable : whether the user has requested vblank events
* @suspend : whether or not a suspend operation is in progress
* @feature_list : list of color processing features supported on a crtc
* @active_list : list of color processing features are active
@@ -171,7 +171,7 @@ struct sde_crtc {
u32 vblank_cb_count;
u64 play_count;
ktime_t vblank_cb_time;
- atomic_t vblank_refcount;
+ bool vblank_enable;
bool suspend;
struct list_head feature_list;
@@ -269,9 +269,9 @@ struct sde_crtc_respool {
* @lm_roi : Current LM ROI, possibly sub-rectangle of mode.
* Origin top left of CRTC.
* @user_roi_list : List of user's requested ROIs as from set property
+ * @property_state: Local storage for msm_prop properties
* @property_values: Current crtc property values
* @input_fence_timeout_ns : Cached input fence timeout, in ns
- * @property_blobs: Reference pointers for blob properties
* @num_dim_layers: Number of dim layers
* @dim_layer: Dim layer configs
* @new_perf: new performance state being requested
@@ -296,9 +296,9 @@ struct sde_crtc_state {
struct sde_rect lm_roi[CRTC_DUAL_MIXERS];
struct msm_roi_list user_roi_list;
- uint64_t property_values[CRTC_PROP_COUNT];
+ struct msm_property_state property_state;
+ struct msm_property_value property_values[CRTC_PROP_COUNT];
uint64_t input_fence_timeout_ns;
- struct drm_property_blob *property_blobs[CRTC_PROP_COUNT];
uint32_t num_dim_layers;
struct sde_hw_dim_layer dim_layer[SDE_MAX_DIM_LAYERS];
@@ -320,7 +320,7 @@ struct sde_crtc_state {
* Returns: Integer value of requested property
*/
#define sde_crtc_get_property(S, X) \
- ((S) && ((X) < CRTC_PROP_COUNT) ? ((S)->property_values[(X)]) : 0)
+ ((S) && ((X) < CRTC_PROP_COUNT) ? ((S)->property_values[(X)].value) : 0)
static inline int sde_crtc_mixer_width(struct sde_crtc *sde_crtc,
struct drm_display_mode *mode)
@@ -369,14 +369,6 @@ void sde_crtc_prepare_commit(struct drm_crtc *crtc,
struct drm_crtc_state *old_state);
/**
- * sde_crtc_complete_commit - callback signalling completion of current commit
- * @crtc: Pointer to drm crtc object
- * @old_state: Pointer to drm crtc old state object
- */
-void sde_crtc_complete_commit(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state);
-
-/**
* sde_crtc_init - create a new crtc object
* @dev: sde device
* @plane: base plane
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 56e1151..0e94085 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -17,6 +17,7 @@
*/
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
+#include <linux/kthread.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/sde_rsc.h>
@@ -206,7 +207,7 @@ struct sde_encoder_virt {
bool idle_pc_supported;
struct mutex rc_lock;
enum sde_enc_rc_states rc_state;
- struct delayed_work delayed_off_work;
+ struct kthread_delayed_work delayed_off_work;
struct msm_display_topology topology;
bool mode_set_complete;
@@ -417,6 +418,9 @@ int sde_encoder_helper_register_irq(struct sde_encoder_phys *phys_enc,
sde_core_irq_unregister_callback(phys_enc->sde_kms,
irq->irq_idx, &irq->cb);
+
+ SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx,
+ irq->irq_idx, SDE_EVTLOG_ERROR);
irq->irq_idx = -EINVAL;
return ret;
}
@@ -432,6 +436,7 @@ int sde_encoder_helper_unregister_irq(struct sde_encoder_phys *phys_enc,
enum sde_intr_idx intr_idx)
{
struct sde_encoder_irq *irq;
+ int ret;
if (!phys_enc) {
SDE_ERROR("invalid encoder\n");
@@ -440,17 +445,32 @@ int sde_encoder_helper_unregister_irq(struct sde_encoder_phys *phys_enc,
irq = &phys_enc->irq[intr_idx];
/* silently skip irqs that weren't registered */
- if (irq->irq_idx < 0)
+ if (irq->irq_idx < 0) {
+ SDE_ERROR(
+ "extra unregister irq, enc%d intr_idx:0x%x hw_idx:0x%x irq_idx:0x%x\n",
+ DRMID(phys_enc->parent), intr_idx, irq->hw_idx,
+ irq->irq_idx);
+ SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx,
+ irq->irq_idx, SDE_EVTLOG_ERROR);
return 0;
+ }
- sde_core_irq_disable(phys_enc->sde_kms, &irq->irq_idx, 1);
- sde_core_irq_unregister_callback(phys_enc->sde_kms, irq->irq_idx,
+ ret = sde_core_irq_disable(phys_enc->sde_kms, &irq->irq_idx, 1);
+ if (ret)
+ SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx,
+ irq->irq_idx, ret, SDE_EVTLOG_ERROR);
+
+ ret = sde_core_irq_unregister_callback(phys_enc->sde_kms, irq->irq_idx,
&irq->cb);
- irq->irq_idx = -EINVAL;
+ if (ret)
+ SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx,
+ irq->irq_idx, ret, SDE_EVTLOG_ERROR);
SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, irq->irq_idx);
SDE_DEBUG_PHYS(phys_enc, "unregistered %d\n", irq->irq_idx);
+ irq->irq_idx = -EINVAL;
+
return 0;
}
@@ -1101,6 +1121,62 @@ static int _sde_encoder_dsc_setup(struct sde_encoder_virt *sde_enc,
return ret;
}
+static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc,
+ struct msm_display_info *disp_info, bool is_dummy)
+{
+ struct sde_vsync_source_cfg vsync_cfg = { 0 };
+ struct msm_drm_private *priv;
+ struct sde_kms *sde_kms;
+ struct sde_hw_mdp *hw_mdptop;
+ struct drm_encoder *drm_enc;
+ int i;
+
+ if (!sde_enc || !disp_info) {
+ SDE_ERROR("invalid param sde_enc:%d or disp_info:%d\n",
+ sde_enc != NULL, disp_info != NULL);
+ return;
+ } else if (sde_enc->num_phys_encs > ARRAY_SIZE(sde_enc->hw_pp)) {
+ SDE_ERROR("invalid num phys enc %d/%d\n",
+ sde_enc->num_phys_encs,
+ (int) ARRAY_SIZE(sde_enc->hw_pp));
+ return;
+ }
+
+ drm_enc = &sde_enc->base;
+ /* this pointers are checked in virt_enable_helper */
+ priv = drm_enc->dev->dev_private;
+
+ sde_kms = to_sde_kms(priv->kms);
+ if (!sde_kms) {
+ SDE_ERROR("invalid sde_kms\n");
+ return;
+ }
+
+ hw_mdptop = sde_kms->hw_mdp;
+ if (!hw_mdptop) {
+ SDE_ERROR("invalid mdptop\n");
+ return;
+ }
+
+ if (hw_mdptop->ops.setup_vsync_source &&
+ disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
+ for (i = 0; i < sde_enc->num_phys_encs; i++)
+ vsync_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx;
+
+ vsync_cfg.pp_count = sde_enc->num_phys_encs;
+ vsync_cfg.frame_rate = sde_enc->disp_info.frame_rate;
+ if (is_dummy)
+ vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_1;
+ else if (disp_info->is_te_using_watchdog_timer)
+ vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0;
+ else
+ vsync_cfg.vsync_source = SDE_VSYNC0_SOURCE_GPIO;
+ vsync_cfg.is_dummy = is_dummy;
+
+ hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg);
+ }
+}
+
static int sde_encoder_update_rsc_client(
struct drm_encoder *drm_enc,
struct sde_encoder_rsc_config *config, bool enable)
@@ -1143,7 +1219,8 @@ static int sde_encoder_update_rsc_client(
rsc_config.fps = disp_info->frame_rate;
rsc_config.vtotal = disp_info->vtotal;
rsc_config.prefill_lines = disp_info->prefill_lines;
- rsc_config.jitter = disp_info->jitter;
+ rsc_config.jitter_numer = disp_info->jitter_numer;
+ rsc_config.jitter_denom = disp_info->jitter_denom;
rsc_config.prefill_lines += config ?
config->inline_rotate_prefill : 0;
/* update it only once */
@@ -1216,6 +1293,9 @@ static void _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
rsc_cfg.inline_rotate_prefill =
sde_crtc_get_inline_prefill(drm_enc->crtc);
+ _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
+ false);
+
/* enable RSC */
sde_encoder_update_rsc_client(drm_enc, &rsc_cfg, true);
@@ -1224,6 +1304,14 @@ static void _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
/* disable RSC */
sde_encoder_update_rsc_client(drm_enc, NULL, false);
+ /**
+ * this call is for hardware workaround on sdm845 and should
+ * not be removed without considering the design changes for
+ * sde rsc + command mode concurrency. It may lead to pp
+ * timeout due to vsync from panel for command mode panel.
+ */
+ _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
+ true);
/* disable all the irq */
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys =
@@ -1248,12 +1336,22 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
{
bool schedule_off = false;
struct sde_encoder_virt *sde_enc;
+ struct msm_drm_private *priv;
+ struct msm_drm_thread *disp_thread;
- if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) {
+ if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private ||
+ !drm_enc->crtc) {
SDE_ERROR("invalid parameters\n");
return -EINVAL;
}
sde_enc = to_sde_encoder_virt(drm_enc);
+ priv = drm_enc->dev->dev_private;
+
+ if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) {
+ SDE_ERROR("invalid crtc index\n");
+ return -EINVAL;
+ }
+ disp_thread = &priv->disp_thread[drm_enc->crtc->index];
/*
* when idle_pc is not supported, process only KICKOFF and STOP
@@ -1272,7 +1370,8 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
switch (sw_event) {
case SDE_ENC_RC_EVENT_KICKOFF:
/* cancel delayed off work, if any */
- if (cancel_delayed_work_sync(&sde_enc->delayed_off_work))
+ if (kthread_cancel_delayed_work_sync(
+ &sde_enc->delayed_off_work))
SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work cancelled\n",
sw_event);
@@ -1319,8 +1418,10 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
}
/* schedule delayed off work */
- schedule_delayed_work(&sde_enc->delayed_off_work,
- msecs_to_jiffies(IDLE_TIMEOUT));
+ kthread_queue_delayed_work(
+ &disp_thread->worker,
+ &sde_enc->delayed_off_work,
+ msecs_to_jiffies(IDLE_TIMEOUT));
SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
SDE_EVTLOG_FUNC_CASE2);
SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work scheduled\n",
@@ -1329,7 +1430,8 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
case SDE_ENC_RC_EVENT_STOP:
/* cancel delayed off work, if any */
- if (cancel_delayed_work_sync(&sde_enc->delayed_off_work))
+ if (kthread_cancel_delayed_work_sync(
+ &sde_enc->delayed_off_work))
SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work cancelled\n",
sw_event);
@@ -1353,6 +1455,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
SDE_ENC_RC_STATE_OFF, SDE_EVTLOG_FUNC_CASE3);
+
sde_enc->rc_state = SDE_ENC_RC_STATE_OFF;
mutex_unlock(&sde_enc->rc_lock);
@@ -1360,7 +1463,8 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
case SDE_ENC_RC_EVENT_EARLY_WAKE_UP:
/* cancel delayed off work, if any */
- if (cancel_delayed_work_sync(&sde_enc->delayed_off_work)) {
+ if (kthread_cancel_delayed_work_sync(
+ &sde_enc->delayed_off_work)) {
SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work cancelled\n",
sw_event);
schedule_off = true;
@@ -1398,7 +1502,9 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
*/
if (schedule_off && !sde_crtc_frame_pending(drm_enc->crtc)) {
/* schedule delayed off work */
- schedule_delayed_work(&sde_enc->delayed_off_work,
+ kthread_queue_delayed_work(
+ &disp_thread->worker,
+ &sde_enc->delayed_off_work,
msecs_to_jiffies(IDLE_TIMEOUT));
SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work scheduled\n",
sw_event);
@@ -1413,6 +1519,22 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) {
SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc:%d !ON state\n",
sw_event, sde_enc->rc_state);
+ SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event,
+ sde_enc->rc_state);
+ mutex_unlock(&sde_enc->rc_lock);
+ return 0;
+ }
+
+ /*
+ * if we are in ON but a frame was just kicked off,
+ * ignore the IDLE event, it's probably a stale timer event
+ */
+ if (sde_enc->frame_busy_mask[0]) {
+ SDE_DEBUG_ENC(sde_enc,
+ "sw_event:%d, rc:%d frame pending\n",
+ sw_event, sde_enc->rc_state);
+ SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event,
+ sde_enc->rc_state);
mutex_unlock(&sde_enc->rc_lock);
return 0;
}
@@ -1436,11 +1558,10 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
return 0;
}
-static void sde_encoder_off_work(struct work_struct *work)
+static void sde_encoder_off_work(struct kthread_work *work)
{
- struct delayed_work *dw = to_delayed_work(work);
- struct sde_encoder_virt *sde_enc = container_of(dw,
- struct sde_encoder_virt, delayed_off_work);
+ struct sde_encoder_virt *sde_enc = container_of(work,
+ struct sde_encoder_virt, delayed_off_work.work);
if (!sde_enc) {
SDE_ERROR("invalid sde encoder\n");
@@ -1550,15 +1671,18 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
struct sde_encoder_virt *sde_enc = NULL;
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
- struct sde_hw_mdp *hw_mdptop;
- int i = 0;
- struct sde_watchdog_te_status te_cfg = { 0 };
if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) {
SDE_ERROR("invalid parameters\n");
return;
}
+
priv = drm_enc->dev->dev_private;
+ sde_kms = to_sde_kms(priv->kms);
+ if (!sde_kms) {
+ SDE_ERROR("invalid sde_kms\n");
+ return;
+ }
sde_enc = to_sde_encoder_virt(drm_enc);
if (!sde_enc || !sde_enc->cur_master) {
@@ -1566,35 +1690,13 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
return;
}
- sde_kms = to_sde_kms(priv->kms);
- hw_mdptop = sde_kms->hw_mdp;
-
- if (!hw_mdptop) {
- SDE_ERROR("invalid mdptop\n");
- return;
- }
-
- sde_kms = to_sde_kms(priv->kms);
- if (!sde_kms) {
- SDE_ERROR("invalid sde_kms\n");
- return;
- }
-
if (sde_enc->cur_master->hw_mdptop &&
sde_enc->cur_master->hw_mdptop->ops.reset_ubwc)
sde_enc->cur_master->hw_mdptop->ops.reset_ubwc(
sde_enc->cur_master->hw_mdptop,
sde_kms->catalog);
- if (hw_mdptop->ops.setup_vsync_sel) {
- for (i = 0; i < sde_enc->num_phys_encs; i++)
- te_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx;
-
- te_cfg.pp_count = sde_enc->num_phys_encs;
- te_cfg.frame_rate = sde_enc->disp_info.frame_rate;
- hw_mdptop->ops.setup_vsync_sel(hw_mdptop, &te_cfg,
- sde_enc->disp_info.is_te_using_watchdog_timer);
- }
+ _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, false);
memset(&sde_enc->prv_conn_roi, 0, sizeof(sde_enc->prv_conn_roi));
memset(&sde_enc->cur_conn_roi, 0, sizeof(sde_enc->cur_conn_roi));
@@ -1709,15 +1811,15 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
}
}
+ if (sde_enc->cur_master && sde_enc->cur_master->ops.disable)
+ sde_enc->cur_master->ops.disable(sde_enc->cur_master);
+
/* after phys waits for frame-done, should be no more frames pending */
if (atomic_xchg(&sde_enc->frame_done_timeout, 0)) {
SDE_ERROR("enc%d timeout pending\n", drm_enc->base.id);
del_timer_sync(&sde_enc->frame_done_timer);
}
- if (sde_enc->cur_master && sde_enc->cur_master->ops.disable)
- sde_enc->cur_master->ops.disable(sde_enc->cur_master);
-
sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_STOP);
if (sde_enc->cur_master) {
@@ -1847,27 +1949,41 @@ static void sde_encoder_frame_done_callback(
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
unsigned int i;
- if (!sde_enc->frame_busy_mask[0]) {
- /* suppress frame_done without waiter, likely autorefresh */
- SDE_EVT32(DRMID(drm_enc), event, ready_phys->intf_idx);
- return;
- }
+ if (event & (SDE_ENCODER_FRAME_EVENT_DONE
+ | SDE_ENCODER_FRAME_EVENT_ERROR
+ | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) {
- /* One of the physical encoders has become idle */
- for (i = 0; i < sde_enc->num_phys_encs; i++)
- if (sde_enc->phys_encs[i] == ready_phys) {
- clear_bit(i, sde_enc->frame_busy_mask);
- SDE_EVT32_VERBOSE(DRMID(drm_enc), i,
- sde_enc->frame_busy_mask[0]);
+ if (!sde_enc->frame_busy_mask[0]) {
+ /**
+ * suppress frame_done without waiter,
+ * likely autorefresh
+ */
+ SDE_EVT32(DRMID(drm_enc), event, ready_phys->intf_idx);
+ return;
}
- if (!sde_enc->frame_busy_mask[0]) {
- atomic_set(&sde_enc->frame_done_timeout, 0);
- del_timer(&sde_enc->frame_done_timer);
+ /* One of the physical encoders has become idle */
+ for (i = 0; i < sde_enc->num_phys_encs; i++) {
+ if (sde_enc->phys_encs[i] == ready_phys) {
+ clear_bit(i, sde_enc->frame_busy_mask);
+ SDE_EVT32_VERBOSE(DRMID(drm_enc), i,
+ sde_enc->frame_busy_mask[0]);
+ }
+ }
- sde_encoder_resource_control(drm_enc,
- SDE_ENC_RC_EVENT_FRAME_DONE);
+ if (!sde_enc->frame_busy_mask[0]) {
+ atomic_set(&sde_enc->frame_done_timeout, 0);
+ del_timer(&sde_enc->frame_done_timer);
+ sde_encoder_resource_control(drm_enc,
+ SDE_ENC_RC_EVENT_FRAME_DONE);
+
+ if (sde_enc->crtc_frame_event_cb)
+ sde_enc->crtc_frame_event_cb(
+ sde_enc->crtc_frame_event_cb_data,
+ event);
+ }
+ } else {
if (sde_enc->crtc_frame_event_cb)
sde_enc->crtc_frame_event_cb(
sde_enc->crtc_frame_event_cb_data, event);
@@ -1908,6 +2024,9 @@ static inline void _sde_encoder_trigger_flush(struct drm_encoder *drm_enc,
pending_kickoff_cnt = sde_encoder_phys_inc_pending(phys);
+ if (phys->ops.is_master && phys->ops.is_master(phys))
+ atomic_inc(&phys->pending_retire_fence_cnt);
+
if (extra_flush_bits && ctl->ops.update_pending_flush)
ctl->ops.update_pending_flush(ctl, extra_flush_bits);
@@ -2017,7 +2136,8 @@ void sde_encoder_helper_hw_reset(struct sde_encoder_phys *phys_enc)
if (rc) {
SDE_ERROR_ENC(sde_enc,
"connector soft reset failure\n");
- SDE_DBG_DUMP("panic");
+ SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus",
+ "panic");
}
}
}
@@ -2025,7 +2145,7 @@ void sde_encoder_helper_hw_reset(struct sde_encoder_phys *phys_enc)
rc = ctl->ops.reset(ctl);
if (rc) {
SDE_ERROR_ENC(sde_enc, "ctl %d reset failure\n", ctl->idx);
- SDE_DBG_DUMP("panic");
+ SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus", "panic");
}
phys_enc->enable_state = SDE_ENC_ENABLED;
@@ -2309,6 +2429,7 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
SDE_EVT32(DRMID(drm_enc));
/* prepare for next kickoff, may include waiting on previous kickoff */
+ SDE_ATRACE_BEGIN("enc_prepare_for_kickoff");
for (i = 0; i < sde_enc->num_phys_encs; i++) {
phys = sde_enc->phys_encs[i];
if (phys) {
@@ -2319,6 +2440,7 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
_sde_encoder_setup_dither(phys);
}
}
+ SDE_ATRACE_END("enc_prepare_for_kickoff");
sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_KICKOFF);
@@ -3009,7 +3131,8 @@ struct drm_encoder *sde_encoder_init(
}
mutex_init(&sde_enc->rc_lock);
- INIT_DELAYED_WORK(&sde_enc->delayed_off_work, sde_encoder_off_work);
+ kthread_init_delayed_work(&sde_enc->delayed_off_work,
+ sde_encoder_off_work);
memcpy(&sde_enc->disp_info, disp_info, sizeof(*disp_info));
@@ -3052,7 +3175,9 @@ int sde_encoder_wait_for_event(struct drm_encoder *drm_enc,
};
if (phys && fn_wait) {
+ SDE_ATRACE_BEGIN("wait_for_completion_event");
ret = fn_wait(phys);
+ SDE_ATRACE_END("wait_for_completion_event");
if (ret)
return ret;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index 9c2d3e9..3dae994 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -24,9 +24,11 @@
#include "msm_prop.h"
#include "sde_hw_mdss.h"
-#define SDE_ENCODER_FRAME_EVENT_DONE BIT(0)
-#define SDE_ENCODER_FRAME_EVENT_ERROR BIT(1)
-#define SDE_ENCODER_FRAME_EVENT_PANEL_DEAD BIT(2)
+#define SDE_ENCODER_FRAME_EVENT_DONE BIT(0)
+#define SDE_ENCODER_FRAME_EVENT_ERROR BIT(1)
+#define SDE_ENCODER_FRAME_EVENT_PANEL_DEAD BIT(2)
+#define SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE BIT(3)
+#define SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE BIT(4)
/**
* Encoder functions and data types
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 4b12651..c1a40f5 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -235,6 +235,8 @@ struct sde_encoder_irq {
* scheduled. Decremented in irq handler
* @pending_ctlstart_cnt: Atomic counter tracking the number of ctl start
* pending.
+ * @pending_retire_fence_cnt: Atomic counter tracking the pending retire
+ * fences that have to be signalled.
* @pending_kickoff_wq: Wait queue for blocking until kickoff completes
* @irq: IRQ tracking structures
*/
@@ -261,6 +263,7 @@ struct sde_encoder_phys {
atomic_t underrun_cnt;
atomic_t pending_ctlstart_cnt;
atomic_t pending_kickoff_cnt;
+ atomic_t pending_retire_fence_cnt;
wait_queue_head_t pending_kickoff_wq;
struct sde_encoder_irq irq[INTR_IDX_MAX];
};
@@ -307,6 +310,8 @@ struct sde_encoder_phys_cmd_autorefresh {
* @serialize_wait4pp: serialize wait4pp feature waits for pp_done interrupt
* after ctl_start instead of before next frame kickoff
* @pp_timeout_report_cnt: number of pingpong done irq timeout errors
+ * @pending_rd_ptr_cnt: atomic counter to indicate if retire fence can be
+ * signaled at the next rd_ptr_irq
* @autorefresh: autorefresh feature state
*/
struct sde_encoder_phys_cmd {
@@ -315,6 +320,7 @@ struct sde_encoder_phys_cmd {
bool serialize_wait4pp;
int pp_timeout_report_cnt;
struct sde_encoder_phys_cmd_autorefresh autorefresh;
+ atomic_t pending_rd_ptr_cnt;
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 6ee1aae..2a46636 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -17,6 +17,7 @@
#include "sde_hw_interrupts.h"
#include "sde_core_irq.h"
#include "sde_formats.h"
+#include "sde_trace.h"
#define SDE_DEBUG_CMDENC(e, fmt, ...) SDE_DEBUG("enc%d intf%d " fmt, \
(e) && (e)->base.parent ? \
@@ -160,24 +161,28 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
struct sde_encoder_phys *phys_enc = arg;
unsigned long lock_flags;
int new_cnt;
+ u32 event = SDE_ENCODER_FRAME_EVENT_DONE |
+ SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
- if (!phys_enc)
+ if (!phys_enc || !phys_enc->hw_pp)
return;
+ SDE_ATRACE_BEGIN("pp_done_irq");
/* notify all synchronous clients first, then asynchronous clients */
if (phys_enc->parent_ops.handle_frame_done)
phys_enc->parent_ops.handle_frame_done(phys_enc->parent,
- phys_enc, SDE_ENCODER_FRAME_EVENT_DONE);
+ phys_enc, event);
spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
SDE_EVT32_IRQ(DRMID(phys_enc->parent),
- phys_enc->hw_pp->idx - PINGPONG_0, new_cnt);
+ phys_enc->hw_pp->idx - PINGPONG_0, new_cnt, event);
/* Signal any waiting atomic commit thread */
wake_up_all(&phys_enc->pending_kickoff_wq);
+ SDE_ATRACE_END("pp_done_irq");
}
static void sde_encoder_phys_cmd_autorefresh_done_irq(void *arg, int irq_idx)
@@ -206,35 +211,88 @@ static void sde_encoder_phys_cmd_autorefresh_done_irq(void *arg, int irq_idx)
static void sde_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx)
{
struct sde_encoder_phys *phys_enc = arg;
+ struct sde_encoder_phys_cmd *cmd_enc;
+ bool signal_fence = false;
- if (!phys_enc)
+ if (!phys_enc || !phys_enc->hw_pp)
return;
+ SDE_ATRACE_BEGIN("rd_ptr_irq");
+ cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
+
+ /**
+ * signal only for master,
+ * - when the ctl_start irq is done and incremented
+ * the pending_rd_ptr_cnt.
+ * - when ctl_start irq status bit is set. This handles the case
+ * where ctl_start status bit is set in hardware, but the interrupt
+ * is delayed due to some reason.
+ */
+ if (sde_encoder_phys_cmd_is_master(phys_enc) &&
+ atomic_read(&phys_enc->pending_retire_fence_cnt)) {
+
+ if (atomic_add_unless(
+ &cmd_enc->pending_rd_ptr_cnt, -1, 0)) {
+ signal_fence = true;
+ } else {
+ signal_fence =
+ sde_core_irq_read_nolock(phys_enc->sde_kms,
+ phys_enc->irq[INTR_IDX_CTL_START].irq_idx,
+ false);
+ if (signal_fence)
+ SDE_EVT32_IRQ(DRMID(phys_enc->parent),
+ phys_enc->hw_pp->idx - PINGPONG_0,
+ atomic_read(
+ &phys_enc->pending_retire_fence_cnt),
+ SDE_EVTLOG_FUNC_CASE1);
+ }
+
+ if (signal_fence && phys_enc->parent_ops.handle_frame_done) {
+ atomic_add_unless(
+ &phys_enc->pending_retire_fence_cnt, -1, 0);
+ phys_enc->parent_ops.handle_frame_done(
+ phys_enc->parent, phys_enc,
+ SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
+ }
+ }
+
SDE_EVT32_IRQ(DRMID(phys_enc->parent),
- phys_enc->hw_pp->idx - PINGPONG_0, 0xfff);
+ phys_enc->hw_pp->idx - PINGPONG_0, signal_fence, 0xfff);
if (phys_enc->parent_ops.handle_vblank_virt)
phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
phys_enc);
+
+ SDE_ATRACE_END("rd_ptr_irq");
}
static void sde_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx)
{
struct sde_encoder_phys *phys_enc = arg;
+ struct sde_encoder_phys_cmd *cmd_enc;
struct sde_hw_ctl *ctl;
- if (!phys_enc)
+ if (!phys_enc || !phys_enc->hw_ctl)
return;
- if (!phys_enc->hw_ctl)
- return;
+ SDE_ATRACE_BEGIN("ctl_start_irq");
+ cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
ctl = phys_enc->hw_ctl;
SDE_EVT32_IRQ(DRMID(phys_enc->parent), ctl->idx - CTL_0, 0xfff);
atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0);
+ /*
+ * this is required for the fence signalling to be done in rd_ptr_irq
+ * after ctrl_start_irq
+ */
+ if (sde_encoder_phys_cmd_is_master(phys_enc)
+ && atomic_read(&phys_enc->pending_retire_fence_cnt))
+ atomic_inc(&cmd_enc->pending_rd_ptr_cnt);
+
/* Signal any waiting ctl start interrupt */
wake_up_all(&phys_enc->pending_kickoff_wq);
+ SDE_ATRACE_END("ctl_start_irq");
}
static void sde_encoder_phys_cmd_underrun_irq(void *arg, int irq_idx)
@@ -332,7 +390,8 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
{
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
- u32 frame_event = SDE_ENCODER_FRAME_EVENT_ERROR;
+ u32 frame_event = SDE_ENCODER_FRAME_EVENT_ERROR
+ | SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
bool do_log = false;
cmd_enc->pp_timeout_report_cnt++;
@@ -345,7 +404,8 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
cmd_enc->pp_timeout_report_cnt,
- atomic_read(&phys_enc->pending_kickoff_cnt));
+ atomic_read(&phys_enc->pending_kickoff_cnt),
+ frame_event);
/* to avoid flooding, only log first time, and "dead" time */
if (do_log) {
@@ -359,9 +419,7 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
SDE_EVT32(DRMID(phys_enc->parent), SDE_EVTLOG_FATAL);
sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_RDPTR);
- SDE_DBG_DUMP("sde", "dsi0_ctrl", "dsi0_phy", "dsi1_ctrl",
- "dsi1_phy", "vbif", "dbg_bus",
- "vbif_dbg_bus", "panic");
+ SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus", "panic");
}
atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
@@ -418,9 +476,7 @@ static int _sde_encoder_phys_cmd_poll_write_pointer_started(
phys_enc->hw_pp->idx - PINGPONG_0,
timeout_us,
ret);
- SDE_DBG_DUMP("sde", "dsi0_ctrl", "dsi0_phy", "dsi1_ctrl",
- "dsi1_phy", "vbif_rt", "dbg_bus",
- "vbif_dbg_bus", "panic");
+ SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus", "panic");
}
return ret;
@@ -527,7 +583,6 @@ static int sde_encoder_phys_cmd_control_vblank_irq(
{
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
- unsigned long lock_flags;
int ret = 0;
if (!phys_enc) {
@@ -543,8 +598,6 @@ static int sde_encoder_phys_cmd_control_vblank_irq(
__builtin_return_address(0),
enable, atomic_read(&phys_enc->vblank_refcount));
- spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
-
SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
enable, atomic_read(&phys_enc->vblank_refcount));
@@ -554,8 +607,6 @@ static int sde_encoder_phys_cmd_control_vblank_irq(
ret = sde_encoder_helper_unregister_irq(phys_enc,
INTR_IDX_RDPTR);
- spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
-
end:
if (ret)
SDE_ERROR_CMDENC(cmd_enc,
@@ -575,6 +626,9 @@ void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc,
cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
+ SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
+ enable, atomic_read(&phys_enc->vblank_refcount));
+
if (enable) {
sde_encoder_helper_register_irq(phys_enc, INTR_IDX_PINGPONG);
sde_encoder_helper_register_irq(phys_enc, INTR_IDX_UNDERRUN);
@@ -607,7 +661,7 @@ static void sde_encoder_phys_cmd_tearcheck_config(
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
struct sde_hw_tear_check tc_cfg = { 0 };
- struct drm_display_mode *mode = &phys_enc->cached_mode;
+ struct drm_display_mode *mode;
bool tc_enable = true;
u32 vsync_hz;
struct msm_drm_private *priv;
@@ -617,6 +671,7 @@ static void sde_encoder_phys_cmd_tearcheck_config(
SDE_ERROR("invalid encoder\n");
return;
}
+ mode = &phys_enc->cached_mode;
SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0);
@@ -627,7 +682,12 @@ static void sde_encoder_phys_cmd_tearcheck_config(
}
sde_kms = phys_enc->sde_kms;
+ if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) {
+ SDE_ERROR("invalid device\n");
+ return;
+ }
priv = sde_kms->dev->dev_private;
+
/*
* TE default: dsi byte clock calculated base on 70 fps;
* around 14 ms to complete a kickoff cycle if te disabled;
@@ -638,8 +698,10 @@ static void sde_encoder_phys_cmd_tearcheck_config(
* frequency divided by the no. of rows (lines) in the LCDpanel.
*/
vsync_hz = sde_power_clk_get_rate(&priv->phandle, "vsync_clk");
- if (!vsync_hz) {
- SDE_DEBUG_CMDENC(cmd_enc, "invalid vsync clock rate\n");
+ if (!vsync_hz || !mode->vtotal || !mode->vrefresh) {
+ SDE_DEBUG_CMDENC(cmd_enc,
+ "invalid params - vsync_hz %u vtot %u vrefresh %u\n",
+ vsync_hz, mode->vtotal, mode->vrefresh);
return;
}
@@ -687,8 +749,8 @@ static void _sde_encoder_phys_cmd_pingpong_config(
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
- if (!phys_enc || !phys_enc->hw_ctl ||
- !phys_enc->hw_ctl->ops.setup_intf_cfg) {
+ if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->hw_pp
+ || !phys_enc->hw_ctl->ops.setup_intf_cfg) {
SDE_ERROR("invalid arg(s), enc %d\n", phys_enc != 0);
return;
}
@@ -717,7 +779,7 @@ static void sde_encoder_phys_cmd_enable_helper(
struct sde_hw_ctl *ctl;
u32 flush_mask = 0;
- if (!phys_enc || !phys_enc->hw_ctl) {
+ if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->hw_pp) {
SDE_ERROR("invalid arg(s), encoder %d\n", phys_enc != 0);
return;
}
@@ -747,10 +809,11 @@ static void sde_encoder_phys_cmd_enable(struct sde_encoder_phys *phys_enc)
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
- if (!phys_enc) {
+ if (!phys_enc || !phys_enc->hw_pp) {
SDE_ERROR("invalid phys encoder\n");
return;
}
+
SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0);
if (phys_enc->enable_state == SDE_ENC_ENABLED) {
@@ -803,7 +866,7 @@ static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc)
to_sde_encoder_phys_cmd(phys_enc);
int ret;
- if (!phys_enc) {
+ if (!phys_enc || !phys_enc->hw_pp) {
SDE_ERROR("invalid encoder\n");
return;
}
@@ -857,6 +920,12 @@ static void sde_encoder_phys_cmd_get_hw_resources(
SDE_ERROR("invalid encoder\n");
return;
}
+
+ if ((phys_enc->intf_idx - INTF_0) >= INTF_MAX) {
+ SDE_ERROR("invalid intf idx:%d\n", phys_enc->intf_idx);
+ return;
+ }
+
SDE_DEBUG_CMDENC(cmd_enc, "\n");
hw_res->intfs[phys_enc->intf_idx - INTF_0] = INTF_MODE_CMD;
}
@@ -869,7 +938,7 @@ static void sde_encoder_phys_cmd_prepare_for_kickoff(
to_sde_encoder_phys_cmd(phys_enc);
int ret;
- if (!phys_enc) {
+ if (!phys_enc || !phys_enc->hw_pp) {
SDE_ERROR("invalid encoder\n");
return;
}
@@ -1219,6 +1288,8 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init(
atomic_set(&phys_enc->vblank_refcount, 0);
atomic_set(&phys_enc->pending_kickoff_cnt, 0);
atomic_set(&phys_enc->pending_ctlstart_cnt, 0);
+ atomic_set(&phys_enc->pending_retire_fence_cnt, 0);
+ atomic_set(&cmd_enc->pending_rd_ptr_cnt, 0);
init_waitqueue_head(&phys_enc->pending_kickoff_wq);
atomic_set(&cmd_enc->autorefresh.kickoff_cnt, 0);
init_waitqueue_head(&cmd_enc->autorefresh.kickoff_wq);
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 afd61ae..933e4812 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -16,6 +16,7 @@
#include "sde_core_irq.h"
#include "sde_formats.h"
#include "dsi_display.h"
+#include "sde_trace.h"
#define SDE_DEBUG_VIDENC(e, fmt, ...) SDE_DEBUG("enc%d intf%d " fmt, \
(e) && (e)->base.parent ? \
@@ -49,6 +50,23 @@ static void drm_mode_to_intf_timing_params(
struct intf_timing_params *timing)
{
memset(timing, 0, sizeof(*timing));
+
+ if ((mode->htotal < mode->hsync_end)
+ || (mode->hsync_start < mode->hdisplay)
+ || (mode->vtotal < mode->vsync_end)
+ || (mode->vsync_start < mode->vdisplay)
+ || (mode->hsync_end < mode->hsync_start)
+ || (mode->vsync_end < mode->vsync_start)) {
+ SDE_ERROR(
+ "invalid params - hstart:%d,hend:%d,htot:%d,hdisplay:%d\n",
+ mode->hsync_start, mode->hsync_end,
+ mode->htotal, mode->hdisplay);
+ SDE_ERROR("vstart:%d,vend:%d,vtot:%d,vdisplay:%d\n",
+ mode->vsync_start, mode->vsync_end,
+ mode->vtotal, mode->vdisplay);
+ return;
+ }
+
/*
* https://www.kernel.org/doc/htmldocs/drm/ch02s05.html
* Active Region Front Porch Sync Back Porch
@@ -139,6 +157,15 @@ static u32 programmable_fetch_get_num_lines(
u32 needed_vfp_lines = worst_case_needed_lines - start_of_frame_lines;
u32 actual_vfp_lines = 0;
+ if (worst_case_needed_lines < start_of_frame_lines) {
+ needed_vfp_lines = 0;
+ SDE_ERROR("invalid params - needed_lines:%d, frame_lines:%d\n",
+ worst_case_needed_lines, start_of_frame_lines);
+ } else {
+ needed_vfp_lines = worst_case_needed_lines
+ - start_of_frame_lines;
+ }
+
/* Fetch must be outside active lines, otherwise undefined. */
if (start_of_frame_lines >= worst_case_needed_lines) {
SDE_DEBUG_VIDENC(vid_enc,
@@ -352,11 +379,25 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
unsigned long lock_flags;
u32 flush_register = 0;
int new_cnt = -1, old_cnt = -1;
+ u32 event = 0;
if (!phys_enc)
return;
hw_ctl = phys_enc->hw_ctl;
+ SDE_ATRACE_BEGIN("vblank_irq");
+
+ /* signal only for master, where there is a pending kickoff */
+ if (sde_encoder_phys_vid_is_master(phys_enc)
+ && atomic_add_unless(
+ &phys_enc->pending_retire_fence_cnt, -1, 0)) {
+ event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE
+ | SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
+
+ if (phys_enc->parent_ops.handle_frame_done)
+ phys_enc->parent_ops.handle_frame_done(phys_enc->parent,
+ phys_enc, event);
+ }
if (phys_enc->parent_ops.handle_vblank_virt)
phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
@@ -379,10 +420,11 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
SDE_EVT32_IRQ(DRMID(phys_enc->parent), vid_enc->hw_intf->idx - INTF_0,
- old_cnt, new_cnt, flush_register);
+ old_cnt, new_cnt, flush_register, event);
/* Signal any waiting atomic commit thread */
wake_up_all(&phys_enc->pending_kickoff_wq);
+ SDE_ATRACE_END("vblank_irq");
}
static void sde_encoder_phys_vid_underrun_irq(void *arg, int irq_idx)
@@ -442,15 +484,18 @@ static void sde_encoder_phys_vid_mode_set(
struct sde_encoder_phys_vid *vid_enc;
if (!phys_enc || !phys_enc->sde_kms) {
- SDE_ERROR("invalid encoder\n");
+ SDE_ERROR("invalid encoder/kms\n");
return;
}
rm = &phys_enc->sde_kms->rm;
vid_enc = to_sde_encoder_phys_vid(phys_enc);
- phys_enc->cached_mode = *adj_mode;
- SDE_DEBUG_VIDENC(vid_enc, "caching mode:\n");
- drm_mode_debug_printmodeline(adj_mode);
+
+ if (adj_mode) {
+ phys_enc->cached_mode = *adj_mode;
+ drm_mode_debug_printmodeline(adj_mode);
+ SDE_DEBUG_VIDENC(vid_enc, "caching mode:\n");
+ }
instance = phys_enc->split_role == ENC_ROLE_SLAVE ? 1 : 0;
@@ -476,7 +521,6 @@ static int sde_encoder_phys_vid_control_vblank_irq(
{
int ret = 0;
struct sde_encoder_phys_vid *vid_enc;
- unsigned long lock_flags;
if (!phys_enc) {
SDE_ERROR("invalid encoder\n");
@@ -493,8 +537,6 @@ static int sde_encoder_phys_vid_control_vblank_irq(
__builtin_return_address(0),
enable, atomic_read(&phys_enc->vblank_refcount));
- spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
-
SDE_EVT32(DRMID(phys_enc->parent), enable,
atomic_read(&phys_enc->vblank_refcount));
@@ -504,8 +546,6 @@ static int sde_encoder_phys_vid_control_vblank_irq(
ret = sde_encoder_helper_unregister_irq(phys_enc,
INTR_IDX_VSYNC);
- spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
-
if (ret)
SDE_ERROR_VIDENC(vid_enc,
"control vblank irq error %d, enable %d\n",
@@ -620,13 +660,18 @@ static void sde_encoder_phys_vid_get_hw_resources(
static int sde_encoder_phys_vid_wait_for_vblank(
struct sde_encoder_phys *phys_enc, bool notify)
{
- struct sde_encoder_wait_info wait_info = {
- .wq = &phys_enc->pending_kickoff_wq,
- .atomic_cnt = &phys_enc->pending_kickoff_cnt,
- .timeout_ms = KICKOFF_TIMEOUT_MS,
- };
+ struct sde_encoder_wait_info wait_info;
int ret;
+ if (!phys_enc) {
+ pr_err("invalid encoder\n");
+ return -EINVAL;
+ }
+
+ wait_info.wq = &phys_enc->pending_kickoff_wq;
+ wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt;
+ wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
+
if (!sde_encoder_phys_vid_is_master(phys_enc)) {
/* signal done for slave video encoder, unless it is pp-split */
if (!_sde_encoder_phys_is_ppsplit(phys_enc) &&
@@ -654,11 +699,7 @@ static int sde_encoder_phys_vid_wait_for_vblank(
static int sde_encoder_phys_vid_wait_for_commit_done(
struct sde_encoder_phys *phys_enc)
{
- int ret;
-
- ret = sde_encoder_phys_vid_wait_for_vblank(phys_enc, true);
-
- return ret;
+ return sde_encoder_phys_vid_wait_for_vblank(phys_enc, true);
}
static void sde_encoder_phys_vid_prepare_for_kickoff(
@@ -688,7 +729,7 @@ static void sde_encoder_phys_vid_prepare_for_kickoff(
SDE_ERROR_VIDENC(vid_enc, "ctl %d reset failure: %d\n",
ctl->idx, rc);
sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_VSYNC);
- SDE_DBG_DUMP("panic");
+ SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus", "panic");
}
programmable_rot_fetch_config(phys_enc, params->inline_rotate_prefill);
@@ -918,6 +959,7 @@ struct sde_encoder_phys *sde_encoder_phys_vid_init(
atomic_set(&phys_enc->vblank_refcount, 0);
atomic_set(&phys_enc->pending_kickoff_cnt, 0);
+ atomic_set(&phys_enc->pending_retire_fence_cnt, 0);
init_waitqueue_head(&phys_enc->pending_kickoff_wq);
phys_enc->enable_state = SDE_ENC_DISABLED;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index 875d99d..c95fb47 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -644,6 +644,7 @@ static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx)
struct sde_encoder_phys_wb *wb_enc = arg;
struct sde_encoder_phys *phys_enc = &wb_enc->base;
struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
+ u32 event = 0;
SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0,
wb_enc->frame_count);
@@ -652,12 +653,20 @@ static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx)
if (phys_enc->enable_state == SDE_ENC_DISABLING)
goto complete;
+ event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE
+ | SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE
+ | SDE_ENCODER_FRAME_EVENT_DONE;
+
+ atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0);
if (phys_enc->parent_ops.handle_frame_done)
phys_enc->parent_ops.handle_frame_done(phys_enc->parent,
- phys_enc, SDE_ENCODER_FRAME_EVENT_DONE);
+ phys_enc, event);
- phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
- phys_enc);
+ if (phys_enc->parent_ops.handle_vblank_virt)
+ phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
+ phys_enc);
+
+ SDE_EVT32_IRQ(DRMID(phys_enc->parent), hw_wb->idx - WB_0, event);
complete:
complete_all(&wb_enc->wbdone_complete);
@@ -783,7 +792,7 @@ static int sde_encoder_phys_wb_wait_for_commit_done(
{
unsigned long ret;
struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
- u32 irq_status;
+ u32 irq_status, event = 0;
u64 wb_time = 0;
int rc = 0;
u32 timeout = max_t(u32, wb_enc->wbdone_timeout, KICKOFF_TIMEOUT_MS);
@@ -802,7 +811,6 @@ static int sde_encoder_phys_wb_wait_for_commit_done(
if (!ret) {
SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc),
wb_enc->frame_count);
-
irq_status = sde_core_irq_read(phys_enc->sde_kms,
wb_enc->irq_idx, true);
if (irq_status) {
@@ -812,10 +820,15 @@ static int sde_encoder_phys_wb_wait_for_commit_done(
} else {
SDE_ERROR("wb:%d kickoff timed out\n",
wb_enc->wb_dev->wb_idx - WB_0);
+ atomic_add_unless(
+ &phys_enc->pending_retire_fence_cnt, -1, 0);
+
+ event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE
+ | SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE
+ | SDE_ENCODER_FRAME_EVENT_ERROR;
if (phys_enc->parent_ops.handle_frame_done)
phys_enc->parent_ops.handle_frame_done(
- phys_enc->parent, phys_enc,
- SDE_ENCODER_FRAME_EVENT_ERROR);
+ phys_enc->parent, phys_enc, event);
rc = -ETIMEDOUT;
}
}
@@ -844,7 +857,7 @@ static int sde_encoder_phys_wb_wait_for_commit_done(
}
SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->frame_count,
- wb_time);
+ wb_time, event, rc);
return rc;
}
@@ -1296,6 +1309,7 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init(
phys_enc->intf_mode = INTF_MODE_WB_LINE;
phys_enc->intf_idx = p->intf_idx;
phys_enc->enc_spinlock = p->enc_spinlock;
+ atomic_set(&phys_enc->pending_retire_fence_cnt, 0);
INIT_LIST_HEAD(&wb_enc->irq_cb.list);
/* create internal buffer for disable logic */
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.c b/drivers/gpu/drm/msm/sde/sde_fence.c
index bd9fdac..b654e5a 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.c
+++ b/drivers/gpu/drm/msm/sde/sde_fence.c
@@ -338,7 +338,7 @@ int sde_fence_create(struct sde_fence_context *ctx, uint64_t *val,
return rc;
}
-void sde_fence_signal(struct sde_fence_context *ctx, bool is_error)
+void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts, bool is_error)
{
unsigned long flags;
struct sde_fence *fc, *next;
@@ -358,16 +358,19 @@ void sde_fence_signal(struct sde_fence_context *ctx, bool is_error)
if ((int)(ctx->done_count - ctx->commit_count) < 0) {
++ctx->done_count;
SDE_DEBUG("fence_signal:done count:%d commit count:%d\n",
- ctx->commit_count, ctx->done_count);
+ ctx->done_count, ctx->commit_count);
} else {
SDE_ERROR("extra signal attempt! done count:%d commit:%d\n",
ctx->done_count, ctx->commit_count);
+ SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count,
+ ktime_to_us(ts), SDE_EVTLOG_FATAL);
spin_unlock_irqrestore(&ctx->lock, flags);
return;
}
spin_unlock_irqrestore(&ctx->lock, flags);
- SDE_EVT32(ctx->drm_id, ctx->done_count);
+ SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count,
+ ktime_to_us(ts));
spin_lock(&ctx->list_lock);
if (list_empty(&ctx->fence_list_head)) {
@@ -382,6 +385,7 @@ void sde_fence_signal(struct sde_fence_context *ctx, bool is_error)
list_for_each_entry_safe(fc, next, &local_list_head, fence_list) {
spin_lock_irqsave(&ctx->lock, flags);
+ fc->base.timestamp = ts;
is_signaled = fence_is_signaled_locked(&fc->base);
spin_unlock_irqrestore(&ctx->lock, flags);
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.h b/drivers/gpu/drm/msm/sde/sde_fence.h
index 207f29c..51afdae 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.h
+++ b/drivers/gpu/drm/msm/sde/sde_fence.h
@@ -127,9 +127,11 @@ int sde_fence_create(struct sde_fence_context *fence, uint64_t *val,
/**
* sde_fence_signal - advance fence timeline to signal outstanding fences
* @fence: Pointer fence container
+ * @ts: fence timestamp
* @is_error: Set to non-zero if the commit didn't complete successfully
*/
-void sde_fence_signal(struct sde_fence_context *fence, bool is_error);
+void sde_fence_signal(struct sde_fence_context *fence, ktime_t ts,
+ bool is_error);
#else
static inline void *sde_sync_get(uint64_t fd)
{
@@ -168,7 +170,7 @@ static inline int sde_fence_get(struct sde_fence_context *fence, uint64_t *val)
}
static inline void sde_fence_signal(struct sde_fence_context *fence,
- bool is_error)
+ ktime_t ts, bool is_error)
{
/* do nothing */
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
index 35fc2b5..5307464 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
@@ -19,6 +19,7 @@
#define IDLE_2_RUN(x) ((x) == (ad4_init | ad4_cfg | ad4_mode | ad4_input))
#define MERGE_WIDTH_RIGHT 6
#define MERGE_WIDTH_LEFT 5
+#define AD_IPC_FRAME_COUNT 2
enum ad4_ops_bitmask {
ad4_init = BIT(AD_INIT),
@@ -31,34 +32,66 @@ enum ad4_ops_bitmask {
enum ad4_state {
ad4_state_idle,
ad4_state_run,
+ /* idle power collapse resume state */
+ ad4_state_ipcr,
ad4_state_max,
};
typedef int (*ad4_prop_setup)(struct sde_hw_dspp *dspp,
struct sde_ad_hw_cfg *ad);
+static int ad4_params_check(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+
+static int ad4_no_op_setup(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+static int ad4_mode_setup(struct sde_hw_dspp *dspp, enum ad4_modes mode);
static int ad4_mode_setup_common(struct sde_hw_dspp *dspp,
struct sde_ad_hw_cfg *cfg);
+static int ad4_init_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg);
static int ad4_init_setup_idle(struct sde_hw_dspp *dspp,
struct sde_ad_hw_cfg *cfg);
+static int ad4_init_setup_run(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+static int ad4_init_setup_ipcr(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+static int ad4_cfg_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg);
static int ad4_cfg_setup_idle(struct sde_hw_dspp *dspp,
struct sde_ad_hw_cfg *cfg);
+static int ad4_cfg_setup_run(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+static int ad4_cfg_setup_ipcr(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+static int ad4_input_setup(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
static int ad4_input_setup_idle(struct sde_hw_dspp *dspp,
struct sde_ad_hw_cfg *cfg);
-static int ad4_mode_setup(struct sde_hw_dspp *dspp, enum ad4_modes mode);
-static int ad4_init_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg);
-static int ad4_cfg_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg);
-static int ad4_input_setup(struct sde_hw_dspp *dspp,
+static int ad4_input_setup_ipcr(struct sde_hw_dspp *dspp,
struct sde_ad_hw_cfg *cfg);
static int ad4_suspend_setup(struct sde_hw_dspp *dspp,
struct sde_ad_hw_cfg *cfg);
-static int ad4_params_check(struct sde_hw_dspp *dspp,
- struct sde_ad_hw_cfg *cfg);
static int ad4_assertive_setup(struct sde_hw_dspp *dspp,
struct sde_ad_hw_cfg *cfg);
static int ad4_backlight_setup(struct sde_hw_dspp *dspp,
struct sde_ad_hw_cfg *cfg);
+static int ad4_ipc_suspend_setup_run(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+static int ad4_ipc_resume_setup_run(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+static int ad4_ipc_resume_setup_ipcr(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+static int ad4_ipc_reset_setup_ipcr(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+static int ad4_mem_init_enable(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+static int ad4_mem_init_disable(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+static int ad4_cfg_ipc_resume(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+static int ad4_cfg_ipc_reset(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+
static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = {
[ad4_state_idle][AD_MODE] = ad4_mode_setup_common,
[ad4_state_idle][AD_INIT] = ad4_init_setup_idle,
@@ -67,13 +100,29 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = {
[ad4_state_idle][AD_SUSPEND] = ad4_suspend_setup,
[ad4_state_idle][AD_ASSERTIVE] = ad4_assertive_setup,
[ad4_state_idle][AD_BACKLIGHT] = ad4_backlight_setup,
+ [ad4_state_idle][AD_IPC_SUSPEND] = ad4_no_op_setup,
+ [ad4_state_idle][AD_IPC_RESUME] = ad4_no_op_setup,
+ [ad4_state_idle][AD_IPC_RESET] = ad4_no_op_setup,
[ad4_state_run][AD_MODE] = ad4_mode_setup_common,
- [ad4_state_run][AD_INIT] = ad4_init_setup,
- [ad4_state_run][AD_CFG] = ad4_cfg_setup,
+ [ad4_state_run][AD_INIT] = ad4_init_setup_run,
+ [ad4_state_run][AD_CFG] = ad4_cfg_setup_run,
[ad4_state_run][AD_INPUT] = ad4_input_setup,
[ad4_state_run][AD_SUSPEND] = ad4_suspend_setup,
[ad4_state_run][AD_ASSERTIVE] = ad4_assertive_setup,
[ad4_state_run][AD_BACKLIGHT] = ad4_backlight_setup,
+ [ad4_state_run][AD_IPC_SUSPEND] = ad4_ipc_suspend_setup_run,
+ [ad4_state_run][AD_IPC_RESUME] = ad4_ipc_resume_setup_run,
+ [ad4_state_run][AD_IPC_RESET] = ad4_no_op_setup,
+ [ad4_state_ipcr][AD_MODE] = ad4_mode_setup_common,
+ [ad4_state_ipcr][AD_INIT] = ad4_init_setup_ipcr,
+ [ad4_state_ipcr][AD_CFG] = ad4_cfg_setup_ipcr,
+ [ad4_state_ipcr][AD_INPUT] = ad4_input_setup_ipcr,
+ [ad4_state_ipcr][AD_SUSPEND] = ad4_suspend_setup,
+ [ad4_state_ipcr][AD_ASSERTIVE] = ad4_assertive_setup,
+ [ad4_state_ipcr][AD_BACKLIGHT] = ad4_backlight_setup,
+ [ad4_state_ipcr][AD_IPC_SUSPEND] = ad4_no_op_setup,
+ [ad4_state_ipcr][AD_IPC_RESUME] = ad4_ipc_resume_setup_ipcr,
+ [ad4_state_ipcr][AD_IPC_RESET] = ad4_ipc_reset_setup_ipcr,
};
struct ad4_info {
@@ -81,14 +130,19 @@ struct ad4_info {
u32 completed_ops_mask;
bool ad4_support;
enum ad4_modes cached_mode;
+ bool is_master;
+ u32 frame_count;
+ u32 tf_ctrl;
+ u32 vc_control_0;
+ u32 last_str;
u32 cached_als;
};
static struct ad4_info info[DSPP_MAX] = {
- [DSPP_0] = {ad4_state_idle, 0, true, AD4_OFF},
- [DSPP_1] = {ad4_state_idle, 0, true, AD4_OFF},
- [DSPP_2] = {ad4_state_max, 0, false, AD4_OFF},
- [DSPP_3] = {ad4_state_max, 0, false, AD4_OFF},
+ [DSPP_0] = {ad4_state_idle, 0, true, AD4_OFF, false},
+ [DSPP_1] = {ad4_state_idle, 0, true, AD4_OFF, false},
+ [DSPP_2] = {ad4_state_max, 0, false, AD4_OFF, false},
+ [DSPP_3] = {ad4_state_max, 0, false, AD4_OFF, false},
};
void sde_setup_dspp_ad4(struct sde_hw_dspp *dspp, void *ad_cfg)
@@ -118,7 +172,7 @@ int sde_validate_dspp_ad4(struct sde_hw_dspp *dspp, u32 *prop)
return -EINVAL;
}
- if (dspp->idx > DSPP_MAX || !info[dspp->idx].ad4_support) {
+ if (dspp->idx >= DSPP_MAX || !info[dspp->idx].ad4_support) {
DRM_ERROR("ad4 not supported for dspp idx %d\n", dspp->idx);
return -EINVAL;
}
@@ -142,7 +196,7 @@ static int ad4_params_check(struct sde_hw_dspp *dspp,
return -EINVAL;
}
- if (dspp->idx > DSPP_MAX || !info[dspp->idx].ad4_support) {
+ if (dspp->idx >= DSPP_MAX || !info[dspp->idx].ad4_support) {
DRM_ERROR("ad4 not supported for dspp idx %d\n", dspp->idx);
return -EINVAL;
}
@@ -170,6 +224,10 @@ static int ad4_params_check(struct sde_hw_dspp *dspp,
return -EINVAL;
}
hw_lm = cfg->hw_cfg->mixer_info;
+ if (!hw_lm) {
+ DRM_ERROR("invalid mixer info\n");
+ return -EINVAL;
+ }
if (cfg->hw_cfg->num_of_mixers == 1 &&
hw_lm->cfg.out_height != cfg->hw_cfg->displayv &&
@@ -179,7 +237,7 @@ static int ad4_params_check(struct sde_hw_dspp *dspp,
cfg->hw_cfg->displayh, cfg->hw_cfg->displayv);
return -EINVAL;
} else if (hw_lm->cfg.out_height != cfg->hw_cfg->displayv &&
- hw_lm->cfg.out_width != (cfg->hw_cfg->displayh >> 1)) {
+ hw_lm->cfg.out_width != (cfg->hw_cfg->displayh >> 1)) {
DRM_ERROR("dual_lm lmh %d lmw %d displayh %d displayw %d\n",
hw_lm->cfg.out_height, hw_lm->cfg.out_width,
cfg->hw_cfg->displayh, cfg->hw_cfg->displayv);
@@ -189,6 +247,11 @@ static int ad4_params_check(struct sde_hw_dspp *dspp,
return 0;
}
+static int ad4_no_op_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg)
+{
+ return 0;
+}
+
static int ad4_mode_setup(struct sde_hw_dspp *dspp, enum ad4_modes mode)
{
u32 blk_offset;
@@ -200,7 +263,8 @@ static int ad4_mode_setup(struct sde_hw_dspp *dspp, enum ad4_modes mode)
info[dspp->idx].state = ad4_state_idle;
info[dspp->idx].completed_ops_mask = 0;
} else {
- info[dspp->idx].state = ad4_state_run;
+ if (info[dspp->idx].state == ad4_state_idle)
+ info[dspp->idx].state = ad4_state_run;
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
0x100);
}
@@ -235,6 +299,7 @@ static int ad4_init_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg)
proc_start = 0;
proc_end = 0xffff;
tile_ctl = 0;
+ info[dspp->idx].is_master = true;
} else {
tile_ctl = 0x5;
if (hw_lm->cfg.right_mixer) {
@@ -244,6 +309,7 @@ static int ad4_init_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg)
proc_start = (cfg->hw_cfg->displayh >> 1);
proc_end = frame_end;
tile_ctl |= 0x10;
+ info[dspp->idx].is_master = false;
} else {
frame_start = 0;
frame_end = (cfg->hw_cfg->displayh >> 1) +
@@ -251,23 +317,21 @@ static int ad4_init_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg)
proc_start = 0;
proc_end = (cfg->hw_cfg->displayh >> 1) - 1;
tile_ctl |= 0x10;
+ info[dspp->idx].is_master = true;
}
}
init = cfg->hw_cfg->payload;
- blk_offset = 8;
- SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
- init->init_param_009);
blk_offset = 0xc;
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
- init->init_param_010);
+ init->init_param_010);
init->init_param_012 = cfg->hw_cfg->displayv & (BIT(17) - 1);
init->init_param_011 = cfg->hw_cfg->displayh & (BIT(17) - 1);
blk_offset = 0x10;
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
- ((init->init_param_011 << 16) | init->init_param_012));
+ ((init->init_param_011 << 16) | init->init_param_012));
blk_offset = 0x14;
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
@@ -275,8 +339,8 @@ static int ad4_init_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg)
blk_offset = 0x44;
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
- ((((init->init_param_013) & (BIT(17) - 1)) << 16) |
- (init->init_param_014 & (BIT(17) - 1))));
+ ((((init->init_param_013) & (BIT(17) - 1)) << 16) |
+ (init->init_param_014 & (BIT(17) - 1))));
blk_offset = 0x5c;
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
@@ -583,23 +647,25 @@ static int ad4_cfg_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg)
val = (ad_cfg->cfg_param_004 & (BIT(16) - 1));
val |= ((ad_cfg->cfg_param_003 & (BIT(16) - 1)) << 16);
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
- blk_offset += 4;
+
+ blk_offset = 0x20;
val = (ad_cfg->cfg_param_005 & (BIT(8) - 1));
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
- blk_offset += 4;
+ blk_offset = 0x24;
val = (ad_cfg->cfg_param_006 & (BIT(7) - 1));
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
blk_offset = 0x30;
val = (ad_cfg->cfg_param_007 & (BIT(8) - 1));
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
- blk_offset += 4;
- val = (ad_cfg->cfg_param_008 & (BIT(8) - 1));
- SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
- blk_offset += 4;
+
+ info[dspp->idx].tf_ctrl = (ad_cfg->cfg_param_008 & (BIT(8) - 1));
+
+ blk_offset = 0x38;
val = (ad_cfg->cfg_param_009 & (BIT(10) - 1));
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
- blk_offset += 4;
+
+ blk_offset = 0x3c;
val = (ad_cfg->cfg_param_010 & (BIT(12) - 1));
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
blk_offset += 4;
@@ -607,7 +673,6 @@ static int ad4_cfg_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg)
val |= (ad_cfg->cfg_param_012 & (BIT(16) - 1));
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
-
blk_offset = 0x88;
val = (ad_cfg->cfg_param_013 & (BIT(8) - 1));
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
@@ -697,14 +762,10 @@ static int ad4_cfg_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg)
blk_offset = 0x134;
val = (ad_cfg->cfg_param_040 & (BIT(12) - 1));
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
- blk_offset += 4;
- val = (ad_cfg->cfg_param_041 & (BIT(7) - 1));
- SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
- blk_offset = 0x15c;
- val = (ad_cfg->cfg_param_042 & (BIT(10) - 1));
- SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
- blk_offset += 4;
+ info[dspp->idx].vc_control_0 = (ad_cfg->cfg_param_041 & (BIT(7) - 1));
+
+ blk_offset += 160;
val = (ad_cfg->cfg_param_043 & (BIT(10) - 1));
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
@@ -791,6 +852,52 @@ static int ad4_init_setup_idle(struct sde_hw_dspp *dspp,
if (ret)
return ret;
+ ret = ad4_mem_init_enable(dspp, cfg);
+ if (ret)
+ return ret;
+
+ info[dspp->idx].completed_ops_mask |= ad4_init;
+
+ if (IDLE_2_RUN(info[dspp->idx].completed_ops_mask))
+ ad4_mode_setup(dspp, info[dspp->idx].cached_mode);
+
+ return 0;
+}
+
+static int ad4_init_setup_run(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ int ret;
+
+ if (!cfg->hw_cfg->payload) {
+ info[dspp->idx].completed_ops_mask &= ~ad4_init;
+ return 0;
+ }
+
+ ret = ad4_init_setup(dspp, cfg);
+ if (ret)
+ return ret;
+ ret = ad4_mem_init_disable(dspp, cfg);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ad4_init_setup_ipcr(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ int ret;
+
+ if (!cfg->hw_cfg->payload) {
+ info[dspp->idx].completed_ops_mask &= ~ad4_init;
+ return 0;
+ }
+
+ ret = ad4_init_setup(dspp, cfg);
+ if (ret)
+ return ret;
+
info[dspp->idx].completed_ops_mask |= ad4_init;
if (IDLE_2_RUN(info[dspp->idx].completed_ops_mask))
@@ -812,6 +919,52 @@ static int ad4_cfg_setup_idle(struct sde_hw_dspp *dspp,
ret = ad4_cfg_setup(dspp, cfg);
if (ret)
return ret;
+ ret = ad4_cfg_ipc_reset(dspp, cfg);
+ if (ret)
+ return ret;
+
+ info[dspp->idx].completed_ops_mask |= ad4_cfg;
+ if (IDLE_2_RUN(info[dspp->idx].completed_ops_mask))
+ ad4_mode_setup(dspp, info[dspp->idx].cached_mode);
+ return 0;
+}
+
+static int ad4_cfg_setup_run(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ int ret;
+
+ if (!cfg->hw_cfg->payload) {
+ info[dspp->idx].completed_ops_mask &= ~ad4_cfg;
+ return 0;
+ }
+
+ ret = ad4_cfg_setup(dspp, cfg);
+ if (ret)
+ return ret;
+ ret = ad4_cfg_ipc_reset(dspp, cfg);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ad4_cfg_setup_ipcr(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ int ret;
+
+ if (!cfg->hw_cfg->payload) {
+ info[dspp->idx].completed_ops_mask &= ~ad4_cfg;
+ return 0;
+ }
+
+ ret = ad4_cfg_setup(dspp, cfg);
+ if (ret)
+ return ret;
+ ret = ad4_cfg_ipc_resume(dspp, cfg);
+ if (ret)
+ return ret;
info[dspp->idx].completed_ops_mask |= ad4_cfg;
if (IDLE_2_RUN(info[dspp->idx].completed_ops_mask))
@@ -835,6 +988,22 @@ static int ad4_input_setup_idle(struct sde_hw_dspp *dspp,
return 0;
}
+static int ad4_input_setup_ipcr(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ int ret;
+
+ ret = ad4_input_setup(dspp, cfg);
+ if (ret)
+ return ret;
+
+ info[dspp->idx].completed_ops_mask |= ad4_input;
+ if (IDLE_2_RUN(info[dspp->idx].completed_ops_mask))
+ ad4_mode_setup(dspp, info[dspp->idx].cached_mode);
+
+ return 0;
+}
+
static int ad4_assertive_setup(struct sde_hw_dspp *dspp,
struct sde_ad_hw_cfg *cfg)
{
@@ -900,3 +1069,182 @@ void sde_read_intr_resp_ad4(struct sde_hw_dspp *dspp, u32 event, u32 *resp)
break;
}
}
+
+static int ad4_ipc_suspend_setup_run(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ u32 strength = 0, i = 0;
+ struct sde_hw_mixer *hw_lm;
+
+ hw_lm = cfg->hw_cfg->mixer_info;
+ if ((cfg->hw_cfg->num_of_mixers == 2) && hw_lm->cfg.right_mixer) {
+ /* this AD core is the salve core */
+ for (i = DSPP_0; i < DSPP_MAX; i++) {
+ if (info[i].is_master) {
+ strength = info[i].last_str;
+ break;
+ }
+ }
+ } else {
+ strength = SDE_REG_READ(&dspp->hw,
+ dspp->cap->sblk->ad.base + 0x4c);
+ }
+ info[dspp->idx].last_str = strength;
+
+ return 0;
+}
+
+static int ad4_ipc_resume_setup_run(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ int ret;
+
+ info[dspp->idx].state = ad4_state_ipcr;
+
+ info[dspp->idx].frame_count = 0;
+ ret = ad4_cfg_ipc_resume(dspp, cfg);
+
+ return ret;
+}
+
+static int ad4_ipc_resume_setup_ipcr(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ info[dspp->idx].frame_count = 0;
+ return 0;
+}
+
+static int ad4_ipc_reset_setup_ipcr(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ int ret;
+ u32 strength = 0, i = 0;
+ struct sde_hw_mixer *hw_lm;
+
+ /* Read AD calculator strength output during the 2 frames of manual
+ * strength mode, and assign the strength output to last_str
+ * when frame count reaches AD_IPC_FRAME_COUNT to avoid flickers
+ * caused by strength was not converged before entering IPC mode
+ */
+ hw_lm = cfg->hw_cfg->mixer_info;
+ if ((cfg->hw_cfg->num_of_mixers == 2) && hw_lm->cfg.right_mixer) {
+ /* this AD core is the salve core */
+ for (i = DSPP_0; i < DSPP_MAX; i++) {
+ if (info[i].is_master) {
+ strength = info[i].last_str;
+ break;
+ }
+ }
+ } else {
+ strength = SDE_REG_READ(&dspp->hw,
+ dspp->cap->sblk->ad.base + 0x4c);
+ }
+
+ if (info[dspp->idx].frame_count == AD_IPC_FRAME_COUNT) {
+ info[dspp->idx].state = ad4_state_run;
+ info[dspp->idx].last_str = strength;
+ ret = ad4_cfg_ipc_reset(dspp, cfg);
+ if (ret)
+ return ret;
+ } else {
+ info[dspp->idx].frame_count++;
+ }
+
+ return 0;
+}
+
+static int ad4_mem_init_enable(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ u32 blk_offset;
+ struct drm_msm_ad4_init *init;
+
+ if (!cfg->hw_cfg->payload) {
+ info[dspp->idx].completed_ops_mask &= ~ad4_init;
+ return 0;
+ }
+
+ if (cfg->hw_cfg->len != sizeof(struct drm_msm_ad4_init)) {
+ DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n",
+ sizeof(struct drm_msm_ad4_init), cfg->hw_cfg->len,
+ cfg->hw_cfg->payload);
+ return -EINVAL;
+ }
+
+ init = cfg->hw_cfg->payload;
+ blk_offset = 0x8;
+ SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
+ (init->init_param_009 & 0xdfff));
+ blk_offset = 0x450;
+ SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, 1);
+
+ return 0;
+}
+
+static int ad4_mem_init_disable(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ u32 blk_offset;
+ struct drm_msm_ad4_init *init;
+
+ if (!cfg->hw_cfg->payload) {
+ info[dspp->idx].completed_ops_mask &= ~ad4_init;
+ return 0;
+ }
+
+ if (cfg->hw_cfg->len != sizeof(struct drm_msm_ad4_init)) {
+ DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n",
+ sizeof(struct drm_msm_ad4_init), cfg->hw_cfg->len,
+ cfg->hw_cfg->payload);
+ return -EINVAL;
+ }
+
+ init = cfg->hw_cfg->payload;
+ blk_offset = 0x8;
+ SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
+ (init->init_param_009 | 0x2000));
+ blk_offset = 0x450;
+ SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, 0);
+
+ return 0;
+}
+
+static int ad4_cfg_ipc_resume(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ u32 blk_offset, val;
+
+ /* disable temporal filters */
+ blk_offset = 0x34;
+ val = (0x55 & (BIT(8) - 1));
+ SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
+
+ /* set manual strength */
+ blk_offset = 0x15c;
+ val = (info[dspp->idx].last_str & (BIT(10) - 1));
+ SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
+
+ /* enable manul mode */
+ blk_offset = 0x138;
+ SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, 0);
+
+ return 0;
+}
+
+static int ad4_cfg_ipc_reset(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ u32 blk_offset;
+
+ /* enable temporal filters */
+ blk_offset = 0x34;
+ SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
+ info[dspp->idx].tf_ctrl);
+
+ /* disable manul mode */
+ blk_offset = 0x138;
+ SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
+ info[dspp->idx].vc_control_0);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 305d45e..b1772ed 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -230,6 +230,12 @@ enum {
};
enum {
+ DSPP_TOP_OFF,
+ DSPP_TOP_SIZE,
+ DSPP_TOP_PROP_MAX,
+};
+
+enum {
DSPP_OFF,
DSPP_SIZE,
DSPP_BLOCKS,
@@ -463,6 +469,11 @@ static struct sde_prop_type mixer_blocks_prop[] = {
{MIXER_GC_PROP, "qcom,sde-mixer-gc", false, PROP_TYPE_U32_ARRAY},
};
+static struct sde_prop_type dspp_top_prop[] = {
+ {DSPP_TOP_OFF, "qcom,sde-dspp-top-off", true, PROP_TYPE_U32},
+ {DSPP_TOP_SIZE, "qcom,sde-dspp-top-size", false, PROP_TYPE_U32},
+};
+
static struct sde_prop_type dspp_prop[] = {
{DSPP_OFF, "qcom,sde-dspp-off", true, PROP_TYPE_U32_ARRAY},
{DSPP_SIZE, "qcom,sde-dspp-size", false, PROP_TYPE_U32},
@@ -1859,6 +1870,54 @@ static int sde_rot_parse_dt(struct device_node *np,
return rc;
}
+static int sde_dspp_top_parse_dt(struct device_node *np,
+ struct sde_mdss_cfg *sde_cfg)
+{
+ int rc, prop_count[DSPP_TOP_PROP_MAX];
+ bool prop_exists[DSPP_TOP_PROP_MAX];
+ struct sde_prop_value *prop_value = NULL;
+ u32 off_count;
+
+ if (!sde_cfg) {
+ SDE_ERROR("invalid argument\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ prop_value = kzalloc(DSPP_TOP_PROP_MAX *
+ sizeof(struct sde_prop_value), GFP_KERNEL);
+ if (!prop_value) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ rc = _validate_dt_entry(np, dspp_top_prop, ARRAY_SIZE(dspp_top_prop),
+ prop_count, &off_count);
+ if (rc)
+ goto end;
+
+ rc = _read_dt_entry(np, dspp_top_prop, ARRAY_SIZE(dspp_top_prop),
+ prop_count, prop_exists, prop_value);
+ if (rc)
+ goto end;
+
+ if (off_count != 1) {
+ SDE_ERROR("invalid dspp_top off_count:%d\n", off_count);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ sde_cfg->dspp_top.base =
+ PROP_VALUE_ACCESS(prop_value, DSPP_TOP_OFF, 0);
+ sde_cfg->dspp_top.len =
+ PROP_VALUE_ACCESS(prop_value, DSPP_TOP_SIZE, 0);
+ snprintf(sde_cfg->dspp_top.name, SDE_HW_BLK_NAME_LEN, "dspp_top");
+
+end:
+ kfree(prop_value);
+ return rc;
+}
+
static int sde_dspp_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
@@ -2992,6 +3051,10 @@ struct sde_mdss_cfg *sde_hw_catalog_init(struct drm_device *dev, u32 hw_rev)
if (rc)
goto end;
+ rc = sde_dspp_top_parse_dt(np, sde_cfg);
+ if (rc)
+ goto end;
+
rc = sde_dspp_parse_dt(np, sde_cfg);
if (rc)
goto end;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index 29698bc..db5a6b4 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -568,6 +568,17 @@ struct sde_lm_cfg {
};
/**
+ * struct sde_dspp_cfg - information of DSPP top block
+ * @id enum identifying this block
+ * @base register offset of this block
+ * @features bit mask identifying sub-blocks/features
+ * supported by this block
+ */
+struct sde_dspp_top_cfg {
+ SDE_HW_BLK_INFO;
+};
+
+/**
* struct sde_dspp_cfg - information of DSPP blocks
* @id enum identifying this block
* @base register offset of this block
@@ -891,6 +902,8 @@ struct sde_mdss_cfg {
u32 mixer_count;
struct sde_lm_cfg mixer[MAX_BLOCKS];
+ struct sde_dspp_top_cfg dspp_top;
+
u32 dspp_count;
struct sde_dspp_cfg dspp[MAX_BLOCKS];
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
index 8f7764d..5cbfe8e 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
@@ -37,4 +37,33 @@ enum {
#define GC_TBL_NUM 3
#define GC_LUT_SWAP_OFF 0x1c
+#define IGC_TBL_NUM 3
+#define IGC_DITHER_OFF 0x7e0
+#define IGC_OPMODE_OFF 0x0
+#define IGC_C0_OFF 0x0
+#define IGC_DATA_MASK (BIT(12) - 1)
+#define IGC_DSPP_SEL_MASK_MAX (BIT(4) - 1)
+#define IGC_DSPP_SEL_MASK(n) \
+ ((IGC_DSPP_SEL_MASK_MAX & ~(1 << (n))) << 28)
+#define IGC_INDEX_UPDATE BIT(25)
+#define IGC_EN BIT(0)
+#define IGC_DIS 0
+#define IGC_DITHER_DATA_MASK (BIT(4) - 1)
+
+#define PCC_NUM_PLANES 3
+#define PCC_NUM_COEFF 11
+#define PCC_EN BIT(0)
+#define PCC_DIS 0
+#define PCC_C_OFF 0x4
+#define PCC_R_OFF 0x10
+#define PCC_G_OFF 0x1c
+#define PCC_B_OFF 0x28
+#define PCC_RG_OFF 0x34
+#define PCC_RB_OFF 0x40
+#define PCC_GB_OFF 0x4c
+#define PCC_RGB_OFF 0x58
+#define PCC_RR_OFF 0x64
+#define PCC_GG_OFF 0x70
+#define PCC_BB_OFF 0x7c
+
#endif /* _SDE_HW_COLOR_PROC_COMMON_V4_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c
index 42d1480..4da0456 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c
@@ -109,3 +109,127 @@ void sde_setup_dspp_3d_gamutv4(struct sde_hw_dspp *ctx, void *cfg)
&op_mode);
}
+
+void sde_setup_dspp_igcv3(struct sde_hw_dspp *ctx, void *cfg)
+{
+ struct drm_msm_igc_lut *lut_cfg;
+ struct sde_hw_cp_cfg *hw_cfg = cfg;
+ int i = 0, j = 0;
+ u32 *addr = NULL;
+ u32 offset = 0;
+
+ if (!ctx || !cfg) {
+ DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg);
+ return;
+ }
+
+ if (!hw_cfg->payload) {
+ DRM_DEBUG_DRIVER("disable igc feature\n");
+ SDE_REG_WRITE(&ctx->hw, IGC_OPMODE_OFF, 0);
+ return;
+ }
+
+ if (hw_cfg->len != sizeof(struct drm_msm_igc_lut)) {
+ DRM_ERROR("invalid size of payload len %d exp %zd\n",
+ hw_cfg->len, sizeof(struct drm_msm_igc_lut));
+ return;
+ }
+
+ lut_cfg = hw_cfg->payload;
+
+ for (i = 0; i < IGC_TBL_NUM; i++) {
+ addr = lut_cfg->c0 + (i * ARRAY_SIZE(lut_cfg->c0));
+ offset = IGC_C0_OFF + (i * sizeof(u32));
+
+ for (j = 0; j < IGC_TBL_LEN; j++) {
+ addr[j] &= IGC_DATA_MASK;
+ addr[j] |= IGC_DSPP_SEL_MASK(ctx->idx - 1);
+ if (j == 0)
+ addr[j] |= IGC_INDEX_UPDATE;
+ /* IGC lut registers are part of DSPP Top HW block */
+ SDE_REG_WRITE(&ctx->hw_top, offset, addr[j]);
+ }
+ }
+
+ if (lut_cfg->flags & IGC_DITHER_ENABLE) {
+ SDE_REG_WRITE(&ctx->hw, IGC_DITHER_OFF,
+ lut_cfg->strength & IGC_DITHER_DATA_MASK);
+ }
+
+ SDE_REG_WRITE(&ctx->hw, IGC_OPMODE_OFF, IGC_EN);
+}
+
+void sde_setup_dspp_pccv4(struct sde_hw_dspp *ctx, void *cfg)
+{
+ struct sde_hw_cp_cfg *hw_cfg = cfg;
+ struct drm_msm_pcc *pcc_cfg;
+ struct drm_msm_pcc_coeff *coeffs = NULL;
+ int i = 0;
+ u32 base = 0;
+
+ if (!ctx || !cfg) {
+ DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg);
+ return;
+ }
+
+ if (!hw_cfg->payload) {
+ DRM_DEBUG_DRIVER("disable pcc feature\n");
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base, 0);
+ return;
+ }
+
+ if (hw_cfg->len != sizeof(struct drm_msm_pcc)) {
+ DRM_ERROR("invalid size of payload len %d exp %zd\n",
+ hw_cfg->len, sizeof(struct drm_msm_pcc));
+ return;
+ }
+
+ pcc_cfg = hw_cfg->payload;
+
+ for (i = 0; i < PCC_NUM_PLANES; i++) {
+ base = ctx->cap->sblk->pcc.base + (i * sizeof(u32));
+ switch (i) {
+ case 0:
+ coeffs = &pcc_cfg->r;
+ SDE_REG_WRITE(&ctx->hw,
+ base + PCC_RR_OFF, pcc_cfg->r_rr);
+ SDE_REG_WRITE(&ctx->hw,
+ base + PCC_GG_OFF, pcc_cfg->r_gg);
+ SDE_REG_WRITE(&ctx->hw,
+ base + PCC_BB_OFF, pcc_cfg->r_bb);
+ break;
+ case 1:
+ coeffs = &pcc_cfg->g;
+ SDE_REG_WRITE(&ctx->hw,
+ base + PCC_RR_OFF, pcc_cfg->g_rr);
+ SDE_REG_WRITE(&ctx->hw,
+ base + PCC_GG_OFF, pcc_cfg->g_gg);
+ SDE_REG_WRITE(&ctx->hw,
+ base + PCC_BB_OFF, pcc_cfg->g_bb);
+ break;
+ case 2:
+ coeffs = &pcc_cfg->b;
+ SDE_REG_WRITE(&ctx->hw,
+ base + PCC_RR_OFF, pcc_cfg->b_rr);
+ SDE_REG_WRITE(&ctx->hw,
+ base + PCC_GG_OFF, pcc_cfg->b_gg);
+ SDE_REG_WRITE(&ctx->hw,
+ base + PCC_BB_OFF, pcc_cfg->b_bb);
+ break;
+ default:
+ DRM_ERROR("invalid pcc plane: %d\n", i);
+ return;
+ }
+
+ SDE_REG_WRITE(&ctx->hw, base + PCC_C_OFF, coeffs->c);
+ SDE_REG_WRITE(&ctx->hw, base + PCC_R_OFF, coeffs->r);
+ SDE_REG_WRITE(&ctx->hw, base + PCC_G_OFF, coeffs->g);
+ SDE_REG_WRITE(&ctx->hw, base + PCC_B_OFF, coeffs->b);
+ SDE_REG_WRITE(&ctx->hw, base + PCC_RG_OFF, coeffs->rg);
+ SDE_REG_WRITE(&ctx->hw, base + PCC_RB_OFF, coeffs->rb);
+ SDE_REG_WRITE(&ctx->hw, base + PCC_GB_OFF, coeffs->gb);
+ SDE_REG_WRITE(&ctx->hw, base + PCC_RGB_OFF, coeffs->rgb);
+ }
+
+ SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base, PCC_EN);
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.h b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.h
index 250830e..ad4f556 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.h
@@ -22,5 +22,19 @@
* @cfg: pointer to sde_hw_cp_cfg
*/
void sde_setup_dspp_3d_gamutv4(struct sde_hw_dspp *ctx, void *cfg);
+/**
+ * sde_setup_dspp_igcv3 - Function for igc v3 version feature
+ * programming.
+ * @ctx: dspp ctx pointer
+ * @cfg: pointer to sde_hw_cp_cfg
+ */
+void sde_setup_dspp_igcv3(struct sde_hw_dspp *ctx, void *cfg);
+/**
+ * sde_setup_dspp_pccv4 - Function for pcc v4 version feature
+ * programming.
+ * @ctx: dspp ctx pointer
+ * @cfg: pointer to sde_hw_cp_cfg
+ */
+void sde_setup_dspp_pccv4(struct sde_hw_dspp *ctx, void *cfg);
#endif /* _SDE_HW_COLOR_PROC_V4_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dsc.c b/drivers/gpu/drm/msm/sde/sde_hw_dsc.c
index 1a346f0..9fd3c25 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dsc.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dsc.c
@@ -120,7 +120,6 @@ static void sde_hw_dsc_config(struct sde_hw_dsc *hw_dsc,
data |= dsc->max_qp_flatness << 5;
data |= dsc->min_qp_flatness;
SDE_REG_WRITE(dsc_c, DSC_FLATNESS, data);
- SDE_REG_WRITE(dsc_c, DSC_FLATNESS, 0x983);
data = dsc->rc_model_size;
SDE_REG_WRITE(dsc_c, DSC_RC_MODEL_SIZE, data);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
index e766cdb..5b3f51e 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
@@ -58,6 +58,16 @@ static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features)
if (c->cap->sblk->pcc.version ==
(SDE_COLOR_PROCESS_VER(0x1, 0x7)))
c->ops.setup_pcc = sde_setup_dspp_pcc_v1_7;
+ else if (c->cap->sblk->pcc.version ==
+ (SDE_COLOR_PROCESS_VER(0x4, 0x0))) {
+ ret = reg_dmav1_init_dspp_op_v4(i, c->idx);
+ if (!ret)
+ c->ops.setup_pcc =
+ reg_dmav1_setup_dspp_pccv4;
+ else
+ c->ops.setup_pcc =
+ sde_setup_dspp_pccv4;
+ }
break;
case SDE_DSPP_HSIC:
if (c->cap->sblk->hsic.version ==
@@ -104,6 +114,18 @@ static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features)
sde_setup_dspp_gc_v1_7;
}
break;
+ case SDE_DSPP_IGC:
+ if (c->cap->sblk->igc.version ==
+ SDE_COLOR_PROCESS_VER(0x3, 0x1)) {
+ ret = reg_dmav1_init_dspp_op_v4(i, c->idx);
+ if (!ret)
+ c->ops.setup_igc =
+ reg_dmav1_setup_dspp_igcv31;
+ else
+ c->ops.setup_igc =
+ sde_setup_dspp_igcv3;
+ }
+ break;
case SDE_DSPP_AD:
if (c->cap->sblk->ad.version ==
SDE_COLOR_PROCESS_VER(4, 0)) {
@@ -145,6 +167,13 @@ struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx,
return ERR_PTR(-EINVAL);
}
+ /* Populate DSPP Top HW block */
+ c->hw_top.base_off = addr;
+ c->hw_top.blk_off = m->dspp_top.base;
+ c->hw_top.length = m->dspp_top.len;
+ c->hw_top.hwversion = m->hwversion;
+ c->hw_top.log_mask = SDE_DBG_MASK_DSPP;
+
/* Assign ops */
c->idx = idx;
c->cap = cfg;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
index 0baa970..44b3831 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
@@ -170,13 +170,17 @@ struct sde_hw_dspp_ops {
* struct sde_hw_dspp - dspp description
* @base: Hardware block base structure
* @hw: Block hardware details
+ * @hw_top: Block hardware top details
* @idx: DSPP index
* @cap: Pointer to layer_cfg
* @ops: Pointer to operations possible for this DSPP
*/
struct sde_hw_dspp {
struct sde_hw_blk base;
- struct sde_hw_blk_reg_map hw;
+ struct sde_hw_blk_reg_map hw;
+
+ /* dspp top */
+ struct sde_hw_blk_reg_map hw_top;
/* dspp */
enum sde_dspp idx;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
index 8c3d4fc..8eebf89fc 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
@@ -710,6 +710,9 @@ static void sde_hw_intr_set_mask(struct sde_hw_intr *intr, uint32_t reg_off,
return;
SDE_REG_WRITE(&intr->hw, reg_off, mask);
+
+ /* ensure register writes go through */
+ wmb();
}
static void sde_hw_intr_dispatch_irq(struct sde_hw_intr *intr,
@@ -731,7 +734,7 @@ static void sde_hw_intr_dispatch_irq(struct sde_hw_intr *intr,
* Now need to go through each IRQ status and find matching
* irq lookup index.
*/
- spin_lock_irqsave(&intr->status_lock, irq_flags);
+ spin_lock_irqsave(&intr->irq_lock, irq_flags);
for (reg_idx = 0; reg_idx < ARRAY_SIZE(sde_intr_set); reg_idx++) {
irq_status = intr->save_irq_status[reg_idx];
@@ -766,7 +769,7 @@ static void sde_hw_intr_dispatch_irq(struct sde_hw_intr *intr,
if (cbfunc)
cbfunc(arg, irq_idx);
else
- intr->ops.clear_interrupt_status(
+ intr->ops.clear_intr_status_nolock(
intr, irq_idx);
/*
@@ -777,7 +780,7 @@ static void sde_hw_intr_dispatch_irq(struct sde_hw_intr *intr,
irq_status &= ~sde_irq_map[irq_idx].irq_mask;
}
}
- spin_unlock_irqrestore(&intr->status_lock, irq_flags);
+ spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
}
static int sde_hw_intr_enable_irq(struct sde_hw_intr *intr, int irq_idx)
@@ -801,7 +804,7 @@ static int sde_hw_intr_enable_irq(struct sde_hw_intr *intr, int irq_idx)
reg_idx = irq->reg_idx;
reg = &sde_intr_set[reg_idx];
- spin_lock_irqsave(&intr->mask_lock, irq_flags);
+ spin_lock_irqsave(&intr->irq_lock, irq_flags);
cache_irq_mask = intr->cache_irq_mask[reg_idx];
if (cache_irq_mask & irq->irq_mask) {
dbgstr = "SDE IRQ already set:";
@@ -814,9 +817,12 @@ static int sde_hw_intr_enable_irq(struct sde_hw_intr *intr, int irq_idx)
/* Enabling interrupts with the new mask */
SDE_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask);
+ /* ensure register write goes through */
+ wmb();
+
intr->cache_irq_mask[reg_idx] = cache_irq_mask;
}
- spin_unlock_irqrestore(&intr->mask_lock, irq_flags);
+ spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
pr_debug("%s MASK:0x%.8x, CACHE-MASK:0x%.8x\n", dbgstr,
irq->irq_mask, cache_irq_mask);
@@ -845,7 +851,7 @@ static int sde_hw_intr_disable_irq(struct sde_hw_intr *intr, int irq_idx)
reg_idx = irq->reg_idx;
reg = &sde_intr_set[reg_idx];
- spin_lock_irqsave(&intr->mask_lock, irq_flags);
+ spin_lock_irqsave(&intr->irq_lock, irq_flags);
cache_irq_mask = intr->cache_irq_mask[reg_idx];
if ((cache_irq_mask & irq->irq_mask) == 0) {
dbgstr = "SDE IRQ is already cleared:";
@@ -858,9 +864,12 @@ static int sde_hw_intr_disable_irq(struct sde_hw_intr *intr, int irq_idx)
/* Cleaning any pending interrupt */
SDE_REG_WRITE(&intr->hw, reg->clr_off, irq->irq_mask);
+ /* ensure register write goes through */
+ wmb();
+
intr->cache_irq_mask[reg_idx] = cache_irq_mask;
}
- spin_unlock_irqrestore(&intr->mask_lock, irq_flags);
+ spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
pr_debug("%s MASK:0x%.8x, CACHE-MASK:0x%.8x\n", dbgstr,
irq->irq_mask, cache_irq_mask);
@@ -878,6 +887,9 @@ static int sde_hw_intr_clear_irqs(struct sde_hw_intr *intr)
for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++)
SDE_REG_WRITE(&intr->hw, sde_intr_set[i].clr_off, 0xffffffff);
+ /* ensure register writes go through */
+ wmb();
+
return 0;
}
@@ -891,6 +903,9 @@ static int sde_hw_intr_disable_irqs(struct sde_hw_intr *intr)
for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++)
SDE_REG_WRITE(&intr->hw, sde_intr_set[i].en_off, 0x00000000);
+ /* ensure register writes go through */
+ wmb();
+
return 0;
}
@@ -926,7 +941,7 @@ static void sde_hw_intr_get_interrupt_statuses(struct sde_hw_intr *intr)
if (!intr)
return;
- spin_lock_irqsave(&intr->status_lock, irq_flags);
+ spin_lock_irqsave(&intr->irq_lock, irq_flags);
for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++) {
/* Read interrupt status */
intr->save_irq_status[i] = SDE_REG_READ(&intr->hw,
@@ -943,25 +958,68 @@ static void sde_hw_intr_get_interrupt_statuses(struct sde_hw_intr *intr)
/* Finally update IRQ status based on enable mask */
intr->save_irq_status[i] &= enable_mask;
}
- spin_unlock_irqrestore(&intr->status_lock, irq_flags);
+
+ /* ensure register writes go through */
+ wmb();
+
+ spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
}
-static void sde_hw_intr_clear_interrupt_status(struct sde_hw_intr *intr,
+static void sde_hw_intr_clear_intr_status_nolock(struct sde_hw_intr *intr,
int irq_idx)
{
int reg_idx;
- unsigned long irq_flags;
if (!intr)
return;
- spin_lock_irqsave(&intr->mask_lock, irq_flags);
-
reg_idx = sde_irq_map[irq_idx].reg_idx;
SDE_REG_WRITE(&intr->hw, sde_intr_set[reg_idx].clr_off,
sde_irq_map[irq_idx].irq_mask);
- spin_unlock_irqrestore(&intr->mask_lock, irq_flags);
+ /* ensure register writes go through */
+ wmb();
+}
+
+static void sde_hw_intr_clear_interrupt_status(struct sde_hw_intr *intr,
+ int irq_idx)
+{
+ unsigned long irq_flags;
+
+ if (!intr)
+ return;
+
+ spin_lock_irqsave(&intr->irq_lock, irq_flags);
+ sde_hw_intr_clear_intr_status_nolock(intr, irq_idx);
+ spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
+}
+
+static u32 sde_hw_intr_get_intr_status_nolock(struct sde_hw_intr *intr,
+ int irq_idx, bool clear)
+{
+ int reg_idx;
+ u32 intr_status;
+
+ if (!intr)
+ return 0;
+
+ if (irq_idx >= ARRAY_SIZE(sde_irq_map) || irq_idx < 0) {
+ pr_err("invalid IRQ index: [%d]\n", irq_idx);
+ return 0;
+ }
+
+ reg_idx = sde_irq_map[irq_idx].reg_idx;
+ intr_status = SDE_REG_READ(&intr->hw,
+ sde_intr_set[reg_idx].status_off) &
+ sde_irq_map[irq_idx].irq_mask;
+ if (intr_status && clear)
+ SDE_REG_WRITE(&intr->hw, sde_intr_set[reg_idx].clr_off,
+ intr_status);
+
+ /* ensure register writes go through */
+ wmb();
+
+ return intr_status;
}
static u32 sde_hw_intr_get_interrupt_status(struct sde_hw_intr *intr,
@@ -979,7 +1037,7 @@ static u32 sde_hw_intr_get_interrupt_status(struct sde_hw_intr *intr,
return 0;
}
- spin_lock_irqsave(&intr->mask_lock, irq_flags);
+ spin_lock_irqsave(&intr->irq_lock, irq_flags);
reg_idx = sde_irq_map[irq_idx].reg_idx;
intr_status = SDE_REG_READ(&intr->hw,
@@ -989,7 +1047,10 @@ static u32 sde_hw_intr_get_interrupt_status(struct sde_hw_intr *intr,
SDE_REG_WRITE(&intr->hw, sde_intr_set[reg_idx].clr_off,
intr_status);
- spin_unlock_irqrestore(&intr->mask_lock, irq_flags);
+ /* ensure register writes go through */
+ wmb();
+
+ spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
return intr_status;
}
@@ -1007,7 +1068,9 @@ static void __setup_intr_ops(struct sde_hw_intr_ops *ops)
ops->get_interrupt_sources = sde_hw_intr_get_interrupt_sources;
ops->get_interrupt_statuses = sde_hw_intr_get_interrupt_statuses;
ops->clear_interrupt_status = sde_hw_intr_clear_interrupt_status;
+ ops->clear_intr_status_nolock = sde_hw_intr_clear_intr_status_nolock;
ops->get_interrupt_status = sde_hw_intr_get_interrupt_status;
+ ops->get_intr_status_nolock = sde_hw_intr_get_intr_status_nolock;
}
static struct sde_mdss_base_cfg *__intr_offset(struct sde_mdss_cfg *m,
@@ -1059,8 +1122,7 @@ struct sde_hw_intr *sde_hw_intr_init(void __iomem *addr,
return ERR_PTR(-ENOMEM);
}
- spin_lock_init(&intr->mask_lock);
- spin_lock_init(&intr->status_lock);
+ spin_lock_init(&intr->irq_lock);
return intr;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
index aaba1be..ced4077 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
@@ -187,6 +187,15 @@ struct sde_hw_intr_ops {
int irq_idx);
/**
+ * clear_intr_status_nolock() - clears the HW interrupts without lock
+ * @intr: HW interrupt handle
+ * @irq_idx: Lookup irq index return from irq_idx_lookup
+ */
+ void (*clear_intr_status_nolock)(
+ struct sde_hw_intr *intr,
+ int irq_idx);
+
+ /**
* get_interrupt_status - Gets HW interrupt status, and clear if set,
* based on given lookup IRQ index.
* @intr: HW interrupt handle
@@ -199,6 +208,17 @@ struct sde_hw_intr_ops {
bool clear);
/**
+ * get_intr_status_nolock - nolock version of get_interrupt_status
+ * @intr: HW interrupt handle
+ * @irq_idx: Lookup irq index return from irq_idx_lookup
+ * @clear: True to clear irq after read
+ */
+ u32 (*get_intr_status_nolock)(
+ struct sde_hw_intr *intr,
+ int irq_idx,
+ bool clear);
+
+ /**
* get_valid_interrupts - Gets a mask of all valid interrupt sources
* within SDE. These are actually status bits
* within interrupt registers that specify the
@@ -232,8 +252,7 @@ struct sde_hw_intr_ops {
* @cache_irq_mask: array of IRQ enable masks reg storage created during init
* @save_irq_status: array of IRQ status reg storage created during init
* @irq_idx_tbl_size: total number of irq_idx mapped in the hw_interrupts
- * @mask_lock: spinlock for accessing IRQ mask
- * @status_lock: spinlock for accessing IRQ status
+ * @irq_lock: spinlock for accessing IRQ resources
*/
struct sde_hw_intr {
struct sde_hw_blk_reg_map hw;
@@ -241,8 +260,7 @@ struct sde_hw_intr {
u32 *cache_irq_mask;
u32 *save_irq_status;
u32 irq_idx_tbl_size;
- spinlock_t mask_lock;
- spinlock_t status_lock;
+ spinlock_t irq_lock;
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index 582ab5a..f07f5ed 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -82,6 +82,19 @@ enum sde_format_flags {
#define SDE_BLEND_BG_INV_MOD_ALPHA (1 << 12)
#define SDE_BLEND_BG_TRANSP_EN (1 << 13)
+#define SDE_VSYNC0_SOURCE_GPIO 0
+#define SDE_VSYNC1_SOURCE_GPIO 1
+#define SDE_VSYNC2_SOURCE_GPIO 2
+#define SDE_VSYNC_SOURCE_INTF_0 3
+#define SDE_VSYNC_SOURCE_INTF_1 4
+#define SDE_VSYNC_SOURCE_INTF_2 5
+#define SDE_VSYNC_SOURCE_INTF_3 6
+#define SDE_VSYNC_SOURCE_WD_TIMER_4 11
+#define SDE_VSYNC_SOURCE_WD_TIMER_3 12
+#define SDE_VSYNC_SOURCE_WD_TIMER_2 13
+#define SDE_VSYNC_SOURCE_WD_TIMER_1 14
+#define SDE_VSYNC_SOURCE_WD_TIMER_0 15
+
enum sde_hw_blk_type {
SDE_HW_BLK_TOP = 0,
SDE_HW_BLK_SSPP,
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 4140a12..9a5035a 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
@@ -90,6 +90,8 @@ static u32 v1_supported[REG_DMA_FEATURES_MAX] = {
[GAMUT] = GRP_VIG_HW_BLK_SELECT | GRP_DSPP_HW_BLK_SELECT,
[VLUT] = GRP_DSPP_HW_BLK_SELECT,
[GC] = GRP_DSPP_HW_BLK_SELECT,
+ [IGC] = DSPP_IGC | GRP_DSPP_HW_BLK_SELECT,
+ [PCC] = GRP_DSPP_HW_BLK_SELECT,
};
static int validate_dma_cfg(struct sde_reg_dma_setup_ops_cfg *cfg);
@@ -182,7 +184,7 @@ static int write_multi_reg(struct sde_reg_dma_setup_ops_cfg *cfg)
loc = (u8 *)cfg->dma_buf->vaddr + cfg->dma_buf->index;
memcpy(loc, cfg->data, cfg->data_size);
cfg->dma_buf->index += cfg->data_size;
- cfg->dma_buf->next_op_allowed = REG_WRITE_OP;
+ cfg->dma_buf->next_op_allowed = REG_WRITE_OP | DECODE_SEL_OP;
cfg->dma_buf->ops_completed |= REG_WRITE_OP;
return 0;
@@ -244,7 +246,7 @@ static int write_single_reg(struct sde_reg_dma_setup_ops_cfg *cfg)
loc[1] = *cfg->data;
cfg->dma_buf->index += ops_mem_size[cfg->ops];
cfg->dma_buf->ops_completed |= REG_WRITE_OP;
- cfg->dma_buf->next_op_allowed = REG_WRITE_OP;
+ cfg->dma_buf->next_op_allowed = REG_WRITE_OP | DECODE_SEL_OP;
return 0;
}
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 285ef11..70427ab 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
@@ -30,6 +30,14 @@
#define GC_LUT_MEM_SIZE ((sizeof(struct drm_msm_pgc_lut)) + \
REG_DMA_HEADERS_BUFFER_SZ)
+#define IGC_LUT_MEM_SIZE ((sizeof(struct drm_msm_igc_lut)) + \
+ REG_DMA_HEADERS_BUFFER_SZ)
+
+#define PCC_LUT_ENTRIES (PCC_NUM_PLANES * PCC_NUM_COEFF)
+#define PCC_LEN (PCC_LUT_ENTRIES * sizeof(u32))
+#define PCC_MEM_SIZE (PCC_LEN + \
+ REG_DMA_HEADERS_BUFFER_SZ)
+
#define REG_MASK(n) ((BIT(n)) - 1)
static struct sde_reg_dma_buffer *dspp_buf[REG_DMA_FEATURES_MAX][DSPP_MAX];
@@ -37,8 +45,8 @@ 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_GAMUT] = GAMUT,
- [SDE_DSPP_IGC] = REG_DMA_FEATURES_MAX,
- [SDE_DSPP_PCC] = REG_DMA_FEATURES_MAX,
+ [SDE_DSPP_IGC] = IGC,
+ [SDE_DSPP_PCC] = PCC,
[SDE_DSPP_GC] = GC,
[SDE_DSPP_HSIC] = REG_DMA_FEATURES_MAX,
[SDE_DSPP_MEMCOLOR] = REG_DMA_FEATURES_MAX,
@@ -52,6 +60,8 @@ static u32 feature_reg_dma_sz[SDE_DSPP_MAX] = {
[SDE_DSPP_VLUT] = VLUT_MEM_SIZE,
[SDE_DSPP_GAMUT] = GAMUT_LUT_MEM_SIZE,
[SDE_DSPP_GC] = GC_LUT_MEM_SIZE,
+ [SDE_DSPP_IGC] = IGC_LUT_MEM_SIZE,
+ [SDE_DSPP_PCC] = PCC_MEM_SIZE,
};
static u32 dspp_mapping[DSPP_MAX] = {
@@ -233,6 +243,7 @@ int reg_dmav1_init_dspp_op_v4(int feature, enum sde_dspp idx)
int rc = -ENOTSUPP;
struct sde_hw_reg_dma_ops *dma_ops;
bool is_supported = false;
+ u32 blk;
if (feature >= SDE_DSPP_MAX || idx >= DSPP_MAX) {
DRM_ERROR("invalid feature %x max %x dspp idx %x max %xd\n",
@@ -250,8 +261,8 @@ int reg_dmav1_init_dspp_op_v4(int feature, enum sde_dspp idx)
if (IS_ERR_OR_NULL(dma_ops))
return -ENOTSUPP;
- rc = dma_ops->check_support(feature_map[feature], dspp_mapping[idx],
- &is_supported);
+ blk = (feature_map[feature] == IGC) ? DSPP_IGC : dspp_mapping[idx];
+ rc = dma_ops->check_support(feature_map[feature], blk, &is_supported);
if (!rc)
rc = (is_supported) ? 0 : -ENOTSUPP;
@@ -379,7 +390,7 @@ static void dspp_3d_gamutv4_off(struct sde_hw_dspp *ctx, void *cfg)
{
struct sde_reg_dma_kickoff_cfg kick_off;
struct sde_hw_cp_cfg *hw_cfg = cfg;
- u32 op_mode;
+ u32 op_mode = 0;
struct sde_hw_reg_dma_ops *dma_ops;
struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
int rc;
@@ -519,7 +530,7 @@ void reg_dmav1_setup_dspp_gcv18(struct sde_hw_dspp *ctx, void *cfg)
int rc, i = 0;
u32 reg;
- rc = reg_dma_dspp_check(ctx, cfg, GAMUT);
+ rc = reg_dma_dspp_check(ctx, cfg, GC);
if (rc)
return;
@@ -603,6 +614,298 @@ void reg_dmav1_setup_dspp_gcv18(struct sde_hw_dspp *ctx, void *cfg)
}
}
+static void _dspp_igcv31_off(struct sde_hw_dspp *ctx, void *cfg)
+{
+ struct sde_reg_dma_kickoff_cfg kick_off;
+ struct sde_hw_cp_cfg *hw_cfg = cfg;
+ struct sde_hw_reg_dma_ops *dma_ops;
+ struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
+ int rc;
+ u32 reg;
+
+ dma_ops = sde_reg_dma_get_ops();
+ dma_ops->reset_reg_dma_buf(dspp_buf[IGC][ctx->idx]);
+
+ REG_DMA_INIT_OPS(dma_write_cfg, dspp_mapping[ctx->idx], IGC,
+ dspp_buf[IGC][ctx->idx]);
+
+ REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("write decode select failed ret %d\n", rc);
+ return;
+ }
+
+ reg = IGC_DIS;
+ REG_DMA_SETUP_OPS(dma_write_cfg,
+ ctx->cap->sblk->igc.base + IGC_OPMODE_OFF,
+ ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("setting opcode failed ret %d\n", rc);
+ return;
+ }
+
+ REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[IGC][ctx->idx],
+ REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE);
+ rc = dma_ops->kick_off(&kick_off);
+ if (rc)
+ DRM_ERROR("failed to kick off ret %d\n", rc);
+}
+
+void reg_dmav1_setup_dspp_igcv31(struct sde_hw_dspp *ctx, void *cfg)
+{
+ struct drm_msm_igc_lut *lut_cfg;
+ struct sde_hw_reg_dma_ops *dma_ops;
+ struct sde_reg_dma_kickoff_cfg kick_off;
+ struct sde_hw_cp_cfg *hw_cfg = cfg;
+ struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
+ int rc, i = 0, j = 0;
+ u32 *addr = NULL;
+ u32 offset = 0;
+ u32 reg;
+
+ rc = reg_dma_dspp_check(ctx, cfg, IGC);
+ if (rc)
+ return;
+
+ if (!hw_cfg->payload) {
+ DRM_DEBUG_DRIVER("disable igc feature\n");
+ _dspp_igcv31_off(ctx, cfg);
+ return;
+ }
+
+ if (hw_cfg->len != sizeof(struct drm_msm_igc_lut)) {
+ DRM_ERROR("invalid size of payload len %d exp %zd\n",
+ hw_cfg->len, sizeof(struct drm_msm_igc_lut));
+ return;
+ }
+
+ lut_cfg = hw_cfg->payload;
+
+ dma_ops = sde_reg_dma_get_ops();
+ dma_ops->reset_reg_dma_buf(dspp_buf[IGC][ctx->idx]);
+
+ REG_DMA_INIT_OPS(dma_write_cfg, DSPP_IGC, IGC, dspp_buf[IGC][ctx->idx]);
+
+ REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("write decode select failed ret %d\n", rc);
+ return;
+ }
+
+ for (i = 0; i < IGC_TBL_NUM; i++) {
+ addr = lut_cfg->c0 + (i * ARRAY_SIZE(lut_cfg->c0));
+ offset = IGC_C0_OFF + (i * sizeof(u32));
+
+ for (j = 0; j < IGC_TBL_LEN; j++) {
+ addr[j] &= IGC_DATA_MASK;
+ addr[j] |= IGC_DSPP_SEL_MASK(ctx->idx - 1);
+ if (j == 0)
+ addr[j] |= IGC_INDEX_UPDATE;
+ }
+
+ REG_DMA_SETUP_OPS(dma_write_cfg, offset, addr,
+ IGC_TBL_LEN * sizeof(u32),
+ REG_BLK_WRITE_INC, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("lut write failed ret %d\n", rc);
+ return;
+ }
+ }
+
+ REG_DMA_INIT_OPS(dma_write_cfg, dspp_mapping[ctx->idx], IGC,
+ dspp_buf[IGC][ctx->idx]);
+
+ REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("write decode select failed ret %d\n", rc);
+ return;
+ }
+
+ if (lut_cfg->flags & IGC_DITHER_ENABLE) {
+ reg = lut_cfg->strength & IGC_DITHER_DATA_MASK;
+ REG_DMA_SETUP_OPS(dma_write_cfg,
+ ctx->cap->sblk->igc.base + IGC_DITHER_OFF,
+ ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("dither strength failed ret %d\n", rc);
+ return;
+ }
+ }
+
+ reg = IGC_EN;
+ REG_DMA_SETUP_OPS(dma_write_cfg,
+ ctx->cap->sblk->igc.base + IGC_OPMODE_OFF,
+ ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("setting opcode failed ret %d\n", rc);
+ return;
+ }
+
+ REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[IGC][ctx->idx],
+ REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE);
+ rc = dma_ops->kick_off(&kick_off);
+ if (rc)
+ DRM_ERROR("failed to kick off ret %d\n", rc);
+}
+
+static void _dspp_pccv4_off(struct sde_hw_dspp *ctx, void *cfg)
+{
+ struct sde_reg_dma_kickoff_cfg kick_off;
+ struct sde_hw_cp_cfg *hw_cfg = cfg;
+ struct sde_hw_reg_dma_ops *dma_ops;
+ struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
+ int rc;
+ u32 reg;
+
+ dma_ops = sde_reg_dma_get_ops();
+ dma_ops->reset_reg_dma_buf(dspp_buf[PCC][ctx->idx]);
+
+ REG_DMA_INIT_OPS(dma_write_cfg, dspp_mapping[ctx->idx], PCC,
+ dspp_buf[PCC][ctx->idx]);
+
+ REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("write decode select failed ret %d\n", rc);
+ return;
+ }
+
+ reg = PCC_DIS;
+ REG_DMA_SETUP_OPS(dma_write_cfg,
+ ctx->cap->sblk->pcc.base,
+ ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("setting opcode failed ret %d\n", rc);
+ return;
+ }
+
+ REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[PCC][ctx->idx],
+ REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE);
+ rc = dma_ops->kick_off(&kick_off);
+ if (rc)
+ DRM_ERROR("failed to kick off ret %d\n", rc);
+}
+
+void reg_dmav1_setup_dspp_pccv4(struct sde_hw_dspp *ctx, void *cfg)
+{
+ struct sde_hw_reg_dma_ops *dma_ops;
+ struct sde_reg_dma_kickoff_cfg kick_off;
+ struct sde_hw_cp_cfg *hw_cfg = cfg;
+ struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
+ struct drm_msm_pcc *pcc_cfg;
+ struct drm_msm_pcc_coeff *coeffs = NULL;
+ u32 *data = NULL;
+ int rc, i = 0;
+ u32 reg = 0;
+
+ rc = reg_dma_dspp_check(ctx, cfg, PCC);
+ if (rc)
+ return;
+
+ if (!hw_cfg->payload) {
+ DRM_DEBUG_DRIVER("disable pcc feature\n");
+ _dspp_pccv4_off(ctx, cfg);
+ return;
+ }
+
+ if (hw_cfg->len != sizeof(struct drm_msm_pcc)) {
+ DRM_ERROR("invalid size of payload len %d exp %zd\n",
+ hw_cfg->len, sizeof(struct drm_msm_pcc));
+ return;
+ }
+
+ pcc_cfg = hw_cfg->payload;
+
+ dma_ops = sde_reg_dma_get_ops();
+ dma_ops->reset_reg_dma_buf(dspp_buf[PCC][ctx->idx]);
+
+ REG_DMA_INIT_OPS(dma_write_cfg, dspp_mapping[ctx->idx],
+ PCC, dspp_buf[PCC][ctx->idx]);
+
+ REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("write decode select failed ret %d\n", rc);
+ return;
+ }
+
+ data = kzalloc(PCC_LEN, GFP_KERNEL);
+ if (!data)
+ return;
+
+ for (i = 0; i < PCC_NUM_PLANES; i++) {
+ switch (i) {
+ case 0:
+ coeffs = &pcc_cfg->r;
+ data[i + 24] = pcc_cfg->r_rr;
+ data[i + 27] = pcc_cfg->r_gg;
+ data[i + 30] = pcc_cfg->r_bb;
+ break;
+ case 1:
+ coeffs = &pcc_cfg->g;
+ data[i + 24] = pcc_cfg->g_rr;
+ data[i + 27] = pcc_cfg->g_gg;
+ data[i + 30] = pcc_cfg->g_bb;
+ break;
+ case 2:
+ coeffs = &pcc_cfg->b;
+ data[i + 24] = pcc_cfg->b_rr;
+ data[i + 27] = pcc_cfg->b_gg;
+ data[i + 30] = pcc_cfg->b_bb;
+ break;
+ default:
+ DRM_ERROR("invalid pcc plane: %d\n", i);
+ goto exit;
+ }
+
+ data[i] = coeffs->c;
+ data[i + 3] = coeffs->r;
+ data[i + 6] = coeffs->g;
+ data[i + 9] = coeffs->b;
+ data[i + 12] = coeffs->rg;
+ data[i + 15] = coeffs->rb;
+ data[i + 18] = coeffs->gb;
+ data[i + 21] = coeffs->rgb;
+ }
+
+ REG_DMA_SETUP_OPS(dma_write_cfg,
+ ctx->cap->sblk->pcc.base + PCC_C_OFF,
+ data, PCC_LEN,
+ REG_BLK_WRITE_SINGLE, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("write pcc lut failed ret %d\n", rc);
+ goto exit;
+ }
+
+ reg = PCC_EN;
+ REG_DMA_SETUP_OPS(dma_write_cfg,
+ ctx->cap->sblk->pcc.base,
+ ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("setting opcode failed ret %d\n", rc);
+ goto exit;
+ }
+
+ REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[PCC][ctx->idx],
+ REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE);
+ rc = dma_ops->kick_off(&kick_off);
+ if (rc)
+ DRM_ERROR("failed to kick off ret %d\n", rc);
+
+exit:
+ kfree(data);
+}
+
int reg_dmav1_deinit_dspp_ops(enum sde_dspp idx)
{
int i;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.h b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.h
index 94e1a5c..bb72c8f 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.h
@@ -46,13 +46,27 @@ void reg_dmav1_setup_dspp_vlutv18(struct sde_hw_dspp *ctx, void *cfg);
void reg_dmav1_setup_dspp_3d_gamutv4(struct sde_hw_dspp *ctx, void *cfg);
/**
- * reg_dmav1_setup_dspp_gc_v18() - gc v18 implementation using reg dma v1.
+ * reg_dmav1_setup_dspp_gcv18() - gc v18 implementation using reg dma v1.
* @ctx: dspp ctx info
* @cfg: pointer to struct sde_hw_cp_cfg
*/
void reg_dmav1_setup_dspp_gcv18(struct sde_hw_dspp *ctx, void *cfg);
/**
+ * reg_dmav1_setup_dspp_igcv31() - igc v31 implementation using reg dma v1.
+ * @ctx: dspp ctx info
+ * @cfg: pointer to struct sde_hw_cp_cfg
+ */
+void reg_dmav1_setup_dspp_igcv31(struct sde_hw_dspp *ctx, void *cfg);
+
+/**
+ * reg_dmav1_setup_dspp_pccv4() - pcc v4 implementation using reg dma v1.
+ * @ctx: dspp ctx info
+ * @cfg: pointer to struct sde_hw_cp_cfg
+ */
+void reg_dmav1_setup_dspp_pccv4(struct sde_hw_dspp *ctx, void *cfg);
+
+/**
* reg_dmav1_deinit_dspp_ops() - deinitialize the dspp feature op for sde v4
* which were initialized.
* @idx: dspp idx
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c
index b773187..613ac53 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c
@@ -38,6 +38,18 @@
#define MDP_WD_TIMER_0_CTL 0x380
#define MDP_WD_TIMER_0_CTL2 0x384
#define MDP_WD_TIMER_0_LOAD_VALUE 0x388
+#define MDP_WD_TIMER_1_CTL 0x390
+#define MDP_WD_TIMER_1_CTL2 0x394
+#define MDP_WD_TIMER_1_LOAD_VALUE 0x398
+#define MDP_WD_TIMER_2_CTL 0x420
+#define MDP_WD_TIMER_2_CTL2 0x424
+#define MDP_WD_TIMER_2_LOAD_VALUE 0x428
+#define MDP_WD_TIMER_3_CTL 0x430
+#define MDP_WD_TIMER_3_CTL2 0x434
+#define MDP_WD_TIMER_3_LOAD_VALUE 0x438
+#define MDP_WD_TIMER_4_CTL 0x440
+#define MDP_WD_TIMER_4_CTL2 0x444
+#define MDP_WD_TIMER_4_LOAD_VALUE 0x448
#define MDP_TICK_COUNT 16
#define XO_CLK_RATE 19200
@@ -204,38 +216,74 @@ static void sde_hw_get_danger_status(struct sde_hw_mdp *mdp,
status->wb[WB_3] = 0;
}
-static void sde_hw_setup_vsync_sel(struct sde_hw_mdp *mdp,
- struct sde_watchdog_te_status *cfg, bool watchdog_te)
+static void sde_hw_setup_vsync_source(struct sde_hw_mdp *mdp,
+ struct sde_vsync_source_cfg *cfg)
{
- struct sde_hw_blk_reg_map *c = &mdp->hw;
- u32 reg = 0;
- int i = 0;
- u32 pp_offset[] = {0xC, 0x8, 0x4, 0x13};
+ struct sde_hw_blk_reg_map *c;
+ u32 reg, wd_load_value, wd_ctl, wd_ctl2, i;
+ static const u32 pp_offset[PINGPONG_MAX] = {0xC, 0x8, 0x4, 0x13, 0x18};
- if (!mdp)
+ if (!mdp || !cfg || (cfg->pp_count > ARRAY_SIZE(cfg->ppnumber)))
return;
+ c = &mdp->hw;
reg = SDE_REG_READ(c, MDP_VSYNC_SEL);
for (i = 0; i < cfg->pp_count; i++) {
int pp_idx = cfg->ppnumber[i] - PINGPONG_0;
+ if (pp_idx >= ARRAY_SIZE(pp_offset))
+ continue;
- if (watchdog_te)
- reg |= 0xF << pp_offset[pp_idx];
- else
- reg &= ~(0xF << pp_offset[pp_idx]);
+ reg &= ~(0xf << pp_offset[pp_idx]);
+ reg |= (cfg->vsync_source & 0xf) << pp_offset[pp_idx];
}
-
SDE_REG_WRITE(c, MDP_VSYNC_SEL, reg);
- if (watchdog_te) {
- SDE_REG_WRITE(c, MDP_WD_TIMER_0_LOAD_VALUE,
+ if (cfg->vsync_source >= SDE_VSYNC_SOURCE_WD_TIMER_4 &&
+ cfg->vsync_source <= SDE_VSYNC_SOURCE_WD_TIMER_0) {
+ switch (cfg->vsync_source) {
+ case SDE_VSYNC_SOURCE_WD_TIMER_4:
+ wd_load_value = MDP_WD_TIMER_4_LOAD_VALUE;
+ wd_ctl = MDP_WD_TIMER_4_CTL;
+ wd_ctl2 = MDP_WD_TIMER_4_CTL2;
+ break;
+ case SDE_VSYNC_SOURCE_WD_TIMER_3:
+ wd_load_value = MDP_WD_TIMER_3_LOAD_VALUE;
+ wd_ctl = MDP_WD_TIMER_3_CTL;
+ wd_ctl2 = MDP_WD_TIMER_3_CTL2;
+ break;
+ case SDE_VSYNC_SOURCE_WD_TIMER_2:
+ wd_load_value = MDP_WD_TIMER_2_LOAD_VALUE;
+ wd_ctl = MDP_WD_TIMER_2_CTL;
+ wd_ctl2 = MDP_WD_TIMER_2_CTL2;
+ break;
+ case SDE_VSYNC_SOURCE_WD_TIMER_1:
+ wd_load_value = MDP_WD_TIMER_1_LOAD_VALUE;
+ wd_ctl = MDP_WD_TIMER_1_CTL;
+ wd_ctl2 = MDP_WD_TIMER_1_CTL2;
+ break;
+ case SDE_VSYNC_SOURCE_WD_TIMER_0:
+ default:
+ wd_load_value = MDP_WD_TIMER_0_LOAD_VALUE;
+ wd_ctl = MDP_WD_TIMER_0_CTL;
+ wd_ctl2 = MDP_WD_TIMER_0_CTL2;
+ break;
+ }
+
+ if (cfg->is_dummy) {
+ SDE_REG_WRITE(c, wd_ctl2, 0x0);
+ } else {
+ SDE_REG_WRITE(c, wd_load_value,
CALCULATE_WD_LOAD_VALUE(cfg->frame_rate));
- SDE_REG_WRITE(c, MDP_WD_TIMER_0_CTL, BIT(0)); /* clear timer */
- reg = SDE_REG_READ(c, MDP_WD_TIMER_0_CTL2);
- reg |= BIT(8); /* enable heartbeat timer */
- reg |= BIT(0); /* enable WD timer */
- SDE_REG_WRITE(c, MDP_WD_TIMER_0_CTL2, reg);
+ SDE_REG_WRITE(c, wd_ctl, BIT(0)); /* clear timer */
+ reg = SDE_REG_READ(c, wd_ctl2);
+ reg |= BIT(8); /* enable heartbeat timer */
+ reg |= BIT(0); /* enable WD timer */
+ SDE_REG_WRITE(c, wd_ctl2, reg);
+ }
+
+ /* make sure that timers are enabled/disabled for vsync state */
+ wmb();
}
}
@@ -308,7 +356,7 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
ops->setup_cdm_output = sde_hw_setup_cdm_output;
ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl;
ops->get_danger_status = sde_hw_get_danger_status;
- ops->setup_vsync_sel = sde_hw_setup_vsync_sel;
+ ops->setup_vsync_source = sde_hw_setup_vsync_source;
ops->get_safe_status = sde_hw_get_safe_status;
ops->setup_dce = sde_hw_setup_dce;
ops->reset_ubwc = sde_hw_reset_ubwc;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.h b/drivers/gpu/drm/msm/sde/sde_hw_top.h
index 573780e..86c4219 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.h
@@ -78,15 +78,21 @@ struct sde_danger_safe_status {
};
/**
- * struct sde_watchdog_te_status - configure watchdog timer to generate TE
+ * struct sde_vsync_source_cfg - configure vsync source and configure the
+ * watchdog timers if required.
* @pp_count: number of ping pongs active
* @frame_rate: Display frame rate
* @ppnumber: ping pong index array
+ * @vsync_source: vsync source selection
+ * @is_dummy: a dummy source of vsync selection. It must not be selected for
+ * any case other than sde rsc idle request.
*/
-struct sde_watchdog_te_status {
+struct sde_vsync_source_cfg {
u32 pp_count;
u32 frame_rate;
u32 ppnumber[PINGPONG_MAX];
+ u32 vsync_source;
+ bool is_dummy;
};
/**
@@ -155,13 +161,12 @@ struct sde_hw_mdp_ops {
struct sde_danger_safe_status *status);
/**
- * setup_vsync_sel - get vsync configuration details
+ * setup_vsync_source - setup vsync source configuration details
* @mdp: mdp top context driver
- * @cfg: watchdog timer configuration
- * @watchdog_te: watchdog timer enable
+ * @cfg: vsync source selection configuration
*/
- void (*setup_vsync_sel)(struct sde_hw_mdp *mdp,
- struct sde_watchdog_te_status *cfg, bool watchdog_te);
+ void (*setup_vsync_source)(struct sde_hw_mdp *mdp,
+ struct sde_vsync_source_cfg *cfg);
/**
* get_safe_status - get safe status
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index b9fbd62..42af245 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -393,9 +393,6 @@ static void sde_kms_complete_commit(struct msm_kms *kms,
{
struct sde_kms *sde_kms;
struct msm_drm_private *priv;
- struct drm_crtc *crtc;
- struct drm_crtc_state *old_crtc_state;
- int i;
if (!kms || !old_state)
return;
@@ -405,8 +402,6 @@ static void sde_kms_complete_commit(struct msm_kms *kms,
return;
priv = sde_kms->dev->dev_private;
- for_each_crtc_in_state(old_state, crtc, old_crtc_state, i)
- sde_crtc_complete_commit(crtc, old_crtc_state);
sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
@@ -519,8 +514,10 @@ static void sde_kms_prepare_fence(struct msm_kms *kms,
}
/* old_state actually contains updated crtc pointers */
- for_each_crtc_in_state(old_state, crtc, old_crtc_state, i)
- sde_crtc_prepare_commit(crtc, old_crtc_state);
+ for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+ if (crtc->state->active)
+ sde_crtc_prepare_commit(crtc, old_crtc_state);
+ }
}
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 8077756..90e6caf 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -957,15 +957,15 @@ static int _sde_plane_setup_scaler3_lut(struct sde_plane *psde,
cfg->dir_lut = msm_property_get_blob(
&psde->property_info,
- pstate->property_blobs, &cfg->dir_len,
+ &pstate->property_state, &cfg->dir_len,
PLANE_PROP_SCALER_LUT_ED);
cfg->cir_lut = msm_property_get_blob(
&psde->property_info,
- pstate->property_blobs, &cfg->cir_len,
+ &pstate->property_state, &cfg->cir_len,
PLANE_PROP_SCALER_LUT_CIR);
cfg->sep_lut = msm_property_get_blob(
&psde->property_info,
- pstate->property_blobs, &cfg->sep_len,
+ &pstate->property_state, &cfg->sep_len,
PLANE_PROP_SCALER_LUT_SEP);
if (!cfg->dir_lut || !cfg->cir_lut || !cfg->sep_lut)
ret = -ENODATA;
@@ -1276,7 +1276,7 @@ static void sde_color_process_plane_setup(struct drm_plane *plane)
if (psde->pipe_hw->ops.setup_pa_memcolor) {
/* Skin memory color setup */
memcol = msm_property_get_blob(&psde->property_info,
- pstate->property_blobs,
+ &pstate->property_state,
&memcol_sz,
PLANE_PROP_SKIN_COLOR);
psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
@@ -1284,7 +1284,7 @@ static void sde_color_process_plane_setup(struct drm_plane *plane)
/* Sky memory color setup */
memcol = msm_property_get_blob(&psde->property_info,
- pstate->property_blobs,
+ &pstate->property_state,
&memcol_sz,
PLANE_PROP_SKY_COLOR);
psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
@@ -1292,7 +1292,7 @@ static void sde_color_process_plane_setup(struct drm_plane *plane)
/* Foliage memory color setup */
memcol = msm_property_get_blob(&psde->property_info,
- pstate->property_blobs,
+ &pstate->property_state,
&memcol_sz,
PLANE_PROP_FOLIAGE_COLOR);
psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
@@ -1753,6 +1753,15 @@ static void sde_plane_rot_calc_cfg(struct drm_plane *plane,
drm_rect_height(&rstate->out_rot_rect) >> 16,
rstate->out_rot_rect.x1 >> 16,
rstate->out_rot_rect.y1 >> 16);
+ SDE_EVT32_VERBOSE(DRMID(plane), rstate->sequence_id,
+ rstate->out_xpos, rstate->nplane,
+ in_rot->x1 >> 16, in_rot->y1 >> 16,
+ drm_rect_width(in_rot) >> 16,
+ drm_rect_height(in_rot) >> 16,
+ rstate->out_rot_rect.x1 >> 16,
+ rstate->out_rot_rect.y1 >> 16,
+ drm_rect_width(&rstate->out_rot_rect) >> 16,
+ drm_rect_height(&rstate->out_rot_rect) >> 16);
}
/**
@@ -1840,7 +1849,7 @@ static int sde_plane_rot_submit_command(struct drm_plane *plane,
struct sde_hw_fmt_layout layout;
memset(&layout, 0, sizeof(struct sde_hw_fmt_layout));
- sde_format_populate_layout(rstate->aspace, state->fb,
+ sde_format_populate_layout(pstate->aspace, state->fb,
&layout);
for (i = 0; i < ARRAY_SIZE(rot_cmd->src_iova); i++) {
rot_cmd->src_iova[i] = layout.plane_addr[i];
@@ -1849,7 +1858,7 @@ static int sde_plane_rot_submit_command(struct drm_plane *plane,
rot_cmd->src_planes = layout.num_planes;
memset(&layout, 0, sizeof(struct sde_hw_fmt_layout));
- sde_format_populate_layout(rstate->aspace, rstate->out_fb,
+ sde_format_populate_layout(pstate->aspace, rstate->out_fb,
&layout);
for (i = 0; i < ARRAY_SIZE(rot_cmd->dst_iova); i++) {
rot_cmd->dst_iova[i] = layout.plane_addr[i];
@@ -1951,7 +1960,7 @@ static void _sde_plane_rot_get_fb(struct drm_plane *plane,
struct sde_kms_fbo *fbo;
struct drm_framebuffer *fb;
- if (!plane || !cstate || !rstate)
+ if (!plane || !cstate || !rstate || !rstate->rot_hw)
return;
fbo = sde_crtc_res_get(cstate, SDE_CRTC_RES_ROT_OUT_FBO,
@@ -2014,27 +2023,6 @@ static int sde_plane_rot_prepare_fb(struct drm_plane *plane,
if (sde_plane_enabled(new_state) && !new_rstate->out_fb)
_sde_plane_rot_get_fb(plane, cstate, new_rstate);
- /* release buffer if output format configuration changes */
- if (new_rstate->out_fb &&
- ((new_rstate->out_fb_height != new_rstate->out_fb->height) ||
- (new_rstate->out_fb_width != new_rstate->out_fb->width) ||
- (new_rstate->out_fb_pixel_format !=
- new_rstate->out_fb->pixel_format) ||
- (new_rstate->out_fb_modifier[0] !=
- new_rstate->out_fb->modifier[0]) ||
- (new_rstate->out_fb_flags != new_rstate->out_fb->flags))) {
-
- SDE_DEBUG("plane%d.%d release fb/fbo\n", plane->base.id,
- new_rstate->sequence_id);
-
- sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FB,
- (u64) &new_rstate->rot_hw->base);
- new_rstate->out_fb = NULL;
- sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FBO,
- (u64) &new_rstate->rot_hw->base);
- new_rstate->out_fbo = NULL;
- }
-
/* create new stream buffer if it is not available */
if (sde_plane_enabled(new_state) && !new_rstate->out_fb) {
u32 fb_w = drm_rect_width(&new_rstate->out_rot_rect) >> 16;
@@ -2042,7 +2030,6 @@ static int sde_plane_rot_prepare_fb(struct drm_plane *plane,
SDE_DEBUG("plane%d.%d allocate fb/fbo\n", plane->base.id,
new_rstate->sequence_id);
- new_rstate->aspace = new_pstate->aspace;
/* check if out_fb is already attached to rotator */
new_rstate->out_fbo = sde_kms_fbo_alloc(plane->dev, fb_w, fb_h,
@@ -2070,6 +2057,8 @@ static int sde_plane_rot_prepare_fb(struct drm_plane *plane,
ret = -EINVAL;
goto error_create_fb;
}
+ SDE_EVT32_VERBOSE(DRMID(plane), new_rstate->sequence_id,
+ new_rstate->out_fb->base.id);
ret = sde_crtc_res_add(cstate, SDE_CRTC_RES_ROT_OUT_FB,
(u64) &new_rstate->rot_hw->base,
@@ -2081,9 +2070,9 @@ static int sde_plane_rot_prepare_fb(struct drm_plane *plane,
}
/* prepare rotator input buffer */
- ret = msm_framebuffer_prepare(new_state->fb, new_rstate->aspace);
+ ret = msm_framebuffer_prepare(new_state->fb, new_pstate->aspace);
if (ret) {
- SDE_ERROR("failed to prepare input framebuffer\n");
+ SDE_ERROR("failed to prepare input framebuffer, %d\n", ret);
goto error_prepare_input_buffer;
}
@@ -2093,9 +2082,10 @@ static int sde_plane_rot_prepare_fb(struct drm_plane *plane,
new_rstate->sequence_id);
ret = msm_framebuffer_prepare(new_rstate->out_fb,
- new_rstate->aspace);
+ new_pstate->aspace);
if (ret) {
- SDE_ERROR("failed to prepare inline framebuffer\n");
+ SDE_ERROR("failed to prepare inline framebuffer, %d\n",
+ ret);
goto error_prepare_output_buffer;
}
}
@@ -2103,7 +2093,7 @@ static int sde_plane_rot_prepare_fb(struct drm_plane *plane,
return 0;
error_prepare_output_buffer:
- msm_framebuffer_cleanup(new_state->fb, new_rstate->aspace);
+ msm_framebuffer_cleanup(new_state->fb, new_pstate->aspace);
error_prepare_input_buffer:
sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FB,
(u64) &new_rstate->rot_hw->base);
@@ -2159,7 +2149,7 @@ static void sde_plane_rot_cleanup_fb(struct drm_plane *plane,
if (sde_plane_enabled(old_state)) {
if (old_rstate->out_fb) {
msm_framebuffer_cleanup(old_rstate->out_fb,
- old_rstate->aspace);
+ old_pstate->aspace);
sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FB,
(u64) &old_rstate->rot_hw->base);
old_rstate->out_fb = NULL;
@@ -2168,7 +2158,7 @@ static void sde_plane_rot_cleanup_fb(struct drm_plane *plane,
old_rstate->out_fbo = NULL;
}
- msm_framebuffer_cleanup(old_state->fb, old_rstate->aspace);
+ msm_framebuffer_cleanup(old_state->fb, old_pstate->aspace);
}
}
@@ -2222,22 +2212,24 @@ static int sde_plane_rot_atomic_check(struct drm_plane *plane,
rstate->out_sbuf = psde->sbuf_mode || rstate->rot90;
if (sde_plane_enabled(state) && rstate->out_sbuf) {
- SDE_DEBUG("plane%d.%d acquire rotator\n",
- plane->base.id, rstate->sequence_id);
+ SDE_DEBUG("plane%d.%d acquire rotator, fb %d\n",
+ plane->base.id, rstate->sequence_id,
+ state->fb ? state->fb->base.id : -1);
hw_blk = sde_crtc_res_get(cstate, SDE_HW_BLK_ROT,
(u64) state->fb);
if (!hw_blk) {
- SDE_ERROR("plane%d no available rotator\n",
- plane->base.id);
+ SDE_ERROR("plane%d.%d no available rotator, fb %d\n",
+ plane->base.id, rstate->sequence_id,
+ state->fb ? state->fb->base.id : -1);
return -EINVAL;
}
rstate->rot_hw = to_sde_hw_rot(hw_blk);
if (!rstate->rot_hw->ops.commit) {
- SDE_ERROR("plane%d invalid rotator ops\n",
- plane->base.id);
+ SDE_ERROR("plane%d.%d invalid rotator ops\n",
+ plane->base.id, rstate->sequence_id);
sde_crtc_res_put(cstate,
SDE_HW_BLK_ROT, (u64) state->fb);
rstate->rot_hw = NULL;
@@ -2251,19 +2243,44 @@ static int sde_plane_rot_atomic_check(struct drm_plane *plane,
}
if (sde_plane_enabled(state) && rstate->out_sbuf && rstate->rot_hw) {
+ uint32_t fb_id;
- SDE_DEBUG("plane%d.%d use rotator\n",
- plane->base.id, rstate->sequence_id);
+ fb_id = state->fb ? state->fb->base.id : -1;
+ SDE_DEBUG("plane%d.%d use rotator, fb %d\n",
+ plane->base.id, rstate->sequence_id, fb_id);
sde_plane_rot_calc_cfg(plane, state);
- /* attempt to reuse stream buffer if already available */
- if (sde_plane_enabled(state))
- _sde_plane_rot_get_fb(plane, cstate, rstate);
-
ret = sde_plane_rot_submit_command(plane, state,
SDE_HW_ROT_CMD_VALIDATE);
+ if (ret)
+ return ret;
+ /* check if stream buffer is already attached to rotator */
+ _sde_plane_rot_get_fb(plane, cstate, rstate);
+
+ /* release buffer if output format configuration changes */
+ if (rstate->out_fb &&
+ ((rstate->out_fb_height != rstate->out_fb->height) ||
+ (rstate->out_fb_width != rstate->out_fb->width) ||
+ (rstate->out_fb_pixel_format !=
+ rstate->out_fb->pixel_format) ||
+ (rstate->out_fb_modifier[0] !=
+ rstate->out_fb->modifier[0]) ||
+ (rstate->out_fb_flags != rstate->out_fb->flags))) {
+
+ SDE_DEBUG("plane%d.%d release fb/fbo\n", plane->base.id,
+ rstate->sequence_id);
+ SDE_EVT32_VERBOSE(DRMID(plane),
+ rstate->sequence_id, fb_id);
+
+ sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FB,
+ (u64) &rstate->rot_hw->base);
+ rstate->out_fb = NULL;
+ sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FBO,
+ (u64) &rstate->rot_hw->base);
+ rstate->out_fbo = NULL;
+ }
} else {
SDE_DEBUG("plane%d.%d bypass rotator\n", plane->base.id,
@@ -2382,8 +2399,6 @@ static int sde_plane_rot_duplicate_state(struct drm_plane *plane,
{
struct sde_plane_state *pstate = to_sde_plane_state(new_state);
struct sde_plane_rot_state *rstate = &pstate->rot;
- struct drm_crtc_state *cstate;
- int ret;
rstate->sequence_id++;
@@ -2391,19 +2406,7 @@ static int sde_plane_rot_duplicate_state(struct drm_plane *plane,
rstate->sequence_id,
!!rstate->out_sbuf, !!rstate->rot_hw);
- cstate = _sde_plane_get_crtc_state(new_state);
- if (IS_ERR(cstate)) {
- ret = PTR_ERR(cstate);
- SDE_ERROR("invalid crtc state %d\n", ret);
- return -EINVAL;
- }
-
- if (rstate->rot_hw && cstate)
- sde_crtc_res_get(cstate, SDE_HW_BLK_ROT, (u64) rstate->in_fb);
- else if (rstate->rot_hw && !cstate)
- SDE_ERROR("plane%d.%d zombie rotator hw\n",
- plane->base.id, rstate->sequence_id);
-
+ rstate->rot_hw = NULL;
rstate->out_fb = NULL;
rstate->out_fbo = NULL;
@@ -2723,16 +2726,19 @@ static void sde_plane_cleanup_fb(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct sde_plane *psde = to_sde_plane(plane);
+ struct sde_plane_state *old_pstate;
struct sde_plane_rot_state *old_rstate;
- if (!old_state->fb)
+ if (!old_state || !old_state->fb)
return;
+ old_pstate = to_sde_plane_state(old_state);
+
SDE_DEBUG_PLANE(psde, "FB[%u]\n", old_state->fb->base.id);
- old_rstate = &to_sde_plane_state(old_state)->rot;
+ old_rstate = &old_pstate->rot;
- msm_framebuffer_cleanup(old_rstate->out_fb, old_rstate->aspace);
+ msm_framebuffer_cleanup(old_rstate->out_fb, old_pstate->aspace);
sde_plane_rot_cleanup_fb(plane, old_state);
}
@@ -3244,7 +3250,8 @@ static int sde_plane_sspp_atomic_update(struct drm_plane *plane,
}
/* determine what needs to be refreshed */
- while ((idx = msm_property_pop_dirty(&psde->property_info)) >= 0) {
+ while ((idx = msm_property_pop_dirty(&psde->property_info,
+ &pstate->property_state)) >= 0) {
switch (idx) {
case PLANE_PROP_SCALER_V1:
case PLANE_PROP_SCALER_V2:
@@ -3438,7 +3445,7 @@ static int sde_plane_sspp_atomic_update(struct drm_plane *plane,
}
if (psde->pipe_hw->ops.setup_sys_cache) {
- if (rstate->out_sbuf) {
+ if (rstate->out_sbuf && rstate->rot_hw) {
if (rstate->nplane < 2)
pstate->sc_cfg.op_mode =
SDE_PIPE_SC_OP_MODE_INLINE_SINGLE;
@@ -3902,7 +3909,8 @@ static inline void _sde_plane_set_scaler_v1(struct sde_plane *psde,
}
/* force property to be dirty, even if the pointer didn't change */
- msm_property_set_dirty(&psde->property_info, PLANE_PROP_SCALER_V1);
+ msm_property_set_dirty(&psde->property_info,
+ &pstate->property_state, PLANE_PROP_SCALER_V1);
/* populate from user space */
pe = &pstate->pixel_ext;
@@ -3968,7 +3976,8 @@ static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde,
}
/* force property to be dirty, even if the pointer didn't change */
- msm_property_set_dirty(&psde->property_info, PLANE_PROP_SCALER_V2);
+ msm_property_set_dirty(&psde->property_info,
+ &pstate->property_state, PLANE_PROP_SCALER_V2);
/* populate from user space */
pe = &pstate->pixel_ext;
@@ -4085,8 +4094,7 @@ static int sde_plane_atomic_set_property(struct drm_plane *plane,
} else {
pstate = to_sde_plane_state(state);
ret = msm_property_atomic_set(&psde->property_info,
- pstate->property_values, pstate->property_blobs,
- property, val);
+ &pstate->property_state, property, val);
if (!ret) {
idx = msm_property_index(&psde->property_info,
property);
@@ -4103,7 +4111,7 @@ static int sde_plane_atomic_set_property(struct drm_plane *plane,
break;
case PLANE_PROP_SCALER_V2:
_sde_plane_set_scaler_v2(psde, pstate,
- (void *)val);
+ (void *)val);
break;
case PLANE_PROP_EXCL_RECT_V1:
_sde_plane_set_excl_rect_v1(psde, pstate,
@@ -4148,8 +4156,7 @@ static int sde_plane_atomic_get_property(struct drm_plane *plane,
pstate = to_sde_plane_state(state);
sde_plane_rot_install_caps(plane);
ret = msm_property_atomic_get(&psde->property_info,
- pstate->property_values, pstate->property_blobs,
- property, val);
+ &pstate->property_state, property, val);
}
return ret;
@@ -4210,7 +4217,7 @@ static void sde_plane_destroy_state(struct drm_plane *plane,
/* destroy value helper */
msm_property_destroy_state(&psde->property_info, pstate,
- pstate->property_values, pstate->property_blobs);
+ &pstate->property_state);
}
static struct drm_plane_state *
@@ -4241,13 +4248,14 @@ sde_plane_duplicate_state(struct drm_plane *plane)
/* duplicate value helper */
msm_property_duplicate_state(&psde->property_info, old_state, pstate,
- pstate->property_values, pstate->property_blobs);
+ &pstate->property_state, pstate->property_values);
/* clear out any input fence */
pstate->input_fence = 0;
input_fence_default = msm_property_get_default(
&psde->property_info, PLANE_PROP_INPUT_FENCE);
- msm_property_set_property(&psde->property_info, pstate->property_values,
+ msm_property_set_property(&psde->property_info,
+ &pstate->property_state,
PLANE_PROP_INPUT_FENCE, input_fence_default);
pstate->dirty = 0x0;
@@ -4287,7 +4295,8 @@ static void sde_plane_reset(struct drm_plane *plane)
/* reset value helper */
msm_property_reset_state(&psde->property_info, pstate,
- pstate->property_values, pstate->property_blobs);
+ &pstate->property_state,
+ pstate->property_values);
pstate->base.plane = plane;
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h
index be0ea67..a5599a5 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.h
+++ b/drivers/gpu/drm/msm/sde/sde_plane.h
@@ -34,7 +34,6 @@
* @rot90: true if rotation of 90 degree is required
* @hflip: true if horizontal flip is required
* @vflip: true if vertical flip is required
- * @aspace: pointer address space for input/output buffers
* @rot_cmd: rotator configuration command
* @nplane: total number of drm plane attached to rotator
* @in_fb: input fb attached to rotator
@@ -64,7 +63,6 @@ struct sde_plane_rot_state {
bool rot90;
bool hflip;
bool vflip;
- struct msm_gem_address_space *aspace;
struct sde_hw_rot_cmd rot_cmd;
int nplane;
/* input */
@@ -121,8 +119,8 @@ enum sde_plane_sclcheck_state {
/**
* struct sde_plane_state: Define sde extension of drm plane state object
* @base: base drm plane state object
+ * @property_state: Local storage for msm_prop properties
* @property_values: cached plane property values
- * @property_blobs: blob properties
* @aspace: pointer to address space for input/output buffers
* @input_fence: dereferenced input fence pointer
* @stage: assigned by crtc blender
@@ -138,8 +136,8 @@ enum sde_plane_sclcheck_state {
*/
struct sde_plane_state {
struct drm_plane_state base;
- uint64_t property_values[PLANE_PROP_COUNT];
- struct drm_property_blob *property_blobs[PLANE_PROP_BLOBCOUNT];
+ struct msm_property_state property_state;
+ struct msm_property_value property_values[PLANE_PROP_COUNT];
struct msm_gem_address_space *aspace;
void *input_fence;
enum sde_stage stage;
@@ -180,8 +178,8 @@ struct sde_multirect_plane_states {
* @X: Property index, from enum msm_mdp_plane_property
* Returns: Integer value of requested property
*/
-#define sde_plane_get_property(S, X) \
- ((S) && ((X) < PLANE_PROP_COUNT) ? ((S)->property_values[(X)]) : 0)
+#define sde_plane_get_property(S, X) ((S) && ((X) < PLANE_PROP_COUNT) ? \
+ ((S)->property_values[(X)].value) : 0)
/**
* sde_plane_pipe - return sspp identifier for the given plane
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index 0382ed0..be3a8af 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -1150,7 +1150,7 @@ void sde_rm_release(struct sde_rm *rm, struct drm_encoder *enc)
(void) msm_property_set_property(
sde_connector_get_propinfo(conn),
- sde_connector_get_property_values(conn->state),
+ sde_connector_get_property_state(conn->state),
CONNECTOR_PROP_TOPOLOGY_NAME,
SDE_RM_TOPOLOGY_NONE);
}
@@ -1170,7 +1170,7 @@ static int _sde_rm_commit_rsvp(
ret = msm_property_set_property(
sde_connector_get_propinfo(conn_state->connector),
- sde_connector_get_property_values(conn_state),
+ sde_connector_get_property_state(conn_state),
CONNECTOR_PROP_TOPOLOGY_NAME,
rsvp->topology);
if (ret) {
@@ -1267,7 +1267,7 @@ int sde_rm_reserve(
(void) msm_property_set_property(
sde_connector_get_propinfo(
conn_state->connector),
- sde_connector_get_property_values(conn_state),
+ sde_connector_get_property_state(conn_state),
CONNECTOR_PROP_TOPOLOGY_NAME,
SDE_RM_TOPOLOGY_NONE);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_trace.h b/drivers/gpu/drm/msm/sde/sde_trace.h
index e233fc7..47fc39b 100644
--- a/drivers/gpu/drm/msm/sde/sde_trace.h
+++ b/drivers/gpu/drm/msm/sde/sde_trace.h
@@ -125,7 +125,7 @@ TRACE_EVENT(sde_cmd_release_bw,
TP_printk("crtc:%d", __entry->crtc_id)
);
-TRACE_EVENT(sde_mark_write,
+TRACE_EVENT(tracing_mark_write,
TP_PROTO(int pid, const char *name, bool trace_begin),
TP_ARGS(pid, name, trace_begin),
TP_STRUCT__entry(
@@ -230,8 +230,8 @@ TRACE_EVENT(sde_perf_crtc_update,
__entry->update_clk)
);
-#define SDE_ATRACE_END(name) trace_sde_mark_write(current->tgid, name, 0)
-#define SDE_ATRACE_BEGIN(name) trace_sde_mark_write(current->tgid, name, 1)
+#define SDE_ATRACE_END(name) trace_tracing_mark_write(current->tgid, name, 0)
+#define SDE_ATRACE_BEGIN(name) trace_tracing_mark_write(current->tgid, name, 1)
#define SDE_ATRACE_FUNC() SDE_ATRACE_BEGIN(__func__)
#define SDE_ATRACE_INT(name, value) \
diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c
index b058bdd..58448ca 100644
--- a/drivers/gpu/drm/msm/sde_dbg.c
+++ b/drivers/gpu/drm/msm/sde_dbg.c
@@ -55,6 +55,12 @@
#define MMSS_VBIF_TEST_BUS_OUT_CTRL 0x210
#define MMSS_VBIF_TEST_BUS_OUT 0x230
+/* Vbif error info */
+#define MMSS_VBIF_XIN_HALT_CTRL1 0x204
+#define MMSS_VBIF_ERR_INFO 0X1a0
+#define MMSS_VBIF_ERR_INFO_1 0x1a4
+#define MMSS_VBIF_CLIENT_NUM 14
+
/* print debug ranges in groups of 4 u32s */
#define REG_DUMP_ALIGN 16
@@ -2366,7 +2372,8 @@ static void _sde_dbg_dump_vbif_dbg_bus(struct sde_dbg_vbif_debug_bus *bus)
bool in_log, in_mem;
u32 **dump_mem = NULL;
u32 *dump_addr = NULL;
- u32 value;
+ u32 value, d0, d1;
+ unsigned long reg;
struct vbif_debug_bus_entry *head;
phys_addr_t phys = 0;
int i, list_size = 0;
@@ -2439,6 +2446,30 @@ static void _sde_dbg_dump_vbif_dbg_bus(struct sde_dbg_vbif_debug_bus *bus)
/* make sure that vbif core is on */
wmb();
+ /**
+ * Extract VBIF error info based on XIN halt status.
+ * If the XIN client is not in HALT state, then retrieve the
+ * VBIF error info for it.
+ */
+ reg = readl_relaxed(mem_base + MMSS_VBIF_XIN_HALT_CTRL1);
+ dev_err(sde_dbg_base.dev, "XIN HALT:0x%lX\n", reg);
+ reg >>= 16;
+ for (i = 0; i < MMSS_VBIF_CLIENT_NUM; i++) {
+ if (!test_bit(0, ®)) {
+ writel_relaxed(i, mem_base + MMSS_VBIF_ERR_INFO);
+ /* make sure reg write goes through */
+ wmb();
+
+ d0 = readl_relaxed(mem_base + MMSS_VBIF_ERR_INFO);
+ d1 = readl_relaxed(mem_base + MMSS_VBIF_ERR_INFO_1);
+
+ dev_err(sde_dbg_base.dev,
+ "Client:%d, errinfo=0x%X, errinfo1=0x%X\n",
+ i, d0, d1);
+ }
+ reg >>= 1;
+ }
+
for (i = 0; i < bus_size; i++) {
head = dbg_bus + i;
diff --git a/drivers/gpu/drm/msm/sde_dbg.h b/drivers/gpu/drm/msm/sde_dbg.h
index 02d46c7..e14d60e 100644
--- a/drivers/gpu/drm/msm/sde_dbg.h
+++ b/drivers/gpu/drm/msm/sde_dbg.h
@@ -27,6 +27,7 @@
#define SDE_EVTLOG_FUNC_CASE5 0x7777
#define SDE_EVTLOG_PANIC 0xdead
#define SDE_EVTLOG_FATAL 0xbad
+#define SDE_EVTLOG_ERROR 0xebad
#define SDE_DBG_DUMP_DATA_LIMITER (NULL)
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index 9730f0b..54bdd42 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -46,8 +46,9 @@
#define RSC_TIME_SLOT_0_NS ((SINGLE_TCS_EXECUTION_TIME * 2) + 100)
#define DEFAULT_PANEL_FPS 60
-#define DEFAULT_PANEL_JITTER 5
-#define DEFAULT_PANEL_PREFILL_LINES 16
+#define DEFAULT_PANEL_JITTER_NUMERATOR 2
+#define DEFAULT_PANEL_JITTER_DENOMINATOR 1
+#define DEFAULT_PANEL_PREFILL_LINES 25
#define DEFAULT_PANEL_VTOTAL (480 + DEFAULT_PANEL_PREFILL_LINES)
#define TICKS_IN_NANO_SECOND 1000000000
@@ -57,6 +58,13 @@
#define TRY_CLK_MODE_SWITCH 0xFFFE
#define STATE_UPDATE_NOT_ALLOWED 0xFFFD
+/**
+ * Expected primary command mode panel vsync ranges
+ * Note: update if a primary panel is expected to run lower than 60fps
+ */
+#define PRIMARY_VBLANK_MIN_US (18 * 1000)
+#define PRIMARY_VBLANK_MAX_US (20 * 1000)
+
static struct sde_rsc_priv *rsc_prv_list[MAX_RSC_COUNT];
/**
@@ -320,21 +328,25 @@ static u32 sde_rsc_timer_calculate(struct sde_rsc_priv *rsc,
/* calculate for 640x480 60 fps resolution by default */
if (!rsc->cmd_config.fps)
rsc->cmd_config.fps = DEFAULT_PANEL_FPS;
- if (!rsc->cmd_config.jitter)
- rsc->cmd_config.jitter = DEFAULT_PANEL_JITTER;
+ if (!rsc->cmd_config.jitter_numer)
+ rsc->cmd_config.jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR;
+ if (!rsc->cmd_config.jitter_denom)
+ rsc->cmd_config.jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR;
if (!rsc->cmd_config.vtotal)
rsc->cmd_config.vtotal = DEFAULT_PANEL_VTOTAL;
if (!rsc->cmd_config.prefill_lines)
rsc->cmd_config.prefill_lines = DEFAULT_PANEL_PREFILL_LINES;
- pr_debug("frame fps:%d jitter:%d vtotal:%d prefill lines:%d\n",
- rsc->cmd_config.fps, rsc->cmd_config.jitter,
- rsc->cmd_config.vtotal, rsc->cmd_config.prefill_lines);
+ pr_debug("frame fps:%d jitter_numer:%d jitter_denom:%d vtotal:%d prefill lines:%d\n",
+ rsc->cmd_config.fps, rsc->cmd_config.jitter_numer,
+ rsc->cmd_config.jitter_denom, rsc->cmd_config.vtotal,
+ rsc->cmd_config.prefill_lines);
/* 1 nano second */
frame_time_ns = TICKS_IN_NANO_SECOND;
frame_time_ns = div_u64(frame_time_ns, rsc->cmd_config.fps);
- frame_jitter = frame_time_ns * rsc->cmd_config.jitter;
+ frame_jitter = frame_time_ns * rsc->cmd_config.jitter_numer;
+ frame_jitter = div_u64(frame_jitter, rsc->cmd_config.jitter_denom);
/* convert it to percentage */
frame_jitter = div_u64(frame_jitter, 100);
@@ -477,8 +489,7 @@ static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc,
/* wait for vsync for vid to cmd state switch and config update */
if (!rc && (rsc->current_state == SDE_RSC_VID_STATE ||
rsc->current_state == SDE_RSC_CMD_STATE))
- drm_wait_one_vblank(rsc->master_drm,
- rsc->primary_client->crtc_id);
+ usleep_range(PRIMARY_VBLANK_MIN_US, PRIMARY_VBLANK_MAX_US);
end:
return rc;
}
@@ -502,8 +513,7 @@ static int sde_rsc_switch_to_clk(struct sde_rsc_priv *rsc)
/* wait for vsync for cmd to clk state switch */
if (!rc && rsc->primary_client &&
(rsc->current_state == SDE_RSC_CMD_STATE))
- drm_wait_one_vblank(rsc->master_drm,
- rsc->primary_client->crtc_id);
+ usleep_range(PRIMARY_VBLANK_MIN_US, PRIMARY_VBLANK_MAX_US);
end:
return rc;
}
@@ -532,8 +542,7 @@ static int sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc,
/* wait for vsync for cmd to vid state switch */
if (!rc && rsc->primary_client &&
(rsc->current_state == SDE_RSC_CMD_STATE))
- drm_wait_one_vblank(rsc->master_drm,
- rsc->primary_client->crtc_id);
+ usleep_range(PRIMARY_VBLANK_MIN_US, PRIMARY_VBLANK_MAX_US);
end:
return rc;
@@ -749,8 +758,9 @@ static int _sde_debugfs_status_show(struct seq_file *s, void *data)
rsc->timer_config.rsc_time_slot_0_ns);
seq_printf(s, "rsc time slot 1(ns):%d\n",
rsc->timer_config.rsc_time_slot_1_ns);
- seq_printf(s, "frame fps:%d jitter:%d vtotal:%d prefill lines:%d\n",
- rsc->cmd_config.fps, rsc->cmd_config.jitter,
+ seq_printf(s, "frame fps:%d jitter_numer:%d jitter_denom:%d vtotal:%d prefill lines:%d\n",
+ rsc->cmd_config.fps, rsc->cmd_config.jitter_numer,
+ rsc->cmd_config.jitter_denom,
rsc->cmd_config.vtotal, rsc->cmd_config.prefill_lines);
seq_puts(s, "\n");
diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c
index 87a350e..26a3154 100644
--- a/drivers/gpu/drm/msm/sde_rsc_hw.c
+++ b/drivers/gpu/drm/msm/sde_rsc_hw.c
@@ -18,12 +18,14 @@
#include <linux/delay.h>
#include "sde_rsc_priv.h"
+#include "sde_dbg.h"
/* display rsc offset */
#define SDE_RSCC_PDC_SEQ_START_ADDR_REG_OFFSET_DRV0 0x020
#define SDE_RSCC_PDC_MATCH_VALUE_LO_REG_OFFSET_DRV0 0x024
#define SDE_RSCC_PDC_MATCH_VALUE_HI_REG_OFFSET_DRV0 0x028
#define SDE_RSCC_PDC_SLAVE_ID_DRV0 0x02c
+#define SDE_RSCC_SEQ_PROGRAM_COUNTER 0x408
#define SDE_RSCC_SEQ_CFG_BR_ADDR_0_DRV0 0x410
#define SDE_RSCC_SEQ_CFG_BR_ADDR_1_DRV0 0x414
#define SDE_RSCC_SEQ_MEM_0_DRV0 0x600
@@ -299,6 +301,7 @@ static int sde_rsc_mode2_exit(struct sde_rsc_priv *rsc,
{
int rc = -EBUSY;
int count, reg;
+ unsigned long power_status;
rsc_event_trigger(rsc, SDE_RSC_EVENT_PRE_CORE_RESTORE);
@@ -335,9 +338,14 @@ static int sde_rsc_mode2_exit(struct sde_rsc_priv *rsc,
/* make sure that mode-2 exit before wait*/
wmb();
- /* check for sequence running status before exiting */
+ /* this wait is required to make sure that gdsc is powered on */
for (count = MAX_CHECK_LOOPS; count > 0; count--) {
- if (regulator_is_enabled(rsc->fs)) {
+ power_status = dss_reg_r(&rsc->wrapper_io,
+ SDE_RSCC_PWR_CTRL, rsc->debug_mode);
+ if (!test_bit(POWER_CTRL_BIT_12, &power_status)) {
+ reg = dss_reg_r(&rsc->drv_io,
+ SDE_RSCC_SEQ_PROGRAM_COUNTER, rsc->debug_mode);
+ SDE_EVT32(count, reg, power_status);
rc = 0;
break;
}
@@ -415,7 +423,7 @@ static int sde_rsc_mode2_entry(struct sde_rsc_priv *rsc)
rc = 0;
break;
}
- usleep_range(1, 2);
+ usleep_range(10, 100);
}
if (rc) {
diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c
index 1483dae..6f66b73 100644
--- a/drivers/gpu/drm/virtio/virtgpu_object.c
+++ b/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -81,8 +81,10 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
return -ENOMEM;
size = roundup(size, PAGE_SIZE);
ret = drm_gem_object_init(vgdev->ddev, &bo->gem_base, size);
- if (ret != 0)
+ if (ret != 0) {
+ kfree(bo);
return ret;
+ }
bo->dumb = false;
virtio_gpu_init_ttm_placement(bo, pinned);
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 13c36e6..742da91 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -55,7 +55,7 @@ static const struct adreno_vbif_platform a5xx_vbif_platforms[] = {
{ adreno_is_a530, a530_vbif },
{ adreno_is_a512, a540_vbif },
{ adreno_is_a510, a530_vbif },
- { adreno_is_a508, a540_vbif },
+ { adreno_is_a508, a530_vbif },
{ adreno_is_a505, a530_vbif },
{ adreno_is_a506, a530_vbif },
};
diff --git a/drivers/gpu/msm/adreno_a5xx_preempt.c b/drivers/gpu/msm/adreno_a5xx_preempt.c
index 43302a0..4036530 100644
--- a/drivers/gpu/msm/adreno_a5xx_preempt.c
+++ b/drivers/gpu/msm/adreno_a5xx_preempt.c
@@ -547,13 +547,42 @@ static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev)
KGSL_MEMFLAGS_GPUREADONLY, KGSL_MEMDESC_PRIVILEGED,
"smmu_info");
}
+
+static void a5xx_preemption_iommu_close(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device);
+
+ kgsl_free_global(device, &iommu->smmu_info);
+}
+
#else
static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev)
{
return -ENODEV;
}
+
+static void a5xx_preemption_iommu_close(struct adreno_device *adreno_dev)
+{
+}
#endif
+static void a5xx_preemption_close(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_preemption *preempt = &adreno_dev->preempt;
+ struct adreno_ringbuffer *rb;
+ unsigned int i;
+
+ del_timer(&preempt->timer);
+ kgsl_free_global(device, &preempt->counters);
+ a5xx_preemption_iommu_close(adreno_dev);
+
+ FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
+ kgsl_free_global(device, &rb->preemption_desc);
+ }
+}
+
int a5xx_preemption_init(struct adreno_device *adreno_dev)
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
@@ -578,7 +607,7 @@ int a5xx_preemption_init(struct adreno_device *adreno_dev)
A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0,
"preemption_counters");
if (ret)
- return ret;
+ goto err;
addr = preempt->counters.gpuaddr;
@@ -586,10 +615,16 @@ int a5xx_preemption_init(struct adreno_device *adreno_dev)
FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
ret = a5xx_preemption_ringbuffer_init(adreno_dev, rb, addr);
if (ret)
- return ret;
+ goto err;
addr += A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE;
}
- return a5xx_preemption_iommu_init(adreno_dev);
+ ret = a5xx_preemption_iommu_init(adreno_dev);
+
+err:
+ if (ret)
+ a5xx_preemption_close(device);
+
+ return ret;
}
diff --git a/drivers/gpu/msm/adreno_a5xx_snapshot.c b/drivers/gpu/msm/adreno_a5xx_snapshot.c
index 2e5913d..78b56bc 100644
--- a/drivers/gpu/msm/adreno_a5xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a5xx_snapshot.c
@@ -360,8 +360,8 @@ static const unsigned int a5xx_registers[] = {
0x0000, 0x0002, 0x0004, 0x0020, 0x0022, 0x0026, 0x0029, 0x002B,
0x002E, 0x0035, 0x0038, 0x0042, 0x0044, 0x0044, 0x0047, 0x0095,
0x0097, 0x00BB, 0x03A0, 0x0464, 0x0469, 0x046F, 0x04D2, 0x04D3,
- 0x04E0, 0x04F4, 0X04F6, 0x0533, 0x0540, 0x0555, 0xF400, 0xF400,
- 0xF800, 0xF807,
+ 0x04E0, 0x04F4, 0X04F8, 0x0529, 0x0531, 0x0533, 0x0540, 0x0555,
+ 0xF400, 0xF400, 0xF800, 0xF807,
/* CP */
0x0800, 0x081A, 0x081F, 0x0841, 0x0860, 0x0860, 0x0880, 0x08A0,
0x0B00, 0x0B12, 0x0B15, 0X0B1C, 0X0B1E, 0x0B28, 0x0B78, 0x0B7F,
@@ -422,8 +422,8 @@ static const unsigned int a5xx_registers[] = {
* is the stop offset (inclusive)
*/
static const unsigned int a5xx_pre_crashdumper_registers[] = {
- /* RBBM: RBBM_STATUS */
- 0x04F5, 0x04F5,
+ /* RBBM: RBBM_STATUS - RBBM_STATUS3 */
+ 0x04F5, 0x04F7, 0x0530, 0x0530,
/* CP: CP_STATUS_1 */
0x0B1D, 0x0B1D,
};
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 7636a42..6fb81ee 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -530,7 +530,8 @@ int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags)
struct kgsl_device *device = dev_get_drvdata(dev);
struct kgsl_pwrctrl *pwr;
struct kgsl_pwrlevel *pwr_level;
- int level, i;
+ int level;
+ unsigned int i;
unsigned long cur_freq, rec_freq;
struct dev_pm_opp *opp;
@@ -574,7 +575,12 @@ int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags)
/* If the governor recommends a new frequency, update it here */
if (rec_freq != cur_freq) {
level = pwr->max_pwrlevel;
- for (i = pwr->min_pwrlevel; i >= pwr->max_pwrlevel; i--)
+ /*
+ * Array index of pwrlevels[] should be within the permitted
+ * power levels, i.e., from max_pwrlevel to min_pwrlevel.
+ */
+ for (i = pwr->min_pwrlevel; (i >= pwr->max_pwrlevel
+ && i <= pwr->min_pwrlevel); i--)
if (rec_freq <= pwr->pwrlevels[i].gpu_freq) {
if (pwr->thermal_cycle == CYCLE_ACTIVE)
level = _thermal_adjust(pwr, i);
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 6aa2e36..946e0ba 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -85,6 +85,7 @@ struct geni_i2c_dev {
int cur_rd;
struct device *wrapper_dev;
void *ipcl;
+ int clk_fld_idx;
};
struct geni_i2c_err_log {
@@ -109,15 +110,55 @@ static struct geni_i2c_err_log gi2c_log[] = {
[GENI_TIMEOUT] = {-ETIMEDOUT, "I2C TXN timed out"},
};
-static inline void qcom_geni_i2c_conf(void __iomem *base, int dfs, int div)
+struct geni_i2c_clk_fld {
+ u32 clk_freq_out;
+ u8 clk_div;
+ u8 t_high;
+ u8 t_low;
+ u8 t_cycle;
+};
+
+static struct geni_i2c_clk_fld geni_i2c_clk_map[] = {
+ {KHz(100), 7, 10, 11, 26},
+ {KHz(400), 2, 5, 12, 24},
+ {KHz(1000), 1, 3, 9, 18},
+};
+
+static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c)
{
- geni_write_reg(dfs, base, SE_GENI_CLK_SEL);
- geni_write_reg((div << 4) | 1, base, GENI_SER_M_CLK_CFG);
- geni_write_reg(((5 << 20) | (0xC << 10) | 0x18),
- base, SE_I2C_SCL_COUNTERS);
+ int i;
+ int ret = 0;
+ bool clk_map_present = false;
+ struct geni_i2c_clk_fld *itr = geni_i2c_clk_map;
+
+ for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) {
+ if (itr->clk_freq_out == gi2c->i2c_rsc.clk_freq_out) {
+ clk_map_present = true;
+ break;
+ }
+ }
+
+ if (clk_map_present)
+ gi2c->clk_fld_idx = i;
+ else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static inline void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c, int dfs)
+{
+ struct geni_i2c_clk_fld *itr = geni_i2c_clk_map + gi2c->clk_fld_idx;
+
+ geni_write_reg(dfs, gi2c->base, SE_GENI_CLK_SEL);
+
+ geni_write_reg((itr->clk_div << 4) | 1, gi2c->base, GENI_SER_M_CLK_CFG);
+ geni_write_reg(((itr->t_high << 20) | (itr->t_low << 10) |
+ itr->t_cycle), gi2c->base, SE_I2C_SCL_COUNTERS);
+
/*
- * Ensure Clk config completes before return.
- */
+ * Ensure Clk config completes before return.
+ */
mb();
}
@@ -283,7 +324,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
pm_runtime_set_suspended(gi2c->dev);
return ret;
}
- qcom_geni_i2c_conf(gi2c->base, 0, 2);
+ qcom_geni_i2c_conf(gi2c, 0);
dev_dbg(gi2c->dev, "i2c xfer:num:%d, msgs:len:%d,flg:%d\n",
num, msgs[0].len, msgs[0].flags);
for (i = 0; i < num; i++) {
@@ -485,12 +526,26 @@ static int geni_i2c_probe(struct platform_device *pdev)
return ret;
}
+ if (of_property_read_u32(pdev->dev.of_node, "qcom,clk-freq-out",
+ &gi2c->i2c_rsc.clk_freq_out)) {
+ dev_info(&pdev->dev,
+ "Bus frequency not specified, default to 400KHz.\n");
+ gi2c->i2c_rsc.clk_freq_out = KHz(400);
+ }
+
gi2c->irq = platform_get_irq(pdev, 0);
if (gi2c->irq < 0) {
dev_err(gi2c->dev, "IRQ error for i2c-geni\n");
return gi2c->irq;
}
+ ret = geni_i2c_clk_map_idx(gi2c);
+ if (ret) {
+ dev_err(gi2c->dev, "Invalid clk frequency %d KHz: %d\n",
+ gi2c->i2c_rsc.clk_freq_out, ret);
+ return ret;
+ }
+
gi2c->adap.algo = &geni_i2c_algo;
init_completion(&gi2c->xfer);
platform_set_drvdata(pdev, gi2c);
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index cb3f515a..01e3a37 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -2342,6 +2342,10 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
+ if (cmd.port_num < rdma_start_port(ib_dev) ||
+ cmd.port_num > rdma_end_port(ib_dev))
+ return -EINVAL;
+
INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd,
out_len);
@@ -2882,6 +2886,10 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
+ if (cmd.attr.port_num < rdma_start_port(ib_dev) ||
+ cmd.attr.port_num > rdma_end_port(ib_dev))
+ return -EINVAL;
+
uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
if (!uobj)
return -ENOMEM;
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
index c9ea89d..0dea590 100644
--- a/drivers/input/misc/hbtp_input.c
+++ b/drivers/input/misc/hbtp_input.c
@@ -1362,10 +1362,12 @@ static ssize_t hbtp_display_pwr_store(struct kobject *kobj,
ret = kstrtou32(buf, 10, &status);
if (ret) {
pr_err("hbtp: ret error: %zd\n", ret);
+ mutex_unlock(&hbtp->mutex);
return ret;
}
if (!hbtp || !hbtp->input_dev) {
pr_err("hbtp: hbtp or hbtp->input_dev not ready!\n");
+ mutex_unlock(&hbtp->mutex);
return ret;
}
if (status) {
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 1d5c514..142357e 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -238,6 +238,7 @@ enum arm_smmu_s2cr_privcfg {
#define ARM_SMMU_CB_FSYNR0 0x68
#define ARM_SMMU_CB_S1_TLBIVA 0x600
#define ARM_SMMU_CB_S1_TLBIASID 0x610
+#define ARM_SMMU_CB_S1_TLBIALL 0x618
#define ARM_SMMU_CB_S1_TLBIVAL 0x620
#define ARM_SMMU_CB_S2_TLBIIPAS2 0x630
#define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638
@@ -249,6 +250,7 @@ enum arm_smmu_s2cr_privcfg {
#define SCTLR_S1_ASIDPNE (1 << 12)
#define SCTLR_CFCFG (1 << 7)
+#define SCTLR_HUPCF (1 << 8)
#define SCTLR_CFIE (1 << 6)
#define SCTLR_CFRE (1 << 5)
#define SCTLR_E (1 << 4)
@@ -415,6 +417,7 @@ struct arm_smmu_device {
#define ARM_SMMU_OPT_SKIP_INIT (1 << 2)
#define ARM_SMMU_OPT_DYNAMIC (1 << 3)
#define ARM_SMMU_OPT_3LVL_TABLES (1 << 4)
+#define ARM_SMMU_OPT_NO_ASID_RETENTION (1 << 5)
u32 options;
enum arm_smmu_arch_version version;
enum arm_smmu_implementation model;
@@ -534,6 +537,7 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
{ ARM_SMMU_OPT_SKIP_INIT, "qcom,skip-init" },
{ 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" },
{ 0, NULL},
};
@@ -991,12 +995,17 @@ static void arm_smmu_tlb_inv_context(void *cookie)
struct arm_smmu_device *smmu = smmu_domain->smmu;
bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
void __iomem *base;
+ bool use_tlbiall = smmu->options & ARM_SMMU_OPT_NO_ASID_RETENTION;
- if (stage1) {
+ if (stage1 && !use_tlbiall) {
base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
writel_relaxed(ARM_SMMU_CB_ASID(smmu, cfg),
base + ARM_SMMU_CB_S1_TLBIASID);
arm_smmu_tlb_sync_cb(smmu, cfg->cbndx);
+ } else if (stage1 && use_tlbiall) {
+ base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+ writel_relaxed(0, base + ARM_SMMU_CB_S1_TLBIALL);
+ arm_smmu_tlb_sync_cb(smmu, cfg->cbndx);
} else {
base = ARM_SMMU_GR0(smmu);
writel_relaxed(ARM_SMMU_CB_VMID(smmu, cfg),
@@ -1013,8 +1022,9 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
struct arm_smmu_device *smmu = smmu_domain->smmu;
bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
void __iomem *reg;
+ bool use_tlbiall = smmu->options & ARM_SMMU_OPT_NO_ASID_RETENTION;
- if (stage1) {
+ if (stage1 && !use_tlbiall) {
reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
reg += leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA;
@@ -1033,6 +1043,10 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
iova += granule >> 12;
} while (size -= granule);
}
+ } else if (stage1 && use_tlbiall) {
+ reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+ reg += ARM_SMMU_CB_S1_TLBIALL;
+ writel_relaxed(0, reg);
} else if (smmu->version == ARM_SMMU_V2) {
reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
reg += leaf ? ARM_SMMU_CB_S2_TLBIIPAS2L :
@@ -1440,6 +1454,11 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
/* SCTLR */
reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_AFE | SCTLR_TRE;
+ if (smmu_domain->attributes & (1 << DOMAIN_ATTR_CB_STALL_DISABLE)) {
+ reg &= ~SCTLR_CFCFG;
+ reg |= SCTLR_HUPCF;
+ }
+
if ((!(smmu_domain->attributes & (1 << DOMAIN_ATTR_S1_BYPASS)) &&
!(smmu_domain->attributes & (1 << DOMAIN_ATTR_EARLY_MAP))) ||
!stage1)
@@ -2567,19 +2586,23 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
int ret = 0;
+ mutex_lock(&smmu_domain->init_mutex);
switch (attr) {
case DOMAIN_ATTR_NESTING:
*(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED);
- return 0;
+ ret = 0;
+ break;
case DOMAIN_ATTR_PT_BASE_ADDR:
*((phys_addr_t *)data) =
smmu_domain->pgtbl_cfg.arm_lpae_s1_cfg.ttbr[0];
- return 0;
+ ret = 0;
+ break;
case DOMAIN_ATTR_CONTEXT_BANK:
/* context bank index isn't valid until we are attached */
- if (smmu_domain->smmu == NULL)
- return -ENODEV;
-
+ if (smmu_domain->smmu == NULL) {
+ ret = -ENODEV;
+ break;
+ }
*((unsigned int *) data) = smmu_domain->cfg.cbndx;
ret = 0;
break;
@@ -2587,9 +2610,10 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
u64 val;
struct arm_smmu_device *smmu = smmu_domain->smmu;
/* not valid until we are attached */
- if (smmu == NULL)
- return -ENODEV;
-
+ if (smmu == NULL) {
+ ret = -ENODEV;
+ break;
+ }
val = smmu_domain->pgtbl_cfg.arm_lpae_s1_cfg.ttbr[0];
if (smmu_domain->cfg.cbar != CBAR_TYPE_S2_TRANS)
val |= (u64)ARM_SMMU_CB_ASID(smmu, &smmu_domain->cfg)
@@ -2600,8 +2624,10 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
}
case DOMAIN_ATTR_CONTEXTIDR:
/* not valid until attached */
- if (smmu_domain->smmu == NULL)
- return -ENODEV;
+ if (smmu_domain->smmu == NULL) {
+ ret = -ENODEV;
+ break;
+ }
*((u32 *)data) = smmu_domain->cfg.procid;
ret = 0;
break;
@@ -2655,8 +2681,10 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
ret = 0;
break;
case DOMAIN_ATTR_PAGE_TABLE_IS_COHERENT:
- if (!smmu_domain->smmu)
- return -ENODEV;
+ if (!smmu_domain->smmu) {
+ ret = -ENODEV;
+ break;
+ }
*((int *)data) = is_iommu_pt_coherent(smmu_domain);
ret = 0;
break;
@@ -2665,9 +2693,16 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
& (1 << DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT));
ret = 0;
break;
+ case DOMAIN_ATTR_CB_STALL_DISABLE:
+ *((int *)data) = !!(smmu_domain->attributes
+ & (1 << DOMAIN_ATTR_CB_STALL_DISABLE));
+ ret = 0;
+ break;
default:
- return -ENODEV;
+ ret = -ENODEV;
+ break;
}
+ mutex_unlock(&smmu_domain->init_mutex);
return ret;
}
@@ -2842,6 +2877,12 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
break;
}
+ case DOMAIN_ATTR_CB_STALL_DISABLE:
+ if (*((int *)data))
+ smmu_domain->attributes |=
+ 1 << DOMAIN_ATTR_CB_STALL_DISABLE;
+ ret = 0;
+ break;
default:
ret = -ENODEV;
}
@@ -3298,14 +3339,23 @@ static int arm_smmu_alloc_cb(struct iommu_domain *domain,
struct device *dev)
{
struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
u32 i, idx;
int cb = -EINVAL;
bool dynamic;
- /* Dynamic domains must set cbndx through domain attribute */
+ /*
+ * Dynamic domains have already set cbndx through domain attribute.
+ * Verify that they picked a valid value.
+ */
dynamic = is_dynamic_domain(domain);
- if (dynamic)
- return INVALID_CBNDX;
+ if (dynamic) {
+ cb = smmu_domain->cfg.cbndx;
+ if (cb < smmu->num_context_banks)
+ return cb;
+ else
+ return -EINVAL;
+ }
mutex_lock(&smmu->stream_map_mutex);
for_each_cfg_sme(fwspec, i, idx) {
diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c
index c98d8c2..56eff61b 100644
--- a/drivers/iommu/iommu-debug.c
+++ b/drivers/iommu/iommu-debug.c
@@ -71,6 +71,8 @@ static const char *iommu_debug_attr_to_string(enum iommu_attr attr)
return "DOMAIN_ATTR_FAST";
case DOMAIN_ATTR_EARLY_MAP:
return "DOMAIN_ATTR_EARLY_MAP";
+ case DOMAIN_ATTR_CB_STALL_DISABLE:
+ return "DOMAIN_ATTR_CB_STALL_DISABLE";
default:
return "Unknown attr!";
}
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index d2cb1e8..3989bc6 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -330,6 +330,16 @@ bool mbox_controller_is_idle(struct mbox_chan *chan)
}
EXPORT_SYMBOL(mbox_controller_is_idle);
+
+void mbox_chan_debug(struct mbox_chan *chan)
+{
+ if (!chan || !chan->cl || !chan->mbox->debug)
+ return;
+
+ return chan->mbox->debug(chan);
+}
+EXPORT_SYMBOL(mbox_chan_debug);
+
/**
* mbox_request_channel - Request a mailbox channel.
* @cl: Identity of the client requesting the channel.
diff --git a/drivers/mailbox/qti-tcs.c b/drivers/mailbox/qti-tcs.c
index be91a65..c50fc0e 100644
--- a/drivers/mailbox/qti-tcs.c
+++ b/drivers/mailbox/qti-tcs.c
@@ -241,11 +241,11 @@ static void print_response(struct tcs_drv *drv, int m)
return;
msg = resp->msg;
- pr_debug("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n",
+ pr_warn("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n",
resp->idx, resp->m, resp->in_use);
- pr_debug("Msg: state=%d\n", msg->state);
+ pr_warn("Msg: state=%d\n", msg->state);
for (i = 0; i < msg->num_payload; i++)
- pr_debug("addr=0x%x data=0x%x complete=0x%x\n",
+ pr_warn("addr=0x%x data=0x%x complete=0x%x\n",
msg->payload[i].addr,
msg->payload[i].data,
msg->payload[i].complete);
@@ -804,14 +804,14 @@ static void print_tcs_regs(struct tcs_drv *drv, int m)
if (!enable)
return;
- pr_debug("TCS-%d contents:\n", m);
+ pr_warn("TCS-%d contents:\n", m);
for (n = 0; n < tcs->ncpt; n++) {
if (!(enable & BIT(n)))
continue;
addr = read_tcs_reg(base, TCS_DRV_CMD_ADDR, m, n);
data = read_tcs_reg(base, TCS_DRV_CMD_DATA, m, n);
msgid = read_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n);
- pr_debug("\tn=%d addr=0x%x data=0x%x hdr=0x%x\n",
+ pr_warn("\tn=%d addr=0x%x data=0x%x hdr=0x%x\n",
n, addr, data, msgid);
}
}
@@ -824,7 +824,7 @@ static void dump_tcs_stats(struct tcs_drv *drv)
for (i = 0; i < drv->num_tcs; i++) {
if (!atomic_read(&drv->tcs_in_use[i]))
continue;
- pr_debug("Time: %llu: TCS-%d:\n\tReq Sent:%d Last Sent:%llu\n\tResp Recv:%d Last Recvd:%llu\n",
+ pr_warn("Time: %llu: TCS-%d:\n\tReq Sent:%d Last Sent:%llu\n\tResp Recv:%d Last Recvd:%llu\n",
curr, i,
atomic_read(&drv->tcs_send_count[i]),
drv->tcs_last_sent_ts[i],
@@ -835,6 +835,13 @@ static void dump_tcs_stats(struct tcs_drv *drv)
}
}
+static void chan_debug(struct mbox_chan *chan)
+{
+ struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
+
+ dump_tcs_stats(drv);
+}
+
/**
* chan_tcs_write: Validate the incoming message and write to the
* appropriate TCS block.
@@ -910,7 +917,6 @@ static int chan_tcs_write(struct mbox_chan *chan, void *data)
/* If we were just busy waiting for TCS, dump the state and return */
if (ret == -EBUSY) {
pr_info_ratelimited("TCS Busy, retrying RPMH message send\n");
- dump_tcs_stats(drv);
ret = -EAGAIN;
}
@@ -1162,6 +1168,7 @@ static int tcs_drv_probe(struct platform_device *pdev)
drv->mbox.txdone_irq = true;
drv->mbox.of_xlate = of_tcs_mbox_xlate;
drv->mbox.is_idle = tcs_drv_is_idle;
+ drv->mbox.debug = chan_debug;
drv->num_tcs = st;
drv->pdev = pdev;
INIT_LIST_HEAD(&drv->response_pending);
@@ -1182,7 +1189,7 @@ static int tcs_drv_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq, tcs_irq_handler,
IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND,
- "tcs_irq", drv);
+ drv->name, drv);
if (ret)
return ret;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index eddd360..8ebf1b9 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1861,7 +1861,7 @@ super_1_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
}
sb = page_address(rdev->sb_page);
sb->data_size = cpu_to_le64(num_sectors);
- sb->super_offset = rdev->sb_start;
+ sb->super_offset = cpu_to_le64(rdev->sb_start);
sb->sb_csum = calc_sb_1_csum(sb);
md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
rdev->sb_page);
@@ -2270,7 +2270,7 @@ static bool does_sb_need_changing(struct mddev *mddev)
/* Check if any mddev parameters have changed */
if ((mddev->dev_sectors != le64_to_cpu(sb->size)) ||
(mddev->reshape_position != le64_to_cpu(sb->reshape_position)) ||
- (mddev->layout != le64_to_cpu(sb->layout)) ||
+ (mddev->layout != le32_to_cpu(sb->layout)) ||
(mddev->raid_disks != le32_to_cpu(sb->raid_disks)) ||
(mddev->chunk_sectors != le32_to_cpu(sb->chunksize)))
return true;
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index c68239e..98b067b 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -468,7 +468,7 @@ __must_check int __media_entity_pipeline_start(struct media_entity *entity,
while ((entity_err = media_entity_graph_walk_next(graph))) {
/* don't let the stream_count go negative */
- if (entity->stream_count > 0) {
+ if (entity_err->stream_count > 0) {
entity_err->stream_count--;
if (entity_err->stream_count == 0)
entity_err->pipe = NULL;
diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c
index 2dac48f..dca0592 100644
--- a/drivers/media/pci/saa7134/saa7134-i2c.c
+++ b/drivers/media/pci/saa7134/saa7134-i2c.c
@@ -355,12 +355,43 @@ static struct i2c_client saa7134_client_template = {
/* ----------------------------------------------------------- */
+/* On Medion 7134 reading EEPROM needs DVB-T demod i2c gate open */
+static void saa7134_i2c_eeprom_md7134_gate(struct saa7134_dev *dev)
+{
+ u8 subaddr = 0x7, dmdregval;
+ u8 data[2];
+ int ret;
+ struct i2c_msg i2cgatemsg_r[] = { {.addr = 0x08, .flags = 0,
+ .buf = &subaddr, .len = 1},
+ {.addr = 0x08,
+ .flags = I2C_M_RD,
+ .buf = &dmdregval, .len = 1}
+ };
+ struct i2c_msg i2cgatemsg_w[] = { {.addr = 0x08, .flags = 0,
+ .buf = data, .len = 2} };
+
+ ret = i2c_transfer(&dev->i2c_adap, i2cgatemsg_r, 2);
+ if ((ret == 2) && (dmdregval & 0x2)) {
+ pr_debug("%s: DVB-T demod i2c gate was left closed\n",
+ dev->name);
+
+ data[0] = subaddr;
+ data[1] = (dmdregval & ~0x2);
+ if (i2c_transfer(&dev->i2c_adap, i2cgatemsg_w, 1) != 1)
+ pr_err("%s: EEPROM i2c gate open failure\n",
+ dev->name);
+ }
+}
+
static int
saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len)
{
unsigned char buf;
int i,err;
+ if (dev->board == SAA7134_BOARD_MD7134)
+ saa7134_i2c_eeprom_md7134_gate(dev);
+
dev->i2c_client.addr = 0xa0 >> 1;
buf = 0;
if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) {
diff --git a/drivers/media/platform/msm/broadcast/tspp.c b/drivers/media/platform/msm/broadcast/tspp.c
index 43b426de..7717759 100644
--- a/drivers/media/platform/msm/broadcast/tspp.c
+++ b/drivers/media/platform/msm/broadcast/tspp.c
@@ -46,7 +46,6 @@
#include <linux/msm-bus.h>
#include <linux/interrupt.h> /* tasklet */
#include <asm/arch_timer.h> /* Timer */
-#include <linux/avtimer_kernel.h> /* Timer */
/*
* General defines
@@ -924,8 +923,6 @@ static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
{
int start_hardware = 0;
u32 ctl;
- u32 tts_ctl;
- int retval;
if (tsif_device->ref_count == 0) {
start_hardware = 1;
@@ -978,39 +975,6 @@ static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
pr_warn("tspp: unknown tsif mode 0x%x",
tsif_device->mode);
}
- /* Set 4bytes Time Stamp for TCR */
- if (tsif_device->tts_source == TSIF_TTS_LPASS_TIMER) {
- if (tsif_device->lpass_timer_enable == 0) {
- retval = avcs_core_open();
- if (retval < 0) {
- pr_warn("tspp: avcs open fail:%d\n",
- retval);
- return retval;
- }
- retval = avcs_core_disable_power_collapse(1);
- if (retval < 0) {
- pr_warn("tspp: avcs power enable:%d\n",
- retval);
- return retval;
- }
- tsif_device->lpass_timer_enable = 1;
- }
-
- tts_ctl = readl_relaxed(tsif_device->base +
- TSIF_TTS_CTL_OFF);
- tts_ctl = 0;
- /* Set LPASS Timer TTS source */
- tts_ctl |= TSIF_TTS_CTL_TTS_SOURCE;
- /* Set 4 byte TTS */
- tts_ctl |= TSIF_TTS_CTL_TTS_LENGTH_0;
-
- writel_relaxed(tts_ctl, tsif_device->base +
- TSIF_TTS_CTL_OFF);
- /* write TTS control register */
- wmb();
- tts_ctl = readl_relaxed(tsif_device->base +
- TSIF_TTS_CTL_OFF);
- }
writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
/* write Status control register */
@@ -1035,13 +999,8 @@ static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
{
- if (tsif_device->ref_count == 0) {
- if (tsif_device->lpass_timer_enable == 1) {
- if (avcs_core_disable_power_collapse(0) == 0)
- tsif_device->lpass_timer_enable = 0;
- }
+ if (tsif_device->ref_count == 0)
return;
- }
tsif_device->ref_count--;
@@ -1957,44 +1916,9 @@ EXPORT_SYMBOL(tspp_get_ref_clk_counter);
int tspp_get_lpass_time_counter(u32 dev, enum tspp_source source,
u64 *lpass_time_counter)
{
- struct tspp_device *pdev;
- struct tspp_tsif_device *tsif_device;
-
- if (!lpass_time_counter)
- return -EINVAL;
-
- pdev = tspp_find_by_id(dev);
- if (!pdev) {
- pr_err("tspp_get_lpass_time_counter: can't find device %i\n",
- dev);
- return -ENODEV;
- }
-
- switch (source) {
- case TSPP_SOURCE_TSIF0:
- tsif_device = &pdev->tsif[0];
- break;
-
- case TSPP_SOURCE_TSIF1:
- tsif_device = &pdev->tsif[1];
- break;
-
- default:
- tsif_device = NULL;
- break;
- }
-
- if (tsif_device && tsif_device->ref_count) {
- if (avcs_core_query_timer(lpass_time_counter) < 0) {
- pr_err("tspp_get_lpass_time_counter: read error\n");
- *lpass_time_counter = 0;
- return -ENETRESET;
- }
- } else
- *lpass_time_counter = 0;
-
- return 0;
+ return -EPERM;
}
+
EXPORT_SYMBOL(tspp_get_lpass_time_counter);
/**
@@ -3035,17 +2959,7 @@ static int msm_tspp_probe(struct platform_device *pdev)
goto err_irq;
device->req_irqs = false;
- /* Check whether AV timer time stamps are enabled */
- if (!of_property_read_u32(pdev->dev.of_node, "qcom,lpass-timer-tts",
- &device->tts_source)) {
- if (device->tts_source == 1)
- device->tts_source = TSIF_TTS_LPASS_TIMER;
- else
- device->tts_source = TSIF_TTS_TCR;
- } else {
- device->tts_source = TSIF_TTS_TCR;
- }
-
+ device->tts_source = TSIF_TTS_TCR;
for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
device->tsif[i].tts_source = device->tts_source;
diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm.h b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm.h
index fc7a493..38f13c4 100644
--- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm.h
+++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm.h
@@ -233,6 +233,7 @@ struct cam_cdm {
struct cam_cdm_client *clients[CAM_PER_CDM_MAX_REGISTERED_CLIENTS];
uint8_t bl_tag;
atomic_t error;
+ atomic_t bl_done;
struct cam_cdm_hw_mem gen_irq;
uint32_t cpas_handle;
};
diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_core_common.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_core_common.c
index 341406a..3604357 100644
--- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_core_common.c
+++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_core_common.c
@@ -107,7 +107,7 @@ struct cam_cdm_bl_cb_request_entry *cam_cdm_find_request_by_bl_tag(
if (node->bl_tag == tag)
return node;
}
- pr_err("Could not find the bl request for tag=%d\n", tag);
+ pr_err("Could not find the bl request for tag=%x\n", tag);
return NULL;
}
@@ -216,7 +216,7 @@ int cam_cdm_stream_ops_internal(void *hw_priv,
{
struct cam_hw_info *cdm_hw = hw_priv;
struct cam_cdm *core = NULL;
- int rc = -1;
+ int rc = -EPERM;
int client_idx;
struct cam_cdm_client *client;
uint32_t *handle = start_args;
@@ -476,7 +476,8 @@ int cam_cdm_process_cmd(void *hw_priv,
core->clients[idx] = NULL;
mutex_unlock(
&cdm_hw->hw_mutex);
- rc = -1;
+ rc = -EPERM;
+ pr_err("Invalid ops for virtual cdm\n");
break;
}
} else {
@@ -521,7 +522,7 @@ int cam_cdm_process_cmd(void *hw_priv,
if (client->refcount != 0) {
pr_err("CDM Client refcount not zero %d",
client->refcount);
- rc = -1;
+ rc = -EPERM;
mutex_unlock(&client->lock);
mutex_unlock(&cdm_hw->hw_mutex);
break;
diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c
index 6009c25..5fac7d8 100644
--- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c
+++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c
@@ -66,19 +66,74 @@ int cam_hw_cdm_bl_fifo_pending_bl_rb(struct cam_hw_info *cdm_hw,
if (cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_PENDING_REQ_RB,
pending_bl)) {
pr_err("Failed to read CDM pending BL's\n");
- rc = -1;
+ rc = -EIO;
}
return rc;
}
+static int cam_hw_cdm_enable_bl_done_irq(struct cam_hw_info *cdm_hw,
+ bool enable)
+{
+ int rc = -EIO;
+ uint32_t irq_mask = 0;
+ struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info;
+
+ if (cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_MASK,
+ &irq_mask)) {
+ pr_err("Failed to read CDM IRQ mask\n");
+ return rc;
+ }
+
+ if (enable == true) {
+ if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK,
+ (irq_mask | 0x4))) {
+ pr_err("Write failed to enable BL done irq\n");
+ } else {
+ atomic_inc(&core->bl_done);
+ rc = 0;
+ CDM_CDBG("BL done irq enabled =%d\n",
+ atomic_read(&core->bl_done));
+ }
+ } else {
+ if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK,
+ (irq_mask & 0x70003))) {
+ pr_err("Write failed to disable BL done irq\n");
+ } else {
+ atomic_dec(&core->bl_done);
+ rc = 0;
+ CDM_CDBG("BL done irq disable =%d\n",
+ atomic_read(&core->bl_done));
+ }
+ }
+ return rc;
+}
+
+static int cam_hw_cdm_enable_core(struct cam_hw_info *cdm_hw, bool enable)
+{
+ int rc = 0;
+
+ if (enable == true) {
+ if (cam_cdm_write_hw_reg(cdm_hw, CDM_CFG_CORE_EN, 0x01)) {
+ pr_err("Failed to Write CDM HW core enable\n");
+ rc = -EIO;
+ }
+ } else {
+ if (cam_cdm_write_hw_reg(cdm_hw, CDM_CFG_CORE_EN, 0x02)) {
+ pr_err("Failed to Write CDM HW core disable\n");
+ rc = -EIO;
+ }
+ }
+ return rc;
+}
+
int cam_hw_cdm_enable_core_dbg(struct cam_hw_info *cdm_hw)
{
int rc = 0;
if (cam_cdm_write_hw_reg(cdm_hw, CDM_DBG_CORE_DBUG, 0x10100)) {
pr_err("Failed to Write CDM HW core debug\n");
- rc = -1;
+ rc = -EIO;
}
return rc;
@@ -90,7 +145,7 @@ int cam_hw_cdm_disable_core_dbg(struct cam_hw_info *cdm_hw)
if (cam_cdm_write_hw_reg(cdm_hw, CDM_DBG_CORE_DBUG, 0)) {
pr_err("Failed to Write CDM HW core debug\n");
- rc = -1;
+ rc = -EIO;
}
return rc;
@@ -137,8 +192,8 @@ void cam_hw_cdm_dump_core_debug_registers(
mutex_lock(&cdm_hw->hw_mutex);
cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_CORE_EN, &dump_reg);
pr_err("CDM HW core status=%x\n", dump_reg);
- /* First pause CDM */
- cam_cdm_write_hw_reg(cdm_hw, CDM_CFG_CORE_EN, 0x03);
+ /* First pause CDM, If it fails still proceed to dump debug info */
+ cam_hw_cdm_enable_core(cdm_hw, false);
cam_hw_cdm_bl_fifo_pending_bl_rb(cdm_hw, &dump_reg);
pr_err("CDM HW current pending BL=%x\n", dump_reg);
loop_cnt = dump_reg;
@@ -196,7 +251,7 @@ void cam_hw_cdm_dump_core_debug_registers(
pr_err("CDM HW current pending BL=%x\n", dump_reg);
/* Enable CDM back */
- cam_cdm_write_hw_reg(cdm_hw, CDM_CFG_CORE_EN, 1);
+ cam_hw_cdm_enable_core(cdm_hw, true);
mutex_unlock(&cdm_hw->hw_mutex);
}
@@ -206,7 +261,7 @@ int cam_hw_cdm_wait_for_bl_fifo(struct cam_hw_info *cdm_hw,
{
uint32_t pending_bl = 0;
int32_t available_bl_slots = 0;
- int rc = -1;
+ int rc = -EIO;
long time_left;
struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info;
@@ -214,7 +269,7 @@ int cam_hw_cdm_wait_for_bl_fifo(struct cam_hw_info *cdm_hw,
if (cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_PENDING_REQ_RB,
&pending_bl)) {
pr_err("Failed to read CDM pending BL's\n");
- rc = -1;
+ rc = -EIO;
break;
}
available_bl_slots = CAM_CDM_HWFIFO_SIZE - pending_bl;
@@ -230,14 +285,24 @@ int cam_hw_cdm_wait_for_bl_fifo(struct cam_hw_info *cdm_hw,
rc = bl_count;
break;
} else if (0 == (available_bl_slots - 1)) {
+ rc = cam_hw_cdm_enable_bl_done_irq(cdm_hw, true);
+ if (rc) {
+ pr_err("Enable BL done irq failed\n");
+ break;
+ }
time_left = wait_for_completion_timeout(
&core->bl_complete, msecs_to_jiffies(
CAM_CDM_BL_FIFO_WAIT_TIMEOUT));
if (time_left <= 0) {
pr_err("CDM HW BL Wait timed out failed\n");
- rc = -1;
+ if (cam_hw_cdm_enable_bl_done_irq(cdm_hw,
+ false))
+ pr_err("Disable BL done irq failed\n");
+ rc = -EIO;
break;
}
+ if (cam_hw_cdm_enable_bl_done_irq(cdm_hw, false))
+ pr_err("Disable BL done irq failed\n");
rc = 0;
CDM_CDBG("CDM HW is ready for data\n");
} else {
@@ -286,8 +351,8 @@ int cam_hw_cdm_submit_gen_irq(struct cam_hw_info *cdm_hw,
rc = -EINVAL;
goto end;
}
- CDM_CDBG("CDM write BL last cmd tag=%d total=%d\n",
- core->bl_tag, req->data->cmd_arrary_count);
+ CDM_CDBG("CDM write BL last cmd tag=%x total=%d cookie=%d\n",
+ core->bl_tag, req->data->cmd_arrary_count, req->data->cookie);
node = kzalloc(sizeof(struct cam_cdm_bl_cb_request_entry),
GFP_KERNEL);
if (!node) {
@@ -311,7 +376,7 @@ int cam_hw_cdm_submit_gen_irq(struct cam_hw_info *cdm_hw,
core->bl_tag);
list_del_init(&node->entry);
kfree(node);
- rc = -1;
+ rc = -EIO;
goto end;
}
@@ -320,7 +385,7 @@ int cam_hw_cdm_submit_gen_irq(struct cam_hw_info *cdm_hw,
core->bl_tag);
list_del_init(&node->entry);
kfree(node);
- rc = -1;
+ rc = -EIO;
}
end:
@@ -331,7 +396,7 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw,
struct cam_cdm_hw_intf_cmd_submit_bl *req,
struct cam_cdm_client *client)
{
- int i, rc = -1;
+ int i, rc;
struct cam_cdm_bl_request *cdm_cmd = req->data;
struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info;
uint32_t pending_bl = 0;
@@ -342,10 +407,8 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw,
req->data->cmd_arrary_count, CAM_CDM_HWFIFO_SIZE);
}
- if (atomic_read(&core->error) != 0) {
- pr_err("HW in error state, cannot trigger transactions now\n");
- return rc;
- }
+ if (atomic_read(&core->error))
+ return -EIO;
mutex_lock(&cdm_hw->hw_mutex);
mutex_lock(&client->lock);
@@ -366,13 +429,13 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw,
pr_err("cmd len(%d) is invalid cnt=%d total cnt=%d\n",
cdm_cmd->cmd[i].len, i,
req->data->cmd_arrary_count);
- rc = -1;
+ rc = -EINVAL;
break;
}
- if (atomic_read(&core->error) != 0) {
- pr_err("HW in error state cmd_count=%d total cnt=%d\n",
+ if (atomic_read(&core->error)) {
+ pr_err_ratelimited("In error state cnt=%d total cnt=%d\n",
i, req->data->cmd_arrary_count);
- rc = -1;
+ rc = -EIO;
break;
}
if (write_count == 0) {
@@ -381,7 +444,7 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw,
if (write_count < 0) {
pr_err("wait for bl fifo failed %d:%d\n",
i, req->data->cmd_arrary_count);
- rc = -1;
+ rc = -EIO;
break;
}
} else {
@@ -397,7 +460,7 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw,
if (!cdm_cmd->cmd[i].bl_addr.hw_iova) {
pr_err("Hw bl hw_iova is invalid %d:%d\n",
i, req->data->cmd_arrary_count);
- rc = -1;
+ rc = -EINVAL;
break;
}
rc = 0;
@@ -407,13 +470,16 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw,
} else {
pr_err("Only mem hdl/hw va type is supported %d\n",
req->data->type);
- rc = -1;
+ rc = -EINVAL;
break;
}
if ((!rc) && (hw_vaddr_ptr) && (len) &&
(len >= cdm_cmd->cmd[i].offset)) {
CDM_CDBG("Got the HW VA\n");
+ if (core->bl_tag >=
+ (CAM_CDM_HWFIFO_SIZE - 1))
+ core->bl_tag = 0;
rc = cam_hw_cdm_bl_write(cdm_hw,
((uint32_t)hw_vaddr_ptr +
cdm_cmd->cmd[i].offset),
@@ -421,7 +487,7 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw,
if (rc) {
pr_err("Hw bl write failed %d:%d\n",
i, req->data->cmd_arrary_count);
- rc = -1;
+ rc = -EIO;
break;
}
} else {
@@ -430,23 +496,24 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw,
cdm_cmd->cmd[i].offset);
pr_err("Sanity check failed for %d:%d\n",
i, req->data->cmd_arrary_count);
- rc = -1;
+ rc = -EINVAL;
break;
}
if (!rc) {
CDM_CDBG("write BL success for cnt=%d with tag=%d\n",
i, core->bl_tag);
- core->bl_tag++;
+
CDM_CDBG("Now commit the BL\n");
if (cam_hw_cdm_commit_bl_write(cdm_hw)) {
pr_err("Cannot commit the BL %d tag=%d\n",
- i, (core->bl_tag - 1));
- rc = -1;
+ i, core->bl_tag);
+ rc = -EIO;
break;
}
CDM_CDBG("BL commit success BL %d tag=%d\n", i,
- (core->bl_tag - 1));
+ core->bl_tag);
+ core->bl_tag++;
if ((req->data->flag == true) &&
(i == (req->data->cmd_arrary_count -
1))) {
@@ -455,9 +522,6 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw,
if (rc == 0)
core->bl_tag++;
}
- if (!rc && ((CAM_CDM_HWFIFO_SIZE - 1) ==
- core->bl_tag))
- core->bl_tag = 0;
}
}
mutex_unlock(&client->lock);
@@ -502,7 +566,8 @@ static void cam_hw_cdm_work(struct work_struct *work)
list_del_init(&node->entry);
kfree(node);
} else {
- pr_err("Invalid node for inline irq\n");
+ pr_err("Invalid node for inline irq status=%x data=%x\n",
+ payload->irq_status, payload->irq_data);
}
mutex_unlock(&cdm_hw->hw_mutex);
}
@@ -514,25 +579,30 @@ static void cam_hw_cdm_work(struct work_struct *work)
}
if (payload->irq_status &
CAM_CDM_IRQ_STATUS_INFO_BL_DONE_MASK) {
- pr_err("CDM HW BL done IRQ\n");
- complete(&core->bl_complete);
+ if (atomic_read(&core->bl_done)) {
+ CDM_CDBG("CDM HW BL done IRQ\n");
+ complete(&core->bl_complete);
+ }
}
if (payload->irq_status &
CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK) {
- pr_err("Invalid command IRQ, Need HW reset\n");
+ pr_err_ratelimited("Invalid command IRQ, Need HW reset\n");
+ atomic_inc(&core->error);
+ cam_hw_cdm_dump_core_debug_registers(cdm_hw);
+ }
+ if (payload->irq_status &
+ CAM_CDM_IRQ_STATUS_ERROR_AHB_BUS_MASK) {
+ pr_err_ratelimited("AHB Error IRQ\n");
atomic_inc(&core->error);
cam_hw_cdm_dump_core_debug_registers(cdm_hw);
atomic_dec(&core->error);
}
if (payload->irq_status &
- CAM_CDM_IRQ_STATUS_ERROR_AHB_BUS_MASK) {
- pr_err("AHB IRQ\n");
- cam_hw_cdm_dump_core_debug_registers(cdm_hw);
- }
- if (payload->irq_status &
CAM_CDM_IRQ_STATUS_ERROR_OVER_FLOW_MASK) {
- pr_err("Overflow IRQ\n");
+ pr_err_ratelimited("Overflow Error IRQ\n");
+ atomic_inc(&core->error);
cam_hw_cdm_dump_core_debug_registers(cdm_hw);
+ atomic_dec(&core->error);
}
kfree(payload);
} else {
@@ -552,7 +622,7 @@ static void cam_hw_cdm_iommu_fault_handler(struct iommu_domain *domain,
core = (struct cam_cdm *)cdm_hw->core_info;
atomic_inc(&core->error);
cam_hw_cdm_dump_core_debug_registers(cdm_hw);
- pr_err("Page fault iova addr %pK\n", (void *)iova);
+ pr_err_ratelimited("Page fault iova addr %pK\n", (void *)iova);
cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_PAGEFAULT,
(void *)iova);
atomic_dec(&core->error);
@@ -576,6 +646,11 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data)
&payload->irq_status)) {
pr_err("Failed to read CDM HW IRQ status\n");
}
+ if (!payload->irq_status) {
+ pr_err_ratelimited("Invalid irq received\n");
+ kfree(payload);
+ return IRQ_HANDLED;
+ }
if (payload->irq_status &
CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK) {
if (cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_USR_DATA,
@@ -618,8 +693,7 @@ int cam_hw_cdm_alloc_genirq_mem(void *hw_priv)
genirq_alloc_cmd.align = 0;
genirq_alloc_cmd.size = (8 * CAM_CDM_HWFIFO_SIZE);
genirq_alloc_cmd.smmu_hdl = cdm_core->iommu_hdl.non_secure;
- genirq_alloc_cmd.flags = 0;
- genirq_alloc_cmd.region = CAM_MEM_MGR_REGION_NON_SECURE_IO;
+ genirq_alloc_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE;
rc = cam_mem_mgr_request_mem(&genirq_alloc_cmd,
&genirq_alloc_out);
if (rc) {
@@ -679,6 +753,8 @@ int cam_hw_cdm_init(void *hw_priv,
CDM_CDBG("Enable soc done\n");
/* Before triggering the reset to HW, clear the reset complete */
+ atomic_set(&cdm_core->error, 0);
+ atomic_set(&cdm_core->bl_done, 0);
reinit_completion(&cdm_core->reset_complete);
reinit_completion(&cdm_core->bl_complete);
@@ -713,13 +789,12 @@ int cam_hw_cdm_init(void *hw_priv,
CDM_CDBG("CDM Init success\n");
cdm_hw->hw_state = CAM_HW_STATE_POWER_UP;
cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK, 0x70003);
- cam_cdm_write_hw_reg(cdm_hw, CDM_CFG_CGC_CFG, 0x7);
rc = 0;
goto end;
}
disable_return:
- rc = -1;
+ rc = -EIO;
cam_soc_util_disable_platform_resource(soc_info, true, true);
end:
return rc;
@@ -757,6 +832,8 @@ int cam_hw_cdm_probe(struct platform_device *pdev)
struct cam_cdm *cdm_core = NULL;
struct cam_cdm_private_dt_data *soc_private = NULL;
struct cam_cpas_register_params cpas_parms;
+ struct cam_ahb_vote ahb_vote;
+ struct cam_axi_vote axi_vote;
cdm_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
if (!cdm_hw_intf)
@@ -788,7 +865,7 @@ int cam_hw_cdm_probe(struct platform_device *pdev)
pr_err("Failed to get dt properties\n");
goto release_mem;
}
- cdm_hw_intf->hw_idx = cdm_hw->soc_info.pdev->id;
+ cdm_hw_intf->hw_idx = cdm_hw->soc_info.index;
cdm_core = (struct cam_cdm *)cdm_hw->core_info;
soc_private = (struct cam_cdm_private_dt_data *)
cdm_hw->soc_info.soc_private;
@@ -798,7 +875,6 @@ int cam_hw_cdm_probe(struct platform_device *pdev)
cdm_core->flags = CAM_CDM_FLAG_PRIVATE_CDM;
cdm_core->bl_tag = 0;
- atomic_set(&cdm_core->error, 0);
cdm_core->id = cam_hw_cdm_get_id_by_name(cdm_core->name);
if (cdm_core->id >= CAM_CDM_MAX) {
pr_err("Failed to get CDM HW name for %s\n", cdm_core->name);
@@ -863,10 +939,20 @@ int cam_hw_cdm_probe(struct platform_device *pdev)
cpas_parms.client_handle);
cdm_core->cpas_handle = cpas_parms.client_handle;
+ ahb_vote.type = CAM_VOTE_ABSOLUTE;
+ ahb_vote.vote.level = CAM_SVS_VOTE;
+ axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
+ axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
+ rc = cam_cpas_start(cdm_core->cpas_handle, &ahb_vote, &axi_vote);
+ if (rc) {
+ pr_err("CPAS start failed\n");
+ goto cpas_unregister;
+ }
+
rc = cam_hw_cdm_init(cdm_hw, NULL, 0);
if (rc) {
pr_err("Failed to Init CDM HW\n");
- goto init_failed;
+ goto cpas_stop;
}
cdm_hw->open_count++;
@@ -876,7 +962,7 @@ int cam_hw_cdm_probe(struct platform_device *pdev)
goto deinit;
}
- if (cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_HW_VERSION,
+ if (cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_TITAN_VERSION,
&cdm_core->hw_family_version)) {
pr_err("Failed to read CDM family Version\n");
goto deinit;
@@ -900,14 +986,23 @@ int cam_hw_cdm_probe(struct platform_device *pdev)
rc = cam_hw_cdm_deinit(cdm_hw, NULL, 0);
if (rc) {
pr_err("Failed to Deinit CDM HW\n");
- goto release_platform_resource;
+ cdm_hw->open_count--;
+ goto cpas_stop;
+ }
+
+ rc = cam_cpas_stop(cdm_core->cpas_handle);
+ if (rc) {
+ pr_err("CPAS stop failed\n");
+ cdm_hw->open_count--;
+ goto cpas_unregister;
}
rc = cam_cdm_intf_register_hw_cdm(cdm_hw_intf,
soc_private, CAM_HW_CDM, &cdm_core->index);
if (rc) {
pr_err("HW CDM Interface registration failed\n");
- goto release_platform_resource;
+ cdm_hw->open_count--;
+ goto cpas_unregister;
}
cdm_hw->open_count--;
mutex_unlock(&cdm_hw->hw_mutex);
@@ -920,7 +1015,10 @@ int cam_hw_cdm_probe(struct platform_device *pdev)
if (cam_hw_cdm_deinit(cdm_hw, NULL, 0))
pr_err("Deinit failed for hw\n");
cdm_hw->open_count--;
-init_failed:
+cpas_stop:
+ if (cam_cpas_stop(cdm_core->cpas_handle))
+ pr_err("CPAS stop failed\n");
+cpas_unregister:
if (cam_cpas_unregister_client(cdm_core->cpas_handle))
pr_err("CPAS unregister failed\n");
release_platform_resource:
diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c
index b1b2117..59f5b92 100644
--- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c
+++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c
@@ -42,7 +42,7 @@ static int get_cdm_mgr_refcount(void)
mutex_lock(&cam_cdm_mgr_lock);
if (cdm_mgr.probe_done == false) {
pr_err("CDM intf mgr not probed yet\n");
- rc = -1;
+ rc = -EPERM;
} else {
CDM_CDBG("CDM intf mgr get refcount=%d\n",
cdm_mgr.refcount);
@@ -73,7 +73,7 @@ static void put_cdm_mgr_refcount(void)
static int get_cdm_iommu_handle(struct cam_iommu_handle *cdm_handles,
uint32_t hw_idx)
{
- int rc = -1;
+ int rc = -EPERM;
struct cam_hw_intf *hw = cdm_mgr.nodes[hw_idx].device;
if (hw->hw_ops.get_hw_caps) {
@@ -87,7 +87,7 @@ static int get_cdm_iommu_handle(struct cam_iommu_handle *cdm_handles,
static int get_cdm_index_by_id(char *identifier,
uint32_t cell_index, uint32_t *hw_index)
{
- int rc = -1, i, j;
+ int rc = -EPERM, i, j;
char client_name[128];
CDM_CDBG("Looking for HW id of =%s and index=%d\n",
@@ -125,7 +125,7 @@ static int get_cdm_index_by_id(char *identifier,
int cam_cdm_get_iommu_handle(char *identifier,
struct cam_iommu_handle *cdm_handles)
{
- int i, j, rc = -1;
+ int i, j, rc = -EPERM;
if ((!identifier) || (!cdm_handles))
return -EINVAL;
@@ -164,7 +164,7 @@ EXPORT_SYMBOL(cam_cdm_get_iommu_handle);
int cam_cdm_acquire(struct cam_cdm_acquire_data *data)
{
- int rc = -1;
+ int rc = -EPERM;
struct cam_hw_intf *hw;
uint32_t hw_index = 0;
@@ -179,7 +179,7 @@ int cam_cdm_acquire(struct cam_cdm_acquire_data *data)
if (data->id > CAM_CDM_HW_ANY) {
pr_err("only CAM_CDM_VIRTUAL/CAM_CDM_HW_ANY is supported\n");
- rc = -1;
+ rc = -EPERM;
goto end;
}
rc = get_cdm_index_by_id(data->identifier, data->cell_index,
@@ -200,7 +200,7 @@ int cam_cdm_acquire(struct cam_cdm_acquire_data *data)
}
} else {
pr_err("idx %d doesn't have acquire ops\n", hw_index);
- rc = -1;
+ rc = -EPERM;
}
}
end:
@@ -216,7 +216,7 @@ EXPORT_SYMBOL(cam_cdm_acquire);
int cam_cdm_release(uint32_t handle)
{
uint32_t hw_index;
- int rc = -1;
+ int rc = -EPERM;
struct cam_hw_intf *hw;
if (get_cdm_mgr_refcount()) {
@@ -250,7 +250,7 @@ EXPORT_SYMBOL(cam_cdm_release);
int cam_cdm_submit_bls(uint32_t handle, struct cam_cdm_bl_request *data)
{
uint32_t hw_index;
- int rc = -1;
+ int rc = -EINVAL;
struct cam_hw_intf *hw;
if (!data)
@@ -258,6 +258,7 @@ int cam_cdm_submit_bls(uint32_t handle, struct cam_cdm_bl_request *data)
if (get_cdm_mgr_refcount()) {
pr_err("CDM intf mgr get refcount failed\n");
+ rc = -EPERM;
return rc;
}
@@ -289,11 +290,12 @@ EXPORT_SYMBOL(cam_cdm_submit_bls);
int cam_cdm_stream_on(uint32_t handle)
{
uint32_t hw_index;
- int rc = -1;
+ int rc = -EINVAL;
struct cam_hw_intf *hw;
if (get_cdm_mgr_refcount()) {
pr_err("CDM intf mgr get refcount failed\n");
+ rc = -EPERM;
return rc;
}
@@ -320,11 +322,12 @@ EXPORT_SYMBOL(cam_cdm_stream_on);
int cam_cdm_stream_off(uint32_t handle)
{
uint32_t hw_index;
- int rc = -1;
+ int rc = -EINVAL;
struct cam_hw_intf *hw;
if (get_cdm_mgr_refcount()) {
pr_err("CDM intf mgr get refcount failed\n");
+ rc = -EPERM;
return rc;
}
@@ -351,11 +354,12 @@ EXPORT_SYMBOL(cam_cdm_stream_off);
int cam_cdm_reset_hw(uint32_t handle)
{
uint32_t hw_index;
- int rc = -1;
+ int rc = -EINVAL;
struct cam_hw_intf *hw;
if (get_cdm_mgr_refcount()) {
pr_err("CDM intf mgr get refcount failed\n");
+ rc = -EPERM;
return rc;
}
@@ -426,13 +430,14 @@ int cam_cdm_intf_deregister_hw_cdm(struct cam_hw_intf *hw,
struct cam_cdm_private_dt_data *data, enum cam_cdm_type type,
uint32_t index)
{
- int rc = -1;
+ int rc = -EINVAL;
if ((!hw) || (!data))
- return -EINVAL;
+ return rc;
if (get_cdm_mgr_refcount()) {
pr_err("CDM intf mgr get refcount failed\n");
+ rc = -EPERM;
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_soc.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_soc.c
index 0f5458c..fbf185c 100644
--- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_soc.c
+++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_soc.c
@@ -48,13 +48,13 @@ bool cam_cdm_read_hw_reg(struct cam_hw_info *cdm_hw,
if ((reg > cdm->offset_tbl->offset_max_size) ||
(reg > cdm->offset_tbl->last_offset)) {
- pr_err("CDM accessing invalid reg=%d\n", reg);
+ pr_err_ratelimited("Invalid reg=%d\n", reg);
goto permission_error;
} else {
reg_addr = (base + (CAM_CDM_OFFSET_FROM_REG(
cdm->offset_tbl, reg)));
if (reg_addr > (base + mem_len)) {
- pr_err("accessing invalid mapped region %d\n", reg);
+ pr_err_ratelimited("Invalid mapped region %d\n", reg);
goto permission_error;
}
*value = cam_io_r_mb(reg_addr);
@@ -84,13 +84,13 @@ bool cam_cdm_write_hw_reg(struct cam_hw_info *cdm_hw,
if ((reg > cdm->offset_tbl->offset_max_size) ||
(reg > cdm->offset_tbl->last_offset)) {
- pr_err("CDM accessing invalid reg=%d\n", reg);
+ pr_err_ratelimited("CDM accessing invalid reg=%d\n", reg);
goto permission_error;
} else {
reg_addr = (base + CAM_CDM_OFFSET_FROM_REG(
cdm->offset_tbl, reg));
if (reg_addr > (base + mem_len)) {
- pr_err("Accessing invalid region %d:%d\n",
+ pr_err_ratelimited("Accessing invalid region %d:%d\n",
reg, (CAM_CDM_OFFSET_FROM_REG(
cdm->offset_tbl, reg)));
goto permission_error;
@@ -106,7 +106,7 @@ bool cam_cdm_write_hw_reg(struct cam_hw_info *cdm_hw,
int cam_cdm_soc_load_dt_private(struct platform_device *pdev,
struct cam_cdm_private_dt_data *ptr)
{
- int i, rc = -1;
+ int i, rc = -EINVAL;
ptr->dt_num_supported_clients = of_property_count_strings(
pdev->dev.of_node,
@@ -186,7 +186,7 @@ int cam_hw_cdm_soc_get_dt_properties(struct cam_hw_info *cdm_hw,
return rc;
error:
- rc = -1;
+ rc = -EINVAL;
kfree(soc_ptr->soc_private);
soc_ptr->soc_private = NULL;
return rc;
diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c
index 3d258b4..a3de3d1 100644
--- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c
+++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c
@@ -323,7 +323,7 @@ int cam_cdm_get_ioremap_from_base(uint32_t hw_base,
struct cam_soc_reg_map *base_table[CAM_SOC_MAX_BLOCK],
void __iomem **device_base)
{
- int ret = -1, i;
+ int ret = -EINVAL, i;
for (i = 0; i < base_array_size; i++) {
if (base_table[i])
diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_virtual_core.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_virtual_core.c
index e34bfc2..bfe14e1 100644
--- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_virtual_core.c
+++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_virtual_core.c
@@ -83,7 +83,7 @@ int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw,
struct cam_cdm_hw_intf_cmd_submit_bl *req,
struct cam_cdm_client *client)
{
- int i, rc = -1;
+ int i, rc = -EINVAL;
struct cam_cdm_bl_request *cdm_cmd = req->data;
struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info;
@@ -97,7 +97,7 @@ int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw,
pr_err("len(%d) is invalid count=%d total cnt=%d\n",
cdm_cmd->cmd[i].len, i,
req->data->cmd_arrary_count);
- rc = -1;
+ rc = -EINVAL;
break;
}
if (req->data->type == CAM_CDM_BL_CMD_TYPE_MEM_HANDLE) {
@@ -113,7 +113,7 @@ int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw,
} else {
pr_err("Only mem hdl/Kernel va type is supported %d\n",
req->data->type);
- rc = -1;
+ rc = -EINVAL;
break;
}
@@ -140,7 +140,7 @@ int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw,
cdm_cmd->cmd[i].offset);
pr_err("Sanity check failed for cmd_count=%d cnt=%d\n",
i, req->data->cmd_arrary_count);
- rc = -1;
+ rc = -EINVAL;
break;
}
if (!rc) {
@@ -229,9 +229,8 @@ int cam_virtual_cdm_probe(struct platform_device *pdev)
}
rc = cam_cdm_soc_load_dt_private(pdev, cdm_hw->soc_info.soc_private);
- if (rc != 0) {
+ if (rc) {
pr_err("Failed to load CDM dt private data\n");
- rc = -1;
kfree(cdm_hw->soc_info.soc_private);
cdm_hw->soc_info.soc_private = NULL;
goto soc_load_failed;
diff --git a/drivers/media/platform/msm/camera/cam_core/Makefile b/drivers/media/platform/msm/camera/cam_core/Makefile
index 60f94d1..6fb1200 100644
--- a/drivers/media/platform/msm/camera/cam_core/Makefile
+++ b/drivers/media/platform/msm/camera/cam_core/Makefile
@@ -1,4 +1,6 @@
ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
obj-$(CONFIG_SPECTRA_CAMERA) += cam_context.o cam_context_utils.o cam_node.o cam_subdev.o
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.h b/drivers/media/platform/msm/camera/cam_core/cam_context.h
index 7f0fb7f..d87c984 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.h
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.h
@@ -13,6 +13,7 @@
#ifndef _CAM_CONTEXT_H_
#define _CAM_CONTEXT_H_
+#include <linux/mutex.h>
#include <linux/spinlock.h>
#include "cam_req_mgr_interface.h"
#include "cam_hw_mgr_intf.h"
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
index edd2e11..e934dff 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
@@ -19,11 +19,12 @@
#include <media/cam_sync.h>
#include <media/cam_defs.h>
-#include "cam_sync_api.h"
-#include "cam_req_mgr_util.h"
+#include "cam_context.h"
#include "cam_mem_mgr.h"
#include "cam_node.h"
-#include "cam_context.h"
+#include "cam_req_mgr_util.h"
+#include "cam_sync_api.h"
+#include "cam_trace.h"
int cam_context_buf_done_from_hw(struct cam_context *ctx,
void *done_event_data, uint32_t bubble_state)
@@ -42,6 +43,8 @@ int cam_context_buf_done_from_hw(struct cam_context *ctx,
req = list_first_entry(&ctx->active_req_list,
struct cam_ctx_request, list);
+ trace_cam_buf_done("UTILS", ctx, req);
+
if (done->request_id != req->request_id) {
pr_err("mismatch: done request [%lld], active request [%lld]\n",
done->request_id, req->request_id);
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c
index ab4c25d..fa26ea0 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_node.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c
@@ -15,6 +15,7 @@
#include <linux/uaccess.h>
#include "cam_node.h"
+#include "cam_trace.h"
static void __cam_node_handle_shutdown(struct cam_node *node)
{
@@ -255,6 +256,8 @@ static int __cam_node_crm_apply_req(struct cam_req_mgr_apply_request *apply)
return -EINVAL;
}
+ trace_cam_apply_req("Node", apply);
+
return cam_context_handle_crm_apply_req(ctx, apply);
}
diff --git a/drivers/media/platform/msm/camera/cam_icp/Makefile b/drivers/media/platform/msm/camera/cam_icp/Makefile
index b35e4e4..5aba168 100644
--- a/drivers/media/platform/msm/camera/cam_icp/Makefile
+++ b/drivers/media/platform/msm/camera/cam_icp/Makefile
@@ -8,6 +8,7 @@
ccflags-y += -Idrivers/media/platform/msm/camera/cam_icp/fw_inc
ccflags-y += -Idrivers/media/platform/msm/camera
ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
obj-$(CONFIG_SPECTRA_CAMERA) += icp_hw/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp_subdev.o cam_icp_context.o hfi.o
diff --git a/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.c b/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.c
index 2311f66..776847d 100644
--- a/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.c
+++ b/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.c
@@ -25,6 +25,7 @@
#include "cam_icp_context.h"
#include "cam_req_mgr_util.h"
#include "cam_mem_mgr.h"
+#include "cam_trace.h"
static int __cam_icp_acquire_dev_in_available(struct cam_context *ctx,
struct cam_acquire_dev_cmd *cmd)
@@ -32,8 +33,10 @@ static int __cam_icp_acquire_dev_in_available(struct cam_context *ctx,
int rc;
rc = cam_context_acquire_dev_to_hw(ctx, cmd);
- if (!rc)
+ if (!rc) {
ctx->state = CAM_CTX_ACQUIRED;
+ trace_cam_context_state("ICP", ctx);
+ }
return rc;
}
@@ -48,6 +51,7 @@ static int __cam_icp_release_dev_in_acquired(struct cam_context *ctx,
pr_err("Unable to release device\n");
ctx->state = CAM_CTX_AVAILABLE;
+ trace_cam_context_state("ICP", ctx);
return rc;
}
@@ -57,8 +61,10 @@ static int __cam_icp_start_dev_in_acquired(struct cam_context *ctx,
int rc;
rc = cam_context_start_dev_to_hw(ctx, cmd);
- if (!rc)
+ if (!rc) {
ctx->state = CAM_CTX_READY;
+ trace_cam_context_state("ICP", ctx);
+ }
return rc;
}
@@ -85,6 +91,7 @@ static int __cam_icp_stop_dev_in_ready(struct cam_context *ctx,
pr_err("Unable to stop device\n");
ctx->state = CAM_CTX_ACQUIRED;
+ trace_cam_context_state("ICP", ctx);
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index fe719c7..f273a7b 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -416,7 +416,8 @@ static int cam_icp_alloc_shared_mem(struct cam_mem_mgr_memory_desc *qtbl)
memset(&out, 0, sizeof(out));
alloc.size = SZ_1M;
alloc.align = 0;
- alloc.region = CAM_MEM_MGR_REGION_SHARED;
+ alloc.flags = CAM_MEM_FLAG_HW_READ_WRITE |
+ CAM_MEM_FLAG_HW_SHARED_ACCESS;
alloc.smmu_hdl = icp_hw_mgr.iommu_hdl;
rc = cam_mem_mgr_request_mem(&alloc, &out);
if (rc)
@@ -462,7 +463,7 @@ static int cam_icp_allocate_hfi_mem(void)
int rc;
rc = cam_smmu_get_region_info(icp_hw_mgr.iommu_hdl,
- CAM_MEM_MGR_REGION_SHARED,
+ CAM_SMMU_REGION_SHARED,
&icp_hw_mgr.hfi_mem.shmem);
if (rc) {
pr_err("Unable to get shared memory info\n");
diff --git a/drivers/media/platform/msm/camera/cam_isp/Makefile b/drivers/media/platform/msm/camera/cam_isp/Makefile
index 77ad6fc..4851535 100644
--- a/drivers/media/platform/msm/camera/cam_isp/Makefile
+++ b/drivers/media/platform/msm/camera/cam_isp/Makefile
@@ -1,8 +1,9 @@
-ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
-ccflags-y += -Idrivers/media/platform/msm/camera/utils
-ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
obj-$(CONFIG_SPECTRA_CAMERA) += isp_hw_mgr/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp_dev.o cam_isp_context.o
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index 83009d2..766ea89 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -21,10 +21,48 @@
#include "cam_mem_mgr.h"
#include "cam_sync_api.h"
#include "cam_req_mgr_dev.h"
+#include "cam_trace.h"
#undef CDBG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+static uint64_t __cam_isp_ctx_get_event_ts(uint32_t evt_id, void *evt_data)
+{
+ uint64_t ts = 0;
+
+ if (!evt_data)
+ return 0;
+
+ switch (evt_id) {
+ case CAM_ISP_HW_EVENT_ERROR:
+ ts = ((struct cam_isp_hw_error_event_data *)evt_data)->
+ timestamp;
+ break;
+ case CAM_ISP_HW_EVENT_SOF:
+ ts = ((struct cam_isp_hw_sof_event_data *)evt_data)->
+ timestamp;
+ break;
+ case CAM_ISP_HW_EVENT_REG_UPDATE:
+ ts = ((struct cam_isp_hw_reg_update_event_data *)evt_data)->
+ timestamp;
+ break;
+ case CAM_ISP_HW_EVENT_EPOCH:
+ ts = ((struct cam_isp_hw_epoch_event_data *)evt_data)->
+ timestamp;
+ break;
+ case CAM_ISP_HW_EVENT_EOF:
+ ts = ((struct cam_isp_hw_eof_event_data *)evt_data)->
+ timestamp;
+ break;
+ case CAM_ISP_HW_EVENT_DONE:
+ break;
+ default:
+ CDBG("%s: Invalid Event Type %d\n", __func__, evt_id);
+ }
+
+ return ts;
+}
+
static int __cam_isp_ctx_handle_buf_done_in_activated_state(
struct cam_isp_context *ctx_isp,
struct cam_isp_hw_done_event_data *done,
@@ -45,6 +83,9 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state(
req = list_first_entry(&ctx->active_req_list,
struct cam_ctx_request, list);
+
+ trace_cam_buf_done("ISP", ctx, req);
+
req_isp = (struct cam_isp_ctx_req *) req->req_priv;
for (i = 0; i < done->num_handles; i++) {
for (j = 0; j < req_isp->num_fence_map_out; j++) {
@@ -99,12 +140,39 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state(
if (req_isp->num_acked == req_isp->num_fence_map_out) {
list_del_init(&req->list);
list_add_tail(&req->list, &ctx->free_req_list);
+ ctx_isp->active_req_cnt--;
+ CDBG("%s: Move active request %lld to free list(cnt = %d)\n",
+ __func__, req->request_id, ctx_isp->active_req_cnt);
}
end:
return rc;
}
+static void __cam_isp_ctx_send_sof_timestamp(
+ struct cam_isp_context *ctx_isp, uint64_t request_id,
+ uint32_t sof_event_status)
+{
+ struct cam_req_mgr_message req_msg;
+
+ req_msg.session_hdl = ctx_isp->base->session_hdl;
+ req_msg.u.frame_msg.frame_id = ctx_isp->frame_id;
+ req_msg.u.frame_msg.request_id = request_id;
+ req_msg.u.frame_msg.timestamp = ctx_isp->sof_timestamp_val;
+ req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl;
+ req_msg.u.frame_msg.sof_status = sof_event_status;
+
+ CDBG("%s: request id:%lld frame number:%lld SOF time stamp:0x%llx\n",
+ __func__, request_id, ctx_isp->frame_id,
+ ctx_isp->sof_timestamp_val);
+ CDBG("%s sof status:%d\n", __func__, sof_event_status);
+
+ if (cam_req_mgr_notify_frame_message(&req_msg,
+ V4L_EVENT_CAM_REQ_MGR_SOF, V4L_EVENT_CAM_REQ_MGR_EVENT))
+ pr_err("%s: Error in notifying the sof time for req id:%lld\n",
+ __func__, request_id);
+}
+
static int __cam_isp_ctx_reg_upd_in_activated_state(
struct cam_isp_context *ctx_isp, void *evt_data)
{
@@ -123,12 +191,15 @@ static int __cam_isp_ctx_reg_upd_in_activated_state(
req_isp = (struct cam_isp_ctx_req *) req->req_priv;
if (req_isp->num_fence_map_out != 0) {
- CDBG("%s: move request %lld to active list\n", __func__,
- req->request_id);
list_add_tail(&req->list, &ctx->active_req_list);
+ ctx_isp->active_req_cnt++;
+ CDBG("%s: move request %lld to active list(cnt = %d)\n",
+ __func__, req->request_id, ctx_isp->active_req_cnt);
} else {
/* no io config, so the request is completed. */
list_add_tail(&req->list, &ctx->free_req_list);
+ CDBG("%s: move active request %lld to free list(cnt = %d)\n",
+ __func__, req->request_id, ctx_isp->active_req_cnt);
}
/*
@@ -145,12 +216,20 @@ static int __cam_isp_ctx_reg_upd_in_activated_state(
static int __cam_isp_ctx_notify_sof_in_actived_state(
struct cam_isp_context *ctx_isp, void *evt_data)
{
- int rc = 0;
struct cam_req_mgr_sof_notify notify;
struct cam_context *ctx = ctx_isp->base;
+ struct cam_ctx_request *req;
+ uint64_t request_id = 0;
- /* notify reqmgr with sof signal */
- if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_sof) {
+ /*
+ * notify reqmgr with sof signal. Note, due to scheduling delay
+ * we can run into situation that two active requests has already
+ * be in the active queue while we try to do the notification.
+ * In this case, we need to skip the current notification. This
+ * helps the state machine to catch up the delay.
+ */
+ if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_sof &&
+ ctx_isp->active_req_cnt <= 2) {
notify.link_hdl = ctx->link_hdl;
notify.dev_hdl = ctx->dev_hdl;
notify.frame_id = ctx_isp->frame_id;
@@ -158,21 +237,40 @@ static int __cam_isp_ctx_notify_sof_in_actived_state(
ctx->ctx_crm_intf->notify_sof(¬ify);
CDBG("%s: Notify CRM SOF frame %lld\n", __func__,
ctx_isp->frame_id);
+
+ list_for_each_entry(req, &ctx->active_req_list, list) {
+ if (req->request_id > ctx_isp->reported_req_id) {
+ request_id = req->request_id;
+ ctx_isp->reported_req_id = request_id;
+ break;
+ }
+ }
+
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_SUCCESS);
} else {
pr_err("%s: Can not notify SOF to CRM\n", __func__);
}
- return rc;
+ return 0;
}
-static int __cam_isp_ctx_sof_in_sof(struct cam_isp_context *ctx_isp,
- void *evt_data)
+static int __cam_isp_ctx_sof_in_activated_state(
+ struct cam_isp_context *ctx_isp, void *evt_data)
{
int rc = 0;
+ struct cam_isp_hw_sof_event_data *sof_event_data = evt_data;
- CDBG("%s: Enter\n", __func__);
+ if (!evt_data) {
+ pr_err("%s: in valid sof event data\n", __func__);
+ return -EINVAL;
+ }
+
ctx_isp->frame_id++;
+ ctx_isp->sof_timestamp_val = sof_event_data->timestamp;
+ CDBG("%s: frame id: %lld time stamp:0x%llx\n", __func__,
+ ctx_isp->frame_id, ctx_isp->sof_timestamp_val);
return rc;
}
@@ -199,11 +297,15 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp,
struct cam_ctx_request, list);
list_del_init(&req->list);
req_isp = (struct cam_isp_ctx_req *) req->req_priv;
- if (req_isp->num_fence_map_out == req_isp->num_acked)
+ if (req_isp->num_fence_map_out == req_isp->num_acked) {
list_add_tail(&req->list, &ctx->free_req_list);
- else {
+ } else {
/* need to handle the buf done */
list_add_tail(&req->list, &ctx->active_req_list);
+ ctx_isp->active_req_cnt++;
+ CDBG("%s: move request %lld to active list(cnt = %d)\n",
+ __func__, req->request_id,
+ ctx_isp->active_req_cnt);
ctx_isp->substate_activated =
CAM_ISP_CTX_ACTIVATED_EPOCH;
}
@@ -215,10 +317,10 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp,
static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp,
void *evt_data)
{
- int rc = 0;
struct cam_ctx_request *req;
struct cam_isp_ctx_req *req_isp;
struct cam_context *ctx = ctx_isp->base;
+ uint64_t request_id = 0;
if (list_empty(&ctx->pending_req_list)) {
/*
@@ -227,6 +329,11 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp,
*/
pr_err("%s: No pending request\n", __func__);
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
+
+ /* Send SOF event as empty frame*/
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+
goto end;
}
@@ -253,14 +360,21 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp,
*/
list_del_init(&req->list);
list_add_tail(&req->list, &ctx->active_req_list);
+ ctx_isp->active_req_cnt++;
+ CDBG("%s: move request %lld to active list(cnt = %d)\n",
+ __func__, req->request_id, ctx_isp->active_req_cnt);
req_isp->bubble_report = 0;
}
+ request_id = req->request_id;
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_ERROR);
+
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE;
CDBG("%s: next substate %d\n", __func__,
ctx_isp->substate_activated);
end:
- return rc;
+ return 0;
}
@@ -280,14 +394,22 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp,
void *evt_data)
{
int rc = 0;
- struct cam_context *ctx = ctx_isp->base;
+ struct cam_context *ctx = ctx_isp->base;
+ struct cam_isp_hw_sof_event_data *sof_event_data = evt_data;
+ if (!evt_data) {
+ pr_err("%s: in valid sof event data\n", __func__);
+ return -EINVAL;
+ }
ctx_isp->frame_id++;
+ ctx_isp->sof_timestamp_val = sof_event_data->timestamp;
+
if (list_empty(&ctx->active_req_list))
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
else
CDBG("%s: Still need to wait for the buf done\n", __func__);
+
CDBG("%s: next substate %d\n", __func__,
ctx_isp->substate_activated);
@@ -305,14 +427,6 @@ static int __cam_isp_ctx_buf_done_in_epoch(struct cam_isp_context *ctx_isp,
return rc;
}
-
-static int __cam_isp_ctx_sof_in_bubble(struct cam_isp_context *ctx_isp,
- void *evt_data)
-{
- ctx_isp->frame_id++;
- return 0;
-}
-
static int __cam_isp_ctx_buf_done_in_bubble(
struct cam_isp_context *ctx_isp, void *evt_data)
{
@@ -324,20 +438,13 @@ static int __cam_isp_ctx_buf_done_in_bubble(
return rc;
}
-static int __cam_isp_ctx_sof_in_bubble_applied(
- struct cam_isp_context *ctx_isp, void *evt_data)
-{
- ctx_isp->frame_id++;
- return 0;
-}
-
-
static int __cam_isp_ctx_epoch_in_bubble_applied(
struct cam_isp_context *ctx_isp, void *evt_data)
{
struct cam_ctx_request *req;
struct cam_isp_ctx_req *req_isp;
struct cam_context *ctx = ctx_isp->base;
+ uint64_t request_id = 0;
/*
* This means we missed the reg upd ack. So we need to
@@ -350,6 +457,9 @@ static int __cam_isp_ctx_epoch_in_bubble_applied(
* Just go back to the bubble state.
*/
pr_err("%s: No pending request.\n", __func__);
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE;
goto end;
}
@@ -376,9 +486,16 @@ static int __cam_isp_ctx_epoch_in_bubble_applied(
*/
list_del_init(&req->list);
list_add_tail(&req->list, &ctx->active_req_list);
+ ctx_isp->active_req_cnt++;
+ CDBG("%s: move request %lld to active list(cnt = %d)\n",
+ __func__, req->request_id, ctx_isp->active_req_cnt);
req_isp->bubble_report = 0;
}
+ request_id = req->request_id;
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_ERROR);
+
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE;
CDBG("%s: next substate %d\n", __func__, ctx_isp->substate_activated);
end:
@@ -457,7 +574,7 @@ static struct cam_isp_ctx_irq_ops
{
.irq_ops = {
NULL,
- __cam_isp_ctx_sof_in_sof,
+ __cam_isp_ctx_sof_in_activated_state,
__cam_isp_ctx_reg_upd_in_sof,
__cam_isp_ctx_notify_sof_in_actived_state,
NULL,
@@ -468,7 +585,7 @@ static struct cam_isp_ctx_irq_ops
{
.irq_ops = {
__cam_isp_ctx_handle_error,
- __cam_isp_ctx_sof_in_sof,
+ __cam_isp_ctx_sof_in_activated_state,
__cam_isp_ctx_reg_upd_in_activated_state,
__cam_isp_ctx_epoch_in_applied,
NULL,
@@ -490,7 +607,7 @@ static struct cam_isp_ctx_irq_ops
{
.irq_ops = {
NULL,
- __cam_isp_ctx_sof_in_bubble,
+ __cam_isp_ctx_sof_in_activated_state,
NULL,
__cam_isp_ctx_notify_sof_in_actived_state,
NULL,
@@ -501,7 +618,7 @@ static struct cam_isp_ctx_irq_ops
{
.irq_ops = {
NULL,
- __cam_isp_ctx_sof_in_bubble_applied,
+ __cam_isp_ctx_sof_in_activated_state,
__cam_isp_ctx_reg_upd_in_activated_state,
__cam_isp_ctx_epoch_in_bubble_applied,
NULL,
@@ -518,7 +635,6 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
uint32_t next_state)
{
int rc = 0;
- int cnt = 0;
struct cam_ctx_request *req;
struct cam_isp_ctx_req *req_isp;
struct cam_isp_context *ctx_isp;
@@ -537,13 +653,12 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
* The maximum number of request allowed to be outstanding is 2.
*
*/
- list_for_each_entry(req, &ctx->active_req_list, list) {
- if (++cnt > 2) {
- pr_err_ratelimited("%s: Apply failed due to congest\n",
- __func__);
- rc = -EFAULT;
- goto end;
- }
+ ctx_isp = (struct cam_isp_context *) ctx->ctx_priv;
+ if (ctx_isp->active_req_cnt >= 2) {
+ CDBG("%s: Reject apply request due to congestion(cnt = %d)\n",
+ __func__, ctx_isp->active_req_cnt);
+ rc = -EFAULT;
+ goto end;
}
req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request,
@@ -560,7 +675,6 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
CDBG("%s: Apply request %lld\n", __func__, req->request_id);
req_isp = (struct cam_isp_ctx_req *) req->req_priv;
- ctx_isp = (struct cam_isp_context *) ctx->ctx_priv;
req_isp->bubble_report = apply->report_if_bubble;
@@ -712,6 +826,8 @@ static int __cam_isp_ctx_flush_req_in_ready(
ctx->state = CAM_CTX_ACQUIRED;
spin_unlock(&ctx->lock);
+ trace_cam_context_state("ISP", ctx);
+
CDBG("%s: Flush request in ready state. next state %d\n",
__func__, ctx->state);
return rc;
@@ -786,6 +902,8 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx,
ctx->link_hdl = 0;
ctx->ctx_crm_intf = NULL;
ctx_isp->frame_id = 0;
+ ctx_isp->active_req_cnt = 0;
+ ctx_isp->reported_req_id = 0;
/*
* Ideally, we should never have any active request here.
@@ -803,6 +921,8 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx,
rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, &flush_req);
ctx->state = CAM_CTX_AVAILABLE;
+
+ trace_cam_context_state("ISP", ctx);
CDBG("%s: next state %d\n", __func__, ctx->state);
return rc;
}
@@ -855,7 +975,7 @@ static int __cam_isp_ctx_config_dev_in_top_state(
CDBG("%s: packet address is 0x%llx\n", __func__, packet_addr);
CDBG("%s: packet with length %zu, offset 0x%llx\n", __func__,
len, cmd->offset);
- CDBG("%s: Packet request id 0x%llx\n", __func__,
+ CDBG("%s: Packet request id %lld\n", __func__,
packet->header.request_id);
CDBG("%s: Packet size 0x%x\n", __func__, packet->header.size);
CDBG("%s: packet op %d\n", __func__, packet->header.op_code);
@@ -1011,6 +1131,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx,
ctx->state = CAM_CTX_ACQUIRED;
+ trace_cam_context_state("ISP", ctx);
CDBG("%s:%d: Acquire success.\n", __func__, __LINE__);
kfree(isp_res);
return rc;
@@ -1032,8 +1153,10 @@ static int __cam_isp_ctx_config_dev_in_acquired(struct cam_context *ctx,
rc = __cam_isp_ctx_config_dev_in_top_state(ctx, cmd);
- if (!rc && ctx->link_hdl)
+ if (!rc && ctx->link_hdl) {
ctx->state = CAM_CTX_READY;
+ trace_cam_context_state("ISP", ctx);
+ }
CDBG("%s: next state %d\n", __func__, ctx->state);
return rc;
@@ -1050,8 +1173,10 @@ static int __cam_isp_ctx_link_in_acquired(struct cam_context *ctx,
ctx->ctx_crm_intf = link->crm_cb;
/* change state only if we had the init config */
- if (!list_empty(&ctx->pending_req_list))
+ if (!list_empty(&ctx->pending_req_list)) {
ctx->state = CAM_CTX_READY;
+ trace_cam_context_state("ISP", ctx);
+ }
CDBG("%s: next state %d\n", __func__, ctx->state);
@@ -1121,6 +1246,8 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
arg.num_hw_update_entries = req_isp->num_cfg;
ctx_isp->frame_id = 0;
+ ctx_isp->active_req_cnt = 0;
+ ctx_isp->reported_req_id = 0;
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
/*
@@ -1129,11 +1256,13 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
* irq handling comes early
*/
ctx->state = CAM_CTX_ACTIVATED;
+ trace_cam_context_state("ISP", ctx);
rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, &arg);
if (rc) {
/* HW failure. user need to clean up the resource */
pr_err("Start HW failed\n");
ctx->state = CAM_CTX_READY;
+ trace_cam_context_state("ISP", ctx);
goto end;
}
CDBG("%s: start device success\n", __func__);
@@ -1149,6 +1278,7 @@ static int __cam_isp_ctx_unlink_in_ready(struct cam_context *ctx,
ctx->link_hdl = 0;
ctx->ctx_crm_intf = NULL;
ctx->state = CAM_CTX_ACQUIRED;
+ trace_cam_context_state("ISP", ctx);
return rc;
}
@@ -1209,6 +1339,8 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock(
list_add_tail(&req->list, &ctx->free_req_list);
}
ctx_isp->frame_id = 0;
+ ctx_isp->active_req_cnt = 0;
+ ctx_isp->reported_req_id = 0;
CDBG("%s: next state %d", __func__, ctx->state);
return rc;
@@ -1221,6 +1353,7 @@ static int __cam_isp_ctx_stop_dev_in_activated(struct cam_context *ctx,
__cam_isp_ctx_stop_dev_in_activated_unlock(ctx);
ctx->state = CAM_CTX_ACQUIRED;
+ trace_cam_context_state("ISP", ctx);
return rc;
}
@@ -1248,6 +1381,7 @@ static int __cam_isp_ctx_release_dev_in_activated(struct cam_context *ctx,
ctx->ctx_crm_intf = NULL;
ctx->state = CAM_CTX_AVAILABLE;
+ trace_cam_context_state("ISP", ctx);
return rc;
}
@@ -1259,8 +1393,9 @@ static int __cam_isp_ctx_apply_req(struct cam_context *ctx,
struct cam_isp_context *ctx_isp =
(struct cam_isp_context *) ctx->ctx_priv;
- CDBG("%s: Enter: apply req in Substate %d\n",
- __func__, ctx_isp->substate_activated);
+ trace_cam_apply_req("ISP", apply);
+ CDBG("%s: Enter: apply req in Substate %d request _id:%lld\n",
+ __func__, ctx_isp->substate_activated, apply->request_id);
if (ctx_isp->substate_machine[ctx_isp->substate_activated].
crm_ops.apply_req) {
rc = ctx_isp->substate_machine[ctx_isp->substate_activated].
@@ -1288,6 +1423,10 @@ static int __cam_isp_ctx_handle_irq_in_activated(void *context,
(struct cam_isp_context *)ctx->ctx_priv;
spin_lock_bh(&ctx->lock);
+
+ trace_cam_isp_activated_irq(ctx, ctx_isp->substate_activated, evt_id,
+ __cam_isp_ctx_get_event_ts(evt_id, evt_data));
+
CDBG("%s: Enter: State %d, Substate %d, evt id %d\n",
__func__, ctx->state, ctx_isp->substate_activated, evt_id);
if (ctx_isp->substate_machine_irq[ctx_isp->substate_activated].
@@ -1383,6 +1522,8 @@ int cam_isp_context_init(struct cam_isp_context *ctx,
ctx->base = ctx_base;
ctx->frame_id = 0;
+ ctx->active_req_cnt = 0;
+ ctx->reported_req_id = 0;
ctx->hw_ctx = NULL;
ctx->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
ctx->substate_machine = cam_isp_ctx_activated_state_machine;
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h
index dae1dda..b0b883c 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h
@@ -106,7 +106,9 @@ struct cam_isp_ctx_req {
* @req_base: Common request object storage
* @req_isp: ISP private request object storage
* @hw_ctx: HW object returned by the acquire device command
- *
+ * @sof_timestamp_val: Captured time stamp value at sof hw event
+ * @active_req_cnt: Counter for the active request
+ * @reported_req_id: Last reported request id
*/
struct cam_isp_context {
struct cam_context *base;
@@ -120,6 +122,9 @@ struct cam_isp_context {
struct cam_isp_ctx_req req_isp[CAM_CTX_REQ_MAX];
void *hw_ctx;
+ uint64_t sof_timestamp_val;
+ int32_t active_req_cnt;
+ int64_t reported_req_id;
};
/**
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/Makefile
index 2c6eaba..7e3c353 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/Makefile
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/Makefile
@@ -7,6 +7,7 @@
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
obj-$(CONFIG_SPECTRA_CAMERA) += hw_utils/ isp_hw/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp_hw_mgr.o cam_ife_hw_mgr.o
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index 2bc4b00..cb38d8f 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -489,6 +489,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_rdi(
continue;
vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops;
+ vfe_acquire.vfe_out.ctx = ife_ctx;
vfe_acquire.vfe_out.out_port_info = out_port;
vfe_acquire.vfe_out.split_id = CAM_ISP_HW_SPLIT_LEFT;
vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index;
@@ -552,6 +553,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_pixel(
vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_OUT;
vfe_acquire.tasklet = ife_ctx->common.tasklet_info;
vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops;
+ vfe_acquire.vfe_out.ctx = ife_ctx;
vfe_acquire.vfe_out.out_port_info = out_port;
vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_vfe;
vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index;
@@ -1334,7 +1336,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
return -EPERM;
}
- CDBG("%s%d: Enter...ctx id:%d\n", __func__, __LINE__, ctx->ctx_index);
+ CDBG("%s:%d Enter ctx id:%d\n", __func__, __LINE__, ctx->ctx_index);
if (cfg->num_hw_update_entries > 0) {
cdm_cmd = ctx->cdm_cmd;
@@ -1980,6 +1982,57 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv,
return rc;
}
+static int cam_ife_mgr_cmd_get_sof_timestamp(
+ struct cam_ife_hw_mgr_ctx *ife_ctx,
+ uint64_t *time_stamp)
+{
+ int rc = -EINVAL;
+ uint32_t i;
+ struct cam_ife_hw_mgr_res *hw_mgr_res;
+ struct cam_hw_intf *hw_intf;
+ struct cam_csid_get_time_stamp_args csid_get_time;
+
+ list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_csid, list) {
+ for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+ if (!hw_mgr_res->hw_res[i] ||
+ (i == CAM_ISP_HW_SPLIT_RIGHT))
+ continue;
+ /*
+ * Get the SOF time stamp from left resource only.
+ * Left resource is master for dual vfe case and
+ * Rdi only context case left resource only hold
+ * the RDI resource
+ */
+ hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+ if (hw_intf->hw_ops.process_cmd) {
+ csid_get_time.node_res =
+ hw_mgr_res->hw_res[i];
+ rc = hw_intf->hw_ops.process_cmd(
+ hw_intf->hw_priv,
+ CAM_IFE_CSID_CMD_GET_TIME_STAMP,
+ &csid_get_time,
+ sizeof(
+ struct cam_csid_get_time_stamp_args));
+ if (!rc)
+ *time_stamp =
+ csid_get_time.time_stamp_val;
+ /*
+ * Single VFE case, Get the time stamp from available
+ * one csid hw in the context
+ * Dual VFE case, get the time stamp from master(left)
+ * would be sufficient
+ */
+ goto end;
+ }
+ }
+ }
+end:
+ if (rc)
+ pr_err("%s:error in getting sof time stamp\n", __func__);
+
+ return rc;
+}
+
static int cam_ife_mgr_process_recovery_cb(void *priv, void *data)
{
int32_t rc = 0;
@@ -2326,7 +2379,9 @@ static int cam_ife_hw_mgr_handle_rup_for_camif_hw_res(
}
- CDBG("%s: Exit (rup_status = %d)!\n", __func__, rup_status);
+ if (!rup_status)
+ CDBG("%s: Exit rup_status = %d\n", __func__, rup_status);
+
return 0;
}
@@ -2470,7 +2525,9 @@ static int cam_ife_hw_mgr_handle_epoch_for_camif_hw_res(
}
}
- CDBG("%s: Exit (epoch_status = %d)!\n", __func__, epoch_status);
+ if (!epoch_status)
+ CDBG("%s: Exit epoch_status = %d\n", __func__, epoch_status);
+
return 0;
}
@@ -2566,11 +2623,16 @@ static int cam_ife_hw_mgr_handle_sof_for_camif_hw_res(
if (core_idx == hw_res_l->hw_intf->hw_idx) {
sof_status = hw_res_l->bottom_half_handler(
hw_res_l, evt_payload);
- if (!sof_status)
+ if (!sof_status) {
+ cam_ife_mgr_cmd_get_sof_timestamp(
+ ife_hwr_mgr_ctx,
+ &sof_done_event_data.timestamp);
+
ife_hwr_irq_sof_cb(
ife_hwr_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_SOF,
&sof_done_event_data);
+ }
}
break;
@@ -2617,12 +2679,16 @@ static int cam_ife_hw_mgr_handle_sof_for_camif_hw_res(
rc = cam_ife_hw_mgr_check_sof_for_dual_vfe(
ife_hwr_mgr_ctx, core_index0, core_index1);
- if (!rc)
+ if (!rc) {
+ cam_ife_mgr_cmd_get_sof_timestamp(
+ ife_hwr_mgr_ctx,
+ &sof_done_event_data.timestamp);
+
ife_hwr_irq_sof_cb(
ife_hwr_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_SOF,
&sof_done_event_data);
-
+ }
break;
default:
@@ -2640,11 +2706,11 @@ static int cam_ife_hw_mgr_handle_buf_done_for_hw_res(
{
int32_t buf_done_status = 0;
- int32_t i = 0;
+ int32_t i;
int32_t rc = 0;
cam_hw_event_cb_func ife_hwr_irq_wm_done_cb;
struct cam_isp_resource_node *hw_res_l = NULL;
- struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx = handler_priv;
+ struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx = NULL;
struct cam_vfe_bus_irq_evt_payload *evt_payload = payload;
struct cam_ife_hw_mgr_res *isp_ife_out_res = NULL;
struct cam_hw_event_recovery_data recovery_data;
@@ -2655,6 +2721,7 @@ static int cam_ife_hw_mgr_handle_buf_done_for_hw_res(
CDBG("%s:Enter\n", __func__);
+ ife_hwr_mgr_ctx = evt_payload->ctx;
ife_hwr_irq_wm_done_cb =
ife_hwr_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_DONE];
@@ -2734,13 +2801,11 @@ static int cam_ife_hw_mgr_handle_buf_done_for_hw_res(
}
break;
}
- CDBG("%s:buf_done status:(%d),isp_ife_out_res->res_id : 0x%x\n",
- __func__, buf_done_status, isp_ife_out_res->res_id);
+ if (!buf_done_status)
+ CDBG("buf_done status:(%d),out_res->res_id: 0x%x\n",
+ buf_done_status, isp_ife_out_res->res_id);
}
-
- CDBG("%s: Exit (buf_done_status (Success) = %d)!\n", __func__,
- buf_done_status);
return rc;
err:
@@ -2775,7 +2840,7 @@ int cam_ife_mgr_do_tasklet_buf_done(void *handler_priv,
return rc;
evt_payload = evt_payload_priv;
- ife_hwr_mgr_ctx = (struct cam_ife_hw_mgr_ctx *)handler_priv;
+ ife_hwr_mgr_ctx = (struct cam_ife_hw_mgr_ctx *)evt_payload->ctx;
CDBG("addr of evt_payload = %llx\n", (uint64_t)evt_payload);
CDBG("bus_irq_status_0: = %x\n", evt_payload->irq_reg_val[0]);
@@ -2786,19 +2851,6 @@ int cam_ife_mgr_do_tasklet_buf_done(void *handler_priv,
CDBG("bus_irq_dual_comp_err: = %x\n", evt_payload->irq_reg_val[5]);
CDBG("bus_irq_dual_comp_owrt: = %x\n", evt_payload->irq_reg_val[6]);
- /*
- * If overflow/overwrite/error/violation are pending
- * for this context it needs to be handled remaining
- * interrupts are ignored.
- */
- rc = cam_ife_hw_mgr_handle_camif_error(ife_hwr_mgr_ctx,
- evt_payload_priv);
- if (rc) {
- pr_err("%s: Encountered Error (%d), ignoring other irqs\n",
- __func__, rc);
- return IRQ_HANDLED;
- }
-
CDBG("%s: Calling Buf_done\n", __func__);
/* WM Done */
return cam_ife_hw_mgr_handle_buf_done_for_hw_res(ife_hwr_mgr_ctx,
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/Makefile
index 19da180..b60e7de 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/Makefile
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/Makefile
@@ -6,6 +6,7 @@
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_tasklet_util.o cam_isp_packet_parser.o
obj-$(CONFIG_SPECTRA_CAMERA) += irq_controller/
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
index bf4d174..9a42b6e 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
@@ -271,14 +271,6 @@ int cam_irq_controller_subscribe_irq(void *irq_controller,
return -EINVAL;
}
- if (sizeof(evt_bit_mask_arr) !=
- sizeof(uint32_t) * controller->num_registers) {
- pr_err("Invalid evt_mask size = %lu expected = %lu\n",
- sizeof(evt_bit_mask_arr),
- sizeof(uint32_t) * controller->num_registers);
- return -EINVAL;
- }
-
evt_handler = kzalloc(sizeof(struct cam_irq_evt_handler), GFP_KERNEL);
if (!evt_handler) {
CDBG("Error allocating hlist_node\n");
@@ -306,6 +298,8 @@ int cam_irq_controller_subscribe_irq(void *irq_controller,
evt_handler->bottom_half = bottom_half;
evt_handler->bottom_half_enqueue_func = bottom_half_enqueue_func;
evt_handler->index = controller->hdl_idx++;
+
+ /* Avoid rollover to negative values */
if (controller->hdl_idx > 0x3FFFFFFF)
controller->hdl_idx = 1;
@@ -468,7 +462,8 @@ static void cam_irq_controller_th_processing(
(void *)th_payload);
if (!rc && evt_handler->bottom_half_handler) {
- CDBG("Enqueuing bottom half\n");
+ CDBG("Enqueuing bottom half for %s\n",
+ controller->name);
if (evt_handler->bottom_half_enqueue_func) {
evt_handler->bottom_half_enqueue_func(
evt_handler->bottom_half,
@@ -492,6 +487,8 @@ irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv)
if (!controller)
return IRQ_NONE;
+ CDBG("locking controller %pK name %s rw_lock %pK\n",
+ controller, controller->name, &controller->rw_lock);
read_lock(&controller->rw_lock);
for (i = 0; i < controller->num_registers; i++) {
controller->irq_status_arr[i] = cam_io_r_mb(
@@ -500,7 +497,8 @@ irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv)
cam_io_w_mb(controller->irq_status_arr[i],
controller->mem_base +
controller->irq_register_arr[i].clear_reg_offset);
- CDBG("Read irq status%d = 0x%x\n", i,
+ CDBG("Read irq status%d (0x%x) = 0x%x\n", i,
+ controller->irq_register_arr[i].status_reg_offset,
controller->irq_status_arr[i]);
for (j = 0; j < CAM_IRQ_PRIORITY_MAX; j++) {
if (controller->irq_register_arr[i].
@@ -512,6 +510,8 @@ irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv)
}
}
read_unlock(&controller->rw_lock);
+ CDBG("unlocked controller %pK name %s rw_lock %pK\n",
+ controller, controller->name, &controller->rw_lock);
CDBG("Status Registers read Successful\n");
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
index 9f2204b4..b32bdb2 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
@@ -50,32 +50,32 @@ enum cam_isp_hw_err_type {
/**
* struct cam_isp_hw_sof_event_data - Event payload for CAM_HW_EVENT_SOF
*
- * @timestamp: Timestamp for the buf done event
+ * @timestamp: Time stamp for the sof event
*
*/
struct cam_isp_hw_sof_event_data {
- struct timeval timestamp;
+ uint64_t timestamp;
};
/**
* struct cam_isp_hw_reg_update_event_data - Event payload for
* CAM_HW_EVENT_REG_UPDATE
*
- * @timestamp: Timestamp for the buf done event
+ * @timestamp: Time stamp for the reg update event
*
*/
struct cam_isp_hw_reg_update_event_data {
- struct timeval timestamp;
+ uint64_t timestamp;
};
/**
* struct cam_isp_hw_epoch_event_data - Event payload for CAM_HW_EVENT_EPOCH
*
- * @timestamp: Timestamp for the buf done event
+ * @timestamp: Time stamp for the epoch event
*
*/
struct cam_isp_hw_epoch_event_data {
- struct timeval timestamp;
+ uint64_t timestamp;
};
/**
@@ -90,29 +90,29 @@ struct cam_isp_hw_done_event_data {
uint32_t num_handles;
uint32_t resource_handle[
CAM_NUM_OUT_PER_COMP_IRQ_MAX];
- struct timeval timestamp;
+ uint64_t timestamp;
};
/**
* struct cam_isp_hw_eof_event_data - Event payload for CAM_HW_EVENT_EOF
*
- * @timestamp: Timestamp for the buf done event
+ * @timestamp: Timestamp for the eof event
*
*/
struct cam_isp_hw_eof_event_data {
- struct timeval timestamp;
+ uint64_t timestamp;
};
/**
* struct cam_isp_hw_error_event_data - Event payload for CAM_HW_EVENT_ERROR
*
- * @error_type: error type for the error event
- * @timestamp: Timestamp for the buf done event
+ * @error_type: Error type for the error event
+ * @timestamp: Timestamp for the error event
*
*/
struct cam_isp_hw_error_event_data {
uint32_t error_type;
- struct timeval timestamp;
+ uint64_t timestamp;
};
/**
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index f09fdc7..e779aef 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -1033,7 +1033,7 @@ static int cam_ife_csid_enable_csi2(
val = (csid_hw->csi2_rx_cfg.lane_num - 1) |
(csid_hw->csi2_rx_cfg.lane_cfg << 4) |
(csid_hw->csi2_rx_cfg.lane_type << 24);
- val |= csid_hw->csi2_rx_cfg.phy_sel & 0x3;
+ val |= (csid_hw->csi2_rx_cfg.phy_sel & 0x3) << 20;
cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr);
@@ -1150,6 +1150,10 @@ static int cam_ife_csid_init_config_ipp_path(
cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
csid_reg->ipp_reg->csid_ipp_cfg0_addr);
+ /* select the post irq sub sample strobe for time stamp capture */
+ cam_io_w_mb(CSID_TIMESTAMP_STB_POST_IRQ, soc_info->reg_map[0].mem_base +
+ csid_reg->ipp_reg->csid_ipp_cfg1_addr);
+
if (path_data->crop_enable) {
val = ((path_data->width +
path_data->start_pixel) & 0xFFFF <<
@@ -1435,6 +1439,10 @@ static int cam_ife_csid_init_config_rdi_path(
cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr);
+ /* select the post irq sub sample strobe for time stamp capture */
+ cam_io_w_mb(CSID_TIMESTAMP_STB_POST_IRQ, soc_info->reg_map[0].mem_base +
+ csid_reg->rdi_reg[id]->csid_rdi_cfg1_addr);
+
if (path_data->crop_enable) {
val = ((path_data->width +
path_data->start_pixel) & 0xFFFF <<
@@ -2220,7 +2228,6 @@ static int cam_ife_csid_process_cmd(void *hw_priv,
csid_hw_info = (struct cam_hw_info *)hw_priv;
csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info;
- mutex_lock(&csid_hw->hw_info->hw_mutex);
switch (cmd_type) {
case CAM_IFE_CSID_CMD_GET_TIME_STAMP:
rc = cam_ife_csid_get_time_stamp(csid_hw, cmd_args);
@@ -2231,7 +2238,6 @@ static int cam_ife_csid_process_cmd(void *hw_priv,
rc = -EINVAL;
break;
}
- mutex_unlock(&csid_hw->hw_info->hw_mutex);
return rc;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
index d36c576..60e184b 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
@@ -65,6 +65,7 @@
#define CSID_PATH_ERROR_PIX_COUNT BIT(13)
#define CSID_PATH_ERROR_LINE_COUNT BIT(14)
+/* enum cam_csid_path_halt_mode select the path halt mode control */
enum cam_csid_path_halt_mode {
CSID_HALT_MODE_INTERNAL,
CSID_HALT_MODE_GLOBAL,
@@ -72,6 +73,16 @@ enum cam_csid_path_halt_mode {
CSID_HALT_MODE_SLAVE,
};
+/**
+ *enum cam_csid_path_timestamp_stb_sel - select the sof/eof strobes used to
+ * capture the timestamp
+ */
+enum cam_csid_path_timestamp_stb_sel {
+ CSID_TIMESTAMP_STB_PRE_HALT,
+ CSID_TIMESTAMP_STB_POST_HALT,
+ CSID_TIMESTAMP_STB_POST_IRQ,
+ CSID_TIMESTAMP_STB_MAX,
+};
struct cam_ife_csid_ipp_reg_offset {
/*Image pixel path register offsets*/
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
index 15db6a6..418280a 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
@@ -108,6 +108,7 @@ struct cam_vfe_hw_get_hw_cap {
* (Default is Master in case of Single VFE)
* @dual_slave_core: If Master and Slave exists, HW Index of Slave
* @cdm_ops: CDM operations
+ * @ctx: Context data
*/
struct cam_vfe_hw_vfe_out_acquire_args {
struct cam_isp_resource_node *rsrc_node;
@@ -118,6 +119,7 @@ struct cam_vfe_hw_vfe_out_acquire_args {
uint32_t is_master;
uint32_t dual_slave_core;
struct cam_cdm_utils_ops *cdm_ops;
+ void *ctx;
};
/*
@@ -192,22 +194,21 @@ struct cam_vfe_top_irq_evt_payload {
*
* @list: list_head node for the payload
* @core_index: Index of VFE HW that generated this IRQ event
- * @core_info: Private data of handler in bottom half context
* @evt_id: IRQ event
* @irq_reg_val: IRQ and Error register values, read when IRQ was
* handled
* @error_type: Identify different errors
* @ts: Timestamp
+ * @ctx: Context data received during acquire
*/
struct cam_vfe_bus_irq_evt_payload {
- struct list_head list;
- uint32_t core_index;
- void *core_info;
- uint32_t evt_id;
- uint32_t irq_reg_val[CAM_IFE_BUS_IRQ_REGISTERS_MAX];
- uint32_t error_type;
- struct cam_vfe_bus_ver2_priv *bus_priv;
- struct cam_isp_timestamp ts;
+ struct list_head list;
+ uint32_t core_index;
+ uint32_t evt_id;
+ uint32_t irq_reg_val[CAM_IFE_BUS_IRQ_REGISTERS_MAX];
+ uint32_t error_type;
+ struct cam_isp_timestamp ts;
+ void *ctx;
};
/*
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
index f6aab7f..e25d973 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
@@ -51,11 +51,6 @@ static uint32_t top_reset_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = {
0x00000000,
};
-static uint32_t bus_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = {
- 0x00000200,
- 0x00000000,
-};
-
static int cam_vfe_get_evt_payload(struct cam_vfe_hw_core_info *core_info,
struct cam_vfe_top_irq_evt_payload **evt_payload)
{
@@ -188,15 +183,25 @@ int cam_vfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size)
CDBG("Enable soc done\n");
+ rc = core_info->vfe_bus->hw_ops.init(core_info->vfe_bus->bus_priv,
+ NULL, 0);
+ if (rc) {
+ pr_err("Bus HW init Failed rc=%d\n", rc);
+ goto disable_soc;
+ }
+
/* Do HW Reset */
rc = cam_vfe_reset(hw_priv, NULL, 0);
if (rc) {
- pr_err("Reset Failed\n");
- goto disable_soc;
+ pr_err("Reset Failed rc=%d\n", rc);
+ goto deinit_bus;
}
return 0;
+deinit_bus:
+ core_info->vfe_bus->hw_ops.deinit(core_info->vfe_bus->bus_priv,
+ NULL, 0);
disable_soc:
cam_vfe_disable_soc_resources(soc_info);
decrement_open_cnt:
@@ -382,10 +387,11 @@ int cam_vfe_reserve(void *hw_priv, void *reserve_args, uint32_t arg_size)
rc = core_info->vfe_top->hw_ops.reserve(
core_info->vfe_top->top_priv,
acquire,
- sizeof(acquire));
+ sizeof(*acquire));
else if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_OUT)
- rc = core_info->vfe_bus->acquire_resource(
- core_info->vfe_bus->bus_priv, acquire);
+ rc = core_info->vfe_bus->hw_ops.reserve(
+ core_info->vfe_bus->bus_priv, acquire,
+ sizeof(*acquire));
else
pr_err("Invalid res type:%d\n", acquire->rsrc_type);
@@ -415,10 +421,11 @@ int cam_vfe_release(void *hw_priv, void *release_args, uint32_t arg_size)
if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN)
rc = core_info->vfe_top->hw_ops.release(
core_info->vfe_top->top_priv, isp_res,
- sizeof(struct cam_isp_resource_node));
+ sizeof(*isp_res));
else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT)
- rc = core_info->vfe_bus->release_resource(
- core_info->vfe_bus->bus_priv, isp_res);
+ rc = core_info->vfe_bus->hw_ops.release(
+ core_info->vfe_bus->bus_priv, isp_res,
+ sizeof(*isp_res));
else
pr_err("Invalid res type:%d\n", isp_res->res_type);
@@ -468,16 +475,7 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size)
else
pr_err("Error! subscribe irq controller failed\n");
} else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) {
- isp_res->irq_handle = cam_irq_controller_subscribe_irq(
- core_info->vfe_irq_controller, CAM_IRQ_PRIORITY_2,
- bus_irq_reg_mask, &core_info->irq_payload,
- core_info->vfe_bus->top_half_handler,
- cam_ife_mgr_do_tasklet_buf_done,
- isp_res->tasklet_info, cam_tasklet_enqueue_cmd);
- if (isp_res->irq_handle > 0)
- rc = core_info->vfe_bus->start_resource(isp_res);
- else
- pr_err("Error! subscribe irq controller failed\n");
+ rc = core_info->vfe_bus->hw_ops.start(isp_res, NULL, 0);
} else {
pr_err("Invalid res type:%d\n", isp_res->res_type);
}
@@ -513,7 +511,7 @@ int cam_vfe_stop(void *hw_priv, void *stop_args, uint32_t arg_size)
} else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) {
cam_irq_controller_unsubscribe_irq(
core_info->vfe_irq_controller, isp_res->irq_handle);
- rc = core_info->vfe_bus->stop_resource(isp_res);
+ rc = core_info->vfe_bus->hw_ops.stop(isp_res, NULL, 0);
} else {
pr_err("Invalid res type:%d\n", isp_res->res_type);
}
@@ -560,7 +558,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
break;
case CAM_VFE_HW_CMD_GET_BUF_UPDATE:
- rc = core_info->vfe_bus->process_cmd(
+ rc = core_info->vfe_bus->hw_ops.process_cmd(
core_info->vfe_bus->bus_priv, cmd_type, cmd_args,
arg_size);
break;
@@ -611,15 +609,15 @@ int cam_vfe_core_init(struct cam_vfe_hw_core_info *core_info,
&core_info->vfe_top);
if (rc) {
pr_err("Error! cam_vfe_top_init failed\n");
- return rc;
+ goto deinit_controller;
}
- rc = cam_vfe_bus_init(vfe_hw_info->bus_version,
- soc_info->reg_map[0].mem_base, hw_intf,
- vfe_hw_info->bus_hw_info, NULL, &core_info->vfe_bus);
+ rc = cam_vfe_bus_init(vfe_hw_info->bus_version, soc_info, hw_intf,
+ vfe_hw_info->bus_hw_info, core_info->vfe_irq_controller,
+ &core_info->vfe_bus);
if (rc) {
pr_err("Error! cam_vfe_bus_init failed\n");
- return rc;
+ goto deinit_top;
}
INIT_LIST_HEAD(&core_info->free_payload_list);
@@ -632,4 +630,46 @@ int cam_vfe_core_init(struct cam_vfe_hw_core_info *core_info,
spin_lock_init(&core_info->spin_lock);
return rc;
+
+deinit_top:
+ cam_vfe_top_deinit(vfe_hw_info->top_version,
+ &core_info->vfe_top);
+
+deinit_controller:
+ cam_irq_controller_deinit(&core_info->vfe_irq_controller);
+
+ return rc;
}
+
+int cam_vfe_core_deinit(struct cam_vfe_hw_core_info *core_info,
+ struct cam_vfe_hw_info *vfe_hw_info)
+{
+ int rc = -EINVAL;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&core_info->spin_lock, flags);
+
+ INIT_LIST_HEAD(&core_info->free_payload_list);
+ for (i = 0; i < CAM_VFE_EVT_MAX; i++)
+ INIT_LIST_HEAD(&core_info->evt_payload[i].list);
+
+ rc = cam_vfe_bus_deinit(vfe_hw_info->bus_version,
+ &core_info->vfe_bus);
+ if (rc)
+ pr_err("Error cam_vfe_bus_deinit failed rc=%d\n", rc);
+
+ rc = cam_vfe_top_deinit(vfe_hw_info->top_version,
+ &core_info->vfe_top);
+ if (rc)
+ pr_err("Error cam_vfe_top_deinit failed rc=%d\n", rc);
+
+ rc = cam_irq_controller_deinit(&core_info->vfe_irq_controller);
+ if (rc)
+ pr_err("Error cam_irq_controller_deinit failed rc=%d\n", rc);
+
+ spin_unlock_irqrestore(&core_info->spin_lock, flags);
+
+ return rc;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h
index 94b4cf0..ee29e1cf 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h
@@ -89,4 +89,7 @@ int cam_vfe_core_init(struct cam_vfe_hw_core_info *core_info,
struct cam_hw_intf *hw_intf,
struct cam_vfe_hw_info *vfe_hw_info);
+int cam_vfe_core_deinit(struct cam_vfe_hw_core_info *core_info,
+ struct cam_vfe_hw_info *vfe_hw_info);
+
#endif /* _CAM_VFE_CORE_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c
index 40279ae..cdb8d6f 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c
@@ -88,14 +88,14 @@ int cam_vfe_probe(struct platform_device *pdev)
rc = cam_vfe_init_soc_resources(&vfe_hw->soc_info, cam_vfe_irq,
vfe_hw);
if (rc < 0) {
- pr_err("Failed to init soc\n");
+ pr_err("Failed to init soc rc=%d\n", rc);
goto free_core_info;
}
rc = cam_vfe_core_init(core_info, &vfe_hw->soc_info,
vfe_hw_intf, hw_info);
if (rc < 0) {
- pr_err("Failed to init core\n");
+ pr_err("Failed to init core rc=%d\n", rc);
goto deinit_soc;
}
@@ -115,6 +115,8 @@ int cam_vfe_probe(struct platform_device *pdev)
return rc;
deinit_soc:
+ if (cam_vfe_deinit_soc_resources(&vfe_hw->soc_info))
+ pr_err("Failed to deinit soc\n");
free_core_info:
kfree(vfe_hw->core_info);
free_vfe_hw:
@@ -125,6 +127,60 @@ int cam_vfe_probe(struct platform_device *pdev)
return rc;
}
+int cam_vfe_remove(struct platform_device *pdev)
+{
+ struct cam_hw_info *vfe_hw = NULL;
+ struct cam_hw_intf *vfe_hw_intf = NULL;
+ struct cam_vfe_hw_core_info *core_info = NULL;
+ int rc = 0;
+
+ vfe_hw_intf = platform_get_drvdata(pdev);
+ if (!vfe_hw_intf) {
+ pr_err("Error! No data in pdev\n");
+ return -EINVAL;
+ }
+
+ CDBG("type %d index %d\n", vfe_hw_intf->hw_type, vfe_hw_intf->hw_idx);
+
+ if (vfe_hw_intf->hw_idx < CAM_VFE_HW_NUM_MAX)
+ cam_vfe_hw_list[vfe_hw_intf->hw_idx] = NULL;
+
+ vfe_hw = vfe_hw_intf->hw_priv;
+ if (!vfe_hw) {
+ pr_err("Error! HW data is NULL\n");
+ rc = -ENODEV;
+ goto free_vfe_hw_intf;
+ }
+
+ core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info;
+ if (!core_info) {
+ pr_err("Error! core data NULL");
+ rc = -EINVAL;
+ goto deinit_soc;
+ }
+
+ rc = cam_vfe_core_deinit(core_info, core_info->vfe_hw_info);
+ if (rc < 0)
+ pr_err("Failed to deinit core rc=%d\n", rc);
+
+ kfree(vfe_hw->core_info);
+
+deinit_soc:
+ rc = cam_vfe_deinit_soc_resources(&vfe_hw->soc_info);
+ if (rc < 0)
+ pr_err("Failed to deinit soc rc=%d\n", rc);
+
+ mutex_destroy(&vfe_hw->hw_mutex);
+ kfree(vfe_hw);
+
+ CDBG("VFE%d remove successful\n", vfe_hw_intf->hw_idx);
+
+free_vfe_hw_intf:
+ kfree(vfe_hw_intf);
+
+ return rc;
+}
+
int cam_vfe_hw_init(struct cam_hw_intf **vfe_hw, uint32_t hw_idx)
{
int rc = 0;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h
index ca54d81..9e73528 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h
@@ -27,4 +27,16 @@
*/
int cam_vfe_probe(struct platform_device *pdev);
+/*
+ * cam_vfe_remove()
+ *
+ * @brief: Driver remove function
+ *
+ * @pdev: Platform Device pointer
+ *
+ * @Return: 0: Success
+ * Non-zero: Failure
+ */
+int cam_vfe_remove(struct platform_device *pdev);
+
#endif /* _CAM_VFE_DEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c
index 9f8f8c5..fa9d86b 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c
@@ -25,7 +25,7 @@ static int cam_vfe_get_dt_properties(struct cam_hw_soc_info *soc_info)
rc = cam_soc_util_get_dt_properties(soc_info);
if (rc) {
- pr_err("Error! get DT properties failed\n");
+ pr_err("Error! get DT properties failed rc=%d\n", rc);
return rc;
}
@@ -40,6 +40,19 @@ static int cam_vfe_request_platform_resource(
rc = cam_soc_util_request_platform_resource(soc_info, vfe_irq_handler,
irq_data);
+ if (rc)
+ pr_err("Error! Request platform resource failed rc=%d\n", rc);
+
+ return rc;
+}
+
+static int cam_vfe_release_platform_resource(struct cam_hw_soc_info *soc_info)
+{
+ int rc = 0;
+
+ rc = cam_soc_util_release_platform_resource(soc_info);
+ if (rc)
+ pr_err("Error! Release platform resource failed rc=%d\n", rc);
return rc;
}
@@ -61,14 +74,14 @@ int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info,
rc = cam_vfe_get_dt_properties(soc_info);
if (rc < 0) {
- pr_err("Error! Get DT properties failed\n");
+ pr_err("Error! Get DT properties failed rc=%d\n", rc);
goto free_soc_private;
}
rc = cam_vfe_request_platform_resource(soc_info, vfe_irq_handler,
irq_data);
if (rc < 0) {
- pr_err("Error! Request platform resources failed\n");
+ pr_err("Error! Request platform resources failed rc=%d\n", rc);
goto free_soc_private;
}
@@ -79,7 +92,7 @@ int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info,
cpas_register_param.dev = &soc_info->pdev->dev;
rc = cam_cpas_register_client(&cpas_register_param);
if (rc) {
- pr_err("CPAS registration failed\n");
+ pr_err("CPAS registration failed rc=%d\n", rc);
goto release_soc;
} else {
soc_private->cpas_handle = cpas_register_param.client_handle;
@@ -95,6 +108,35 @@ int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info,
return rc;
}
+int cam_vfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+ int rc = 0;
+ struct cam_vfe_soc_private *soc_private;
+
+ if (!soc_info) {
+ pr_err("Error! soc_info NULL\n");
+ return -ENODEV;
+ }
+
+ soc_private = soc_info->soc_private;
+ if (!soc_private) {
+ pr_err("Error! soc_private NULL\n");
+ return -ENODEV;
+ }
+
+ rc = cam_cpas_unregister_client(soc_private->cpas_handle);
+ if (rc)
+ pr_err("CPAS unregistration failed rc=%d\n", rc);
+
+ rc = cam_vfe_release_platform_resource(soc_info);
+ if (rc < 0)
+ pr_err("Error! Release platform resources failed rc=%d\n", rc);
+
+ kfree(soc_private);
+
+ return rc;
+}
+
int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info)
{
int rc = 0;
@@ -117,7 +159,7 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info)
rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote);
if (rc) {
- pr_err("Error! CPAS start failed.\n");
+ pr_err("Error! CPAS start failed rc=%d\n", rc);
rc = -EFAULT;
goto end;
}
@@ -125,7 +167,7 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info)
rc = cam_soc_util_enable_platform_resource(soc_info, true,
CAM_TURBO_VOTE, true);
if (rc) {
- pr_err("Error! enable platform failed\n");
+ pr_err("Error! enable platform failed rc=%d\n", rc);
goto stop_cpas;
}
@@ -152,13 +194,13 @@ int cam_vfe_disable_soc_resources(struct cam_hw_soc_info *soc_info)
rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
if (rc) {
- pr_err("%s: disable platform failed\n", __func__);
+ pr_err("Disable platform failed rc=%d\n", rc);
return rc;
}
rc = cam_cpas_stop(soc_private->cpas_handle);
if (rc) {
- pr_err("Error! CPAS stop failed.\n");
+ pr_err("Error! CPAS stop failed rc=%d\n", rc);
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h
index 27fb192..094c977 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h
@@ -45,6 +45,18 @@ int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info,
irq_handler_t vfe_irq_handler, void *irq_data);
/*
+ * cam_vfe_deinit_soc_resources()
+ *
+ * @Brief: Deinitialize SOC resources including private data
+ *
+ * @soc_info: Device soc information
+ *
+ * @Return: 0: Success
+ * Non-zero: Failure
+ */
+int cam_vfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info);
+
+/*
* cam_vfe_enable_soc_resources()
*
* @brief: Enable regulator, irq resources, start CPAS
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c
index 2245ab1..0ac5f6d 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c
@@ -30,6 +30,7 @@ MODULE_DEVICE_TABLE(of, cam_vfe170_dt_match);
static struct platform_driver cam_vfe170_driver = {
.probe = cam_vfe_probe,
+ .remove = cam_vfe_remove,
.driver = {
.name = "cam_vfe170",
.owner = THIS_MODULE,
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile
index cea1137..4a328ee 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile
@@ -1,7 +1,10 @@
ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils/
ccflags-y += -Idrivers/media/platform/msm/camera/cam_cdm/
ccflags-y += -Idrivers/media/platform/msm/camera/cam_core/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c
index 50952f8..63ca5c2 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c
@@ -17,17 +17,17 @@
#include "cam_vfe_bus_ver2.h"
int cam_vfe_bus_init(uint32_t bus_version,
- void __iomem *mem_base,
+ struct cam_hw_soc_info *soc_info,
struct cam_hw_intf *hw_intf,
void *bus_hw_info,
void *vfe_irq_controller,
- struct cam_vfe_bus **vfe_bus)
+ struct cam_vfe_bus **vfe_bus)
{
int rc = -ENODEV;
switch (bus_version) {
case CAM_VFE_BUS_VER_2_0:
- rc = cam_vfe_bus_ver2_init(mem_base, hw_intf, bus_hw_info,
+ rc = cam_vfe_bus_ver2_init(soc_info, hw_intf, bus_hw_info,
vfe_irq_controller, vfe_bus);
break;
default:
@@ -37,3 +37,21 @@ int cam_vfe_bus_init(uint32_t bus_version,
return rc;
}
+
+int cam_vfe_bus_deinit(uint32_t bus_version,
+ struct cam_vfe_bus **vfe_bus)
+{
+ int rc = -ENODEV;
+
+ switch (bus_version) {
+ case CAM_VFE_BUS_VER_2_0:
+ rc = cam_vfe_bus_ver2_deinit(vfe_bus);
+ break;
+ default:
+ pr_err("Unsupported Bus Version %x\n", bus_version);
+ break;
+ }
+
+ return rc;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
index c4fae99..489689c 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
@@ -17,8 +17,10 @@
#include "cam_io_util.h"
#include "cam_cdm_util.h"
#include "cam_hw_intf.h"
+#include "cam_ife_hw_mgr.h"
#include "cam_vfe_hw_intf.h"
#include "cam_irq_controller.h"
+#include "cam_tasklet_util.h"
#include "cam_vfe_bus.h"
#include "cam_vfe_bus_ver2.h"
#include "cam_vfe_core.h"
@@ -26,28 +28,25 @@
#undef CDBG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
-#define FRAME_BASED_EN 0
+static const char drv_name[] = "vfe_bus";
+
+#define CAM_VFE_BUS_IRQ_REG0 0
+#define CAM_VFE_BUS_IRQ_REG1 1
+#define CAM_VFE_BUS_IRQ_REG2 2
+#define CAM_VFE_BUS_IRQ_MAX 3
+
+#define CAM_VFE_BUS_VER2_PAYLOAD_MAX 256
#define MAX_BUF_UPDATE_REG_NUM \
(sizeof(struct cam_vfe_bus_ver2_reg_offset_bus_client)/4)
#define MAX_REG_VAL_PAIR_SIZE \
- (MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES)
+ (MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES)
#define CAM_VFE_ADD_REG_VAL_PAIR(buf_array, index, offset, val) \
- do { \
- buf_array[index++] = offset; \
- buf_array[index++] = val; \
- } while (0)
-
-static uint32_t irq_reg_offset[CAM_IFE_BUS_IRQ_REGISTERS_MAX] = {
- 0x0000205C,
- 0x00002060,
- 0x00002064,
- 0x0000206C,
- 0x00002070,
- 0x00002074,
- 0x00002078,
-};
+ do { \
+ buf_array[index++] = offset; \
+ buf_array[index++] = val; \
+ } while (0)
enum cam_vfe_bus_packer_format {
PACKER_FMT_PLAIN_128 = 0x0,
@@ -70,23 +69,29 @@ enum cam_vfe_bus_packer_format {
};
struct cam_vfe_bus_ver2_common_data {
+ uint32_t core_index;
void __iomem *mem_base;
struct cam_hw_intf *hw_intf;
void *bus_irq_controller;
void *vfe_irq_controller;
struct cam_vfe_bus_ver2_reg_offset_common *common_reg;
uint32_t io_buf_update[
- MAX_REG_VAL_PAIR_SIZE];
+ MAX_REG_VAL_PAIR_SIZE];
+
+ struct cam_vfe_bus_irq_evt_payload evt_payload[
+ CAM_VFE_BUS_VER2_PAYLOAD_MAX];
+ struct list_head free_payload_list;
};
struct cam_vfe_bus_ver2_wm_resource_data {
uint32_t index;
struct cam_vfe_bus_ver2_common_data *common_data;
struct cam_vfe_bus_ver2_reg_offset_bus_client *hw_regs;
+ void *ctx;
uint32_t irq_enabled;
-
uint32_t init_cfg_done;
+
uint32_t offset;
uint32_t width;
uint32_t height;
@@ -127,6 +132,8 @@ struct cam_vfe_bus_ver2_comp_grp_data {
uint32_t dual_slave_core;
uint32_t intra_client_mask;
uint32_t composite_mask;
+
+ void *ctx;
};
struct cam_vfe_bus_ver2_vfe_out_data {
@@ -147,7 +154,6 @@ struct cam_vfe_bus_ver2_vfe_out_data {
struct cam_cdm_utils_ops *cdm_util_ops;
};
-
struct cam_vfe_bus_ver2_priv {
struct cam_vfe_bus_ver2_common_data common_data;
@@ -159,12 +165,59 @@ struct cam_vfe_bus_ver2_priv {
struct list_head free_dual_comp_grp;
struct list_head used_comp_grp;
- struct cam_vfe_bus_irq_evt_payload evt_payload[128];
- struct list_head free_payload_list;
+ uint32_t irq_handle;
};
+static int cam_vfe_bus_get_evt_payload(
+ struct cam_vfe_bus_ver2_common_data *common_data,
+ struct cam_vfe_bus_irq_evt_payload **evt_payload)
+{
+ if (list_empty(&common_data->free_payload_list)) {
+ *evt_payload = NULL;
+ pr_err("No free payload\n");
+ return -ENODEV;
+ }
+
+ *evt_payload = list_first_entry(&common_data->free_payload_list,
+ struct cam_vfe_bus_irq_evt_payload, list);
+ list_del_init(&(*evt_payload)->list);
+ return 0;
+}
+
static int cam_vfe_bus_put_evt_payload(void *core_info,
- struct cam_vfe_bus_irq_evt_payload **evt_payload);
+ struct cam_vfe_bus_irq_evt_payload **evt_payload)
+{
+ struct cam_vfe_bus_ver2_common_data *common_data = NULL;
+ uint32_t *ife_irq_regs = NULL;
+ uint32_t status_reg0, status_reg1, status_reg2;
+
+ if (!core_info) {
+ pr_err("Invalid param core_info NULL");
+ return -EINVAL;
+ }
+ if (*evt_payload == NULL) {
+ pr_err("No payload to put\n");
+ return -EINVAL;
+ }
+
+ ife_irq_regs = (*evt_payload)->irq_reg_val;
+ status_reg0 = ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0];
+ status_reg1 = ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS1];
+ status_reg2 = ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS2];
+
+ if (status_reg0 || status_reg1 || status_reg2) {
+ CDBG("status0 0x%x status1 0x%x status2 0x%x\n",
+ status_reg0, status_reg1, status_reg2);
+ return 0;
+ }
+
+ common_data = core_info;
+ list_add_tail(&(*evt_payload)->list,
+ &common_data->free_payload_list);
+ *evt_payload = NULL;
+
+ return 0;
+}
static int cam_vfe_bus_ver2_get_intra_client_mask(
enum cam_vfe_bus_ver2_vfe_core_id dual_slave_core,
@@ -371,7 +424,6 @@ static int cam_vfe_bus_get_num_wm(
case CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS:
switch (format) {
case CAM_FORMAT_PLAIN64:
- case CAM_FORMAT_PLAIN128:
return 1;
default:
break;
@@ -583,7 +635,26 @@ static enum cam_vfe_bus_packer_format
switch (out_fmt) {
case CAM_FORMAT_NV21:
case CAM_FORMAT_NV12:
- return PACKER_FMT_PLAIN_8;
+ return PACKER_FMT_PLAIN_8_LSB_MSB_10;
+ case CAM_FORMAT_PLAIN16_16:
+ return PACKER_FMT_PLAIN_16_16BPP;
+ case CAM_FORMAT_PLAIN64:
+ return PACKER_FMT_PLAIN_64;
+ case CAM_FORMAT_MIPI_RAW_6:
+ case CAM_FORMAT_MIPI_RAW_8:
+ case CAM_FORMAT_MIPI_RAW_10:
+ case CAM_FORMAT_MIPI_RAW_12:
+ case CAM_FORMAT_MIPI_RAW_14:
+ case CAM_FORMAT_MIPI_RAW_16:
+ case CAM_FORMAT_MIPI_RAW_20:
+ case CAM_FORMAT_QTI_RAW_8:
+ case CAM_FORMAT_QTI_RAW_10:
+ case CAM_FORMAT_QTI_RAW_12:
+ case CAM_FORMAT_QTI_RAW_14:
+ case CAM_FORMAT_PLAIN128:
+ case CAM_FORMAT_PD8:
+ case CAM_FORMAT_PD10:
+ return PACKER_FMT_PLAIN_128;
default:
return PACKER_FMT_MAX;
}
@@ -592,6 +663,8 @@ static enum cam_vfe_bus_packer_format
static int cam_vfe_bus_acquire_wm(
struct cam_vfe_bus_ver2_priv *ver2_bus_priv,
struct cam_isp_out_port_info *out_port_info,
+ void *tasklet,
+ void *ctx,
enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id,
enum cam_vfe_bus_plane_type plane,
enum cam_isp_hw_split_id split_id,
@@ -615,10 +688,12 @@ static int cam_vfe_bus_acquire_wm(
}
wm_res_local = &ver2_bus_priv->bus_client[wm_idx];
+ wm_res_local->tasklet_info = tasklet;
wm_res_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
rsrc_data = wm_res_local->res_priv;
rsrc_data->irq_enabled = subscribe_irq;
+ rsrc_data->ctx = ctx;
rsrc_data->format = out_port_info->format;
rsrc_data->pack_fmt = cam_vfe_bus_get_packer_fmt(rsrc_data->format);
@@ -628,7 +703,6 @@ static int cam_vfe_bus_acquire_wm(
if (rsrc_data->index < 3) {
rsrc_data->width = rsrc_data->width * 5/4 * rsrc_data->height;
rsrc_data->height = 1;
- rsrc_data->pack_fmt = 0x0;
rsrc_data->en_cfg = 0x3;
} else if (rsrc_data->index < 5 ||
rsrc_data->index == 7 || rsrc_data->index == 8) {
@@ -664,18 +738,15 @@ static int cam_vfe_bus_acquire_wm(
pr_err("Invalid plane type %d\n", plane);
return -EINVAL;
}
- rsrc_data->pack_fmt = 0xE;
rsrc_data->en_cfg = 0x1;
} else if (rsrc_data->index >= 11) {
rsrc_data->width = 0;
rsrc_data->height = 0;
- rsrc_data->pack_fmt = 0x0;
rsrc_data->stride = 1;
rsrc_data->en_cfg = 0x3;
} else {
rsrc_data->width = rsrc_data->width * 4;
rsrc_data->height = rsrc_data->height / 2;
- rsrc_data->pack_fmt = 0x0;
rsrc_data->en_cfg = 0x1;
}
@@ -718,6 +789,8 @@ static int cam_vfe_bus_release_wm(void *bus_priv,
rsrc_data->ubwc_meta_offset = 0;
rsrc_data->init_cfg_done = 0;
rsrc_data->en_cfg = 0;
+
+ wm_res->tasklet_info = NULL;
wm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
return 0;
@@ -730,6 +803,7 @@ static int cam_vfe_bus_start_wm(struct cam_isp_resource_node *wm_res)
wm_res->res_priv;
struct cam_vfe_bus_ver2_common_data *common_data =
rsrc_data->common_data;
+ uint32_t bus_irq_reg_mask[CAM_VFE_BUS_IRQ_MAX] = {0};
cam_io_w_mb(0, common_data->mem_base + rsrc_data->hw_regs->header_addr);
cam_io_w_mb(0, common_data->mem_base + rsrc_data->hw_regs->header_cfg);
@@ -753,6 +827,28 @@ static int cam_vfe_bus_start_wm(struct cam_isp_resource_node *wm_res)
cam_io_w(0x0,
common_data->mem_base + rsrc_data->hw_regs->framedrop_period);
+ /* Subscribe IRQ */
+ if (rsrc_data->irq_enabled) {
+ CDBG("Subscribe WM%d IRQ\n", rsrc_data->index);
+ bus_irq_reg_mask[CAM_VFE_BUS_IRQ_REG1] =
+ (1 << rsrc_data->index);
+ wm_res->irq_handle = cam_irq_controller_subscribe_irq(
+ common_data->bus_irq_controller, CAM_IRQ_PRIORITY_1,
+ bus_irq_reg_mask, wm_res,
+ wm_res->top_half_handler,
+ cam_ife_mgr_do_tasklet_buf_done,
+ wm_res->tasklet_info, cam_tasklet_enqueue_cmd);
+ if (wm_res->irq_handle < 0) {
+ pr_err("Subscribe IRQ failed for WM %d\n",
+ rsrc_data->index);
+ return -EFAULT;
+ }
+ }
+
+ /* Enable WM */
+ cam_io_w_mb(rsrc_data->en_cfg, common_data->mem_base +
+ rsrc_data->hw_regs->cfg);
+
CDBG("WM res %d width = %d, height = %d\n", rsrc_data->index,
rsrc_data->width, rsrc_data->height);
CDBG("WM res %d pk_fmt = %d\n", rsrc_data->index,
@@ -781,12 +877,10 @@ static int cam_vfe_bus_stop_wm(struct cam_isp_resource_node *wm_res)
CDBG("irq_enabled %d", rsrc_data->irq_enabled);
/* Unsubscribe IRQ */
- if (rsrc_data->irq_enabled) {
- /*
- * Currently all WM IRQ are unsubscribed in one place. Need to
- * make it dynamic.
- */
- }
+ if (rsrc_data->irq_enabled)
+ rc = cam_irq_controller_unsubscribe_irq(
+ common_data->bus_irq_controller,
+ wm_res->irq_handle);
/* Halt & Reset WM */
cam_io_w_mb(BIT(rsrc_data->index),
@@ -800,7 +894,42 @@ static int cam_vfe_bus_stop_wm(struct cam_isp_resource_node *wm_res)
static int cam_vfe_bus_handle_wm_done_top_half(uint32_t evt_id,
struct cam_irq_th_payload *th_payload)
{
- return -EPERM;
+ int32_t rc;
+ int i;
+ struct cam_isp_resource_node *wm_res = NULL;
+ struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = NULL;
+ struct cam_vfe_bus_irq_evt_payload *evt_payload;
+
+ wm_res = th_payload->handler_priv;
+ if (!wm_res) {
+ pr_err_ratelimited("Error! No resource\n");
+ return -ENODEV;
+ }
+
+ rsrc_data = wm_res->res_priv;
+
+ CDBG("IRQ status_0 = %x\n", th_payload->evt_status_arr[0]);
+ CDBG("IRQ status_1 = %x\n", th_payload->evt_status_arr[1]);
+
+ rc = cam_vfe_bus_get_evt_payload(rsrc_data->common_data, &evt_payload);
+ if (rc) {
+ pr_err_ratelimited("No tasklet_cmd is free in queue\n");
+ return rc;
+ }
+
+ cam_isp_hw_get_timestamp(&evt_payload->ts);
+
+ evt_payload->ctx = rsrc_data->ctx;
+ evt_payload->core_index = rsrc_data->common_data->core_index;
+ evt_payload->evt_id = evt_id;
+
+ for (i = 0; i < th_payload->num_registers; i++)
+ evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i];
+
+ th_payload->evt_payload_priv = evt_payload;
+
+ CDBG("Exit\n");
+ return rc;
}
static int cam_vfe_bus_handle_wm_done_bottom_half(void *wm_node,
@@ -825,9 +954,10 @@ static int cam_vfe_bus_handle_wm_done_bottom_half(void *wm_node,
~BIT(rsrc_data->index);
rc = CAM_VFE_IRQ_STATUS_SUCCESS;
}
+ CDBG("status_reg %x rc %d\n", status_reg, rc);
if (rc == CAM_VFE_IRQ_STATUS_SUCCESS)
- cam_vfe_bus_put_evt_payload(evt_payload->core_info,
+ cam_vfe_bus_put_evt_payload(rsrc_data->common_data,
&evt_payload);
return rc;
@@ -838,15 +968,13 @@ static int cam_vfe_bus_init_wm_resource(uint32_t index,
struct cam_vfe_bus_ver2_hw_info *ver2_hw_info,
struct cam_isp_resource_node *wm_res)
{
- int rc = 0;
struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data;
rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_wm_resource_data),
GFP_KERNEL);
if (!rsrc_data) {
- CDBG("Failed to alloc for wm res priv\n");
- rc = -ENOMEM;
- return rc;
+ CDBG("Failed to alloc for WM res priv\n");
+ return -ENOMEM;
}
wm_res->res_priv = rsrc_data;
@@ -863,7 +991,32 @@ static int cam_vfe_bus_init_wm_resource(uint32_t index,
wm_res->bottom_half_handler = cam_vfe_bus_handle_wm_done_bottom_half;
wm_res->hw_intf = ver2_bus_priv->common_data.hw_intf;
- return rc;
+ return 0;
+}
+
+static int cam_vfe_bus_deinit_wm_resource(
+ struct cam_isp_resource_node *wm_res)
+{
+ struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data;
+
+ wm_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE;
+ INIT_LIST_HEAD(&wm_res->list);
+
+ wm_res->start = NULL;
+ wm_res->stop = NULL;
+ wm_res->top_half_handler = NULL;
+ wm_res->bottom_half_handler = NULL;
+ wm_res->hw_intf = NULL;
+
+ rsrc_data = wm_res->res_priv;
+ wm_res->res_priv = NULL;
+ if (!rsrc_data) {
+ pr_err("Error! WM res priv is NULL\n");
+ return -ENOMEM;
+ }
+ kfree(rsrc_data);
+
+ return 0;
}
static void cam_vfe_bus_add_wm_to_comp_grp(
@@ -901,6 +1054,8 @@ static void cam_vfe_bus_match_comp_grp(
static int cam_vfe_bus_acquire_comp_grp(
struct cam_vfe_bus_ver2_priv *ver2_bus_priv,
struct cam_isp_out_port_info *out_port_info,
+ void *tasklet,
+ void *ctx,
uint32_t unique_id,
uint32_t is_dual,
uint32_t is_master,
@@ -942,6 +1097,7 @@ static int cam_vfe_bus_acquire_comp_grp(
}
list_del(&comp_grp_local->list);
+ comp_grp_local->tasklet_info = tasklet;
comp_grp_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
rsrc_data->is_master = is_master;
@@ -964,6 +1120,7 @@ static int cam_vfe_bus_acquire_comp_grp(
}
}
+ rsrc_data->ctx = ctx;
*comp_grp = comp_grp_local;
return rc;
@@ -1017,6 +1174,7 @@ static int cam_vfe_bus_release_comp_grp(
in_rsrc_data->composite_mask = 0;
in_rsrc_data->dual_slave_core = CAM_VFE_BUS_VER2_VFE_CORE_MAX;
+ comp_grp->tasklet_info = NULL;
comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
return 0;
@@ -1029,11 +1187,7 @@ static int cam_vfe_bus_start_comp_grp(struct cam_isp_resource_node *comp_grp)
comp_grp->res_priv;
struct cam_vfe_bus_ver2_common_data *common_data =
rsrc_data->common_data;
-
- /*
- * Individual Comp_Grp Subscribe IRQ can be done here once
- * dynamic IRQ enable support is added.
- */
+ uint32_t bus_irq_reg_mask[CAM_VFE_BUS_IRQ_MAX] = {0};
cam_io_w_mb(rsrc_data->composite_mask, common_data->mem_base +
rsrc_data->hw_regs->comp_mask);
@@ -1055,9 +1209,30 @@ static int cam_vfe_bus_start_comp_grp(struct cam_isp_resource_node *comp_grp)
cam_io_w_mb(intra_client_en, common_data->mem_base +
common_data->common_reg->dual_master_comp_cfg);
+
+ bus_irq_reg_mask[CAM_VFE_BUS_IRQ_REG2] = (1 << dual_comp_grp);
+ } else {
+ /* IRQ bits for COMP GRP start at 5. So add 5 to the shift */
+ bus_irq_reg_mask[CAM_VFE_BUS_IRQ_REG0] =
+ (1 << (rsrc_data->comp_grp_type + 5));
+ }
+
+ /* Subscribe IRQ */
+ CDBG("Subscribe COMP_GRP%d IRQ\n", rsrc_data->comp_grp_type);
+ comp_grp->irq_handle = cam_irq_controller_subscribe_irq(
+ common_data->bus_irq_controller, CAM_IRQ_PRIORITY_1,
+ bus_irq_reg_mask, comp_grp,
+ comp_grp->top_half_handler,
+ cam_ife_mgr_do_tasklet_buf_done,
+ comp_grp->tasklet_info, cam_tasklet_enqueue_cmd);
+ if (comp_grp->irq_handle < 0) {
+ pr_err("Subscribe IRQ failed for comp_grp %d\n",
+ rsrc_data->comp_grp_type);
+ return -EFAULT;
}
comp_grp->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
+
return rc;
}
@@ -1070,6 +1245,9 @@ static int cam_vfe_bus_stop_comp_grp(struct cam_isp_resource_node *comp_grp)
rsrc_data->common_data;
/* Unsubscribe IRQ */
+ rc = cam_irq_controller_unsubscribe_irq(
+ common_data->bus_irq_controller,
+ comp_grp->irq_handle);
cam_io_w_mb(rsrc_data->composite_mask, common_data->mem_base +
rsrc_data->hw_regs->comp_mask);
@@ -1097,7 +1275,42 @@ static int cam_vfe_bus_stop_comp_grp(struct cam_isp_resource_node *comp_grp)
static int cam_vfe_bus_handle_comp_done_top_half(uint32_t evt_id,
struct cam_irq_th_payload *th_payload)
{
- return -EPERM;
+ int32_t rc;
+ int i;
+ struct cam_isp_resource_node *comp_grp = NULL;
+ struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = NULL;
+ struct cam_vfe_bus_irq_evt_payload *evt_payload;
+
+ comp_grp = th_payload->handler_priv;
+ if (!comp_grp) {
+ pr_err_ratelimited("Error! No resource\n");
+ return -ENODEV;
+ }
+
+ rsrc_data = comp_grp->res_priv;
+
+ CDBG("IRQ status_0 = %x\n", th_payload->evt_status_arr[0]);
+ CDBG("IRQ status_1 = %x\n", th_payload->evt_status_arr[1]);
+
+ rc = cam_vfe_bus_get_evt_payload(rsrc_data->common_data, &evt_payload);
+ if (rc) {
+ pr_err_ratelimited("No tasklet_cmd is free in queue\n");
+ return rc;
+ }
+
+ cam_isp_hw_get_timestamp(&evt_payload->ts);
+
+ evt_payload->ctx = rsrc_data->ctx;
+ evt_payload->core_index = rsrc_data->common_data->core_index;
+ evt_payload->evt_id = evt_id;
+
+ for (i = 0; i < th_payload->num_registers; i++)
+ evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i];
+
+ th_payload->evt_payload_priv = evt_payload;
+
+ CDBG("Exit\n");
+ return rc;
}
static int cam_vfe_bus_handle_comp_done_bottom_half(
@@ -1113,12 +1326,13 @@ static int cam_vfe_bus_handle_comp_done_bottom_half(
uint32_t comp_err_reg;
uint32_t comp_grp_id;
+ CDBG("comp grp type %d\n", rsrc_data->comp_grp_type);
+
if (!evt_payload)
return rc;
cam_ife_irq_regs = evt_payload->irq_reg_val;
- CDBG("comp grp type %d\n", rsrc_data->comp_grp_type);
switch (rsrc_data->comp_grp_type) {
case CAM_VFE_BUS_VER2_COMP_GRP_0:
case CAM_VFE_BUS_VER2_COMP_GRP_1:
@@ -1155,8 +1369,8 @@ static int cam_vfe_bus_handle_comp_done_bottom_half(
rc = CAM_VFE_IRQ_STATUS_SUCCESS;
}
- CDBG("status reg = 0x%x, bit index = %d\n",
- status_reg, (comp_grp_id + 5));
+ CDBG("status reg = 0x%x, bit index = %d rc %d\n",
+ status_reg, (comp_grp_id + 5), rc);
break;
case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0:
@@ -1197,11 +1411,13 @@ static int cam_vfe_bus_handle_comp_done_bottom_half(
break;
default:
rc = CAM_VFE_IRQ_STATUS_ERR;
+ pr_err("Error! Invalid comp_grp_type %u\n",
+ rsrc_data->comp_grp_type);
break;
}
if (rc == CAM_VFE_IRQ_STATUS_SUCCESS)
- cam_vfe_bus_put_evt_payload(evt_payload->core_info,
+ cam_vfe_bus_put_evt_payload(rsrc_data->common_data,
&evt_payload);
return rc;
@@ -1212,8 +1428,7 @@ static int cam_vfe_bus_init_comp_grp(uint32_t index,
struct cam_vfe_bus_ver2_hw_info *ver2_hw_info,
struct cam_isp_resource_node *comp_grp)
{
- struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data =
- comp_grp->res_priv;
+ struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = NULL;
rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_comp_grp_data),
GFP_KERNEL);
@@ -1231,7 +1446,6 @@ static int cam_vfe_bus_init_comp_grp(uint32_t index,
rsrc_data->hw_regs = &ver2_hw_info->comp_grp_reg[index];
rsrc_data->dual_slave_core = CAM_VFE_BUS_VER2_VFE_CORE_MAX;
-
if (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 &&
rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5)
list_add_tail(&comp_grp->list,
@@ -1250,7 +1464,34 @@ static int cam_vfe_bus_init_comp_grp(uint32_t index,
return 0;
}
-static int cam_vfe_bus_acquire_vfe_out(void *bus_priv, void *acquire_args)
+static int cam_vfe_bus_deinit_comp_grp(
+ struct cam_isp_resource_node *comp_grp)
+{
+ struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data =
+ comp_grp->res_priv;
+
+ comp_grp->start = NULL;
+ comp_grp->stop = NULL;
+ comp_grp->top_half_handler = NULL;
+ comp_grp->bottom_half_handler = NULL;
+ comp_grp->hw_intf = NULL;
+
+ list_del_init(&comp_grp->list);
+ comp_grp->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE;
+
+ comp_grp->res_priv = NULL;
+
+ if (!rsrc_data) {
+ pr_err("Error! comp_grp_priv is NULL\n");
+ return -ENODEV;
+ }
+ kfree(rsrc_data);
+
+ return 0;
+}
+
+static int cam_vfe_bus_acquire_vfe_out(void *bus_priv, void *acquire_args,
+ uint32_t args_size)
{
int rc = -ENODEV;
int i;
@@ -1306,30 +1547,43 @@ static int cam_vfe_bus_acquire_vfe_out(void *bus_priv, void *acquire_args)
CAM_ISP_RES_COMP_GROUP_ID_MAX)) {
rc = cam_vfe_bus_acquire_comp_grp(ver2_bus_priv,
out_acquire_args->out_port_info,
+ acq_args->tasklet,
+ out_acquire_args->ctx,
out_acquire_args->unique_id,
out_acquire_args->is_dual,
out_acquire_args->is_master,
out_acquire_args->dual_slave_core,
&rsrc_data->comp_grp);
- if (rc < 0)
+ if (rc) {
+ pr_err("VFE%d Comp_Grp acquire failed for Out %d rc=%d\n",
+ rsrc_data->common_data->core_index,
+ vfe_out_res_id, rc);
return rc;
+ }
subscribe_irq = 0;
- } else
+ } else {
subscribe_irq = 1;
+ }
/* Reserve WM */
for (i = 0; i < num_wm; i++) {
rc = cam_vfe_bus_acquire_wm(ver2_bus_priv,
out_acquire_args->out_port_info,
+ acq_args->tasklet,
+ out_acquire_args->ctx,
vfe_out_res_id,
i,
out_acquire_args->split_id,
subscribe_irq,
&rsrc_data->wm_res[i],
&client_done_mask);
- if (rc < 0)
+ if (rc) {
+ pr_err("VFE%d WM acquire failed for Out %d rc=%d\n",
+ rsrc_data->common_data->core_index,
+ vfe_out_res_id, rc);
goto release_wm;
+ }
if (rsrc_data->comp_grp)
cam_vfe_bus_add_wm_to_comp_grp(rsrc_data->comp_grp,
@@ -1352,11 +1606,21 @@ static int cam_vfe_bus_acquire_vfe_out(void *bus_priv, void *acquire_args)
return rc;
}
-static int cam_vfe_bus_release_vfe_out(void *bus_priv,
- struct cam_isp_resource_node *vfe_out)
+static int cam_vfe_bus_release_vfe_out(void *bus_priv, void *release_args,
+ uint32_t args_size)
{
uint32_t i;
- struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv;
+ struct cam_isp_resource_node *vfe_out = NULL;
+ struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL;
+
+ if (!bus_priv || !release_args) {
+ pr_err("Invalid input bus_priv %pK release_args %pK\n",
+ bus_priv, release_args);
+ return -EINVAL;
+ }
+
+ vfe_out = release_args;
+ rsrc_data = vfe_out->res_priv;
if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) {
pr_err("Error! Invalid resource state:%d\n",
@@ -1381,12 +1645,20 @@ static int cam_vfe_bus_release_vfe_out(void *bus_priv,
return 0;
}
-static int cam_vfe_bus_start_vfe_out(struct cam_isp_resource_node *vfe_out)
+static int cam_vfe_bus_start_vfe_out(
+ struct cam_isp_resource_node *vfe_out)
{
int rc = 0, i;
- struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv;
- struct cam_vfe_bus_ver2_common_data *common_data =
- rsrc_data->common_data;
+ struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL;
+ struct cam_vfe_bus_ver2_common_data *common_data = NULL;
+
+ if (!vfe_out) {
+ pr_err("Invalid input\n");
+ return -EINVAL;
+ }
+
+ rsrc_data = vfe_out->res_priv;
+ common_data = rsrc_data->common_data;
CDBG("Start resource index %d\n", rsrc_data->out_type);
@@ -1396,28 +1668,12 @@ static int cam_vfe_bus_start_vfe_out(struct cam_isp_resource_node *vfe_out)
return -EACCES;
}
- /* Enable IRQ Mask */
- cam_io_w_mb(0x00001FE0, common_data->mem_base + 0x2044);
- cam_io_w_mb(0x000FFFE7, common_data->mem_base + 0x2048);
- cam_io_w_mb(0x000000FF, common_data->mem_base + 0x204c);
-
for (i = 0; i < rsrc_data->num_wm; i++)
rc = cam_vfe_bus_start_wm(rsrc_data->wm_res[i]);
if (rsrc_data->comp_grp)
rc = cam_vfe_bus_start_comp_grp(rsrc_data->comp_grp);
- /* VFE_MODULE_BUS_CGC_OVERRIDE */
- cam_io_w_mb(0xFFFFFFFF, rsrc_data->common_data->mem_base + 0x0000003C);
- /* VFE_MODULE_COLOR_CGC_OVERRIDE */
- cam_io_w_mb(0xFFFFFFFF, rsrc_data->common_data->mem_base + 0x00000034);
- /* VFE_MODULE_ZOOM_CGC_OVERRIDE */
- cam_io_w_mb(0xFFFFFFFF, rsrc_data->common_data->mem_base + 0x38);
- /* VFE_MODULE_LENS_CGC_OVERRIDE */
- cam_io_w_mb(0xFFFFFFFF, rsrc_data->common_data->mem_base + 0x0000002C);
- /* VFE_MODULE_STATS_CGC_OVERRIDE */
- cam_io_w_mb(0xFFFFFFFF, rsrc_data->common_data->mem_base + 0x00000030);
-
/* BUS_WR_INPUT_IF_ADDR_SYNC_CFG */
cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x0000207C);
/* BUS_WR_INPUT_IF_ADDR_SYNC_FRAME_HEADER */
@@ -1440,13 +1696,22 @@ static int cam_vfe_bus_start_vfe_out(struct cam_isp_resource_node *vfe_out)
/* BUS_WR_TEST_BUS_CTRL */
cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x0000211C);
+ vfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
return rc;
}
-static int cam_vfe_bus_stop_vfe_out(struct cam_isp_resource_node *vfe_out)
+static int cam_vfe_bus_stop_vfe_out(
+ struct cam_isp_resource_node *vfe_out)
{
int rc = 0, i;
- struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv;
+ struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL;
+
+ if (!vfe_out) {
+ pr_err("Invalid input\n");
+ return -EINVAL;
+ }
+
+ rsrc_data = vfe_out->res_priv;
if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE ||
vfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) {
@@ -1459,7 +1724,6 @@ static int cam_vfe_bus_stop_vfe_out(struct cam_isp_resource_node *vfe_out)
for (i = 0; i < rsrc_data->num_wm; i++)
rc = cam_vfe_bus_stop_wm(rsrc_data->wm_res[i]);
- vfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
vfe_out->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
return rc;
@@ -1533,122 +1797,39 @@ static int cam_vfe_bus_init_vfe_out_resource(uint32_t index,
return 0;
}
-static int cam_vfe_bus_get_evt_payload(
- struct cam_vfe_bus_ver2_priv *bus_priv,
- struct cam_vfe_bus_irq_evt_payload **evt_payload)
+static int cam_vfe_bus_deinit_vfe_out_resource(
+ struct cam_isp_resource_node *vfe_out)
{
- if (list_empty(&bus_priv->free_payload_list)) {
- *evt_payload = NULL;
- pr_err("No free payload\n");
- return -ENODEV;
+ struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv;
+
+ vfe_out->start = NULL;
+ vfe_out->stop = NULL;
+ vfe_out->top_half_handler = NULL;
+ vfe_out->bottom_half_handler = NULL;
+ vfe_out->hw_intf = NULL;
+
+ vfe_out->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE;
+ INIT_LIST_HEAD(&vfe_out->list);
+ vfe_out->res_priv = NULL;
+
+ if (!rsrc_data) {
+ pr_err("Error! vfe out priv is NULL\n");
+ return -ENOMEM;
}
+ kfree(rsrc_data);
- *evt_payload = list_first_entry(&bus_priv->free_payload_list,
- struct cam_vfe_bus_irq_evt_payload, list);
- list_del_init(&(*evt_payload)->list);
- return 0;
-}
-
-static int cam_vfe_bus_put_evt_payload(void *core_info,
- struct cam_vfe_bus_irq_evt_payload **evt_payload)
-{
- struct cam_vfe_bus_ver2_priv *bus_priv = NULL;
- uint32_t *cam_ife_irq_regs = (*evt_payload)->irq_reg_val;
- uint32_t status_reg0, status_reg1;
-
- status_reg0 = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0];
- status_reg1 = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS1];
-
- if (status_reg0 || status_reg1) {
- CDBG("status0 0x%x status1 0x%x\n", status_reg0, status_reg1);
- return 0;
- }
-
- if (!core_info) {
- pr_err("Invalid param core_info NULL");
- return -EINVAL;
- }
- if (*evt_payload == NULL) {
- pr_err("No payload to put\n");
- return -EINVAL;
- }
- bus_priv = (*evt_payload)->bus_priv;
- list_add_tail(&(*evt_payload)->list, &bus_priv->free_payload_list);
- *evt_payload = NULL;
return 0;
}
static int cam_vfe_bus_ver2_handle_irq(uint32_t evt_id,
struct cam_irq_th_payload *th_payload)
{
- int32_t rc;
- int i;
- struct cam_vfe_irq_handler_priv *handler_priv;
- struct cam_vfe_hw_core_info *core_info;
- struct cam_vfe_bus_irq_evt_payload *evt_payload;
- struct cam_vfe_bus *bus_info;
struct cam_vfe_bus_ver2_priv *bus_priv;
- struct cam_irq_controller_reg_info *reg_info;
- uint32_t irq_mask;
- int found = 0;
- handler_priv = th_payload->handler_priv;
- core_info = handler_priv->core_info;
- bus_info = core_info->vfe_bus;
- bus_priv = bus_info->bus_priv;
- reg_info = &bus_priv->common_data.common_reg->irq_reg_info;
-
- /*
- * add reset ack handling here once supported.
- * Just clear all the bus irq status registers and ignore the reset.
- */
-
+ bus_priv = th_payload->handler_priv;
CDBG("Enter\n");
- rc = cam_vfe_bus_get_evt_payload(bus_priv, &evt_payload);
- if (rc) {
- pr_err("No tasklet_cmd is free in queue\n");
- return rc;
- }
-
- cam_isp_hw_get_timestamp(&evt_payload->ts);
-
- evt_payload->core_index = handler_priv->core_index;
- evt_payload->core_info = handler_priv->core_info;
- evt_payload->bus_priv = bus_priv;
- CDBG("core_idx %d, core_info %llx\n", handler_priv->core_index,
- (uint64_t)handler_priv->core_info);
-
- for (i = 0; i < CAM_IFE_BUS_IRQ_REGISTERS_MAX; i++) {
- irq_mask = cam_io_r(handler_priv->mem_base +
- irq_reg_offset[i] - (0xC * 2));
- evt_payload->irq_reg_val[i] = irq_mask &
- cam_io_r(handler_priv->mem_base + irq_reg_offset[i]);
- if (evt_payload->irq_reg_val[i])
- found = 1;
- CDBG("irq_status%d = 0x%x\n", i, evt_payload->irq_reg_val[i]);
- }
- for (i = 0; i <= CAM_IFE_IRQ_BUS_REG_STATUS2; i++) {
- cam_io_w(evt_payload->irq_reg_val[i], handler_priv->mem_base +
- reg_info->irq_reg_set[i].clear_reg_offset);
- CDBG("Clear irq_status%d = 0x%x offset 0x%x\n", i,
- evt_payload->irq_reg_val[i],
- reg_info->irq_reg_set[i].clear_reg_offset);
- }
- cam_io_w(reg_info->global_clear_bitmask, handler_priv->mem_base +
- reg_info->global_clear_offset);
- CDBG("Global clear bitmask = 0x%x offset 0x%x\n",
- reg_info->global_clear_bitmask,
- reg_info->global_clear_offset);
-
- if (found)
- th_payload->evt_payload_priv = evt_payload;
- else {
- cam_vfe_bus_put_evt_payload(evt_payload->core_info,
- &evt_payload);
- rc = -ENOMSG;
- }
-
- return rc;
+ return cam_irq_controller_handle_irq(evt_id,
+ bus_priv->common_data.bus_irq_controller);
}
static int cam_vfe_bus_update_buf(void *priv, void *cmd_args,
@@ -1882,6 +2063,69 @@ static int cam_vfe_bus_update_buf(void *priv, void *cmd_args,
return 0;
}
+static int cam_vfe_bus_start_hw(void *hw_priv,
+ void *start_hw_args, uint32_t arg_size)
+{
+ return cam_vfe_bus_start_vfe_out(hw_priv);
+}
+
+static int cam_vfe_bus_stop_hw(void *hw_priv,
+ void *stop_hw_args, uint32_t arg_size)
+{
+ return cam_vfe_bus_stop_vfe_out(hw_priv);
+}
+
+static int cam_vfe_bus_init_hw(void *hw_priv,
+ void *init_hw_args, uint32_t arg_size)
+{
+ struct cam_vfe_bus_ver2_priv *bus_priv = hw_priv;
+ uint32_t top_irq_reg_mask[2] = {0};
+
+ if (!bus_priv) {
+ pr_err("Error! Invalid args\n");
+ return -EINVAL;
+ }
+
+ top_irq_reg_mask[0] = (1 << 9);
+
+ bus_priv->irq_handle = cam_irq_controller_subscribe_irq(
+ bus_priv->common_data.vfe_irq_controller,
+ CAM_IRQ_PRIORITY_2,
+ top_irq_reg_mask,
+ bus_priv,
+ cam_vfe_bus_ver2_handle_irq,
+ NULL,
+ NULL,
+ NULL);
+
+ if (bus_priv->irq_handle <= 0) {
+ pr_err("Failed to subscribe BUS IRQ\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int cam_vfe_bus_deinit_hw(void *hw_priv,
+ void *deinit_hw_args, uint32_t arg_size)
+{
+ struct cam_vfe_bus_ver2_priv *bus_priv = hw_priv;
+ int rc;
+
+ if (!bus_priv || (bus_priv->irq_handle <= 0)) {
+ pr_err("Error! Invalid args\n");
+ return -EINVAL;
+ }
+
+ rc = cam_irq_controller_unsubscribe_irq(
+ bus_priv->common_data.vfe_irq_controller,
+ bus_priv->irq_handle);
+ if (rc)
+ pr_err("Failed to unsubscribe irq rc=%d\n", rc);
+
+ return rc;
+}
+
static int cam_vfe_bus_process_cmd(void *priv,
uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
{
@@ -1906,7 +2150,7 @@ static int cam_vfe_bus_process_cmd(void *priv,
}
int cam_vfe_bus_ver2_init(
- void __iomem *mem_base,
+ struct cam_hw_soc_info *soc_info,
struct cam_hw_intf *hw_intf,
void *bus_hw_info,
void *vfe_irq_controller,
@@ -1919,11 +2163,18 @@ int cam_vfe_bus_ver2_init(
CDBG("Enter\n");
+ if (!soc_info || !hw_intf || !bus_hw_info || !vfe_irq_controller) {
+ pr_err("Error! Invalid params soc_info %pK hw_intf %pK hw_info %pK controller %pK\n",
+ soc_info, hw_intf, bus_hw_info, vfe_irq_controller);
+ rc = -EINVAL;
+ goto end;
+ }
+
vfe_bus_local = kzalloc(sizeof(struct cam_vfe_bus), GFP_KERNEL);
if (!vfe_bus_local) {
CDBG("Failed to alloc for vfe_bus\n");
rc = -ENOMEM;
- goto err_alloc_bus;
+ goto end;
}
bus_priv = kzalloc(sizeof(struct cam_vfe_bus_ver2_priv),
@@ -1931,15 +2182,25 @@ int cam_vfe_bus_ver2_init(
if (!bus_priv) {
CDBG("Failed to alloc for vfe_bus_priv\n");
rc = -ENOMEM;
- goto err_alloc_priv;
+ goto free_bus_local;
}
vfe_bus_local->bus_priv = bus_priv;
- bus_priv->common_data.mem_base = mem_base;
+ bus_priv->common_data.core_index = soc_info->index;
+ bus_priv->common_data.mem_base =
+ CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX);
bus_priv->common_data.hw_intf = hw_intf;
bus_priv->common_data.vfe_irq_controller = vfe_irq_controller;
bus_priv->common_data.common_reg = &ver2_hw_info->common_reg;
+ rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base,
+ &ver2_hw_info->common_reg.irq_reg_info,
+ &bus_priv->common_data.bus_irq_controller);
+ if (rc) {
+ pr_err("Error! cam_irq_controller_init failed\n");
+ goto free_bus_priv;
+ }
+
INIT_LIST_HEAD(&bus_priv->free_comp_grp);
INIT_LIST_HEAD(&bus_priv->free_dual_comp_grp);
INIT_LIST_HEAD(&bus_priv->used_comp_grp);
@@ -1948,8 +2209,8 @@ int cam_vfe_bus_ver2_init(
rc = cam_vfe_bus_init_wm_resource(i, bus_priv, bus_hw_info,
&bus_priv->bus_client[i]);
if (rc < 0) {
- pr_err("Error! Init WM failed\n");
- goto err_init_wm;
+ pr_err("Error! Init WM failed rc=%d\n", rc);
+ goto deinit_wm;
}
}
@@ -1957,8 +2218,8 @@ int cam_vfe_bus_ver2_init(
rc = cam_vfe_bus_init_comp_grp(i, bus_priv, bus_hw_info,
&bus_priv->comp_grp[i]);
if (rc < 0) {
- pr_err("Error! Init Comp Grp failed\n");
- goto err_init_comp_grp;
+ pr_err("Error! Init Comp Grp failed rc=%d\n", rc);
+ goto deinit_comp_grp;
}
}
@@ -1966,36 +2227,119 @@ int cam_vfe_bus_ver2_init(
rc = cam_vfe_bus_init_vfe_out_resource(i, bus_priv, bus_hw_info,
&bus_priv->vfe_out[i]);
if (rc < 0) {
- pr_err("Error! Init VFE Out failed\n");
- goto err_init_vfe_out;
+ pr_err("Error! Init VFE Out failed rc=%d\n", rc);
+ goto deinit_vfe_out;
}
}
- INIT_LIST_HEAD(&bus_priv->free_payload_list);
- for (i = 0; i < 128; i++) {
- INIT_LIST_HEAD(&bus_priv->evt_payload[i].list);
- list_add_tail(&bus_priv->evt_payload[i].list,
- &bus_priv->free_payload_list);
+ INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list);
+ for (i = 0; i < CAM_VFE_BUS_VER2_PAYLOAD_MAX; i++) {
+ INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list);
+ list_add_tail(&bus_priv->common_data.evt_payload[i].list,
+ &bus_priv->common_data.free_payload_list);
}
- vfe_bus_local->acquire_resource = cam_vfe_bus_acquire_vfe_out;
- vfe_bus_local->release_resource = cam_vfe_bus_release_vfe_out;
- vfe_bus_local->start_resource = cam_vfe_bus_start_vfe_out;
- vfe_bus_local->stop_resource = cam_vfe_bus_stop_vfe_out;
- vfe_bus_local->top_half_handler = cam_vfe_bus_ver2_handle_irq;
+ vfe_bus_local->hw_ops.reserve = cam_vfe_bus_acquire_vfe_out;
+ vfe_bus_local->hw_ops.release = cam_vfe_bus_release_vfe_out;
+ vfe_bus_local->hw_ops.start = cam_vfe_bus_start_hw;
+ vfe_bus_local->hw_ops.stop = cam_vfe_bus_stop_hw;
+ vfe_bus_local->hw_ops.init = cam_vfe_bus_init_hw;
+ vfe_bus_local->hw_ops.deinit = cam_vfe_bus_deinit_hw;
+ vfe_bus_local->top_half_handler = cam_vfe_bus_ver2_handle_irq;
vfe_bus_local->bottom_half_handler = NULL;
- vfe_bus_local->process_cmd = cam_vfe_bus_process_cmd;
+ vfe_bus_local->hw_ops.process_cmd = cam_vfe_bus_process_cmd;
*vfe_bus = vfe_bus_local;
+ CDBG("Exit\n");
return rc;
-err_init_vfe_out:
-err_init_comp_grp:
-err_init_wm:
+deinit_vfe_out:
+ if (i < 0)
+ i = CAM_VFE_BUS_VER2_VFE_OUT_MAX;
+ for (--i; i >= 0; i--)
+ cam_vfe_bus_deinit_vfe_out_resource(&bus_priv->vfe_out[i]);
+
+deinit_comp_grp:
+ if (i < 0)
+ i = CAM_VFE_BUS_VER2_COMP_GRP_MAX;
+ for (--i; i >= 0; i--)
+ cam_vfe_bus_deinit_comp_grp(&bus_priv->comp_grp[i]);
+
+deinit_wm:
+ if (i < 0)
+ i = CAM_VFE_BUS_VER2_MAX_CLIENTS;
+ for (--i; i >= 0; i--)
+ cam_vfe_bus_deinit_wm_resource(&bus_priv->bus_client[i]);
+
+free_bus_priv:
kfree(vfe_bus_local->bus_priv);
-err_alloc_priv:
+
+free_bus_local:
kfree(vfe_bus_local);
-err_alloc_bus:
+
+end:
return rc;
}
+
+int cam_vfe_bus_ver2_deinit(
+ struct cam_vfe_bus **vfe_bus)
+{
+ int i, rc = 0;
+ struct cam_vfe_bus_ver2_priv *bus_priv = NULL;
+ struct cam_vfe_bus *vfe_bus_local;
+
+ if (!vfe_bus || !*vfe_bus) {
+ pr_err("Error! Invalid input\n");
+ return -EINVAL;
+ }
+ vfe_bus_local = *vfe_bus;
+
+ bus_priv = vfe_bus_local->bus_priv;
+ if (!bus_priv) {
+ pr_err("Error! bus_priv is NULL\n");
+ rc = -ENODEV;
+ goto free_bus_local;
+ }
+
+ INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list);
+ for (i = 0; i < CAM_VFE_BUS_VER2_PAYLOAD_MAX; i++)
+ INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list);
+
+ for (i = 0; i < CAM_VFE_BUS_VER2_MAX_CLIENTS; i++) {
+ rc = cam_vfe_bus_deinit_wm_resource(&bus_priv->bus_client[i]);
+ if (rc < 0)
+ pr_err("Error! Deinit WM failed rc=%d\n", rc);
+ }
+
+ for (i = 0; i < CAM_VFE_BUS_VER2_COMP_GRP_MAX; i++) {
+ rc = cam_vfe_bus_deinit_comp_grp(&bus_priv->comp_grp[i]);
+ if (rc < 0)
+ pr_err("Error! Deinit Comp Grp failed rc=%d\n", rc);
+ }
+
+ for (i = 0; i < CAM_VFE_BUS_VER2_VFE_OUT_MAX; i++) {
+ rc = cam_vfe_bus_deinit_vfe_out_resource(&bus_priv->vfe_out[i]);
+ if (rc < 0)
+ pr_err("Error! Deinit VFE Out failed rc=%d\n", rc);
+ }
+
+ INIT_LIST_HEAD(&bus_priv->free_comp_grp);
+ INIT_LIST_HEAD(&bus_priv->free_dual_comp_grp);
+ INIT_LIST_HEAD(&bus_priv->used_comp_grp);
+
+ rc = cam_irq_controller_deinit(
+ &bus_priv->common_data.bus_irq_controller);
+ if (rc)
+ pr_err("Error! Deinit IRQ Controller failed rc=%d\n", rc);
+
+ kfree(vfe_bus_local->bus_priv);
+
+free_bus_local:
+ kfree(vfe_bus_local);
+
+ *vfe_bus = NULL;
+
+ return rc;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h
index e451174..ba98077 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h
@@ -171,18 +171,34 @@ struct cam_vfe_bus_ver2_hw_info {
*
* @Brief: Initialize Bus layer
*
- * @mem_base: Mapped base address of register space
+ * @soc_info: Soc Information for the associated HW
* @hw_intf: HW Interface of HW to which this resource belongs
* @bus_hw_info: BUS HW info that contains details of BUS registers
* @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top
* level IRQs
* @vfe_bus: Pointer to vfe_bus structure which will be filled
* and returned on successful initialize
+ *
+ * @Return: 0: Success
+ * Non-zero: Failure
*/
-int cam_vfe_bus_ver2_init(void __iomem *mem_base,
+int cam_vfe_bus_ver2_init(
+ struct cam_hw_soc_info *soc_info,
struct cam_hw_intf *hw_intf,
void *bus_hw_info,
void *vfe_irq_controller,
struct cam_vfe_bus **vfe_bus);
+/*
+ * cam_vfe_bus_ver2_deinit()
+ *
+ * @Brief: Deinitialize Bus layer
+ *
+ * @vfe_bus: Pointer to vfe_bus structure to deinitialize
+ *
+ * @Return: 0: Success
+ * Non-zero: Failure
+ */
+int cam_vfe_bus_ver2_deinit(struct cam_vfe_bus **vfe_bus);
+
#endif /* _CAM_VFE_BUS_VER2_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h
index d202c13..c089911 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h
@@ -14,6 +14,7 @@
#define _CAM_VFE_BUS_H_
#include <uapi/media/cam_isp.h>
+#include "cam_hw_intf.h"
#include "cam_isp_hw.h"
#define CAM_VFE_BUS_VER_1_0 0x1000
@@ -31,25 +32,14 @@ enum cam_vfe_bus_plane_type {
* @Brief: Bus interface structure
*
* @bus_priv: Private data of BUS
- * @acquire_resource: Function pointer for acquiring BUS output resource
- * @release_resource: Function pointer for releasing BUS resource
- * @start_resource: Function for starting BUS Output resource
- * @stop_resource: Function for stopping BUS Output resource
- * @process_cmd: Function to process commands specific to BUS
- * resources
+ * @hw_ops: Hardware interface functions
* @top_half_handler: Top Half handler function
* @bottom_half_handler: Bottom Half handler function
*/
struct cam_vfe_bus {
void *bus_priv;
- int (*acquire_resource)(void *bus_priv, void *acquire_args);
- int (*release_resource)(void *bus_priv,
- struct cam_isp_resource_node *vfe_out);
- int (*start_resource)(struct cam_isp_resource_node *vfe_out);
- int (*stop_resource)(struct cam_isp_resource_node *vfe_out);
- int (*process_cmd)(void *priv, uint32_t cmd_type, void *cmd_args,
- uint32_t arg_size);
+ struct cam_hw_ops hw_ops;
CAM_IRQ_HANDLER_TOP_HALF top_half_handler;
CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler;
};
@@ -60,19 +50,36 @@ struct cam_vfe_bus {
* @Brief: Initialize Bus layer
*
* @bus_version: Version of BUS to initialize
- * @mem_base: Mapped base address of register space
+ * @soc_info: Soc Information for the associated HW
* @hw_intf: HW Interface of HW to which this resource belongs
* @bus_hw_info: BUS HW info that contains details of BUS registers
* @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top
* level IRQs
* @vfe_bus: Pointer to vfe_bus structure which will be filled
* and returned on successful initialize
+ *
+ * @Return: 0: Success
+ * Non-zero: Failure
*/
int cam_vfe_bus_init(uint32_t bus_version,
- void __iomem *mem_base,
+ struct cam_hw_soc_info *soc_info,
struct cam_hw_intf *hw_intf,
void *bus_hw_info,
void *vfe_irq_controller,
struct cam_vfe_bus **vfe_bus);
+/*
+ * cam_vfe_bus_deinit()
+ *
+ * @Brief: Deinitialize Bus layer
+ *
+ * @bus_version: Version of BUS to deinitialize
+ * @vfe_bus: Pointer to vfe_bus structure to deinitialize
+ *
+ * @Return: 0: Success
+ * Non-zero: Failure
+ */
+int cam_vfe_bus_deinit(uint32_t bus_version,
+ struct cam_vfe_bus **vfe_bus);
+
#endif /* _CAM_VFE_BUS_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
index 6dd67df..fa00769 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
@@ -229,7 +229,7 @@ int cam_vfe_camif_ver2_init(
struct cam_vfe_camif_ver2_hw_info *camif_info = camif_hw_info;
camif_priv = kzalloc(sizeof(struct cam_vfe_mux_camif_data),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!camif_priv) {
CDBG("Error! Failed to alloc for camif_priv\n");
return -ENOMEM;
@@ -251,3 +251,24 @@ int cam_vfe_camif_ver2_init(
return 0;
}
+int cam_vfe_camif_ver2_deinit(
+ struct cam_isp_resource_node *camif_node)
+{
+ struct cam_vfe_mux_camif_data *camif_priv = camif_node->res_priv;
+
+ camif_node->start = NULL;
+ camif_node->stop = NULL;
+ camif_node->top_half_handler = NULL;
+ camif_node->bottom_half_handler = NULL;
+
+ camif_node->res_priv = NULL;
+
+ if (!camif_priv) {
+ pr_err("Error! camif_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ kfree(camif_priv);
+
+ return 0;
+}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h
index cc6aab0..553abf2 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h
@@ -75,4 +75,7 @@ int cam_vfe_camif_ver2_init(
void *camif_hw_info,
struct cam_isp_resource_node *camif_node);
+int cam_vfe_camif_ver2_deinit(
+ struct cam_isp_resource_node *camif_node);
+
#endif /* _CAM_VFE_CAMIF_VER2_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c
index 5f77a7c..f96f4d9 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c
@@ -187,3 +187,23 @@ int cam_vfe_rdi_ver2_init(
return 0;
}
+int cam_vfe_rdi_ver2_deinit(
+ struct cam_isp_resource_node *rdi_node)
+{
+ struct cam_vfe_mux_rdi_data *rdi_priv = rdi_node->res_priv;
+
+ rdi_node->start = NULL;
+ rdi_node->stop = NULL;
+ rdi_node->top_half_handler = NULL;
+ rdi_node->bottom_half_handler = NULL;
+
+ rdi_node->res_priv = NULL;
+
+ if (!rdi_priv) {
+ pr_err("Error! rdi_priv NULL\n");
+ return -ENODEV;
+ }
+ kfree(rdi_priv);
+
+ return 0;
+}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h
index 967cec3..9893474 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h
@@ -43,4 +43,7 @@ int cam_vfe_rdi_ver2_init(
void *rdi_hw_info,
struct cam_isp_resource_node *rdi_node);
+int cam_vfe_rdi_ver2_deinit(
+ struct cam_isp_resource_node *rdi_node);
+
#endif /* _CAM_VFE_RDI_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c
index e2bceb8..ee608fa 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c
@@ -36,3 +36,20 @@ int cam_vfe_top_init(uint32_t top_version,
return rc;
}
+int cam_vfe_top_deinit(uint32_t top_version,
+ struct cam_vfe_top **vfe_top)
+{
+ int rc = -EINVAL;
+
+ switch (top_version) {
+ case CAM_VFE_TOP_VER_2_0:
+ rc = cam_vfe_top_ver2_deinit(vfe_top);
+ break;
+ default:
+ pr_err("Error! Unsupported Version %x\n", top_version);
+ break;
+ }
+
+ return rc;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
index 3ef4f49..ce7c63e 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
@@ -359,7 +359,7 @@ int cam_vfe_top_ver2_init(
if (!vfe_top) {
CDBG("Error! Failed to alloc for vfe_top\n");
rc = -ENOMEM;
- goto err_alloc_top;
+ goto end;
}
top_priv = kzalloc(sizeof(struct cam_vfe_top_ver2_priv),
@@ -367,7 +367,7 @@ int cam_vfe_top_ver2_init(
if (!top_priv) {
CDBG("Error! Failed to alloc for vfe_top_priv\n");
rc = -ENOMEM;
- goto err_alloc_priv;
+ goto free_vfe_top;
}
vfe_top->top_priv = top_priv;
@@ -384,16 +384,16 @@ int cam_vfe_top_ver2_init(
&ver2_hw_info->camif_hw_info,
&top_priv->mux_rsrc[i]);
if (rc)
- goto err_mux_init;
+ goto deinit_resources;
} else {
/* set the RDI resource id */
top_priv->mux_rsrc[i].res_id =
- CAM_ISP_HW_VFE_IN_RDI0 + j;
+ CAM_ISP_HW_VFE_IN_RDI0 + j++;
+
rc = cam_vfe_rdi_ver2_init(hw_intf, soc_info,
NULL, &top_priv->mux_rsrc[i]);
if (rc)
goto deinit_resources;
- j++;
}
}
@@ -416,10 +416,71 @@ int cam_vfe_top_ver2_init(
return rc;
deinit_resources:
-err_mux_init:
+ for (--i; i >= 0; i--) {
+ if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) {
+ if (cam_vfe_camif_ver2_deinit(&top_priv->mux_rsrc[i]))
+ pr_err("Camif Deinit failed\n");
+ } else {
+ if (cam_vfe_rdi_ver2_deinit(&top_priv->mux_rsrc[i]))
+ pr_err("RDI Deinit failed\n");
+ }
+ top_priv->mux_rsrc[i].res_state =
+ CAM_ISP_RESOURCE_STATE_UNAVAILABLE;
+ }
+
kfree(vfe_top->top_priv);
-err_alloc_priv:
+free_vfe_top:
kfree(vfe_top);
-err_alloc_top:
+end:
return rc;
}
+
+int cam_vfe_top_ver2_deinit(struct cam_vfe_top **vfe_top_ptr)
+{
+ int i, rc = 0;
+ struct cam_vfe_top_ver2_priv *top_priv = NULL;
+ struct cam_vfe_top *vfe_top;
+
+ if (!vfe_top_ptr) {
+ pr_err("Error! Invalid input\n");
+ return -EINVAL;
+ }
+
+ vfe_top = *vfe_top_ptr;
+ if (!vfe_top) {
+ pr_err("Error! vfe_top NULL\n");
+ return -ENODEV;
+ }
+
+ top_priv = vfe_top->top_priv;
+ if (!top_priv) {
+ pr_err("Error! vfe_top_priv NULL\n");
+ rc = -ENODEV;
+ goto free_vfe_top;
+ }
+
+ for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+ top_priv->mux_rsrc[i].res_state =
+ CAM_ISP_RESOURCE_STATE_UNAVAILABLE;
+ if (top_priv->mux_rsrc[i].res_id ==
+ CAM_ISP_HW_VFE_IN_CAMIF) {
+ rc = cam_vfe_camif_ver2_deinit(&top_priv->mux_rsrc[i]);
+ if (rc)
+ pr_err("Error! Camif deinit failed rc=%d\n",
+ rc);
+ } else {
+ rc = cam_vfe_rdi_ver2_deinit(&top_priv->mux_rsrc[i]);
+ if (rc)
+ pr_err("Error! RDI deinit failed rc=%d\n", rc);
+ }
+ }
+
+ kfree(vfe_top->top_priv);
+
+free_vfe_top:
+ kfree(vfe_top);
+ *vfe_top_ptr = NULL;
+
+ return rc;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h
index 1038721..0813202 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h
@@ -58,6 +58,8 @@ struct cam_vfe_top_ver2_hw_info {
int cam_vfe_top_ver2_init(struct cam_hw_soc_info *soc_info,
struct cam_hw_intf *hw_intf,
void *top_hw_info,
- struct cam_vfe_top **vfe_top);
+ struct cam_vfe_top **vfe_top);
+
+int cam_vfe_top_ver2_deinit(struct cam_vfe_top **vfe_top);
#endif /* _CAM_VFE_TOP_VER2_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h
index 44c046d..dbb211f 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h
@@ -50,4 +50,7 @@ int cam_vfe_top_init(uint32_t top_version,
void *top_hw_info,
struct cam_vfe_top **vfe_top);
+int cam_vfe_top_deinit(uint32_t top_version,
+ struct cam_vfe_top **vfe_top);
+
#endif /* _CAM_VFE_TOP_H_*/
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
index e6da6ca..f514139 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
@@ -1,4 +1,6 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core/
ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_dev.o \
cam_req_mgr_util.o \
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
index edfc245..2f9db97 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
@@ -735,18 +735,19 @@ static int cam_mem_util_unmap(int32_t idx)
if (tbl.bufq[idx].i_hdl && tbl.bufq[idx].kmdvaddr)
ion_unmap_kernel(tbl.client, tbl.bufq[idx].i_hdl);
- if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE ||
- tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) {
-
+ /* SHARED flag gets precedence, all other flags after it */
+ if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) {
+ region = CAM_SMMU_REGION_SHARED;
+ } else {
if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE)
region = CAM_SMMU_REGION_IO;
-
- if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS)
- region = CAM_SMMU_REGION_SHARED;
-
- rc = cam_mem_util_unmap_hw_va(idx, region);
}
+ if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE ||
+ tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS)
+ rc = cam_mem_util_unmap_hw_va(idx, region);
+
+
mutex_lock(&tbl.bufq[idx].q_lock);
tbl.bufq[idx].flags = 0;
tbl.bufq[idx].buf_handle = -1;
@@ -820,15 +821,16 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp,
uint32_t mem_handle;
int32_t smmu_hdl = 0;
int32_t num_hdl = 0;
- enum cam_smmu_region_id region;
+ enum cam_smmu_region_id region = CAM_SMMU_REGION_SHARED;
if (!inp || !out) {
pr_err("Invalid params\n");
return -EINVAL;
}
- if (inp->region != CAM_MEM_MGR_REGION_SHARED &&
- inp->region != CAM_MEM_MGR_REGION_NON_SECURE_IO) {
+ if (!(inp->flags & CAM_MEM_FLAG_HW_READ_WRITE ||
+ inp->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS ||
+ inp->flags & CAM_MEM_FLAG_CACHE)) {
pr_err("Invalid flags for request mem\n");
return -EINVAL;
}
@@ -866,11 +868,13 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp,
goto smmu_fail;
}
- if (inp->region == CAM_MEM_MGR_REGION_SHARED)
+ /* SHARED flag gets precedence, all other flags after it */
+ if (inp->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) {
region = CAM_SMMU_REGION_SHARED;
-
- if (inp->region == CAM_MEM_MGR_REGION_NON_SECURE_IO)
- region = CAM_SMMU_REGION_IO;
+ } else {
+ if (inp->flags & CAM_MEM_FLAG_HW_READ_WRITE)
+ region = CAM_SMMU_REGION_IO;
+ }
rc = cam_smmu_map_iova(inp->smmu_hdl,
ion_fd,
@@ -915,13 +919,13 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp,
out->smmu_hdl = smmu_hdl;
out->mem_handle = mem_handle;
out->len = inp->size;
- out->region = inp->region;
+ out->region = region;
return rc;
slot_fail:
cam_smmu_unmap_iova(inp->smmu_hdl,
ion_fd,
- inp->region);
+ region);
smmu_fail:
ion_unmap_kernel(tbl.client, hdl);
map_fail:
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h
index 32a754e..0858b8a 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h
@@ -14,13 +14,7 @@
#define _CAM_MEM_MGR_API_H_
#include <media/cam_req_mgr.h>
-
-/* Region IDs for memory manager */
-#define CAM_MEM_MGR_REGION_FIRMWARE 0
-#define CAM_MEM_MGR_REGION_SHARED 1
-#define CAM_MEM_MGR_REGION_NON_SECURE_IO 2
-#define CAM_MEM_MGR_REGION_SECURE_IO 3
-#define CAM_MEM_MGR_REGION_SCRATCH 4
+#include "cam_smmu_api.h"
/**
* struct cam_mem_mgr_request_desc
@@ -36,7 +30,6 @@ struct cam_mem_mgr_request_desc {
uint64_t align;
int32_t smmu_hdl;
uint32_t flags;
- uint32_t region;
};
/**
@@ -55,7 +48,7 @@ struct cam_mem_mgr_memory_desc {
int32_t smmu_hdl;
uint32_t mem_handle;
uint64_t len;
- uint32_t region;
+ enum cam_smmu_region_id region;
};
/**
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index ed251eb..f5dfcf2 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -19,6 +19,7 @@
#include "cam_req_mgr_core.h"
#include "cam_req_mgr_workq.h"
#include "cam_req_mgr_debug.h"
+#include "cam_trace.h"
static struct cam_req_mgr_core_device *g_crm_core_dev;
@@ -975,7 +976,7 @@ int cam_req_mgr_process_send_req(void *priv, void *data)
* cam_req_mgr_process_flush_req()
*
* @brief: This runs in workque thread context. Call core funcs to check
- * which requests need to be removedcancelled.
+ * which requests need to be removed/cancelled.
* @priv : link information.
* @data : contains information about frame_id, link etc.
*
@@ -1007,6 +1008,8 @@ int cam_req_mgr_process_flush_req(void *priv, void *data)
in_q = link->req.in_q;
+ trace_cam_flush_req(flush_info);
+
mutex_lock(&link->req.lock);
if (flush_info->flush_type == CAM_REQ_MGR_FLUSH_TYPE_ALL) {
for (i = 0; i < in_q->num_slots; i++) {
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/Makefile
index 8670d80..4e8ea8b 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/Makefile
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/Makefile
@@ -1,8 +1,10 @@
-ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
-ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
-ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
obj-$(CONFIG_SPECTRA_CAMERA) += cam_actuator_dev.o cam_actuator_core.o cam_actuator_soc.o
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
index 0a96f18..37dbf9e 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
@@ -13,7 +13,8 @@
#include <linux/module.h>
#include <cam_sensor_cmn_header.h>
#include "cam_actuator_core.h"
-#include <cam_sensor_util.h>
+#include "cam_sensor_util.h"
+#include "cam_trace.h"
int32_t cam_actuator_slaveInfo_pkt_parser(struct cam_actuator_ctrl_t *a_ctrl,
uint32_t *cmd_buf)
@@ -111,6 +112,9 @@ int32_t cam_actuator_apply_request(struct cam_req_mgr_apply_request *apply)
return -EINVAL;
}
request_id = apply->request_id % MAX_PER_FRAME_ARRAY;
+
+ trace_cam_apply_req("Actuator", apply);
+
CDBG("%s:%d Request Id: %lld\n",
__func__, __LINE__, apply->request_id);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
index 48e3c2e..f8ea769 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
@@ -14,6 +14,7 @@
#include "cam_req_mgr_dev.h"
#include "cam_actuator_soc.h"
#include "cam_actuator_core.h"
+#include "cam_trace.h"
static long cam_actuator_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/Makefile
index 57dfed5..ba81259 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/Makefile
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/Makefile
@@ -3,5 +3,6 @@
ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_cci_dev.o cam_cci_core.o cam_cci_soc.o
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/Makefile
index 0337b32..8edbea5 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/Makefile
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/Makefile
@@ -4,5 +4,6 @@
ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_csiphy_soc.o cam_csiphy_dev.o cam_csiphy_core.o
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
index 71a88bf..6b20bcc 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
@@ -37,7 +37,7 @@ void cam_csiphy_reset(struct csiphy_device *csiphy_dev)
base = soc_info->reg_map[0].mem_base;
for (i = 0; i < size; i++) {
- cam_io_w(
+ cam_io_w_mb(
csiphy_dev->ctrl_reg->
csiphy_reset_reg[i].reg_data,
base +
@@ -128,7 +128,7 @@ void cam_csiphy_cphy_irq_config(struct csiphy_device *csiphy_dev)
csiphy_dev->soc_info.reg_map[0].mem_base;
for (i = 0; i < csiphy_dev->num_irq_registers; i++)
- cam_io_w(csiphy_dev->ctrl_reg->
+ cam_io_w_mb(csiphy_dev->ctrl_reg->
csiphy_irq_reg[i].reg_data,
csiphybase +
csiphy_dev->ctrl_reg->
@@ -142,7 +142,7 @@ void cam_csiphy_cphy_irq_disable(struct csiphy_device *csiphy_dev)
csiphy_dev->soc_info.reg_map[0].mem_base;
for (i = 0; i < csiphy_dev->num_irq_registers; i++)
- cam_io_w(0x0,
+ cam_io_w_mb(0x0,
csiphybase +
csiphy_dev->ctrl_reg->
csiphy_irq_reg[i].reg_addr);
@@ -171,22 +171,22 @@ irqreturn_t cam_csiphy_irq(int irq_num, void *data)
base +
csiphy_dev->ctrl_reg->csiphy_reg.
mipi_csiphy_interrupt_status0_addr + 0x4*i);
- cam_io_w(irq,
+ cam_io_w_mb(irq,
base +
csiphy_dev->ctrl_reg->csiphy_reg.
mipi_csiphy_interrupt_clear0_addr + 0x4*i);
pr_err_ratelimited(
"%s CSIPHY%d_IRQ_STATUS_ADDR%d = 0x%x\n",
__func__, soc_info->index, i, irq);
- cam_io_w(0x0,
+ cam_io_w_mb(0x0,
base +
csiphy_dev->ctrl_reg->csiphy_reg.
mipi_csiphy_interrupt_clear0_addr + 0x4*i);
}
- cam_io_w(0x1, base +
+ cam_io_w_mb(0x1, base +
csiphy_dev->ctrl_reg->
csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr);
- cam_io_w(0x0, base +
+ cam_io_w_mb(0x0, base +
csiphy_dev->ctrl_reg->
csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr);
@@ -198,7 +198,8 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev)
int32_t rc = 0;
uint32_t lane_enable = 0, mask = 1, size = 0;
uint16_t lane_mask = 0, i = 0, cfg_size = 0;
- uint8_t settle_cnt, lane_cnt, lane_pos = 0;
+ uint8_t lane_cnt, lane_pos = 0;
+ uint16_t settle_cnt = 0;
void __iomem *csiphybase;
struct csiphy_reg_t (*reg_array)[MAX_SETTINGS_PER_LANE];
@@ -257,13 +258,13 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev)
switch (csiphy_dev->ctrl_reg->
csiphy_common_reg[i].csiphy_param_type) {
case CSIPHY_LANE_ENABLE:
- cam_io_w(lane_enable,
+ cam_io_w_mb(lane_enable,
csiphybase +
csiphy_dev->ctrl_reg->
csiphy_common_reg[i].reg_addr);
break;
case CSIPHY_DEFAULT_PARAMS:
- cam_io_w(csiphy_dev->ctrl_reg->
+ cam_io_w_mb(csiphy_dev->ctrl_reg->
csiphy_common_reg[i].reg_data,
csiphybase +
csiphy_dev->ctrl_reg->
@@ -284,22 +285,22 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev)
for (i = 0; i < cfg_size; i++) {
switch (reg_array[lane_pos][i].csiphy_param_type) {
case CSIPHY_LANE_ENABLE:
- cam_io_w(lane_enable,
+ cam_io_w_mb(lane_enable,
csiphybase +
reg_array[lane_pos][i].reg_addr);
break;
case CSIPHY_DEFAULT_PARAMS:
- cam_io_w(reg_array[lane_pos][i].reg_data,
+ cam_io_w_mb(reg_array[lane_pos][i].reg_data,
csiphybase +
reg_array[lane_pos][i].reg_addr);
break;
case CSIPHY_SETTLE_CNT_LOWER_BYTE:
- cam_io_w(settle_cnt & 0xFF,
+ cam_io_w_mb(settle_cnt & 0xFF,
csiphybase +
reg_array[lane_pos][i].reg_addr);
break;
case CSIPHY_SETTLE_CNT_HIGHER_BYTE:
- cam_io_w((settle_cnt >> 8) & 0xFF,
+ cam_io_w_mb((settle_cnt >> 8) & 0xFF,
csiphybase +
reg_array[lane_pos][i].reg_addr);
break;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/Makefile
index d8c75fb..5a9441f 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/Makefile
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/Makefile
@@ -1,8 +1,10 @@
-ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
-ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
-ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_dev.o cam_sensor_core.o cam_sensor_soc.o
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index 031c340..be8306c 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -13,8 +13,9 @@
#include <linux/module.h>
#include <cam_sensor_cmn_header.h>
#include "cam_sensor_core.h"
-#include <cam_sensor_util.h>
+#include "cam_sensor_util.h"
#include "cam_soc_util.h"
+#include "cam_trace.h"
static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl,
void *arg)
@@ -1004,6 +1005,9 @@ int32_t cam_sensor_apply_request(struct cam_req_mgr_apply_request *apply)
}
CDBG("%s:%d Req Id: %lld\n", __func__, __LINE__,
apply->request_id);
+
+ trace_cam_apply_req("Sensor", apply);
+
rc = cam_sensor_apply_settings(s_ctrl, apply->request_id);
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/Makefile
index 6292a9f..4c3b8e8 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/Makefile
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/Makefile
@@ -4,5 +4,6 @@
ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_io.o cam_sensor_cci_i2c.o cam_sensor_qup_i2c.o
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/Makefile
index 770391c..bf61fb3 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/Makefile
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/Makefile
@@ -2,5 +2,6 @@
ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_util.o
diff --git a/drivers/media/platform/msm/camera/cam_utils/Makefile b/drivers/media/platform/msm/camera/cam_utils/Makefile
index f22115c..370651f 100644
--- a/drivers/media/platform/msm/camera/cam_utils/Makefile
+++ b/drivers/media/platform/msm/camera/cam_utils/Makefile
@@ -1,3 +1,5 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core/
ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
-obj-$(CONFIG_SPECTRA_CAMERA) += cam_soc_util.o cam_io_util.o cam_packet_util.o
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_soc_util.o cam_io_util.o cam_packet_util.o cam_debug_util.o cam_trace.o
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
new file mode 100644
index 0000000..eb5e7d8
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
@@ -0,0 +1,101 @@
+/* Copyright (c) 2017, The Linux Foundataion. 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/io.h>
+#include "cam_debug_util.h"
+
+static const char *cam_debug_module_id_to_name(unsigned int module_id)
+{
+ const char *name = NULL;
+
+ switch (module_id) {
+ case CAM_CDM:
+ name = "CAM-CDM";
+ break;
+ case CAM_CORE:
+ name = "CAM-CORE";
+ break;
+ case CAM_CRM:
+ name = "CAM_CRM";
+ break;
+ case CAM_CPAS:
+ name = "CAM-CPAS";
+ break;
+ case CAM_ISP:
+ name = "CAM-ISP";
+ break;
+ case CAM_SENSOR:
+ name = "CAM-SENSOR";
+ break;
+ case CAM_SMMU:
+ name = "CAM-SMMU";
+ break;
+ case CAM_SYNC:
+ name = "CAM-SYNC";
+ break;
+ case CAM_ICP:
+ name = "CAM-ICP";
+ break;
+ case CAM_JPEG:
+ name = "CAM-JPEG";
+ break;
+ case CAM_FD:
+ name = "CAM-FD";
+ break;
+ case CAM_LRME:
+ name = "CAM-LRME";
+ break;
+ case CAM_FLASH:
+ name = "CAM-FLASH";
+ break;
+ default:
+ name = "CAM";
+ break;
+ }
+
+ return name;
+}
+
+void cam_debug_log(unsigned int module_id, enum cam_debug_level dbg_level,
+ const char *func, const int line, const char *fmt, ...)
+{
+ char str_buffer[STR_BUFFER_MAX_LENGTH];
+ const char *module_name;
+ va_list args;
+
+ va_start(args, fmt);
+ vsnprintf(str_buffer, STR_BUFFER_MAX_LENGTH, fmt, args);
+ va_end(args);
+
+ module_name = cam_debug_module_id_to_name(module_id);
+
+ switch (dbg_level) {
+ case CAM_LEVEL_INFO:
+ pr_info("CAM_INFO: %s: %s: %d: %s\n",
+ module_name, func, line, str_buffer);
+ break;
+ case CAM_LEVEL_WARN:
+ pr_warn("CAM_WARN: %s: %s: %d: %s\n",
+ module_name, func, line, str_buffer);
+ break;
+ case CAM_LEVEL_ERR:
+ pr_err("CAM_ERR: %s: %s: %d: %s\n",
+ module_name, func, line, str_buffer);
+ break;
+ case CAM_LEVEL_DBG:
+ pr_info("CAM_DBG: %s: %s: %d: %s\n",
+ module_name, func, line, str_buffer);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
index 5989f1a..34adb0e 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundataion. All rights reserved.
+/* 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
@@ -13,7 +13,6 @@
#ifndef _CAM_DEBUG_UTIL_H_
#define _CAM_DEBUG_UTIL_H_
-#define DEFAULT 0xFFFF
#define CAM_CDM (1 << 0)
#define CAM_CORE (1 << 1)
#define CAM_CPAS (1 << 2)
@@ -26,32 +25,91 @@
#define CAM_JPEG (1 << 9)
#define CAM_FD (1 << 10)
#define CAM_LRME (1 << 11)
+#define CAM_FLASH (1 << 12)
-#define GROUP DEFAULT
-#define TRACE_ON 0
+#define STR_BUFFER_MAX_LENGTH 1024
+#define GROUP 0x0000
-#define CAM_ERR(__module, fmt, args...) \
- do { if (GROUP & __module) { \
- if (TRACE_ON) \
- trace_printk(fmt, ##args); \
- else \
- pr_err(fmt, ##args); \
- } } while (0)
+enum cam_debug_level {
+ CAM_LEVEL_INFO,
+ CAM_LEVEL_WARN,
+ CAM_LEVEL_ERR,
+ CAM_LEVEL_DBG,
+};
-#define CAM_WARN(__module, fmt, args...) \
- do { if (GROUP & __module) { \
- if (TRACE_ON) \
- trace_printk(fmt, ##args); \
- else \
- pr_warn(fmt, ##args); \
- } } while (0)
+/*
+ * cam_debug_log()
+ *
+ * @brief: Get the Module name form module ID and print
+ * respective debug logs
+ *
+ * @module_id : Respective Module ID which is calling this function
+ * @dbg_level : Debug level from cam_module_debug_level enum entries
+ * @func : Function which is calling to print logs
+ * @line : Line number associated with the function which is calling
+ * to print log
+ * @fmt : Formatted string which needs to be print in the log
+ *
+ */
+void cam_debug_log(unsigned int module_id, enum cam_debug_level dbg_level,
+ const char *func, const int line, const char *fmt, ...);
-#define CAM_INFO(__module, fmt, args...) \
- do { if (GROUP & __module) { \
- if (TRACE_ON) \
- trace_printk(fmt, ##args); \
- else \
- pr_info(fmt, ##args); \
- } } while (0)
+/*
+ * CAM_ERR
+ * @brief : This Macro will print error logs
+ *
+ * @__module : Respective module id which is been calling this Macro
+ * @fmt : Formatted string which needs to be print in log
+ * @args: Arguments which needs to be print in log
+ */
+#define CAM_ERR(__module, fmt, args...) \
+ { \
+ cam_debug_log(__module, CAM_LEVEL_ERR, \
+ __func__, __LINE__, fmt, ##args); \
+ }
+
+/*
+ * CAM_WARN
+ * @brief : This Macro will print warning logs
+ *
+ * @__module : Respective module id which is been calling this Macro
+ * @fmt : Formatted string which needs to be print in log
+ * @args : Arguments which needs to be print in log
+ */
+#define CAM_WARN(__module, fmt, args...) \
+ { \
+ cam_debug_log(__module, CAM_LEVEL_WARN, \
+ __func__, __LINE__, fmt, ##args); \
+ }
+
+/*
+ * CAM_INFO
+ * @brief : This Macro will print Information logs
+ *
+ * @__module : Respective module id which is been calling this Macro
+ * @fmt : Formatted string which needs to be print in log
+ * @args : Arguments which needs to be print in log
+ */
+#define CAM_INFO(__module, fmt, args...) \
+ { \
+ cam_debug_log(__module, CAM_LEVEL_INFO, \
+ __func__, __LINE__, fmt, ##args); \
+ }
+
+/*
+ * CAM_DBG
+ * @brief : This Macro will print debug logs when enabled using GROUP
+ *
+ * @__module : Respective module id which is been calling this Macro
+ * @fmt : Formatted string which needs to be print in log
+ * @args : Arguments which needs to be print in log
+ */
+#define CAM_DBG(__module, fmt, args...) \
+ do { \
+ if (GROUP & __module) { \
+ cam_debug_log(__module, CAM_LEVEL_DBG, \
+ __func__, __LINE__, fmt, ##args); \
+ } \
+ } while (0)
#endif /* _CAM_DEBUG_UTIL_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
index 0be2aaa..1d86bb1 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
@@ -574,7 +574,7 @@ static int cam_soc_util_get_gpio_info(struct cam_hw_soc_info *soc_info)
goto free_gpio_array;
}
- for (i = 0; i <= gpio_array_size; i++)
+ for (i = 0; i < gpio_array_size; i++)
gconf->cam_gpio_common_tbl[i].gpio = gpio_array[i];
gconf->cam_gpio_common_tbl_size = gpio_array_size;
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_trace.c b/drivers/media/platform/msm/camera/cam_utils/cam_trace.c
new file mode 100644
index 0000000..08129f3
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_trace.c
@@ -0,0 +1,16 @@
+/* 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.
+ *
+ */
+
+/* Instantiate tracepoints */
+#define CREATE_TRACE_POINTS
+#include "cam_trace.h"
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_trace.h b/drivers/media/platform/msm/camera/cam_utils/cam_trace.h
new file mode 100644
index 0000000..f233799
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_trace.h
@@ -0,0 +1,128 @@
+/* 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.
+ *
+ */
+
+#if !defined(_CAM_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _CAM_TRACE_H
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM camera
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE cam_trace
+
+#include <linux/tracepoint.h>
+#include <media/cam_req_mgr.h>
+#include "cam_context.h"
+
+TRACE_EVENT(cam_context_state,
+ TP_PROTO(const char *name, struct cam_context *ctx),
+ TP_ARGS(name, ctx),
+ TP_STRUCT__entry(
+ __field(void*, ctx)
+ __field(uint32_t, state)
+ __string(name, name)
+ ),
+ TP_fast_assign(
+ __entry->ctx = ctx;
+ __entry->state = ctx->state;
+ __assign_str(name, name);
+ ),
+ TP_printk(
+ "%s: State ctx=%p ctx_state=%u",
+ __get_str(name), __entry->ctx, __entry->state
+ )
+);
+
+TRACE_EVENT(cam_isp_activated_irq,
+ TP_PROTO(struct cam_context *ctx, unsigned int substate,
+ unsigned int event, uint64_t timestamp),
+ TP_ARGS(ctx, substate, event, timestamp),
+ TP_STRUCT__entry(
+ __field(void*, ctx)
+ __field(uint32_t, state)
+ __field(uint32_t, substate)
+ __field(uint32_t, event)
+ __field(uint64_t, ts)
+ ),
+ TP_fast_assign(
+ __entry->ctx = ctx;
+ __entry->state = ctx->state;
+ __entry->substate = substate;
+ __entry->event = event;
+ __entry->ts = timestamp;
+ ),
+ TP_printk(
+ "ISP: IRQ ctx=%p ctx_state=%u substate=%u event=%u ts=%llu",
+ __entry->ctx, __entry->state, __entry->substate,
+ __entry->event, __entry->ts
+ )
+);
+
+TRACE_EVENT(cam_buf_done,
+ TP_PROTO(const char *ctx_type, struct cam_context *ctx,
+ struct cam_ctx_request *req),
+ TP_ARGS(ctx_type, ctx, req),
+ TP_STRUCT__entry(
+ __string(ctx_type, ctx_type)
+ __field(void*, ctx)
+ __field(uint64_t, request)
+ ),
+ TP_fast_assign(
+ __assign_str(ctx_type, ctx_type);
+ __entry->ctx = ctx;
+ __entry->request = req->request_id;
+ ),
+ TP_printk(
+ "%5s: BufDone ctx=%p request=%llu",
+ __get_str(ctx_type), __entry->ctx, __entry->request
+ )
+);
+
+TRACE_EVENT(cam_apply_req,
+ TP_PROTO(const char *entity, struct cam_req_mgr_apply_request *req),
+ TP_ARGS(entity, req),
+ TP_STRUCT__entry(
+ __string(entity, entity)
+ __field(uint64_t, req_id)
+ ),
+ TP_fast_assign(
+ __assign_str(entity, entity);
+ __entry->req_id = req->request_id;
+ ),
+ TP_printk(
+ "%8s: ApplyRequest request=%llu",
+ __get_str(entity), __entry->req_id
+ )
+);
+
+TRACE_EVENT(cam_flush_req,
+ TP_PROTO(struct cam_req_mgr_flush_info *info),
+ TP_ARGS(info),
+ TP_STRUCT__entry(
+ __field(uint32_t, type)
+ __field(int64_t, req_id)
+ ),
+ TP_fast_assign(
+ __entry->type = info->flush_type;
+ __entry->req_id = info->req_id;
+ ),
+ TP_printk(
+ "FlushRequest type=%u request=%llu",
+ __entry->type, __entry->req_id
+ )
+);
+#endif /* _CAM_TRACE_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
index 15b8a2d..ae01baf 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
@@ -283,6 +283,59 @@ void sde_mdp_set_ot_limit(struct sde_mdp_set_ot_params *params)
return;
}
+/*
+ * sde_mdp_set_vbif_memtype - set memtype output for the given xin port
+ * @mdata: pointer to global rotator data
+ * @xin_id: xin identifier
+ * @memtype: memtype output configuration
+ * return: none
+ */
+static void sde_mdp_set_vbif_memtype(struct sde_rot_data_type *mdata,
+ u32 xin_id, u32 memtype)
+{
+ u32 reg_off;
+ u32 bit_off;
+ u32 reg_val;
+
+ /*
+ * Assume 4 bits per bit field, 8 fields per 32-bit register.
+ */
+ if (xin_id >= 8)
+ return;
+
+ reg_off = MMSS_VBIF_NRT_VBIF_OUT_AXI_AMEMTYPE_CONF0;
+
+ bit_off = (xin_id & 0x7) * 4;
+ reg_val = SDE_VBIF_READ(mdata, reg_off);
+ reg_val &= ~(0x7 << bit_off);
+ reg_val |= (memtype & 0x7) << bit_off;
+ SDE_VBIF_WRITE(mdata, reg_off, reg_val);
+}
+
+/*
+ * sde_mdp_init_vbif - initialize static vbif configuration
+ * return: 0 if success; error code otherwise
+ */
+int sde_mdp_init_vbif(void)
+{
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+ int i;
+
+ if (!mdata)
+ return -EINVAL;
+
+ if (mdata->vbif_memtype_count && mdata->vbif_memtype) {
+ for (i = 0; i < mdata->vbif_memtype_count; i++)
+ sde_mdp_set_vbif_memtype(mdata, i,
+ mdata->vbif_memtype[i]);
+
+ SDEROT_DBG("amemtype=0x%x\n", SDE_VBIF_READ(mdata,
+ MMSS_VBIF_NRT_VBIF_OUT_AXI_AMEMTYPE_CONF0));
+ }
+
+ return 0;
+}
+
struct reg_bus_client *sde_reg_bus_vote_client_create(char *client_name)
{
struct reg_bus_client *client;
@@ -398,6 +451,32 @@ static int sde_mdp_parse_dt_prop_len(struct platform_device *pdev,
return len;
}
+static void sde_mdp_parse_vbif_memtype(struct platform_device *pdev,
+ struct sde_rot_data_type *mdata)
+{
+ int rc;
+
+ mdata->vbif_memtype_count = sde_mdp_parse_dt_prop_len(pdev,
+ "qcom,mdss-rot-vbif-memtype");
+ mdata->vbif_memtype = kzalloc(sizeof(u32) *
+ mdata->vbif_memtype_count, GFP_KERNEL);
+ if (!mdata->vbif_memtype) {
+ mdata->vbif_memtype_count = 0;
+ return;
+ }
+
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-rot-vbif-memtype", mdata->vbif_memtype,
+ mdata->vbif_memtype_count);
+ if (rc) {
+ SDEROT_DBG("vbif memtype not found\n");
+ kfree(mdata->vbif_memtype);
+ mdata->vbif_memtype = NULL;
+ mdata->vbif_memtype_count = 0;
+ return;
+ }
+}
+
static void sde_mdp_parse_vbif_qos(struct platform_device *pdev,
struct sde_rot_data_type *mdata)
{
@@ -409,14 +488,19 @@ static void sde_mdp_parse_vbif_qos(struct platform_device *pdev,
"qcom,mdss-rot-vbif-qos-setting");
mdata->vbif_nrt_qos = kzalloc(sizeof(u32) *
mdata->npriority_lvl, GFP_KERNEL);
- if (!mdata->vbif_nrt_qos)
+ if (!mdata->vbif_nrt_qos) {
+ mdata->npriority_lvl = 0;
return;
+ }
rc = sde_mdp_parse_dt_handler(pdev,
"qcom,mdss-rot-vbif-qos-setting", mdata->vbif_nrt_qos,
mdata->npriority_lvl);
if (rc) {
SDEROT_DBG("vbif setting not found\n");
+ kfree(mdata->vbif_nrt_qos);
+ mdata->vbif_nrt_qos = NULL;
+ mdata->npriority_lvl = 0;
return;
}
}
@@ -579,6 +663,8 @@ static int sde_mdp_parse_dt_misc(struct platform_device *pdev,
sde_mdp_parse_vbif_qos(pdev, mdata);
+ sde_mdp_parse_vbif_memtype(pdev, mdata);
+
sde_mdp_parse_rot_lut_setting(pdev, mdata);
sde_mdp_parse_inline_rot_lut_setting(pdev, mdata);
@@ -588,6 +674,17 @@ static int sde_mdp_parse_dt_misc(struct platform_device *pdev,
return 0;
}
+static void sde_mdp_destroy_dt_misc(struct platform_device *pdev,
+ struct sde_rot_data_type *mdata)
+{
+ kfree(mdata->vbif_memtype);
+ mdata->vbif_memtype = NULL;
+ kfree(mdata->vbif_rt_qos);
+ mdata->vbif_rt_qos = NULL;
+ kfree(mdata->vbif_nrt_qos);
+ mdata->vbif_nrt_qos = NULL;
+}
+
#define MDP_REG_BUS_VECTOR_ENTRY(ab_val, ib_val) \
{ \
.src = MSM_BUS_MASTER_AMPSS_M0, \
@@ -742,6 +839,7 @@ void sde_rotator_base_destroy(struct sde_rot_data_type *mdata)
sde_rot_res = NULL;
sde_mdp_bus_scale_unregister(mdata);
+ sde_mdp_destroy_dt_misc(pdev, mdata);
sde_rot_iounmap(&mdata->vbif_nrt_io);
sde_rot_iounmap(&mdata->sde_io);
devm_kfree(&pdev->dev, mdata);
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 313c709..b1438d5 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -225,6 +225,9 @@ struct sde_rot_data_type {
u32 *vbif_nrt_qos;
u32 npriority_lvl;
+ u32 vbif_memtype_count;
+ u32 *vbif_memtype;
+
int iommu_attached;
int iommu_ref_cnt;
@@ -271,6 +274,8 @@ u32 sde_mdp_get_ot_limit(u32 width, u32 height, u32 pixfmt, u32 fps, u32 is_rd);
void sde_mdp_set_ot_limit(struct sde_mdp_set_ot_params *params);
+int sde_mdp_init_vbif(void);
+
#define SDE_VBIF_WRITE(mdata, offset, value) \
(sde_reg_w(&mdata->vbif_nrt_io, offset, value, 0))
#define SDE_VBIF_READ(mdata, offset) \
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 df2642c..9d10b06 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -341,6 +341,8 @@ static int sde_rotator_footswitch_ctrl(struct sde_rot_mgr *mgr, bool on)
if (!on) {
mgr->minimum_bw_vote = 0;
sde_rotator_update_perf(mgr);
+ } else {
+ sde_mdp_init_vbif();
}
mgr->regulator_enable = on;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
index 3e686e9..da36e38 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -1136,6 +1136,9 @@ static ssize_t sde_rotator_debug_base_offset_write(struct file *file,
if (sscanf(buf, "%5x %x", &off, &cnt) < 2)
return -EINVAL;
+ if (off % sizeof(u32))
+ return -EINVAL;
+
if (off > dbg->max_offset)
return -EINVAL;
@@ -1204,6 +1207,9 @@ static ssize_t sde_rotator_debug_base_reg_write(struct file *file,
if (cnt < 2)
return -EFAULT;
+ if (off % sizeof(u32))
+ return -EFAULT;
+
if (off >= dbg->max_offset)
return -EFAULT;
@@ -1252,6 +1258,9 @@ static ssize_t sde_rotator_debug_base_reg_read(struct file *file,
goto debug_read_error;
}
+ if (dbg->off % sizeof(u32))
+ return -EFAULT;
+
ptr = dbg->base + dbg->off;
tot = 0;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
index 573e0a8..27e9ba6 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
@@ -783,10 +783,15 @@ struct sde_mdp_format_params *sde_get_format_params(u32 format)
if (!fmt_found) {
for (i = 0; i < ARRAY_SIZE(sde_mdp_format_ubwc_map); i++) {
fmt = &sde_mdp_format_ubwc_map[i].mdp_format;
- if (format == fmt->format)
+ if (format == fmt->format) {
+ fmt_found = true;
break;
+ }
}
}
+ /* If format not supported than return NULL */
+ if (!fmt_found)
+ fmt = NULL;
return fmt;
}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
index de448a4..5593919 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
@@ -65,6 +65,7 @@
#define MMSS_VBIF_NRT_VBIF_IN_WR_LIM_CONF2 0x00C8
#define MMSS_VBIF_NRT_VBIF_OUT_RD_LIM_CONF0 0x00D0
#define MMSS_VBIF_NRT_VBIF_OUT_WR_LIM_CONF0 0x00D4
+#define MMSS_VBIF_NRT_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x0160
#define MMSS_VBIF_NRT_VBIF_QOS_RP_REMAP_000 0x0550
#define MMSS_VBIF_NRT_VBIF_QOS_LVL_REMAP_000 0x0590
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 743d2f7..205eeef 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -1446,6 +1446,9 @@ static void sde_hw_rotator_setup_wbengine(struct sde_hw_rotator_context *ctx,
if (bw > 0xFF)
bw = 0xFF;
+ else if (bw == 0)
+ bw = 1;
+
SDE_REGDMA_WRITE(wrptr, ROT_WB_TRAFFIC_SHAPER_WR_CLIENT,
BIT(31) | (cfg->prefill_bw ? BIT(27) : 0) | bw);
SDEROT_DBG("Enable ROT_WB Traffic Shaper:%d\n", bw);
diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
index 9f8b341..a7b1852 100644
--- a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
+++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
@@ -846,10 +846,6 @@ static int __get_target_freq(struct devfreq *dev, unsigned long *freq)
if (!dev || !freq)
return -EINVAL;
- /* Start with highest frequecy and decide correct one later*/
-
- ab_kbps = INT_MAX;
-
gov = container_of(dev->governor,
struct governor, devfreq_gov);
dev->profile->get_dev_status(dev->dev.parent, &stats);
@@ -860,11 +856,11 @@ static int __get_target_freq(struct devfreq *dev, unsigned long *freq)
for (c = 0; c < vidc_data->data_count; ++c) {
if (vidc_data->data->power_mode == VIDC_POWER_TURBO) {
+ ab_kbps = INT_MAX;
goto exit;
}
}
- ab_kbps = 0;
for (c = 0; c < vidc_data->data_count; ++c)
ab_kbps += __calculate(&vidc_data->data[c], gov->mode);
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 1991a34..32e79f2 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1360,11 +1360,15 @@ int create_pkt_cmd_session_set_property(
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR;
hfi = (struct hfi_conceal_color *) &pkt->rg_property_data[1];
- if (hfi)
- hfi->conceal_color =
+ if (hfi) {
+ hfi->conceal_color_8bit =
((struct hfi_conceal_color *) pdata)->
- conceal_color;
- pkt->size += sizeof(u32) * 2;
+ conceal_color_8bit;
+ hfi->conceal_color_10bit =
+ ((struct hfi_conceal_color *) pdata)->
+ conceal_color_10bit;
+ }
+ pkt->size += sizeof(u32) + sizeof(struct hfi_conceal_color);
break;
}
case HAL_PARAM_VPE_ROTATION:
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 6e28e70..988f79c 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -24,7 +24,8 @@
#define MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS MIN_NUM_CAPTURE_BUFFERS
#define MIN_NUM_DEC_OUTPUT_BUFFERS 4
#define MIN_NUM_DEC_CAPTURE_BUFFERS 4
-#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8010
+// Y=16(0-9bits), Cb(10-19bits)=Cr(20-29bits)=128, black by default
+#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010
#define MB_SIZE_IN_PIXEL (16 * 16)
#define OPERATING_FRAME_RATE_STEP (1 << 16)
@@ -264,11 +265,20 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = {
.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
},
{
- .id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR,
- .name = "Picture concealed color",
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_8BIT,
+ .name = "Picture concealed color 8bit",
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0x0,
- .maximum = 0xffffff,
+ .maximum = 0xff3fcff,
+ .default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_10BIT,
+ .name = "Picture concealed color 10bit",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0x0,
+ .maximum = 0x3fffffff,
.default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
.step = 1,
},
@@ -991,11 +1001,6 @@ int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
break;
}
break;
- case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR:
- property_id = HAL_PARAM_VDEC_CONCEAL_COLOR;
- property_val = ctrl->val;
- pdata = &property_val;
- break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
property_id =
@@ -1056,9 +1061,6 @@ int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
inst, inst->clk_data.operating_rate >> 16,
ctrl->val >> 16);
inst->clk_data.operating_rate = ctrl->val;
-
- msm_vidc_update_operating_rate(inst);
-
break;
default:
break;
@@ -1084,29 +1086,37 @@ int msm_vdec_s_ext_ctrl(struct msm_vidc_inst *inst,
int rc = 0, i = 0, fourcc = 0;
struct v4l2_ext_control *ext_control;
struct v4l2_control control;
+ struct hal_conceal_color conceal_color = {0};
+ struct hfi_device *hdev;
- if (!inst || !inst->core || !ctrl) {
+ if (!inst || !inst->core || !inst->core->device || !ctrl) {
dprintk(VIDC_ERR,
"%s invalid parameters\n", __func__);
return -EINVAL;
}
+ hdev = inst->core->device;
+
+ v4l2_try_ext_ctrls(&inst->ctrl_handler, ctrl);
+
ext_control = ctrl->controls;
- control.id =
- V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE;
for (i = 0; i < ctrl->count; i++) {
switch (ext_control[i].id) {
case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
control.value = ext_control[i].value;
-
+ control.id =
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE;
rc = msm_comm_s_ctrl(inst, &control);
if (rc)
dprintk(VIDC_ERR,
"%s Failed setting stream output mode : %d\n",
__func__, rc);
+ rc = msm_vidc_update_host_buff_counts(inst);
break;
case V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT:
+ control.id =
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE;
switch (ext_control[i].value) {
case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE:
if (!msm_comm_g_ctrl_for_id(inst, control.id)) {
@@ -1142,6 +1152,7 @@ int msm_vdec_s_ext_ctrl(struct msm_vidc_inst *inst,
break;
}
}
+ rc = msm_vidc_update_host_buff_counts(inst);
inst->clk_data.dpb_fourcc = fourcc;
break;
default:
@@ -1152,6 +1163,36 @@ int msm_vdec_s_ext_ctrl(struct msm_vidc_inst *inst,
break;
}
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_8BIT:
+ conceal_color.conceal_color_8bit = ext_control[i].value;
+ i++;
+ switch (ext_control[i].id) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_10BIT:
+ conceal_color.conceal_color_10bit =
+ ext_control[i].value;
+ dprintk(VIDC_DBG,
+ "conceal color: 8bit=0x%x 10bit=0x%x",
+ conceal_color.conceal_color_8bit,
+ conceal_color.conceal_color_10bit);
+ rc = call_hfi_op(hdev, session_set_property,
+ inst->session,
+ HAL_PARAM_VDEC_CONCEAL_COLOR,
+ &conceal_color);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s Failed setting conceal color",
+ __func__);
+ }
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "%s Could not find CONCEAL_COLOR_10BIT ext_control",
+ __func__);
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ break;
default:
dprintk(VIDC_ERR
, "%s Unsupported set control %d",
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 90a38bb..5c587e2 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1748,8 +1748,6 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
ctrl->val >> 16);
inst->clk_data.operating_rate = ctrl->val;
- msm_vidc_update_operating_rate(inst);
-
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 98a59a5..427568c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -429,7 +429,7 @@ int msm_vidc_release_buffer(void *instance, int type, unsigned int index)
print_vidc_buffer(VIDC_DBG, "release buf", inst, mbuf);
msm_comm_unmap_vidc_buffer(inst, mbuf);
list_del(&mbuf->list);
- kfree(mbuf);
+ kref_put_mbuf(mbuf);
}
mutex_unlock(&inst->registeredbufs.lock);
@@ -998,7 +998,7 @@ static int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
}
msm_comm_unmap_vidc_buffer(inst, temp);
list_del(&temp->list);
- kfree(temp);
+ kref_put_mbuf(temp);
}
mutex_unlock(&inst->registeredbufs.lock);
}
@@ -1075,10 +1075,16 @@ static void msm_vidc_buf_queue(struct vb2_buffer *vb2)
inst, vb2);
return;
}
+ if (!kref_get_mbuf(inst, mbuf)) {
+ dprintk(VIDC_ERR, "%s: mbuf not found\n", __func__);
+ return;
+ }
rc = msm_comm_qbuf(inst, mbuf);
if (rc)
print_vidc_buffer(VIDC_ERR, "failed qbuf", inst, mbuf);
+
+ kref_put_mbuf(mbuf);
}
static const struct vb2_ops msm_vidc_vb2q_ops = {
@@ -1620,7 +1626,7 @@ static void msm_vidc_cleanup_instance(struct msm_vidc_inst *inst)
print_vidc_buffer(VIDC_ERR, "undequeud buf", inst, temp);
msm_comm_unmap_vidc_buffer(inst, temp);
list_del(&temp->list);
- kfree(temp);
+ kref_put_mbuf(temp);
}
mutex_unlock(&inst->registeredbufs.lock);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 86dc973..4327309 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -791,8 +791,6 @@ void msm_clock_data_reset(struct msm_vidc_inst *inst)
msm_dcvs_print_dcvs_stats(dcvs);
- msm_vidc_update_operating_rate(inst);
-
rc = msm_comm_scale_clocks_and_bus(inst);
if (rc)
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 844a4e1..03ad0a0 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1492,6 +1492,7 @@ static void handle_event_change(enum hal_command_response cmd, void *data)
break;
case HAL_EVENT_RELEASE_BUFFER_REFERENCE:
{
+ struct msm_vidc_buffer *mbuf;
u32 planes[VIDEO_MAX_PLANES] = {0};
dprintk(VIDC_DBG,
@@ -1501,8 +1502,15 @@ static void handle_event_change(enum hal_command_response cmd, void *data)
planes[0] = event_notify->packet_buffer;
planes[1] = event_notify->extra_data_buffer;
- handle_release_buffer_reference(inst, planes);
-
+ mbuf = msm_comm_get_buffer_using_device_planes(inst, planes);
+ if (!mbuf || !kref_get_mbuf(inst, mbuf)) {
+ dprintk(VIDC_ERR,
+ "%s: data_addr %x, extradata_addr %x not found\n",
+ __func__, planes[0], planes[1]);
+ } else {
+ handle_release_buffer_reference(inst, mbuf);
+ kref_put_mbuf(mbuf);
+ }
goto err_bad_event;
}
default:
@@ -2176,7 +2184,7 @@ static void handle_ebd(enum hal_command_response cmd, void *data)
{
struct msm_vidc_cb_data_done *response = data;
struct msm_vidc_buffer *mbuf;
- struct vb2_buffer *vb;
+ struct vb2_buffer *vb, *vb2;
struct msm_vidc_inst *inst;
struct vidc_hal_ebd *empty_buf_done;
struct vb2_v4l2_buffer *vbuf;
@@ -2200,18 +2208,31 @@ static void handle_ebd(enum hal_command_response cmd, void *data)
planes[1] = empty_buf_done->extra_data_buffer;
mbuf = msm_comm_get_buffer_using_device_planes(inst, planes);
- if (!mbuf) {
+ if (!mbuf || !kref_get_mbuf(inst, mbuf)) {
dprintk(VIDC_ERR,
"%s: data_addr %x, extradata_addr %x not found\n",
__func__, planes[0], planes[1]);
goto exit;
}
+ vb2 = msm_comm_get_vb_using_vidc_buffer(inst, mbuf);
+
+ /*
+ * take registeredbufs.lock to update mbuf & vb2 variables together
+ * so that both are in sync else if mbuf and vb2 variables are not
+ * in sync msm_comm_compare_vb2_planes() returns false for the
+ * right buffer due to data_offset field mismatch.
+ */
+ mutex_lock(&inst->registeredbufs.lock);
vb = &mbuf->vvb.vb2_buf;
vb->planes[0].bytesused = response->input_done.filled_len;
if (vb->planes[0].bytesused > vb->planes[0].length)
dprintk(VIDC_INFO, "bytesused overflow length\n");
+ vb->planes[0].data_offset = response->input_done.offset;
+ if (vb->planes[0].data_offset > vb->planes[0].length)
+ dprintk(VIDC_INFO, "data_offset overflow length\n");
+
if (empty_buf_done->status == VIDC_ERR_NOT_SUPPORTED) {
dprintk(VIDC_INFO, "Failed : Unsupported input stream\n");
mbuf->vvb.flags |= V4L2_QCOM_BUF_INPUT_UNSUPPORTED;
@@ -2228,26 +2249,28 @@ static void handle_ebd(enum hal_command_response cmd, void *data)
if (extra_idx && extra_idx < VIDEO_MAX_PLANES)
vb->planes[extra_idx].bytesused = vb->planes[extra_idx].length;
+ if (vb2) {
+ vbuf = to_vb2_v4l2_buffer(vb2);
+ vbuf->flags |= mbuf->vvb.flags;
+ for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) {
+ vb2->planes[i].bytesused =
+ mbuf->vvb.vb2_buf.planes[i].bytesused;
+ vb2->planes[i].data_offset =
+ mbuf->vvb.vb2_buf.planes[i].data_offset;
+ }
+ }
+ mutex_unlock(&inst->registeredbufs.lock);
+
update_recon_stats(inst, &empty_buf_done->recon_stats);
msm_vidc_clear_freq_entry(inst, mbuf->smem[0].device_addr);
-
- vb = msm_comm_get_vb_using_vidc_buffer(inst, mbuf);
- if (vb) {
- vbuf = to_vb2_v4l2_buffer(vb);
- vbuf->flags |= mbuf->vvb.flags;
- for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++)
- vb->planes[i].bytesused =
- mbuf->vvb.vb2_buf.planes[i].bytesused;
- }
/*
* put_buffer should be done before vb2_buffer_done else
* client might queue the same buffer before it is unmapped
- * in put_buffer. also don't use mbuf after put_buffer
- * as it may be freed in put_buffer.
+ * in put_buffer.
*/
msm_comm_put_vidc_buffer(inst, mbuf);
- msm_comm_vb2_buffer_done(inst, vb);
-
+ msm_comm_vb2_buffer_done(inst, vb2);
+ kref_put_mbuf(mbuf);
exit:
put_inst(inst);
}
@@ -2299,7 +2322,7 @@ static void handle_fbd(enum hal_command_response cmd, void *data)
struct msm_vidc_cb_data_done *response = data;
struct msm_vidc_buffer *mbuf;
struct msm_vidc_inst *inst;
- struct vb2_buffer *vb = NULL;
+ struct vb2_buffer *vb, *vb2;
struct vidc_hal_fbd *fill_buf_done;
struct vb2_v4l2_buffer *vbuf;
enum hal_buffer buffer_type;
@@ -2326,12 +2349,13 @@ static void handle_fbd(enum hal_command_response cmd, void *data)
buffer_type = msm_comm_get_hal_output_buffer(inst);
if (fill_buf_done->buffer_type == buffer_type) {
mbuf = msm_comm_get_buffer_using_device_planes(inst, planes);
- if (!mbuf) {
+ if (!mbuf || !kref_get_mbuf(inst, mbuf)) {
dprintk(VIDC_ERR,
"%s: data_addr %x, extradata_addr %x not found\n",
__func__, planes[0], planes[1]);
goto exit;
}
+ vb2 = msm_comm_get_vb_using_vidc_buffer(inst, mbuf);
} else {
if (handle_multi_stream_buffers(inst,
fill_buf_done->packet_buffer1))
@@ -2340,6 +2364,14 @@ static void handle_fbd(enum hal_command_response cmd, void *data)
&fill_buf_done->packet_buffer1);
goto exit;
}
+
+ /*
+ * take registeredbufs.lock to update mbuf & vb2 variables together
+ * so that both are in sync else if mbuf and vb2 variables are not
+ * in sync msm_comm_compare_vb2_planes() returns false for the
+ * right buffer due to data_offset field mismatch.
+ */
+ mutex_lock(&inst->registeredbufs.lock);
vb = &mbuf->vvb.vb2_buf;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME ||
@@ -2351,10 +2383,12 @@ static void handle_fbd(enum hal_command_response cmd, void *data)
"fbd:Overflow bytesused = %d; length = %d\n",
vb->planes[0].bytesused,
vb->planes[0].length);
- if (vb->planes[0].data_offset != fill_buf_done->offset1)
- dprintk(VIDC_ERR, "%s: data_offset %d vs %d\n",
- __func__, vb->planes[0].data_offset,
- fill_buf_done->offset1);
+ vb->planes[0].data_offset = fill_buf_done->offset1;
+ if (vb->planes[0].data_offset > vb->planes[0].length)
+ dprintk(VIDC_INFO,
+ "fbd:Overflow data_offset = %d; length = %d\n",
+ vb->planes[0].data_offset,
+ vb->planes[0].length);
if (!(fill_buf_done->flags1 & HAL_BUFFERFLAG_TIMESTAMPINVALID)) {
time_usec = fill_buf_done->timestamp_hi;
time_usec = (time_usec << 32) | fill_buf_done->timestamp_lo;
@@ -2412,23 +2446,27 @@ static void handle_fbd(enum hal_command_response cmd, void *data)
break;
}
- vb = msm_comm_get_vb_using_vidc_buffer(inst, mbuf);
- if (vb) {
- vbuf = to_vb2_v4l2_buffer(vb);
+ if (vb2) {
+ vbuf = to_vb2_v4l2_buffer(vb2);
vbuf->flags = mbuf->vvb.flags;
- vb->timestamp = mbuf->vvb.vb2_buf.timestamp;
- for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++)
- vb->planes[i].bytesused =
+ vb2->timestamp = mbuf->vvb.vb2_buf.timestamp;
+ for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) {
+ vb2->planes[i].bytesused =
mbuf->vvb.vb2_buf.planes[i].bytesused;
+ vb2->planes[i].data_offset =
+ mbuf->vvb.vb2_buf.planes[i].data_offset;
+ }
}
+ mutex_unlock(&inst->registeredbufs.lock);
+
/*
* put_buffer should be done before vb2_buffer_done else
* client might queue the same buffer before it is unmapped
- * in put_buffer. also don't use mbuf after put_buffer
- * as it may be freed in put_buffer.
+ * in put_buffer.
*/
msm_comm_put_vidc_buffer(inst, mbuf);
- msm_comm_vb2_buffer_done(inst, vb);
+ msm_comm_vb2_buffer_done(inst, vb2);
+ kref_put_mbuf(mbuf);
exit:
put_inst(inst);
@@ -3174,6 +3212,11 @@ static int set_output_buffers(struct msm_vidc_inst *inst,
buffer_type);
return 0;
}
+
+ /* For DPB buffers, Always use FW count */
+ output_buf->buffer_count_actual = output_buf->buffer_count_min_host =
+ output_buf->buffer_count_min;
+
dprintk(VIDC_DBG,
"output: num = %d, size = %d\n",
output_buf->buffer_count_actual,
@@ -4749,8 +4792,7 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
/* remove from list */
list_del(&mbuf->list);
- kfree(mbuf);
- mbuf = NULL;
+ kref_put_mbuf(mbuf);
}
mutex_unlock(&inst->registeredbufs.lock);
@@ -4940,6 +4982,7 @@ int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst)
{
u32 x_min, x_max, y_min, y_max;
u32 input_height, input_width, output_height, output_width;
+ u32 rotation;
input_height = inst->prop.height[OUTPUT_PORT];
input_width = inst->prop.width[OUTPUT_PORT];
@@ -4975,6 +5018,20 @@ int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst)
return 0;
}
+ rotation = msm_comm_g_ctrl_for_id(inst,
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION);
+
+ if ((output_width != output_height) &&
+ (rotation == V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90 ||
+ rotation == V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270)) {
+
+ output_width = inst->prop.height[CAPTURE_PORT];
+ output_height = inst->prop.width[CAPTURE_PORT];
+ dprintk(VIDC_DBG,
+ "Rotation=%u Swapped Output W=%u H=%u to check scaling",
+ rotation, output_width, output_height);
+ }
+
x_min = (1<<16)/inst->capability.scale_x.min;
y_min = (1<<16)/inst->capability.scale_y.min;
x_max = inst->capability.scale_x.max >> 16;
@@ -5923,6 +5980,7 @@ struct msm_vidc_buffer *msm_comm_get_vidc_buffer(struct msm_vidc_inst *inst,
rc = -ENOMEM;
goto exit;
}
+ kref_init(&mbuf->kref);
}
vbuf = to_vb2_v4l2_buffer(vb2);
@@ -5986,11 +6044,11 @@ struct msm_vidc_buffer *msm_comm_get_vidc_buffer(struct msm_vidc_inst *inst,
return mbuf;
exit:
- mutex_unlock(&inst->registeredbufs.lock);
dprintk(VIDC_ERR, "%s: rc %d\n", __func__, rc);
msm_comm_unmap_vidc_buffer(inst, mbuf);
if (!found)
- kfree(mbuf);
+ kref_put_mbuf(mbuf);
+ mutex_unlock(&inst->registeredbufs.lock);
return ERR_PTR(rc);
}
@@ -6042,24 +6100,26 @@ void msm_comm_put_vidc_buffer(struct msm_vidc_inst *inst,
*/
if (!mbuf->smem[0].refcount) {
list_del(&mbuf->list);
- kfree(mbuf);
- mbuf = NULL;
+ kref_put_mbuf(mbuf);
}
unlock:
mutex_unlock(&inst->registeredbufs.lock);
}
-void handle_release_buffer_reference(struct msm_vidc_inst *inst, u32 *planes)
+void handle_release_buffer_reference(struct msm_vidc_inst *inst,
+ struct msm_vidc_buffer *mbuf)
{
int rc = 0;
- struct msm_vidc_buffer *mbuf = NULL;
+ struct msm_vidc_buffer *temp;
bool found = false;
int i = 0;
mutex_lock(&inst->registeredbufs.lock);
found = false;
- list_for_each_entry(mbuf, &inst->registeredbufs.list, list) {
- if (msm_comm_compare_device_planes(mbuf, planes)) {
+ /* check if mbuf was not removed by any chance */
+ list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+ if (msm_comm_compare_vb2_planes(inst, mbuf,
+ &temp->vvb.vb2_buf)) {
found = true;
break;
}
@@ -6077,13 +6137,10 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, u32 *planes)
/* refcount is not zero if client queued the same buffer */
if (!mbuf->smem[0].refcount) {
list_del(&mbuf->list);
- kfree(mbuf);
- mbuf = NULL;
+ kref_put_mbuf(mbuf);
}
} else {
- dprintk(VIDC_ERR,
- "%s: data_addr %x extradata_addr %x not found\n",
- __func__, planes[0], planes[1]);
+ print_vidc_buffer(VIDC_ERR, "mbuf not found", inst, mbuf);
goto unlock;
}
@@ -6097,8 +6154,9 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, u32 *planes)
* and if found queue it to video hw (if not flushing).
*/
found = false;
- list_for_each_entry(mbuf, &inst->registeredbufs.list, list) {
- if (msm_comm_compare_device_plane(mbuf, planes, 0)) {
+ list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+ if (msm_comm_compare_vb2_plane(inst, mbuf,
+ &temp->vvb.vb2_buf, 0)) {
found = true;
break;
}
@@ -6113,8 +6171,7 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, u32 *planes)
msm_comm_unmap_vidc_buffer(inst, mbuf);
/* remove from list */
list_del(&mbuf->list);
- kfree(mbuf);
- mbuf = NULL;
+ kref_put_mbuf(mbuf);
/* don't queue the buffer */
found = false;
@@ -6161,3 +6218,41 @@ int msm_comm_unmap_vidc_buffer(struct msm_vidc_inst *inst,
return rc;
}
+static void kref_free_mbuf(struct kref *kref)
+{
+ struct msm_vidc_buffer *mbuf = container_of(kref,
+ struct msm_vidc_buffer, kref);
+
+ kfree(mbuf);
+}
+
+void kref_put_mbuf(struct msm_vidc_buffer *mbuf)
+{
+ if (!mbuf)
+ return;
+
+ kref_put(&mbuf->kref, kref_free_mbuf);
+}
+
+bool kref_get_mbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf)
+{
+ struct msm_vidc_buffer *temp;
+ bool matches = false;
+ bool ret = false;
+
+ if (!inst || !mbuf)
+ return false;
+
+ mutex_lock(&inst->registeredbufs.lock);
+ list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+ if (temp == mbuf) {
+ matches = true;
+ break;
+ }
+ }
+ ret = (matches && kref_get_unless_zero(&mbuf->kref)) ? true : false;
+ mutex_unlock(&inst->registeredbufs.lock);
+
+ return ret;
+}
+
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index bc881a0..18ba4a5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -116,7 +116,8 @@ struct msm_vidc_buffer *msm_comm_get_vidc_buffer(struct msm_vidc_inst *inst,
struct vb2_buffer *vb2);
void msm_comm_put_vidc_buffer(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf);
-void handle_release_buffer_reference(struct msm_vidc_inst *inst, u32 *planes);
+void handle_release_buffer_reference(struct msm_vidc_inst *inst,
+ struct msm_vidc_buffer *mbuf);
int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst,
struct vb2_buffer *vb);
int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst,
@@ -145,4 +146,7 @@ void print_vb2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
struct vb2_buffer *vb2);
void print_v4l2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
struct v4l2_buffer *v4l2);
+void kref_put_mbuf(struct msm_vidc_buffer *mbuf);
+bool kref_get_mbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf);
+
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 58c3b0f..5be1ee2 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -430,7 +430,8 @@ void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
case MSM_VIDC_DEBUGFS_EVENT_FBD:
inst->count.fbd++;
inst->debug.samples++;
- if (inst->count.ebd && inst->count.fbd == inst->count.ftb) {
+ if (inst->count.fbd &&
+ inst->count.fbd == inst->count.ftb) {
toc(inst, FRAME_PROCESSING);
dprintk(VIDC_PROF, "FBD: FW needs output buffers\n");
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 49e6c3ec..e554a46 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -387,6 +387,7 @@ void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
struct msm_vidc_buffer {
struct list_head list;
+ struct kref kref;
struct msm_smem smem[VIDEO_MAX_PLANES];
struct vb2_v4l2_buffer vvb;
bool deferred;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 0069e40..b430d14 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1681,9 +1681,16 @@ static int venus_hfi_core_init(void *device)
}
dev = device;
- mutex_lock(&dev->lock);
dprintk(VIDC_DBG, "Core initializing\n");
+
+ mutex_lock(&dev->lock);
+
+ dev->bus_vote.data =
+ kzalloc(sizeof(struct vidc_bus_vote_data), GFP_KERNEL);
+ dev->bus_vote.data_count = 1;
+ dev->bus_vote.data->power_mode = VIDC_POWER_TURBO;
+
rc = __load_fw(dev);
if (rc) {
dprintk(VIDC_ERR, "Failed to load Venus FW\n");
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 79ce858..fbd3b02 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -996,6 +996,11 @@ struct buffer_requirements {
struct hal_buffer_requirements buffer[HAL_BUFFER_MAX];
};
+struct hal_conceal_color {
+ u32 conceal_color_8bit;
+ u32 conceal_color_10bit;
+};
+
union hal_get_property {
struct hal_frame_rate frame_rate;
struct hal_uncompressed_format_select format_select;
@@ -1045,6 +1050,7 @@ union hal_get_property {
struct hal_buffer_alloc_mode buffer_alloc_mode;
struct buffer_requirements buf_req;
enum hal_h264_entropy h264_entropy;
+ struct hal_conceal_color conceal_color;
};
/* HAL Response */
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index d5624ce..a522918 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -478,7 +478,8 @@ struct hfi_vpe_rotation_type {
};
struct hfi_conceal_color {
- u32 conceal_color;
+ u32 conceal_color_8bit;
+ u32 conceal_color_10bit;
};
struct hfi_intra_period {
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index b373acb..232c290 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -228,7 +228,7 @@ static int wcd9xxx_slim_read_device(struct wcd9xxx *wcd9xxx, unsigned short reg,
if (!wcd9xxx->dev_up) {
dev_dbg_ratelimited(
- wcd9xxx->dev, "%s: No read allowed. dev_up = %d\n",
+ wcd9xxx->dev, "%s: No read allowed. dev_up = %lu\n",
__func__, wcd9xxx->dev_up);
return 0;
}
@@ -268,7 +268,7 @@ static int wcd9xxx_slim_write_device(struct wcd9xxx *wcd9xxx,
if (!wcd9xxx->dev_up) {
dev_dbg_ratelimited(
- wcd9xxx->dev, "%s: No write allowed. dev_up = %d\n",
+ wcd9xxx->dev, "%s: No write allowed. dev_up = %lu\n",
__func__, wcd9xxx->dev_up);
return 0;
}
@@ -345,7 +345,7 @@ int wcd9xxx_slim_write_repeat(struct wcd9xxx *wcd9xxx, unsigned short reg,
if (!wcd9xxx->dev_up) {
dev_dbg_ratelimited(
- wcd9xxx->dev, "%s: No write allowed. dev_up = %d\n",
+ wcd9xxx->dev, "%s: No write allowed. dev_up = %lu\n",
__func__, wcd9xxx->dev_up);
ret = 0;
goto done;
@@ -426,7 +426,7 @@ int wcd9xxx_slim_bulk_write(struct wcd9xxx *wcd9xxx,
if (!wcd9xxx->dev_up) {
dev_dbg_ratelimited(
- wcd9xxx->dev, "%s: No write allowed. dev_up = %d\n",
+ wcd9xxx->dev, "%s: No write allowed. dev_up = %lu\n",
__func__, wcd9xxx->dev_up);
return 0;
}
@@ -1479,12 +1479,27 @@ static int wcd9xxx_slim_device_reset(struct slim_device *sldev)
return -EINVAL;
}
- dev_info(wcd9xxx->dev, "%s: device reset, dev_up = %d\n",
- __func__, wcd9xxx->dev_up);
- if (wcd9xxx->dev_up)
- return 0;
+ /*
+ * Wait for 500 ms for device down to complete. Observed delay
+ * of ~200ms for device down to complete after being called,
+ * due to context switch issue.
+ */
+ ret = wait_on_bit_timeout(&wcd9xxx->dev_up, 0,
+ TASK_INTERRUPTIBLE,
+ msecs_to_jiffies(500));
+ if (ret)
+ pr_err("%s: slim device down not complete in 500 msec\n",
+ __func__);
mutex_lock(&wcd9xxx->reset_lock);
+
+ dev_info(wcd9xxx->dev, "%s: device reset, dev_up = %lu\n",
+ __func__, wcd9xxx->dev_up);
+ if (wcd9xxx->dev_up) {
+ mutex_unlock(&wcd9xxx->reset_lock);
+ return 0;
+ }
+
ret = wcd9xxx_reset(wcd9xxx->dev);
if (ret)
dev_err(wcd9xxx->dev, "%s: Resetting Codec failed\n", __func__);
@@ -1502,8 +1517,8 @@ static int wcd9xxx_slim_device_up(struct slim_device *sldev)
pr_err("%s: wcd9xxx is NULL\n", __func__);
return -EINVAL;
}
- dev_info(wcd9xxx->dev, "%s: slim device up, dev_up = %d\n",
- __func__, wcd9xxx->dev_up);
+ dev_info(wcd9xxx->dev, "%s: slim device up, dev_up = %lu\n",
+ __func__, wcd9xxx->dev_up);
if (wcd9xxx->dev_up)
return 0;
@@ -1525,18 +1540,20 @@ static int wcd9xxx_slim_device_down(struct slim_device *sldev)
return -EINVAL;
}
- dev_info(wcd9xxx->dev, "%s: device down, dev_up = %d\n",
- __func__, wcd9xxx->dev_up);
- if (!wcd9xxx->dev_up)
- return 0;
-
- wcd9xxx->dev_up = false;
-
mutex_lock(&wcd9xxx->reset_lock);
+
+ dev_info(wcd9xxx->dev, "%s: device down, dev_up = %lu\n",
+ __func__, wcd9xxx->dev_up);
+ if (!wcd9xxx->dev_up) {
+ mutex_unlock(&wcd9xxx->reset_lock);
+ return 0;
+ }
+
if (wcd9xxx->dev_down)
wcd9xxx->dev_down(wcd9xxx);
wcd9xxx_irq_exit(&wcd9xxx->core_res);
wcd9xxx_reset_low(wcd9xxx->dev);
+ wcd9xxx->dev_up = false;
mutex_unlock(&wcd9xxx->reset_lock);
return 0;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index e8b9b48..7077b30 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -281,6 +281,7 @@ struct qseecom_control {
wait_queue_head_t app_block_wq;
atomic_t qseecom_state;
int is_apps_region_protected;
+ bool smcinvoke_support;
};
struct qseecom_sec_buf_fd_info {
@@ -580,10 +581,12 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[1] = req_64bit->sb_ptr;
desc.args[2] = req_64bit->sb_len;
}
+ qseecom.smcinvoke_support = true;
smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
ret = scm_call2(smc_id, &desc);
if (ret) {
+ qseecom.smcinvoke_support = false;
smc_id = TZ_OS_REGISTER_LISTENER_ID;
__qseecom_reentrancy_check_if_no_app_blocked(
smc_id);
@@ -1012,10 +1015,14 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
struct qseecom_continue_blocked_request_ireq *req =
(struct qseecom_continue_blocked_request_ireq *)
req_buf;
- smc_id = TZ_OS_CONTINUE_BLOCKED_REQUEST_ID;
+ if (qseecom.smcinvoke_support)
+ smc_id =
+ TZ_OS_CONTINUE_BLOCKED_REQUEST_SMCINVOKE_ID;
+ else
+ smc_id = TZ_OS_CONTINUE_BLOCKED_REQUEST_ID;
desc.arginfo =
TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID;
- desc.args[0] = req->app_id;
+ desc.args[0] = req->app_or_session_id;
ret = scm_call2(smc_id, &desc);
break;
}
@@ -1842,7 +1849,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
return ret;
}
-int __qseecom_process_reentrancy_blocked_on_listener(
+static int __qseecom_process_blocked_on_listener_legacy(
struct qseecom_command_scm_resp *resp,
struct qseecom_registered_app_list *ptr_app,
struct qseecom_dev_handle *data)
@@ -1851,9 +1858,8 @@ int __qseecom_process_reentrancy_blocked_on_listener(
int ret = 0;
struct qseecom_continue_blocked_request_ireq ireq;
struct qseecom_command_scm_resp continue_resp;
- sigset_t new_sigset, old_sigset;
- unsigned long flags;
bool found_app = false;
+ unsigned long flags;
if (!resp || !data) {
pr_err("invalid resp or data pointer\n");
@@ -1893,32 +1899,30 @@ int __qseecom_process_reentrancy_blocked_on_listener(
pr_debug("lsntr %d in_use = %d\n",
resp->data, list_ptr->listener_in_use);
ptr_app->blocked_on_listener_id = resp->data;
+
/* sleep until listener is available */
- do {
- qseecom.app_block_ref_cnt++;
- ptr_app->app_blocked = true;
- sigfillset(&new_sigset);
- sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
- mutex_unlock(&app_access_lock);
- do {
- if (!wait_event_freezable(
- list_ptr->listener_block_app_wq,
- !list_ptr->listener_in_use)) {
- break;
- }
- } while (1);
- mutex_lock(&app_access_lock);
- sigprocmask(SIG_SETMASK, &old_sigset, NULL);
- ptr_app->app_blocked = false;
- qseecom.app_block_ref_cnt--;
- } while (list_ptr->listener_in_use == true);
+ qseecom.app_block_ref_cnt++;
+ ptr_app->app_blocked = true;
+ mutex_unlock(&app_access_lock);
+ if (wait_event_freezable(
+ list_ptr->listener_block_app_wq,
+ !list_ptr->listener_in_use)) {
+ pr_err("Interrupted: listener_id %d, app_id %d\n",
+ resp->data, ptr_app->app_id);
+ ret = -ERESTARTSYS;
+ goto exit;
+ }
+ mutex_lock(&app_access_lock);
+ ptr_app->app_blocked = false;
+ qseecom.app_block_ref_cnt--;
+
ptr_app->blocked_on_listener_id = 0;
/* notify the blocked app that listener is available */
pr_warn("Lsntr %d is available, unblock app(%d) %s in TZ\n",
resp->data, data->client.app_id,
data->client.app_name);
ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
- ireq.app_id = data->client.app_id;
+ ireq.app_or_session_id = data->client.app_id;
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
&ireq, sizeof(ireq),
&continue_resp, sizeof(continue_resp));
@@ -1937,6 +1941,73 @@ int __qseecom_process_reentrancy_blocked_on_listener(
return ret;
}
+static int __qseecom_process_blocked_on_listener_smcinvoke(
+ struct qseecom_command_scm_resp *resp)
+{
+ struct qseecom_registered_listener_list *list_ptr;
+ int ret = 0;
+ struct qseecom_continue_blocked_request_ireq ireq;
+ struct qseecom_command_scm_resp continue_resp;
+ unsigned int session_id;
+
+ if (!resp) {
+ pr_err("invalid resp pointer\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+ session_id = resp->resp_type;
+ list_ptr = __qseecom_find_svc(resp->data);
+ if (!list_ptr) {
+ pr_err("Invalid listener ID\n");
+ ret = -ENODATA;
+ goto exit;
+ }
+ pr_debug("lsntr %d in_use = %d\n",
+ resp->data, list_ptr->listener_in_use);
+ /* sleep until listener is available */
+ qseecom.app_block_ref_cnt++;
+ mutex_unlock(&app_access_lock);
+ if (wait_event_freezable(
+ list_ptr->listener_block_app_wq,
+ !list_ptr->listener_in_use)) {
+ pr_err("Interrupted: listener_id %d, session_id %d\n",
+ resp->data, session_id);
+ ret = -ERESTARTSYS;
+ goto exit;
+ }
+ mutex_lock(&app_access_lock);
+ qseecom.app_block_ref_cnt--;
+
+ /* notify TZ that listener is available */
+ pr_warn("Lsntr %d is available, unblock session(%d) in TZ\n",
+ resp->data, session_id);
+ ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
+ ireq.app_or_session_id = session_id;
+ ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
+ &ireq, sizeof(ireq),
+ &continue_resp, sizeof(continue_resp));
+ if (ret) {
+ pr_err("scm_call for continue blocked req for session %d failed, ret %d\n",
+ session_id, ret);
+ goto exit;
+ }
+ resp->result = QSEOS_RESULT_INCOMPLETE;
+exit:
+ return ret;
+}
+
+static int __qseecom_process_reentrancy_blocked_on_listener(
+ struct qseecom_command_scm_resp *resp,
+ struct qseecom_registered_app_list *ptr_app,
+ struct qseecom_dev_handle *data)
+{
+ if (!qseecom.smcinvoke_support)
+ return __qseecom_process_blocked_on_listener_legacy(
+ resp, ptr_app, data);
+ else
+ return __qseecom_process_blocked_on_listener_smcinvoke(
+ resp);
+}
static int __qseecom_reentrancy_process_incomplete_cmd(
struct qseecom_dev_handle *data,
struct qseecom_command_scm_resp *resp)
@@ -4703,18 +4774,15 @@ int qseecom_process_listener_from_smcinvoke(struct scm_desc *desc)
}
resp.result = desc->ret[0]; /*req_cmd*/
- resp.resp_type = desc->ret[1]; /*app_id*/
+ resp.resp_type = desc->ret[1]; /*incomplete:unused;blocked:session_id*/
resp.data = desc->ret[2]; /*listener_id*/
- dummy_private_data.client.app_id = desc->ret[1];
- dummy_app_entry.app_id = desc->ret[1];
-
mutex_lock(&app_access_lock);
ret = __qseecom_process_reentrancy(&resp, &dummy_app_entry,
&dummy_private_data);
mutex_unlock(&app_access_lock);
if (ret)
- pr_err("Failed to req cmd %d lsnr %d on app %d, ret = %d\n",
+ pr_err("Failed on cmd %d for lsnr %d session %d, ret = %d\n",
(int)desc->ret[0], (int)desc->ret[2],
(int)desc->ret[1], ret);
desc->ret[0] = resp.result;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 3e9448b..0bf89b4 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -495,11 +495,6 @@ static int mmc_devfreq_set_target(struct device *dev,
if (!clk_scaling->enable)
goto out;
- if (*freq == UINT_MAX)
- *freq = clk_scaling->freq_table[1];
- else
- *freq = clk_scaling->freq_table[0];
-
pr_debug("%s: target freq = %lu (%s)\n", mmc_hostname(host),
*freq, current->comm);
diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c
index bfe1242..7c3638c 100644
--- a/drivers/mmc/host/cmdq_hci.c
+++ b/drivers/mmc/host/cmdq_hci.c
@@ -729,6 +729,15 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq)
goto ring_doorbell;
}
+ if (cq_host->ops->crypto_cfg) {
+ err = cq_host->ops->crypto_cfg(mmc, mrq, tag);
+ if (err) {
+ pr_err("%s: failed to configure crypto: err %d tag %d\n",
+ mmc_hostname(mmc), err, tag);
+ goto out;
+ }
+ }
+
task_desc = (__le64 __force *)get_desc(cq_host, tag);
cmdq_prep_task_desc(mrq, &data, 1,
@@ -778,6 +787,8 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag)
CMDQ_SEND_STATUS_TRIGGER, CQ_VENDOR_CFG);
cmdq_runtime_pm_put(cq_host);
+ if (cq_host->ops->crypto_cfg_reset)
+ cq_host->ops->crypto_cfg_reset(mmc, tag);
mrq->done(mrq);
}
diff --git a/drivers/mmc/host/cmdq_hci.h b/drivers/mmc/host/cmdq_hci.h
index 5347b3ab..8e9f765 100644
--- a/drivers/mmc/host/cmdq_hci.h
+++ b/drivers/mmc/host/cmdq_hci.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-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
@@ -208,6 +208,9 @@ struct cmdq_host_ops {
void (*enhanced_strobe_mask)(struct mmc_host *mmc, bool set);
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);
+ void (*crypto_cfg_reset)(struct mmc_host *mmc, unsigned int slot);
};
static inline void cmdq_writel(struct cmdq_host *host, u32 val, int reg)
diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c
index ba6e51c..acc4ae0 100644
--- a/drivers/mmc/host/sdhci-msm-ice.c
+++ b/drivers/mmc/host/sdhci-msm-ice.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -13,19 +13,6 @@
#include "sdhci-msm-ice.h"
-static void sdhci_msm_ice_success_cb(void *host_ctrl,
- enum ice_event_completion evt)
-{
- struct sdhci_msm_host *msm_host = (struct sdhci_msm_host *)host_ctrl;
-
- if ((msm_host->ice.state == SDHCI_MSM_ICE_STATE_DISABLED &&
- evt == ICE_INIT_COMPLETION) || (msm_host->ice.state ==
- SDHCI_MSM_ICE_STATE_SUSPENDED && evt == ICE_RESUME_COMPLETION))
- msm_host->ice.state = SDHCI_MSM_ICE_STATE_ACTIVE;
-
- complete(&msm_host->ice.async_done);
-}
-
static void sdhci_msm_ice_error_cb(void *host_ctrl, u32 error)
{
struct sdhci_msm_host *msm_host = (struct sdhci_msm_host *)host_ctrl;
@@ -35,8 +22,6 @@ static void sdhci_msm_ice_error_cb(void *host_ctrl, u32 error)
if (msm_host->ice.state == SDHCI_MSM_ICE_STATE_ACTIVE)
msm_host->ice.state = SDHCI_MSM_ICE_STATE_DISABLED;
-
- complete(&msm_host->ice.async_done);
}
static struct platform_device *sdhci_msm_ice_get_pdevice(struct device *dev)
@@ -194,34 +179,69 @@ int sdhci_msm_ice_init(struct sdhci_host *host)
struct sdhci_msm_host *msm_host = pltfm_host->priv;
int err = 0;
- init_completion(&msm_host->ice.async_done);
- if (msm_host->ice.vops->config) {
+ if (msm_host->ice.vops->init) {
+ err = sdhci_msm_ice_pltfm_init(msm_host);
+ if (err)
+ goto out;
+
+ if (msm_host->ice_hci_support)
+ sdhci_msm_enable_ice_hci(host, true);
+
err = msm_host->ice.vops->init(msm_host->ice.pdev,
msm_host,
- sdhci_msm_ice_success_cb,
sdhci_msm_ice_error_cb);
if (err) {
pr_err("%s: ice init err %d\n",
mmc_hostname(host->mmc), err);
- return err;
+ sdhci_msm_ice_print_regs(host);
+ if (msm_host->ice_hci_support)
+ sdhci_msm_enable_ice_hci(host, false);
+ goto out;
}
+ msm_host->ice.state = SDHCI_MSM_ICE_STATE_ACTIVE;
}
- if (!wait_for_completion_timeout(&msm_host->ice.async_done,
- msecs_to_jiffies(SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS))) {
- pr_err("%s: ice init timedout after %d ms\n",
- mmc_hostname(host->mmc),
- SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS);
- sdhci_msm_ice_print_regs(host);
- return -ETIMEDOUT;
- }
+out:
+ return err;
+}
- 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;
- }
- return 0;
+void sdhci_msm_ice_cfg_reset(struct sdhci_host *host, u32 slot)
+{
+ writel_relaxed(SDHCI_MSM_ICE_ENABLE_BYPASS,
+ host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot);
+}
+
+static
+void sdhci_msm_ice_update_cfg(struct sdhci_host *host, u64 lba,
+ u32 slot, unsigned int bypass, short key_index)
+{
+ unsigned int ctrl_info_val = 0;
+
+ /* Configure ICE index */
+ ctrl_info_val =
+ (key_index &
+ MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX)
+ << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX;
+
+ /* Configure data unit size of transfer request */
+ ctrl_info_val |=
+ (SDHCI_MSM_ICE_TR_DATA_UNIT_512_B &
+ MASK_SDHCI_MSM_ICE_CTRL_INFO_CDU)
+ << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU;
+
+ /* Configure ICE bypass mode */
+ ctrl_info_val |=
+ (bypass & MASK_SDHCI_MSM_ICE_CTRL_INFO_BYPASS)
+ << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_BYPASS;
+
+ writel_relaxed((lba & 0xFFFFFFFF),
+ host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_1_n + 16 * slot);
+ writel_relaxed(((lba >> 32) & 0xFFFFFFFF),
+ host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_2_n + 16 * slot);
+ writel_relaxed(ctrl_info_val,
+ host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot);
+ /* Ensure ICE registers are configured before issuing SDHCI request */
+ mb();
}
int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
@@ -232,7 +252,6 @@ int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
int err = 0;
struct ice_data_setting ice_set;
sector_t lba = 0;
- unsigned int ctrl_info_val = 0;
unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS;
struct request *req;
@@ -247,9 +266,10 @@ int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
req = mrq->req;
if (req) {
lba = req->__sector;
- if (msm_host->ice.vops->config) {
- err = msm_host->ice.vops->config(msm_host->ice.pdev,
- req, &ice_set);
+ if (msm_host->ice.vops->config_start) {
+ err = msm_host->ice.vops->config_start(
+ msm_host->ice.pdev,
+ req, &ice_set, false);
if (err) {
pr_err("%s: ice config failed %d\n",
mmc_hostname(host->mmc), err);
@@ -274,32 +294,8 @@ int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
ice_set.crypto_data.key_index);
}
- /* Configure ICE index */
- ctrl_info_val =
- (ice_set.crypto_data.key_index &
- MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX)
- << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX;
-
- /* Configure data unit size of transfer request */
- ctrl_info_val |=
- (SDHCI_MSM_ICE_TR_DATA_UNIT_512_B &
- MASK_SDHCI_MSM_ICE_CTRL_INFO_CDU)
- << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU;
-
- /* Configure ICE bypass mode */
- ctrl_info_val |=
- (bypass & MASK_SDHCI_MSM_ICE_CTRL_INFO_BYPASS)
- << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_BYPASS;
-
- writel_relaxed((lba & 0xFFFFFFFF),
- host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_1_n + 16 * slot);
- writel_relaxed(((lba >> 32) & 0xFFFFFFFF),
- host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_2_n + 16 * slot);
- writel_relaxed(ctrl_info_val,
- host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot);
-
- /* Ensure ICE registers are configured before issuing SDHCI request */
- mb();
+ sdhci_msm_ice_update_cfg(host, lba, slot, bypass,
+ ice_set.crypto_data.key_index);
return 0;
}
@@ -315,25 +311,19 @@ int sdhci_msm_ice_reset(struct sdhci_host *host)
return -EINVAL;
}
- init_completion(&msm_host->ice.async_done);
-
if (msm_host->ice.vops->reset) {
err = msm_host->ice.vops->reset(msm_host->ice.pdev);
if (err) {
pr_err("%s: ice reset failed %d\n",
mmc_hostname(host->mmc), err);
+ sdhci_msm_ice_print_regs(host);
return err;
}
}
- if (!wait_for_completion_timeout(&msm_host->ice.async_done,
- msecs_to_jiffies(SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS))) {
- pr_err("%s: ice reset timedout after %d ms\n",
- mmc_hostname(host->mmc),
- SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS);
- sdhci_msm_ice_print_regs(host);
- return -ETIMEDOUT;
- }
+ /* If ICE HCI support is present then re-enable it */
+ if (msm_host->ice_hci_support)
+ sdhci_msm_enable_ice_hci(host, true);
if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
pr_err("%s: ice is in invalid state after reset %d\n",
@@ -356,8 +346,6 @@ int sdhci_msm_ice_resume(struct sdhci_host *host)
return -EINVAL;
}
- init_completion(&msm_host->ice.async_done);
-
if (msm_host->ice.vops->resume) {
err = msm_host->ice.vops->resume(msm_host->ice.pdev);
if (err) {
@@ -367,20 +355,7 @@ int sdhci_msm_ice_resume(struct sdhci_host *host)
}
}
- if (!wait_for_completion_timeout(&msm_host->ice.async_done,
- msecs_to_jiffies(SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS))) {
- pr_err("%s: ice resume timedout after %d ms\n",
- mmc_hostname(host->mmc),
- SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS);
- sdhci_msm_ice_print_regs(host);
- return -ETIMEDOUT;
- }
-
- if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
- pr_err("%s: ice is in invalid state after resume %d\n",
- mmc_hostname(host->mmc), msm_host->ice.state);
- return -EINVAL;
- }
+ msm_host->ice.state = SDHCI_MSM_ICE_STATE_ACTIVE;
return 0;
}
diff --git a/drivers/mmc/host/sdhci-msm-ice.h b/drivers/mmc/host/sdhci-msm-ice.h
index 88ef0e2..23922cf 100644
--- a/drivers/mmc/host/sdhci-msm-ice.h
+++ b/drivers/mmc/host/sdhci-msm-ice.h
@@ -17,7 +17,6 @@
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/async.h>
#include <linux/blkdev.h>
#include <crypto/ice.h>
@@ -97,6 +96,7 @@ enum {
#ifdef CONFIG_MMC_SDHCI_MSM_ICE
int sdhci_msm_ice_get_dev(struct sdhci_host *host);
int sdhci_msm_ice_init(struct sdhci_host *host);
+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_reset(struct sdhci_host *host);
@@ -120,6 +120,11 @@ inline int sdhci_msm_ice_init(struct sdhci_host *host)
{
return 0;
}
+
+inline void sdhci_msm_ice_cfg_reset(struct sdhci_host *host, u32 slot)
+{
+}
+
inline int sdhci_msm_ice_cfg(struct sdhci_host *host,
struct mmc_request *mrq, u32 slot)
{
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index f3f181d..b6c17ec0 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -42,6 +42,7 @@
#include <trace/events/mmc.h>
#include "sdhci-msm.h"
+#include "sdhci-msm-ice.h"
#include "cmdq_hci.h"
#define QOS_REMOVE_DELAY_MS 10
@@ -1814,6 +1815,8 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
int len, i;
int clk_table_len;
u32 *clk_table = NULL;
+ int ice_clk_table_len;
+ u32 *ice_clk_table = NULL;
enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
const char *lower_bus_speed = NULL;
@@ -1871,6 +1874,20 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
pdata->sup_clk_table = clk_table;
pdata->sup_clk_cnt = clk_table_len;
+ if (msm_host->ice.pdev) {
+ if (sdhci_msm_dt_get_array(dev, "qcom,ice-clk-rates",
+ &ice_clk_table, &ice_clk_table_len, 0)) {
+ dev_err(dev, "failed parsing supported ice clock rates\n");
+ goto out;
+ }
+ if (!ice_clk_table || !ice_clk_table_len) {
+ dev_err(dev, "Invalid clock table\n");
+ goto out;
+ }
+ pdata->sup_ice_clk_table = ice_clk_table;
+ pdata->sup_ice_clk_cnt = ice_clk_table_len;
+ }
+
pdata->vreg_data = devm_kzalloc(dev, sizeof(struct
sdhci_msm_slot_reg_data),
GFP_KERNEL);
@@ -1940,6 +1957,8 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
msm_host->core_3_0v_support = true;
pdata->sdr104_wa = of_property_read_bool(np, "qcom,sdr104-wa");
+ msm_host->regs_restore.is_supported =
+ of_property_read_bool(np, "qcom,restore-after-cx-collapse");
return pdata;
out:
@@ -2831,6 +2850,103 @@ static unsigned int sdhci_msm_get_sup_clk_rate(struct sdhci_host *host,
return sel_clk;
}
+static void sdhci_msm_registers_save(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
+
+ if (!msm_host->regs_restore.is_supported)
+ return;
+
+ msm_host->regs_restore.vendor_func = readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
+ msm_host->regs_restore.vendor_pwrctl_mask =
+ readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_PWRCTL_MASK);
+ msm_host->regs_restore.vendor_func2 =
+ readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC_FUNC2);
+ msm_host->regs_restore.vendor_func3 =
+ readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC3);
+ msm_host->regs_restore.hc_2c_2e =
+ sdhci_readl(host, SDHCI_CLOCK_CONTROL);
+ msm_host->regs_restore.hc_3c_3e =
+ sdhci_readl(host, SDHCI_AUTO_CMD_ERR);
+ msm_host->regs_restore.vendor_pwrctl_ctl =
+ readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_PWRCTL_CTL);
+ msm_host->regs_restore.hc_38_3a =
+ sdhci_readl(host, SDHCI_SIGNAL_ENABLE);
+ msm_host->regs_restore.hc_34_36 =
+ sdhci_readl(host, SDHCI_INT_ENABLE);
+ msm_host->regs_restore.hc_28_2a =
+ sdhci_readl(host, SDHCI_HOST_CONTROL);
+ msm_host->regs_restore.vendor_caps_0 =
+ readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC_CAPABILITIES0);
+ msm_host->regs_restore.hc_caps_1 =
+ sdhci_readl(host, SDHCI_CAPABILITIES_1);
+ msm_host->regs_restore.testbus_config = readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_TESTBUS_CONFIG);
+ msm_host->regs_restore.is_valid = true;
+
+ pr_debug("%s: %s: registers saved. PWRCTL_MASK = 0x%x\n",
+ mmc_hostname(host->mmc), __func__,
+ readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_PWRCTL_MASK));
+}
+
+static void sdhci_msm_registers_restore(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ const struct sdhci_msm_offset *msm_host_offset =
+ msm_host->offset;
+
+ if (!msm_host->regs_restore.is_supported ||
+ !msm_host->regs_restore.is_valid)
+ return;
+
+ writel_relaxed(msm_host->regs_restore.vendor_func, host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC);
+ writel_relaxed(msm_host->regs_restore.vendor_pwrctl_mask,
+ host->ioaddr + msm_host_offset->CORE_PWRCTL_MASK);
+ writel_relaxed(msm_host->regs_restore.vendor_func2,
+ host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC_FUNC2);
+ writel_relaxed(msm_host->regs_restore.vendor_func3,
+ host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC3);
+ sdhci_writel(host, msm_host->regs_restore.hc_2c_2e,
+ SDHCI_CLOCK_CONTROL);
+ sdhci_writel(host, msm_host->regs_restore.hc_3c_3e,
+ SDHCI_AUTO_CMD_ERR);
+ writel_relaxed(msm_host->regs_restore.vendor_pwrctl_ctl,
+ host->ioaddr + msm_host_offset->CORE_PWRCTL_CTL);
+ sdhci_writel(host, msm_host->regs_restore.hc_38_3a,
+ SDHCI_SIGNAL_ENABLE);
+ sdhci_writel(host, msm_host->regs_restore.hc_34_36,
+ SDHCI_INT_ENABLE);
+ sdhci_writel(host, msm_host->regs_restore.hc_28_2a,
+ SDHCI_HOST_CONTROL);
+ writel_relaxed(msm_host->regs_restore.vendor_caps_0,
+ host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC_CAPABILITIES0);
+ sdhci_writel(host, msm_host->regs_restore.hc_caps_1,
+ SDHCI_CAPABILITIES_1);
+ writel_relaxed(msm_host->regs_restore.testbus_config, host->ioaddr +
+ msm_host_offset->CORE_TESTBUS_CONFIG);
+ msm_host->regs_restore.is_valid = false;
+
+ pr_debug("%s: %s: registers restored. PWRCTL_MASK = 0x%x\n",
+ mmc_hostname(host->mmc), __func__,
+ readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_PWRCTL_MASK));
+}
+
static int sdhci_msm_enable_controller_clock(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -2858,11 +2974,23 @@ static int sdhci_msm_enable_controller_clock(struct sdhci_host *host)
goto disable_pclk;
}
+ if (!IS_ERR(msm_host->ice_clk)) {
+ rc = clk_prepare_enable(msm_host->ice_clk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the ice-clk with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto disable_host_clk;
+ }
+ }
atomic_set(&msm_host->controller_clock, 1);
pr_debug("%s: %s: enabled controller clock\n",
mmc_hostname(host->mmc), __func__);
+ sdhci_msm_registers_restore(host);
goto out;
+disable_host_clk:
+ if (!IS_ERR(msm_host->clk))
+ clk_disable_unprepare(msm_host->clk);
disable_pclk:
if (!IS_ERR(msm_host->pclk))
clk_disable_unprepare(msm_host->pclk);
@@ -2879,12 +3007,13 @@ static void sdhci_msm_disable_controller_clock(struct sdhci_host *host)
struct sdhci_msm_host *msm_host = pltfm_host->priv;
if (atomic_read(&msm_host->controller_clock)) {
+ sdhci_msm_registers_save(host);
if (!IS_ERR(msm_host->clk))
clk_disable_unprepare(msm_host->clk);
- if (!IS_ERR(msm_host->pclk))
- clk_disable_unprepare(msm_host->pclk);
if (!IS_ERR(msm_host->ice_clk))
clk_disable_unprepare(msm_host->ice_clk);
+ if (!IS_ERR(msm_host->pclk))
+ clk_disable_unprepare(msm_host->pclk);
sdhci_msm_bus_voting(host, 0);
atomic_set(&msm_host->controller_clock, 0);
pr_debug("%s: %s: disabled controller clock\n",
@@ -2957,14 +3086,9 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable)
clk_disable_unprepare(msm_host->sleep_clk);
if (!IS_ERR_OR_NULL(msm_host->ff_clk))
clk_disable_unprepare(msm_host->ff_clk);
- clk_disable_unprepare(msm_host->clk);
- if (!IS_ERR(msm_host->pclk))
- clk_disable_unprepare(msm_host->pclk);
if (!IS_ERR_OR_NULL(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk);
-
- atomic_set(&msm_host->controller_clock, 0);
- sdhci_msm_bus_voting(host, 0);
+ sdhci_msm_disable_controller_clock(host);
}
atomic_set(&msm_host->clks_on, enable);
goto out;
@@ -2977,6 +3101,8 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable)
disable_controller_clk:
if (!IS_ERR_OR_NULL(msm_host->clk))
clk_disable_unprepare(msm_host->clk);
+ if (!IS_ERR(msm_host->ice_clk))
+ clk_disable_unprepare(msm_host->ice_clk);
if (!IS_ERR_OR_NULL(msm_host->pclk))
clk_disable_unprepare(msm_host->pclk);
atomic_set(&msm_host->controller_clock, 0);
@@ -3282,6 +3408,7 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
int i, index = 0;
u32 test_bus_val = 0;
u32 debug_reg[MAX_TEST_BUS] = {0};
+ u32 sts = 0;
sdhci_msm_cache_debug_data(host);
pr_info("----------- VENDOR REGISTER DUMP -----------\n");
@@ -3344,6 +3471,29 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
pr_info(" Test bus[%d to %d]: 0x%08x 0x%08x 0x%08x 0x%08x\n",
i, i + 3, debug_reg[i], debug_reg[i+1],
debug_reg[i+2], debug_reg[i+3]);
+ if (host->is_crypto_en) {
+ sdhci_msm_ice_get_status(host, &sts);
+ pr_info("%s: ICE status %x\n", mmc_hostname(host->mmc), sts);
+ sdhci_msm_ice_print_regs(host);
+ }
+}
+
+static void sdhci_msm_reset(struct sdhci_host *host, u8 mask)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+ /* Set ICE core to be reset in sync with SDHC core */
+ if (msm_host->ice.pdev) {
+ if (msm_host->ice_hci_support)
+ writel_relaxed(1, host->ioaddr +
+ HC_VENDOR_SPECIFIC_ICE_CTRL);
+ else
+ writel_relaxed(1,
+ host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL);
+ }
+
+ sdhci_reset(host, mask);
}
/*
@@ -3926,6 +4076,8 @@ static unsigned int sdhci_msm_get_current_limit(struct sdhci_host *host)
}
static struct sdhci_ops sdhci_msm_ops = {
+ .crypto_engine_cfg = sdhci_msm_ice_cfg,
+ .crypto_engine_reset = sdhci_msm_ice_reset,
.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
.check_power_status = sdhci_msm_check_power_status,
.platform_execute_tuning = sdhci_msm_execute_tuning,
@@ -3939,7 +4091,7 @@ static struct sdhci_ops sdhci_msm_ops = {
.config_auto_tuning_cmd = sdhci_msm_config_auto_tuning_cmd,
.enable_controller_clock = sdhci_msm_enable_controller_clock,
.set_bus_width = sdhci_set_bus_width,
- .reset = sdhci_reset,
+ .reset = sdhci_msm_reset,
.clear_set_dumpregs = sdhci_msm_clear_set_dumpregs,
.enhanced_strobe_mask = sdhci_msm_enhanced_strobe_mask,
.reset_workaround = sdhci_msm_reset_workaround,
@@ -4138,7 +4290,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata, 0);
if (IS_ERR(host)) {
ret = PTR_ERR(host);
- goto out;
+ goto out_host_free;
}
pltfm_host = sdhci_priv(host);
@@ -4146,6 +4298,31 @@ static int sdhci_msm_probe(struct platform_device *pdev)
msm_host->mmc = host->mmc;
msm_host->pdev = pdev;
+ /* get the ice device vops if present */
+ ret = sdhci_msm_ice_get_dev(host);
+ if (ret == -EPROBE_DEFER) {
+ /*
+ * SDHCI driver might be probed before ICE driver does.
+ * In that case we would like to return EPROBE_DEFER code
+ * in order to delay its probing.
+ */
+ dev_err(&pdev->dev, "%s: required ICE device not probed yet err = %d\n",
+ __func__, ret);
+ goto out_host_free;
+
+ } else if (ret == -ENODEV) {
+ /*
+ * ICE device is not enabled in DTS file. No need for further
+ * initialization of ICE driver.
+ */
+ dev_warn(&pdev->dev, "%s: ICE device is not enabled",
+ __func__);
+ } else if (ret) {
+ dev_err(&pdev->dev, "%s: sdhci_msm_ice_get_dev failed %d\n",
+ __func__, ret);
+ goto out_host_free;
+ }
+
/* Extract platform data */
if (pdev->dev.of_node) {
ret = of_alias_get_id(pdev->dev.of_node, "sdhc");
@@ -4205,6 +4382,28 @@ static int sdhci_msm_probe(struct platform_device *pdev)
}
atomic_set(&msm_host->controller_clock, 1);
+ if (msm_host->ice.pdev) {
+ /* Setup SDC ICE clock */
+ msm_host->ice_clk = devm_clk_get(&pdev->dev, "ice_core_clk");
+ if (!IS_ERR(msm_host->ice_clk)) {
+ /* ICE core has only one clock frequency for now */
+ ret = clk_set_rate(msm_host->ice_clk,
+ msm_host->pdata->sup_ice_clk_table[0]);
+ if (ret) {
+ dev_err(&pdev->dev, "ICE_CLK rate set failed (%d) for %u\n",
+ ret,
+ msm_host->pdata->sup_ice_clk_table[0]);
+ goto pclk_disable;
+ }
+ ret = clk_prepare_enable(msm_host->ice_clk);
+ if (ret)
+ goto pclk_disable;
+
+ msm_host->ice_clk_rate =
+ msm_host->pdata->sup_clk_table[0];
+ }
+ }
+
/* Setup SDC MMC clock */
msm_host->clk = devm_clk_get(&pdev->dev, "core_clk");
if (IS_ERR(msm_host->clk)) {
@@ -4431,6 +4630,21 @@ static int sdhci_msm_probe(struct platform_device *pdev)
msm_host->mmc->sdr104_wa = msm_host->pdata->sdr104_wa;
+ /* Initialize ICE if present */
+ if (msm_host->ice.pdev) {
+ ret = sdhci_msm_ice_init(host);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: SDHCi ICE init failed (%d)\n",
+ mmc_hostname(host->mmc), ret);
+ ret = -EINVAL;
+ goto vreg_deinit;
+ }
+ host->is_crypto_en = true;
+ /* Packed commands cannot be encrypted/decrypted using ICE */
+ msm_host->mmc->caps2 &= ~(MMC_CAP2_PACKED_WR |
+ MMC_CAP2_PACKED_WR_CONTROL);
+ }
+
init_completion(&msm_host->pwr_irq_completion);
if (gpio_is_valid(msm_host->pdata->status_gpio)) {
@@ -4570,6 +4784,8 @@ static int sdhci_msm_probe(struct platform_device *pdev)
clk_disable_unprepare(msm_host->bus_clk);
pltfm_free:
sdhci_pltfm_free(pdev);
+out_host_free:
+ devm_kfree(&pdev->dev, msm_host);
out:
pr_debug("%s: Exit %s\n", dev_name(&pdev->dev), __func__);
return ret;
@@ -4659,6 +4875,7 @@ static int sdhci_msm_runtime_suspend(struct device *dev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
ktime_t start = ktime_get();
+ int ret;
if (host->mmc->card && mmc_card_sdio(host->mmc->card))
goto defer_disable_host_irq;
@@ -4680,6 +4897,12 @@ static int sdhci_msm_runtime_suspend(struct device *dev)
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);
+ if (ret < 0)
+ pr_err("%s: failed to suspend crypto engine %d\n",
+ mmc_hostname(host->mmc), ret);
+ }
return 0;
}
@@ -4689,6 +4912,21 @@ static int sdhci_msm_runtime_resume(struct device *dev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
ktime_t start = ktime_get();
+ int ret;
+
+ if (host->is_crypto_en) {
+ ret = sdhci_msm_enable_controller_clock(host);
+ if (ret) {
+ pr_err("%s: Failed to enable reqd clocks\n",
+ mmc_hostname(host->mmc));
+ goto skip_ice_resume;
+ }
+ ret = sdhci_msm_ice_resume(host);
+ if (ret)
+ pr_err("%s: failed to resume crypto engine %d\n",
+ mmc_hostname(host->mmc), ret);
+ }
+skip_ice_resume:
if (host->mmc->card && mmc_card_sdio(host->mmc->card))
goto defer_enable_host_irq;
diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h
index c536a7d..cdbaaa9 100644
--- a/drivers/mmc/host/sdhci-msm.h
+++ b/drivers/mmc/host/sdhci-msm.h
@@ -165,11 +165,28 @@ struct sdhci_msm_bus_vote {
struct sdhci_msm_ice_data {
struct qcom_ice_variant_ops *vops;
- struct completion async_done;
struct platform_device *pdev;
int state;
};
+struct sdhci_msm_regs_restore {
+ bool is_supported;
+ bool is_valid;
+ u32 vendor_pwrctl_mask;
+ u32 vendor_pwrctl_ctl;
+ u32 vendor_caps_0;
+ u32 vendor_func;
+ u32 vendor_func2;
+ u32 vendor_func3;
+ u32 hc_2c_2e;
+ u32 hc_28_2a;
+ u32 hc_34_36;
+ u32 hc_38_3a;
+ u32 hc_3c_3e;
+ u32 hc_caps_1;
+ u32 testbus_config;
+};
+
struct sdhci_msm_debug_data {
struct mmc_host copy_mmc;
struct mmc_card copy_card;
@@ -226,6 +243,7 @@ struct sdhci_msm_host {
const struct sdhci_msm_offset *offset;
bool core_3_0v_support;
bool pltfm_init_done;
+ struct sdhci_msm_regs_restore regs_restore;
};
extern char *saved_command_line;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 8fbcdae..3eada3b 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -305,6 +305,8 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
/* Resetting the controller clears many */
host->preset_enabled = false;
}
+ if (host->is_crypto_en)
+ host->crypto_reset_reqd = true;
}
static void sdhci_init(struct sdhci_host *host, int soft)
@@ -1749,6 +1751,33 @@ static int sdhci_get_tuning_cmd(struct sdhci_host *host)
return MMC_SEND_TUNING_BLOCK;
}
+static int sdhci_crypto_cfg(struct sdhci_host *host, struct mmc_request *mrq,
+ u32 slot)
+{
+ int err = 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_cfg) {
+ err = host->ops->crypto_engine_cfg(host, mrq, slot);
+ if (err) {
+ pr_err("%s: failed to configure crypto\n",
+ mmc_hostname(host->mmc));
+ goto out;
+ }
+ }
+out:
+ return err;
+}
+
static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sdhci_host *host;
@@ -1815,6 +1844,13 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
sdhci_get_tuning_cmd(host));
}
+ if (host->is_crypto_en) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ if (sdhci_crypto_cfg(host, mrq, 0))
+ goto end_req;
+ spin_lock_irqsave(&host->lock, flags);
+ }
+
if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
sdhci_send_command(host, mrq->sbc);
else
@@ -1823,6 +1859,12 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
+ return;
+end_req:
+ mrq->cmd->error = -EIO;
+ if (mrq->data)
+ mrq->data->error = -EIO;
+ mmc_request_done(host->mmc, mrq);
}
void sdhci_set_bus_width(struct sdhci_host *host, int width)
@@ -3704,6 +3746,27 @@ static void sdhci_cmdq_post_cqe_halt(struct mmc_host *mmc)
SDHCI_INT_RESPONSE, SDHCI_INT_ENABLE);
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 sdhci_host *host = mmc_priv(mmc);
+
+ if (!host->is_crypto_en)
+ return 0;
+
+ return sdhci_crypto_cfg(host, mrq, slot);
+}
+
+static void sdhci_cmdq_crypto_cfg_reset(struct mmc_host *mmc, unsigned int slot)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ if (!host->is_crypto_en)
+ return;
+
+ if (host->ops->crypto_cfg_reset)
+ host->ops->crypto_cfg_reset(host, slot);
+}
#else
static void sdhci_cmdq_set_transfer_params(struct mmc_host *mmc)
{
@@ -3747,6 +3810,18 @@ static void sdhci_cmdq_clear_set_dumpregs(struct mmc_host *mmc, bool set)
static void sdhci_cmdq_post_cqe_halt(struct mmc_host *mmc)
{
+
+}
+
+static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc,
+ struct mmc_request *mrq, u32 slot)
+{
+ return 0;
+}
+
+static void sdhci_cmdq_crypto_cfg_reset(struct mmc_host *mmc, unsigned int slot)
+{
+
}
#endif
@@ -3759,6 +3834,8 @@ static const struct cmdq_host_ops sdhci_cmdq_ops = {
.enhanced_strobe_mask = sdhci_enhanced_strobe_mask,
.post_cqe_halt = sdhci_cmdq_post_cqe_halt,
.set_transfer_params = sdhci_cmdq_set_transfer_params,
+ .crypto_cfg = sdhci_cmdq_crypto_cfg,
+ .crypto_cfg_reset = sdhci_cmdq_crypto_cfg_reset,
};
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index d9e656a..04e806c 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -628,6 +628,8 @@ struct sdhci_host {
enum sdhci_power_policy power_policy;
bool sdio_irq_async_status;
+ bool is_crypto_en;
+ bool crypto_reset_reqd;
u32 auto_cmd_err_sts;
struct ratelimit_state dbg_dump_rs;
@@ -666,6 +668,10 @@ struct sdhci_ops {
unsigned int (*get_ro)(struct sdhci_host *host);
void (*reset)(struct sdhci_host *host, u8 mask);
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_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);
void (*hw_reset)(struct sdhci_host *host);
void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 6063cf4..410bcda 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -3133,7 +3133,7 @@ int ath10k_pci_setup_resource(struct ath10k *ar)
setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
(unsigned long)ar);
- if (QCA_REV_6174(ar))
+ if (QCA_REV_6174(ar) || QCA_REV_9377(ar))
ath10k_pci_override_ce_config(ar);
ret = ath10k_pci_alloc_pipes(ar);
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 9afd6f2..bb36fe5 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -46,6 +46,12 @@ static struct ieee80211_channel wil_60ghz_channels[] = {
/* channel 4 not supported yet */
};
+#ifdef CONFIG_PM
+static struct wiphy_wowlan_support wil_wowlan_support = {
+ .flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT,
+};
+#endif
+
/* Vendor id to be used in vendor specific command and events
* to user space.
* NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID,
@@ -1883,6 +1889,10 @@ static void wil_wiphy_init(struct wiphy *wiphy)
wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
}
+
+#ifdef CONFIG_PM
+ wiphy->wowlan = &wil_wowlan_support;
+#endif
}
struct wireless_dev *wil_cfg80211_init(struct device *dev)
diff --git a/drivers/net/wireless/ath/wil6210/sysfs.c b/drivers/net/wireless/ath/wil6210/sysfs.c
index b4c4d09..b91bf51 100644
--- a/drivers/net/wireless/ath/wil6210/sysfs.c
+++ b/drivers/net/wireless/ath/wil6210/sysfs.c
@@ -291,6 +291,8 @@ int wil6210_sysfs_init(struct wil6210_priv *wil)
return err;
}
+ kobject_uevent(&dev->kobj, KOBJ_CHANGE);
+
return 0;
}
@@ -299,4 +301,5 @@ void wil6210_sysfs_remove(struct wil6210_priv *wil)
struct device *dev = wil_to_dev(wil);
sysfs_remove_group(&dev->kobj, &wil6210_attribute_group);
+ kobject_uevent(&dev->kobj, KOBJ_CHANGE);
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 0f5dde1..01d44f9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -414,23 +414,24 @@ static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_vif *vif,
enum nl80211_iftype new_type)
{
- int iftype_num[NUM_NL80211_IFTYPES];
struct brcmf_cfg80211_vif *pos;
bool check_combos = false;
int ret = 0;
+ struct iface_combination_params params = {
+ .num_different_channels = 1,
+ };
- memset(&iftype_num[0], 0, sizeof(iftype_num));
list_for_each_entry(pos, &cfg->vif_list, list)
if (pos == vif) {
- iftype_num[new_type]++;
+ params.iftype_num[new_type]++;
} else {
/* concurrent interfaces so need check combinations */
check_combos = true;
- iftype_num[pos->wdev.iftype]++;
+ params.iftype_num[pos->wdev.iftype]++;
}
if (check_combos)
- ret = cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
+ ret = cfg80211_check_combinations(cfg->wiphy, ¶ms);
return ret;
}
@@ -438,15 +439,16 @@ static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
enum nl80211_iftype new_type)
{
- int iftype_num[NUM_NL80211_IFTYPES];
struct brcmf_cfg80211_vif *pos;
+ struct iface_combination_params params = {
+ .num_different_channels = 1,
+ };
- memset(&iftype_num[0], 0, sizeof(iftype_num));
list_for_each_entry(pos, &cfg->vif_list, list)
- iftype_num[pos->wdev.iftype]++;
+ params.iftype_num[pos->wdev.iftype]++;
- iftype_num[new_type]++;
- return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
+ params.iftype_num[new_type]++;
+ return cfg80211_check_combinations(cfg->wiphy, ¶ms);
}
static void convert_key_from_CPU(struct brcmf_wsec_key *key,
diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
index 3c89a73..c09e61f 100644
--- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
+++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
@@ -11,9 +11,14 @@
*/
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/seq_file.h>
#include <linux/err.h>
#include <linux/stacktrace.h>
#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#ifdef CONFIG_WCNSS_SKB_PRE_ALLOC
+#include <linux/skbuff.h>
+#endif
static DEFINE_SPINLOCK(alloc_lock);
@@ -21,6 +26,11 @@ static DEFINE_SPINLOCK(alloc_lock);
#define WCNSS_MAX_STACK_TRACE 64
#endif
+#define PRE_ALLOC_DEBUGFS_DIR "cnss-prealloc"
+#define PRE_ALLOC_DEBUGFS_FILE_OBJ "status"
+
+static struct dentry *debug_base;
+
struct wcnss_prealloc {
int occupied;
unsigned int size;
@@ -228,14 +238,89 @@ int wcnss_pre_alloc_reset(void)
}
EXPORT_SYMBOL(wcnss_pre_alloc_reset);
+static int prealloc_memory_stats_show(struct seq_file *fp, void *data)
+{
+ int i = 0;
+ int used_slots = 0, free_slots = 0;
+ unsigned int tsize = 0, tused = 0, size = 0;
+
+ seq_puts(fp, "\nSlot_Size(Kb)\t\t[Used : Free]\n");
+ for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
+ tsize += wcnss_allocs[i].size;
+ if (size != wcnss_allocs[i].size) {
+ if (size) {
+ seq_printf(
+ fp, "[%d : %d]\n",
+ used_slots, free_slots);
+ }
+
+ size = wcnss_allocs[i].size;
+ used_slots = 0;
+ free_slots = 0;
+ seq_printf(fp, "%d Kb\t\t\t", size / 1024);
+ }
+
+ if (wcnss_allocs[i].occupied) {
+ tused += wcnss_allocs[i].size;
+ ++used_slots;
+ } else {
+ ++free_slots;
+ }
+ }
+ seq_printf(fp, "[%d : %d]\n", used_slots, free_slots);
+
+ /* Convert byte to Kb */
+ if (tsize)
+ tsize = tsize / 1024;
+ if (tused)
+ tused = tused / 1024;
+ seq_printf(fp, "\nMemory Status:\nTotal Memory: %dKb\n", tsize);
+ seq_printf(fp, "Used: %dKb\nFree: %dKb\n", tused, tsize - tused);
+
+ return 0;
+}
+
+static int prealloc_memory_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, prealloc_memory_stats_show, NULL);
+}
+
+static const struct file_operations prealloc_memory_stats_fops = {
+ .owner = THIS_MODULE,
+ .open = prealloc_memory_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static int __init wcnss_pre_alloc_init(void)
{
- return wcnss_prealloc_init();
+ int ret;
+
+ ret = wcnss_prealloc_init();
+ if (ret) {
+ pr_err("%s: Failed to init the prealloc pool\n", __func__);
+ return ret;
+ }
+
+ debug_base = debugfs_create_dir(PRE_ALLOC_DEBUGFS_DIR, NULL);
+ if (IS_ERR_OR_NULL(debug_base)) {
+ pr_err("%s: Failed to create debugfs dir\n", __func__);
+ } else if (IS_ERR_OR_NULL(debugfs_create_file(
+ PRE_ALLOC_DEBUGFS_FILE_OBJ,
+ 0644, debug_base, NULL,
+ &prealloc_memory_stats_fops))) {
+ pr_err("%s: Failed to create debugfs file\n", __func__);
+ debugfs_remove_recursive(debug_base);
+ }
+
+ return ret;
}
static void __exit wcnss_pre_alloc_exit(void)
{
wcnss_prealloc_deinit();
+ debugfs_remove_recursive(debug_base);
}
module_init(wcnss_pre_alloc_init);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index d3bad57..0fd7d7e 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2662,7 +2662,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
tasklet_hrtimer_init(&data->beacon_timer,
mac80211_hwsim_beacon,
- CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS);
+ CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
spin_lock_bh(&hwsim_radio_lock);
list_add_tail(&data->list, &hwsim_radios);
diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3.h b/drivers/phy/phy-qcom-ufs-qmp-v3.h
index f731aac..4d00878 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-v3.h
+++ b/drivers/phy/phy-qcom-ufs-qmp-v3.h
@@ -150,11 +150,15 @@
#define UFS_PHY_MULTI_LANE_CTRL1 PHY_OFF(0x1C4)
/* UFS PHY TX registers */
+#define QSERDES_TX0_RES_CODE_LANE_OFFSET_TX TX_OFF(0, 0x44)
+#define QSERDES_TX0_RES_CODE_LANE_OFFSET_RX TX_OFF(0, 0x48)
#define QSERDES_TX0_TRANSCEIVER_BIAS_EN TX_OFF(0, 0x5C)
#define QSERDES_TX0_LANE_MODE_1 TX_OFF(0, 0x8C)
#define QSERDES_TX0_LANE_MODE_2 TX_OFF(0, 0x90)
#define QSERDES_TX0_LANE_MODE_3 TX_OFF(0, 0x94)
+#define QSERDES_TX1_RES_CODE_LANE_OFFSET_TX TX_OFF(1, 0x44)
+#define QSERDES_TX1_RES_CODE_LANE_OFFSET_RX TX_OFF(1, 0x48)
#define QSERDES_TX1_LANE_MODE_1 TX_OFF(1, 0x8C)
@@ -177,6 +181,7 @@
#define QSERDES_RX0_SIGDET_LVL RX_OFF(0, 0x108)
#define QSERDES_RX0_SIGDET_DEGLITCH_CNTRL RX_OFF(0, 0x10C)
#define QSERDES_RX0_RX_INTERFACE_MODE RX_OFF(0, 0x11C)
+#define QSERDES_RX0_RX_MODE_00 RX_OFF(0, 0x164)
#define QSERDES_RX1_UCDR_SVS_SO_GAIN_HALF RX_OFF(1, 0x24)
#define QSERDES_RX1_UCDR_SVS_SO_GAIN_QUARTER RX_OFF(1, 0x28)
@@ -193,6 +198,7 @@
#define QSERDES_RX1_SIGDET_LVL RX_OFF(1, 0x108)
#define QSERDES_RX1_SIGDET_DEGLITCH_CNTRL RX_OFF(1, 0x10C)
#define QSERDES_RX1_RX_INTERFACE_MODE RX_OFF(1, 0x11C)
+#define QSERDES_RX1_RX_MODE_00 RX_OFF(1, 0x164)
#define UFS_PHY_RX_LINECFG_DISABLE_BIT BIT(1)
@@ -223,7 +229,7 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORE_CLK_EN, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x04),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IVCO, 0x0F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IVCO, 0x07),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL1, 0xFF),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE0, 0x82),
@@ -255,13 +261,16 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_TERM_BW, 0x5B),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL2, 0x06),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL3, 0x04),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL4, 0x1D),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL4, 0x1B),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SVS_SO_GAIN_HALF, 0x04),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SVS_SO_GAIN, 0x04),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE, 0x4B),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_PI_CONTROLS, 0x81),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_FASTLOCK_COUNT_LOW, 0x80),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX0_RES_CODE_LANE_OFFSET_TX, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX0_RES_CODE_LANE_OFFSET_RX, 0x07),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00, 0x59),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6E),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02),
@@ -281,7 +290,7 @@ static struct ufs_qcom_phy_calibration phy_cal_table_2nd_lane[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_TERM_BW, 0x5B),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL2, 0x06),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL3, 0x04),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL4, 0x1D),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL4, 0x1B),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN_HALF, 0x04),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN, 0x04),
@@ -289,6 +298,9 @@ static struct ufs_qcom_phy_calibration phy_cal_table_2nd_lane[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_PI_CONTROLS, 0x81),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_FASTLOCK_COUNT_LOW, 0x80),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_MULTI_LANE_CTRL1, 0x02),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX1_RES_CODE_LANE_OFFSET_TX, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX1_RES_CODE_LANE_OFFSET_RX, 0x07),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00, 0x59),
};
static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
diff --git a/drivers/pinctrl/freescale/pinctrl-mxs.c b/drivers/pinctrl/freescale/pinctrl-mxs.c
index 41b5b07..6852010 100644
--- a/drivers/pinctrl/freescale/pinctrl-mxs.c
+++ b/drivers/pinctrl/freescale/pinctrl-mxs.c
@@ -194,6 +194,16 @@ static int mxs_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
return 0;
}
+static void mxs_pinctrl_rmwl(u32 value, u32 mask, u8 shift, void __iomem *reg)
+{
+ u32 tmp;
+
+ tmp = readl(reg);
+ tmp &= ~(mask << shift);
+ tmp |= value << shift;
+ writel(tmp, reg);
+}
+
static int mxs_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
unsigned group)
{
@@ -211,8 +221,7 @@ static int mxs_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
reg += bank * 0x20 + pin / 16 * 0x10;
shift = pin % 16 * 2;
- writel(0x3 << shift, reg + CLR);
- writel(g->muxsel[i] << shift, reg + SET);
+ mxs_pinctrl_rmwl(g->muxsel[i], 0x3, shift, reg);
}
return 0;
@@ -279,8 +288,7 @@ static int mxs_pinconf_group_set(struct pinctrl_dev *pctldev,
/* mA */
if (config & MA_PRESENT) {
shift = pin % 8 * 4;
- writel(0x3 << shift, reg + CLR);
- writel(ma << shift, reg + SET);
+ mxs_pinctrl_rmwl(ma, 0x3, shift, reg);
}
/* vol */
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index c43b1e9..0d34d8a4 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -13,6 +13,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/dmi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -1524,10 +1525,32 @@ static void chv_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
+/*
+ * Certain machines seem to hardcode Linux IRQ numbers in their ACPI
+ * tables. Since we leave GPIOs that are not capable of generating
+ * interrupts out of the irqdomain the numbering will be different and
+ * cause devices using the hardcoded IRQ numbers fail. In order not to
+ * break such machines we will only mask pins from irqdomain if the machine
+ * is not listed below.
+ */
+static const struct dmi_system_id chv_no_valid_mask[] = {
+ {
+ /* See https://bugzilla.kernel.org/show_bug.cgi?id=194945 */
+ .ident = "Acer Chromebook (CYAN)",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Edgar"),
+ DMI_MATCH(DMI_BIOS_DATE, "05/21/2016"),
+ },
+ },
+ {}
+};
+
static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
{
const struct chv_gpio_pinrange *range;
struct gpio_chip *chip = &pctrl->chip;
+ bool need_valid_mask = !dmi_check_system(chv_no_valid_mask);
int ret, i, offset;
*chip = chv_gpio_chip;
@@ -1536,7 +1559,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
chip->label = dev_name(pctrl->dev);
chip->parent = pctrl->dev;
chip->base = -1;
- chip->irq_need_valid_mask = true;
+ chip->irq_need_valid_mask = need_valid_mask;
ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
if (ret) {
@@ -1567,7 +1590,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
intsel &= CHV_PADCTRL0_INTSEL_MASK;
intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
- if (intsel >= pctrl->community->nirqs)
+ if (need_valid_mask && intsel >= pctrl->community->nirqs)
clear_bit(i, chip->irq_valid_mask);
}
diff --git a/drivers/pinctrl/meson/pinctrl-meson8b.c b/drivers/pinctrl/meson/pinctrl-meson8b.c
index 76f077f..f87ef5a 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8b.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8b.c
@@ -739,8 +739,8 @@ static const char * const sdxc_c_groups[] = {
static const char * const nand_groups[] = {
"nand_io", "nand_io_ce0", "nand_io_ce1",
"nand_io_rb0", "nand_ale", "nand_cle",
- "nand_wen_clk", "nand_ren_clk", "nand_dqs0",
- "nand_dqs1"
+ "nand_wen_clk", "nand_ren_clk", "nand_dqs_0",
+ "nand_dqs_1"
};
static const char * const nor_groups[] = {
diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
index b68ae42..743d1f4 100644
--- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c
+++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
@@ -405,6 +405,36 @@ static const struct msm_pingroup ipq4019_groups[] = {
PINGROUP(67, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(68, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(69, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(70, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(71, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(72, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(73, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(74, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(75, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(76, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(77, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(78, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(79, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(80, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(81, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(82, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(83, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(84, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(85, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(86, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(87, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(88, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(89, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(90, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(91, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(92, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(93, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(94, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(95, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(96, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(97, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(98, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(99, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
};
static const struct msm_pinctrl_soc_data ipq4019_pinctrl = {
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c
index c93628e..1f742f8 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm670.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c
@@ -28,6 +28,7 @@
#define NORTH 0x00500000
#define SOUTH 0x00900000
#define WEST 0x00100000
+#define DUMMY 0x0
#define REG_SIZE 0x1000
#define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
{ \
@@ -254,12 +255,14 @@ static const struct pinctrl_pin_desc sdm670_pins[] = {
PINCTRL_PIN(147, "GPIO_147"),
PINCTRL_PIN(148, "GPIO_148"),
PINCTRL_PIN(149, "GPIO_149"),
- PINCTRL_PIN(150, "SDC1_CLK"),
- PINCTRL_PIN(151, "SDC1_CMD"),
- PINCTRL_PIN(152, "SDC1_DATA"),
- PINCTRL_PIN(153, "SDC2_CLK"),
- PINCTRL_PIN(154, "SDC2_CMD"),
- PINCTRL_PIN(155, "SDC2_DATA"),
+ PINCTRL_PIN(150, "SDC1_RCLK"),
+ PINCTRL_PIN(151, "SDC1_CLK"),
+ PINCTRL_PIN(152, "SDC1_CMD"),
+ PINCTRL_PIN(153, "SDC1_DATA"),
+ PINCTRL_PIN(154, "SDC2_CLK"),
+ PINCTRL_PIN(155, "SDC2_CMD"),
+ PINCTRL_PIN(156, "SDC2_DATA"),
+ PINCTRL_PIN(157, "UFS_RESET"),
};
#define DECLARE_MSM_GPIO_PINS(pin) \
@@ -322,10 +325,23 @@ DECLARE_MSM_GPIO_PINS(54);
DECLARE_MSM_GPIO_PINS(55);
DECLARE_MSM_GPIO_PINS(56);
DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
DECLARE_MSM_GPIO_PINS(65);
DECLARE_MSM_GPIO_PINS(66);
DECLARE_MSM_GPIO_PINS(67);
DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
DECLARE_MSM_GPIO_PINS(75);
DECLARE_MSM_GPIO_PINS(76);
DECLARE_MSM_GPIO_PINS(77);
@@ -355,6 +371,7 @@ DECLARE_MSM_GPIO_PINS(100);
DECLARE_MSM_GPIO_PINS(101);
DECLARE_MSM_GPIO_PINS(102);
DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
DECLARE_MSM_GPIO_PINS(105);
DECLARE_MSM_GPIO_PINS(106);
DECLARE_MSM_GPIO_PINS(107);
@@ -401,243 +418,128 @@ DECLARE_MSM_GPIO_PINS(147);
DECLARE_MSM_GPIO_PINS(148);
DECLARE_MSM_GPIO_PINS(149);
-static const unsigned int sdc1_clk_pins[] = { 150 };
-static const unsigned int sdc1_cmd_pins[] = { 151 };
-static const unsigned int sdc1_data_pins[] = { 152 };
-static const unsigned int sdc2_clk_pins[] = { 153 };
-static const unsigned int sdc2_cmd_pins[] = { 154 };
-static const unsigned int sdc2_data_pins[] = { 155 };
+static const unsigned int sdc1_rclk_pins[] = { 150 };
+static const unsigned int sdc1_clk_pins[] = { 151 };
+static const unsigned int sdc1_cmd_pins[] = { 152 };
+static const unsigned int sdc1_data_pins[] = { 153 };
+static const unsigned int sdc2_clk_pins[] = { 154 };
+static const unsigned int sdc2_cmd_pins[] = { 155 };
+static const unsigned int sdc2_data_pins[] = { 156 };
+static const unsigned int ufs_reset_pins[] = { 157 };
enum sdm670_functions {
msm_mux_qup0,
msm_mux_gpio,
- msm_mux_reserved0,
- msm_mux_reserved1,
- msm_mux_reserved2,
- msm_mux_reserved3,
msm_mux_qup9,
msm_mux_qdss_cti,
- msm_mux_reserved4,
- msm_mux_reserved5,
msm_mux_ddr_pxi0,
- msm_mux_reserved6,
msm_mux_ddr_bist,
msm_mux_atest_tsens2,
msm_mux_vsense_trigger,
msm_mux_atest_usb1,
- msm_mux_reserved7,
msm_mux_qup_l4,
msm_mux_GP_PDM1,
- msm_mux_reserved8,
msm_mux_qup_l5,
- msm_mux_reserved9,
msm_mux_mdp_vsync,
msm_mux_qup_l6,
msm_mux_wlan2_adc1,
msm_mux_atest_usb11,
msm_mux_ddr_pxi2,
- msm_mux_reserved10,
msm_mux_edp_lcd,
msm_mux_dbg_out,
msm_mux_wlan2_adc0,
msm_mux_atest_usb10,
- msm_mux_reserved11,
msm_mux_m_voc,
msm_mux_tsif1_sync,
msm_mux_ddr_pxi3,
- msm_mux_reserved12,
msm_mux_cam_mclk,
msm_mux_pll_bypassnl,
msm_mux_qdss_gpio0,
- msm_mux_reserved13,
msm_mux_pll_reset,
msm_mux_qdss_gpio1,
- msm_mux_reserved14,
msm_mux_qdss_gpio2,
- msm_mux_reserved15,
msm_mux_qdss_gpio3,
- msm_mux_reserved16,
msm_mux_cci_i2c,
msm_mux_qup1,
msm_mux_qdss_gpio4,
- msm_mux_reserved17,
msm_mux_qdss_gpio5,
- msm_mux_reserved18,
msm_mux_qdss_gpio6,
- msm_mux_reserved19,
msm_mux_qdss_gpio7,
- msm_mux_reserved20,
msm_mux_cci_timer0,
msm_mux_gcc_gp2,
msm_mux_qdss_gpio8,
- msm_mux_reserved21,
msm_mux_cci_timer1,
msm_mux_gcc_gp3,
msm_mux_qdss_gpio,
- msm_mux_reserved22,
msm_mux_cci_timer2,
msm_mux_qdss_gpio9,
- msm_mux_reserved23,
msm_mux_cci_timer3,
msm_mux_cci_async,
msm_mux_qdss_gpio10,
- msm_mux_reserved24,
msm_mux_cci_timer4,
msm_mux_qdss_gpio11,
- msm_mux_reserved25,
msm_mux_qdss_gpio12,
msm_mux_JITTER_BIST,
- msm_mux_reserved26,
msm_mux_qup2,
msm_mux_qdss_gpio13,
msm_mux_PLL_BIST,
- msm_mux_reserved27,
msm_mux_qdss_gpio14,
msm_mux_AGERA_PLL,
- msm_mux_reserved28,
msm_mux_phase_flag1,
msm_mux_qdss_gpio15,
msm_mux_atest_tsens,
- msm_mux_reserved29,
msm_mux_phase_flag2,
- msm_mux_reserved30,
msm_mux_qup11,
msm_mux_qup14,
- msm_mux_reserved31,
- msm_mux_reserved32,
- msm_mux_reserved33,
- msm_mux_reserved34,
msm_mux_pci_e0,
msm_mux_QUP_L4,
- msm_mux_reserved35,
msm_mux_QUP_L5,
- msm_mux_reserved36,
msm_mux_QUP_L6,
- msm_mux_reserved37,
msm_mux_usb_phy,
- msm_mux_reserved38,
msm_mux_lpass_slimbus,
- msm_mux_reserved39,
msm_mux_sd_write,
msm_mux_tsif1_error,
- msm_mux_reserved40,
msm_mux_qup3,
- msm_mux_reserved41,
- msm_mux_reserved42,
- msm_mux_reserved43,
- msm_mux_reserved44,
- msm_mux_bt_reset,
msm_mux_qup6,
- msm_mux_reserved45,
- msm_mux_reserved46,
- msm_mux_reserved47,
- msm_mux_reserved124,
- msm_mux_reserved125,
- msm_mux_reserved126,
- msm_mux_reserved127,
- msm_mux_reserved128,
- msm_mux_reserved129,
- msm_mux_qlink_request,
- msm_mux_reserved130,
- msm_mux_qlink_enable,
- msm_mux_reserved131,
- msm_mux_reserved132,
- msm_mux_reserved133,
- msm_mux_reserved134,
- msm_mux_pa_indicator,
- msm_mux_reserved135,
- msm_mux_reserved136,
- msm_mux_phase_flag26,
- msm_mux_reserved137,
- msm_mux_phase_flag27,
- msm_mux_reserved138,
- msm_mux_phase_flag28,
- msm_mux_reserved139,
- msm_mux_phase_flag6,
- msm_mux_reserved140,
- msm_mux_phase_flag29,
- msm_mux_reserved141,
- msm_mux_phase_flag30,
- msm_mux_reserved142,
- msm_mux_phase_flag31,
- msm_mux_reserved143,
- msm_mux_mss_lte,
- msm_mux_reserved144,
- msm_mux_reserved145,
- msm_mux_reserved146,
- msm_mux_reserved147,
- msm_mux_reserved148,
- msm_mux_reserved149,
- msm_mux_reserved48,
msm_mux_qup12,
- msm_mux_reserved49,
- msm_mux_reserved50,
- msm_mux_reserved51,
msm_mux_phase_flag16,
- msm_mux_reserved52,
msm_mux_qup10,
msm_mux_phase_flag11,
- msm_mux_reserved53,
msm_mux_GP_PDM0,
msm_mux_phase_flag12,
msm_mux_wlan1_adc1,
msm_mux_atest_usb13,
msm_mux_ddr_pxi1,
- msm_mux_reserved54,
msm_mux_phase_flag13,
msm_mux_wlan1_adc0,
msm_mux_atest_usb12,
- msm_mux_reserved55,
msm_mux_phase_flag17,
- msm_mux_reserved56,
msm_mux_qua_mi2s,
msm_mux_gcc_gp1,
msm_mux_phase_flag18,
- msm_mux_reserved57,
msm_mux_pri_mi2s,
msm_mux_qup8,
msm_mux_wsa_clk,
- msm_mux_reserved65,
msm_mux_pri_mi2s_ws,
msm_mux_wsa_data,
- msm_mux_reserved66,
- msm_mux_wsa_en,
msm_mux_atest_usb2,
- msm_mux_reserved67,
msm_mux_atest_usb23,
- msm_mux_reserved68,
msm_mux_ter_mi2s,
msm_mux_phase_flag8,
msm_mux_atest_usb22,
- msm_mux_reserved75,
msm_mux_phase_flag9,
msm_mux_atest_usb21,
- msm_mux_reserved76,
msm_mux_phase_flag4,
msm_mux_atest_usb20,
- msm_mux_reserved77,
- msm_mux_ssc_irq,
- msm_mux_reserved78,
msm_mux_sec_mi2s,
msm_mux_GP_PDM2,
- msm_mux_reserved79,
- msm_mux_reserved80,
msm_mux_qup15,
- msm_mux_reserved81,
- msm_mux_reserved82,
- msm_mux_reserved83,
- msm_mux_reserved84,
msm_mux_qup5,
- msm_mux_reserved85,
msm_mux_copy_gp,
- msm_mux_reserved86,
- msm_mux_reserved87,
- msm_mux_reserved88,
msm_mux_tsif1_clk,
msm_mux_qup4,
msm_mux_tgu_ch3,
msm_mux_phase_flag10,
- msm_mux_reserved89,
msm_mux_tsif1_en,
msm_mux_mdp_vsync0,
msm_mux_mdp_vsync1,
@@ -645,83 +547,61 @@ enum sdm670_functions {
msm_mux_mdp_vsync3,
msm_mux_tgu_ch0,
msm_mux_phase_flag0,
- msm_mux_reserved90,
msm_mux_tsif1_data,
msm_mux_sdc4_cmd,
msm_mux_tgu_ch1,
- msm_mux_reserved91,
msm_mux_tsif2_error,
msm_mux_sdc43,
msm_mux_vfr_1,
msm_mux_tgu_ch2,
- msm_mux_reserved92,
msm_mux_tsif2_clk,
msm_mux_sdc4_clk,
msm_mux_qup7,
- msm_mux_reserved93,
msm_mux_tsif2_en,
msm_mux_sdc42,
- msm_mux_reserved94,
msm_mux_tsif2_data,
msm_mux_sdc41,
- msm_mux_reserved95,
msm_mux_tsif2_sync,
msm_mux_sdc40,
msm_mux_phase_flag3,
- msm_mux_reserved96,
msm_mux_ldo_en,
- msm_mux_reserved97,
msm_mux_ldo_update,
- msm_mux_reserved98,
msm_mux_phase_flag14,
msm_mux_prng_rosc,
- msm_mux_reserved99,
msm_mux_phase_flag15,
- msm_mux_reserved100,
msm_mux_phase_flag5,
- msm_mux_reserved101,
msm_mux_pci_e1,
- msm_mux_reserved102,
msm_mux_COPY_PHASE,
- msm_mux_reserved103,
msm_mux_uim2_data,
msm_mux_qup13,
- msm_mux_reserved105,
msm_mux_uim2_clk,
- msm_mux_reserved106,
msm_mux_uim2_reset,
- msm_mux_reserved107,
msm_mux_uim2_present,
- msm_mux_reserved108,
msm_mux_uim1_data,
- msm_mux_reserved109,
msm_mux_uim1_clk,
- msm_mux_reserved110,
msm_mux_uim1_reset,
- msm_mux_reserved111,
msm_mux_uim1_present,
- msm_mux_reserved112,
msm_mux_uim_batt,
msm_mux_edp_hot,
- msm_mux_reserved113,
msm_mux_NAV_PPS,
msm_mux_GPS_TX,
- msm_mux_reserved114,
- msm_mux_reserved115,
- msm_mux_reserved116,
msm_mux_atest_char,
- msm_mux_reserved117,
msm_mux_adsp_ext,
msm_mux_atest_char3,
- msm_mux_reserved118,
msm_mux_atest_char2,
- msm_mux_reserved119,
msm_mux_atest_char1,
- msm_mux_reserved120,
msm_mux_atest_char0,
- msm_mux_reserved121,
- msm_mux_reserved122,
- msm_mux_reserved123,
+ msm_mux_qlink_request,
+ msm_mux_qlink_enable,
+ msm_mux_pa_indicator,
+ msm_mux_phase_flag26,
+ msm_mux_phase_flag27,
+ msm_mux_phase_flag28,
+ msm_mux_phase_flag6,
+ msm_mux_phase_flag29,
+ msm_mux_phase_flag30,
+ msm_mux_phase_flag31,
+ msm_mux_mss_lte,
msm_mux_NA,
};
@@ -735,31 +615,21 @@ static const char * const gpio_groups[] = {
"gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
"gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
"gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
- "gpio43", "gpio44", "gpio46", "gpio47", "gpio48", "gpio49", "gpio50",
- "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56", "gpio57",
- "gpio65", "gpio66", "gpio75", "gpio76", "gpio77", "gpio81", "gpio82",
- "gpio83", "gpio84", "gpio85", "gpio86", "gpio87", "gpio88", "gpio89",
- "gpio90", "gpio91", "gpio92", "gpio93", "gpio94", "gpio95", "gpio96",
- "gpio97", "gpio98", "gpio99", "gpio100", "gpio101", "gpio102",
- "gpio103", "gpio105", "gpio106", "gpio107", "gpio108", "gpio109",
- "gpio110", "gpio111", "gpio112", "gpio113", "gpio114", "gpio115",
- "gpio116", "gpio126", "gpio127", "gpio128", "gpio129", "gpio130",
- "gpio131", "gpio132", "gpio133", "gpio134", "gpio135", "gpio136",
- "gpio137", "gpio138", "gpio139", "gpio140", "gpio141", "gpio142",
- "gpio143", "gpio144", "gpio145", "gpio146", "gpio147", "gpio148",
- "gpio149",
-};
-static const char * const reserved0_groups[] = {
- "gpio0",
-};
-static const char * const reserved1_groups[] = {
- "gpio1",
-};
-static const char * const reserved2_groups[] = {
- "gpio2",
-};
-static const char * const reserved3_groups[] = {
- "gpio3",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio65", "gpio66", "gpio67", "gpio68", "gpio75", "gpio76",
+ "gpio77", "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83",
+ "gpio84", "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90",
+ "gpio91", "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97",
+ "gpio98", "gpio99", "gpio100", "gpio101", "gpio102", "gpio103",
+ "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+ "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+ "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+ "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+ "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
+ "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
+ "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146",
+ "gpio147", "gpio148", "gpio149",
};
static const char * const qup9_groups[] = {
"gpio4", "gpio5", "gpio6", "gpio7",
@@ -767,18 +637,9 @@ static const char * const qup9_groups[] = {
static const char * const qdss_cti_groups[] = {
"gpio4", "gpio5", "gpio51", "gpio52", "gpio90", "gpio91",
};
-static const char * const reserved4_groups[] = {
- "gpio4",
-};
-static const char * const reserved5_groups[] = {
- "gpio5",
-};
static const char * const ddr_pxi0_groups[] = {
"gpio6", "gpio7",
};
-static const char * const reserved6_groups[] = {
- "gpio6",
-};
static const char * const ddr_bist_groups[] = {
"gpio7", "gpio8", "gpio9", "gpio10",
};
@@ -791,24 +652,15 @@ static const char * const vsense_trigger_groups[] = {
static const char * const atest_usb1_groups[] = {
"gpio7",
};
-static const char * const reserved7_groups[] = {
- "gpio7",
-};
static const char * const qup_l4_groups[] = {
"gpio8", "gpio105", "gpio123",
};
static const char * const GP_PDM1_groups[] = {
"gpio8", "gpio66",
};
-static const char * const reserved8_groups[] = {
- "gpio8",
-};
static const char * const qup_l5_groups[] = {
"gpio9", "gpio106", "gpio124",
};
-static const char * const reserved9_groups[] = {
- "gpio9",
-};
static const char * const mdp_vsync_groups[] = {
"gpio10", "gpio11", "gpio12", "gpio97", "gpio98",
};
@@ -824,9 +676,6 @@ static const char * const atest_usb11_groups[] = {
static const char * const ddr_pxi2_groups[] = {
"gpio10", "gpio11",
};
-static const char * const reserved10_groups[] = {
- "gpio10",
-};
static const char * const edp_lcd_groups[] = {
"gpio11",
};
@@ -839,9 +688,6 @@ static const char * const wlan2_adc0_groups[] = {
static const char * const atest_usb10_groups[] = {
"gpio11",
};
-static const char * const reserved11_groups[] = {
- "gpio11",
-};
static const char * const m_voc_groups[] = {
"gpio12",
};
@@ -851,9 +697,6 @@ static const char * const tsif1_sync_groups[] = {
static const char * const ddr_pxi3_groups[] = {
"gpio12", "gpio13",
};
-static const char * const reserved12_groups[] = {
- "gpio12",
-};
static const char * const cam_mclk_groups[] = {
"gpio13", "gpio14", "gpio15", "gpio16",
};
@@ -863,30 +706,18 @@ static const char * const pll_bypassnl_groups[] = {
static const char * const qdss_gpio0_groups[] = {
"gpio13", "gpio117",
};
-static const char * const reserved13_groups[] = {
- "gpio13",
-};
static const char * const pll_reset_groups[] = {
"gpio14",
};
static const char * const qdss_gpio1_groups[] = {
"gpio14", "gpio118",
};
-static const char * const reserved14_groups[] = {
- "gpio14",
-};
static const char * const qdss_gpio2_groups[] = {
"gpio15", "gpio119",
};
-static const char * const reserved15_groups[] = {
- "gpio15",
-};
static const char * const qdss_gpio3_groups[] = {
"gpio16", "gpio120",
};
-static const char * const reserved16_groups[] = {
- "gpio16",
-};
static const char * const cci_i2c_groups[] = {
"gpio17", "gpio18", "gpio19", "gpio20",
};
@@ -896,27 +727,15 @@ static const char * const qup1_groups[] = {
static const char * const qdss_gpio4_groups[] = {
"gpio17", "gpio121",
};
-static const char * const reserved17_groups[] = {
- "gpio17",
-};
static const char * const qdss_gpio5_groups[] = {
"gpio18", "gpio122",
};
-static const char * const reserved18_groups[] = {
- "gpio18",
-};
static const char * const qdss_gpio6_groups[] = {
"gpio19", "gpio41",
};
-static const char * const reserved19_groups[] = {
- "gpio19",
-};
static const char * const qdss_gpio7_groups[] = {
"gpio20", "gpio42",
};
-static const char * const reserved20_groups[] = {
- "gpio20",
-};
static const char * const cci_timer0_groups[] = {
"gpio21",
};
@@ -926,9 +745,6 @@ static const char * const gcc_gp2_groups[] = {
static const char * const qdss_gpio8_groups[] = {
"gpio21", "gpio75",
};
-static const char * const reserved21_groups[] = {
- "gpio21",
-};
static const char * const cci_timer1_groups[] = {
"gpio22",
};
@@ -938,18 +754,12 @@ static const char * const gcc_gp3_groups[] = {
static const char * const qdss_gpio_groups[] = {
"gpio22", "gpio30", "gpio123", "gpio124",
};
-static const char * const reserved22_groups[] = {
- "gpio22",
-};
static const char * const cci_timer2_groups[] = {
"gpio23",
};
static const char * const qdss_gpio9_groups[] = {
"gpio23", "gpio76",
};
-static const char * const reserved23_groups[] = {
- "gpio23",
-};
static const char * const cci_timer3_groups[] = {
"gpio24",
};
@@ -959,27 +769,18 @@ static const char * const cci_async_groups[] = {
static const char * const qdss_gpio10_groups[] = {
"gpio24", "gpio77",
};
-static const char * const reserved24_groups[] = {
- "gpio24",
-};
static const char * const cci_timer4_groups[] = {
"gpio25",
};
static const char * const qdss_gpio11_groups[] = {
"gpio25", "gpio79",
};
-static const char * const reserved25_groups[] = {
- "gpio25",
-};
static const char * const qdss_gpio12_groups[] = {
"gpio26", "gpio80",
};
static const char * const JITTER_BIST_groups[] = {
"gpio26", "gpio35",
};
-static const char * const reserved26_groups[] = {
- "gpio26",
-};
static const char * const qup2_groups[] = {
"gpio27", "gpio28", "gpio29", "gpio30",
};
@@ -989,18 +790,12 @@ static const char * const qdss_gpio13_groups[] = {
static const char * const PLL_BIST_groups[] = {
"gpio27", "gpio36",
};
-static const char * const reserved27_groups[] = {
- "gpio27",
-};
static const char * const qdss_gpio14_groups[] = {
"gpio28", "gpio43",
};
static const char * const AGERA_PLL_groups[] = {
"gpio28", "gpio37",
};
-static const char * const reserved28_groups[] = {
- "gpio28",
-};
static const char * const phase_flag1_groups[] = {
"gpio29",
};
@@ -1010,246 +805,57 @@ static const char * const qdss_gpio15_groups[] = {
static const char * const atest_tsens_groups[] = {
"gpio29",
};
-static const char * const reserved29_groups[] = {
- "gpio29",
-};
static const char * const phase_flag2_groups[] = {
"gpio30",
};
-static const char * const reserved30_groups[] = {
- "gpio30",
-};
static const char * const qup11_groups[] = {
"gpio31", "gpio32", "gpio33", "gpio34",
};
static const char * const qup14_groups[] = {
"gpio31", "gpio32", "gpio33", "gpio34",
};
-static const char * const reserved31_groups[] = {
- "gpio31",
-};
-static const char * const reserved32_groups[] = {
- "gpio32",
-};
-static const char * const reserved33_groups[] = {
- "gpio33",
-};
-static const char * const reserved34_groups[] = {
- "gpio34",
-};
static const char * const pci_e0_groups[] = {
"gpio35", "gpio36",
};
static const char * const QUP_L4_groups[] = {
"gpio35", "gpio75",
};
-static const char * const reserved35_groups[] = {
- "gpio35",
-};
static const char * const QUP_L5_groups[] = {
"gpio36", "gpio76",
};
-static const char * const reserved36_groups[] = {
- "gpio36",
-};
static const char * const QUP_L6_groups[] = {
"gpio37", "gpio77",
};
-static const char * const reserved37_groups[] = {
- "gpio37",
-};
static const char * const usb_phy_groups[] = {
"gpio38",
};
-static const char * const reserved38_groups[] = {
- "gpio38",
-};
static const char * const lpass_slimbus_groups[] = {
"gpio39",
};
-static const char * const reserved39_groups[] = {
- "gpio39",
-};
static const char * const sd_write_groups[] = {
"gpio40",
};
static const char * const tsif1_error_groups[] = {
"gpio40",
};
-static const char * const reserved40_groups[] = {
- "gpio40",
-};
static const char * const qup3_groups[] = {
"gpio41", "gpio42", "gpio43", "gpio44",
};
-static const char * const reserved41_groups[] = {
- "gpio41",
-};
-static const char * const reserved42_groups[] = {
- "gpio42",
-};
-static const char * const reserved43_groups[] = {
- "gpio43",
-};
-static const char * const reserved44_groups[] = {
- "gpio44",
-};
-static const char * const bt_reset_groups[] = {
- "gpio45",
-};
static const char * const qup6_groups[] = {
"gpio45", "gpio46", "gpio47", "gpio48",
};
-static const char * const reserved45_groups[] = {
- "gpio45",
-};
-static const char * const reserved46_groups[] = {
- "gpio46",
-};
-static const char * const reserved47_groups[] = {
- "gpio47",
-};
-static const char * const reserved124_groups[] = {
- "gpio124",
-};
-static const char * const reserved125_groups[] = {
- "gpio125",
-};
-static const char * const reserved126_groups[] = {
- "gpio126",
-};
-static const char * const reserved127_groups[] = {
- "gpio127",
-};
-static const char * const reserved128_groups[] = {
- "gpio128",
-};
-static const char * const reserved129_groups[] = {
- "gpio129",
-};
-static const char * const qlink_request_groups[] = {
- "gpio130",
-};
-static const char * const reserved130_groups[] = {
- "gpio130",
-};
-static const char * const qlink_enable_groups[] = {
- "gpio131",
-};
-static const char * const reserved131_groups[] = {
- "gpio131",
-};
-static const char * const reserved132_groups[] = {
- "gpio132",
-};
-static const char * const reserved133_groups[] = {
- "gpio133",
-};
-static const char * const reserved134_groups[] = {
- "gpio134",
-};
-static const char * const pa_indicator_groups[] = {
- "gpio135",
-};
-static const char * const reserved135_groups[] = {
- "gpio135",
-};
-static const char * const reserved136_groups[] = {
- "gpio136",
-};
-static const char * const phase_flag26_groups[] = {
- "gpio137",
-};
-static const char * const reserved137_groups[] = {
- "gpio137",
-};
-static const char * const phase_flag27_groups[] = {
- "gpio138",
-};
-static const char * const reserved138_groups[] = {
- "gpio138",
-};
-static const char * const phase_flag28_groups[] = {
- "gpio139",
-};
-static const char * const reserved139_groups[] = {
- "gpio139",
-};
-static const char * const phase_flag6_groups[] = {
- "gpio140",
-};
-static const char * const reserved140_groups[] = {
- "gpio140",
-};
-static const char * const phase_flag29_groups[] = {
- "gpio141",
-};
-static const char * const reserved141_groups[] = {
- "gpio141",
-};
-static const char * const phase_flag30_groups[] = {
- "gpio142",
-};
-static const char * const reserved142_groups[] = {
- "gpio142",
-};
-static const char * const phase_flag31_groups[] = {
- "gpio143",
-};
-static const char * const reserved143_groups[] = {
- "gpio143",
-};
-static const char * const mss_lte_groups[] = {
- "gpio144", "gpio145",
-};
-static const char * const reserved144_groups[] = {
- "gpio144",
-};
-static const char * const reserved145_groups[] = {
- "gpio145",
-};
-static const char * const reserved146_groups[] = {
- "gpio146",
-};
-static const char * const reserved147_groups[] = {
- "gpio147",
-};
-static const char * const reserved148_groups[] = {
- "gpio148",
-};
-static const char * const reserved149_groups[] = {
- "gpio149", "gpio149",
-};
-static const char * const reserved48_groups[] = {
- "gpio48",
-};
static const char * const qup12_groups[] = {
"gpio49", "gpio50", "gpio51", "gpio52",
};
-static const char * const reserved49_groups[] = {
- "gpio49",
-};
-static const char * const reserved50_groups[] = {
- "gpio50",
-};
-static const char * const reserved51_groups[] = {
- "gpio51",
-};
static const char * const phase_flag16_groups[] = {
"gpio52",
};
-static const char * const reserved52_groups[] = {
- "gpio52",
-};
static const char * const qup10_groups[] = {
"gpio53", "gpio54", "gpio55", "gpio56",
};
static const char * const phase_flag11_groups[] = {
"gpio53",
};
-static const char * const reserved53_groups[] = {
- "gpio53",
-};
static const char * const GP_PDM0_groups[] = {
"gpio54", "gpio95",
};
@@ -1265,9 +871,6 @@ static const char * const atest_usb13_groups[] = {
static const char * const ddr_pxi1_groups[] = {
"gpio54", "gpio55",
};
-static const char * const reserved54_groups[] = {
- "gpio54",
-};
static const char * const phase_flag13_groups[] = {
"gpio55",
};
@@ -1277,15 +880,9 @@ static const char * const wlan1_adc0_groups[] = {
static const char * const atest_usb12_groups[] = {
"gpio55",
};
-static const char * const reserved55_groups[] = {
- "gpio55",
-};
static const char * const phase_flag17_groups[] = {
"gpio56",
};
-static const char * const reserved56_groups[] = {
- "gpio56",
-};
static const char * const qua_mi2s_groups[] = {
"gpio57",
};
@@ -1295,9 +892,6 @@ static const char * const gcc_gp1_groups[] = {
static const char * const phase_flag18_groups[] = {
"gpio57",
};
-static const char * const reserved57_groups[] = {
- "gpio57",
-};
static const char * const pri_mi2s_groups[] = {
"gpio65", "gpio67", "gpio68",
};
@@ -1307,33 +901,18 @@ static const char * const qup8_groups[] = {
static const char * const wsa_clk_groups[] = {
"gpio65",
};
-static const char * const reserved65_groups[] = {
- "gpio65",
-};
static const char * const pri_mi2s_ws_groups[] = {
"gpio66",
};
static const char * const wsa_data_groups[] = {
"gpio66",
};
-static const char * const reserved66_groups[] = {
- "gpio66",
-};
-static const char * const wsa_en_groups[] = {
- "gpio67", "gpio68",
-};
static const char * const atest_usb2_groups[] = {
"gpio67",
};
-static const char * const reserved67_groups[] = {
- "gpio67",
-};
static const char * const atest_usb23_groups[] = {
"gpio68",
};
-static const char * const reserved68_groups[] = {
- "gpio68",
-};
static const char * const ter_mi2s_groups[] = {
"gpio75", "gpio76", "gpio77", "gpio78",
};
@@ -1343,79 +922,33 @@ static const char * const phase_flag8_groups[] = {
static const char * const atest_usb22_groups[] = {
"gpio75",
};
-static const char * const reserved75_groups[] = {
- "gpio75",
-};
static const char * const phase_flag9_groups[] = {
"gpio76",
};
static const char * const atest_usb21_groups[] = {
"gpio76",
};
-static const char * const reserved76_groups[] = {
- "gpio76",
-};
static const char * const phase_flag4_groups[] = {
"gpio77",
};
static const char * const atest_usb20_groups[] = {
"gpio77",
};
-static const char * const reserved77_groups[] = {
- "gpio77",
-};
-static const char * const ssc_irq_groups[] = {
- "gpio78", "gpio79", "gpio80", "gpio117", "gpio118", "gpio119",
- "gpio120", "gpio121", "gpio122", "gpio123", "gpio124", "gpio125",
-};
-static const char * const reserved78_groups[] = {
- "gpio78",
-};
static const char * const sec_mi2s_groups[] = {
"gpio79", "gpio80", "gpio81", "gpio82", "gpio83",
};
static const char * const GP_PDM2_groups[] = {
"gpio79",
};
-static const char * const reserved79_groups[] = {
- "gpio79",
-};
-static const char * const reserved80_groups[] = {
- "gpio80",
-};
static const char * const qup15_groups[] = {
"gpio81", "gpio82", "gpio83", "gpio84",
};
-static const char * const reserved81_groups[] = {
- "gpio81",
-};
-static const char * const reserved82_groups[] = {
- "gpio82",
-};
-static const char * const reserved83_groups[] = {
- "gpio83",
-};
-static const char * const reserved84_groups[] = {
- "gpio84",
-};
static const char * const qup5_groups[] = {
"gpio85", "gpio86", "gpio87", "gpio88",
};
-static const char * const reserved85_groups[] = {
- "gpio85",
-};
static const char * const copy_gp_groups[] = {
"gpio86",
};
-static const char * const reserved86_groups[] = {
- "gpio86",
-};
-static const char * const reserved87_groups[] = {
- "gpio87",
-};
-static const char * const reserved88_groups[] = {
- "gpio88",
-};
static const char * const tsif1_clk_groups[] = {
"gpio89",
};
@@ -1428,9 +961,6 @@ static const char * const tgu_ch3_groups[] = {
static const char * const phase_flag10_groups[] = {
"gpio89",
};
-static const char * const reserved89_groups[] = {
- "gpio89",
-};
static const char * const tsif1_en_groups[] = {
"gpio90",
};
@@ -1452,9 +982,6 @@ static const char * const tgu_ch0_groups[] = {
static const char * const phase_flag0_groups[] = {
"gpio90",
};
-static const char * const reserved90_groups[] = {
- "gpio90",
-};
static const char * const tsif1_data_groups[] = {
"gpio91",
};
@@ -1464,9 +991,6 @@ static const char * const sdc4_cmd_groups[] = {
static const char * const tgu_ch1_groups[] = {
"gpio91",
};
-static const char * const reserved91_groups[] = {
- "gpio91",
-};
static const char * const tsif2_error_groups[] = {
"gpio92",
};
@@ -1479,9 +1003,6 @@ static const char * const vfr_1_groups[] = {
static const char * const tgu_ch2_groups[] = {
"gpio92",
};
-static const char * const reserved92_groups[] = {
- "gpio92",
-};
static const char * const tsif2_clk_groups[] = {
"gpio93",
};
@@ -1491,27 +1012,18 @@ static const char * const sdc4_clk_groups[] = {
static const char * const qup7_groups[] = {
"gpio93", "gpio94", "gpio95", "gpio96",
};
-static const char * const reserved93_groups[] = {
- "gpio93",
-};
static const char * const tsif2_en_groups[] = {
"gpio94",
};
static const char * const sdc42_groups[] = {
"gpio94",
};
-static const char * const reserved94_groups[] = {
- "gpio94",
-};
static const char * const tsif2_data_groups[] = {
"gpio95",
};
static const char * const sdc41_groups[] = {
"gpio95",
};
-static const char * const reserved95_groups[] = {
- "gpio95",
-};
static const char * const tsif2_sync_groups[] = {
"gpio96",
};
@@ -1521,114 +1033,63 @@ static const char * const sdc40_groups[] = {
static const char * const phase_flag3_groups[] = {
"gpio96",
};
-static const char * const reserved96_groups[] = {
- "gpio96",
-};
static const char * const ldo_en_groups[] = {
"gpio97",
};
-static const char * const reserved97_groups[] = {
- "gpio97",
-};
static const char * const ldo_update_groups[] = {
"gpio98",
};
-static const char * const reserved98_groups[] = {
- "gpio98",
-};
static const char * const phase_flag14_groups[] = {
"gpio99",
};
static const char * const prng_rosc_groups[] = {
"gpio99", "gpio102",
};
-static const char * const reserved99_groups[] = {
- "gpio99",
-};
static const char * const phase_flag15_groups[] = {
"gpio100",
};
-static const char * const reserved100_groups[] = {
- "gpio100",
-};
static const char * const phase_flag5_groups[] = {
"gpio101",
};
-static const char * const reserved101_groups[] = {
- "gpio101",
-};
static const char * const pci_e1_groups[] = {
"gpio102", "gpio103",
};
-static const char * const reserved102_groups[] = {
- "gpio102",
-};
static const char * const COPY_PHASE_groups[] = {
"gpio103",
};
-static const char * const reserved103_groups[] = {
- "gpio103",
-};
static const char * const uim2_data_groups[] = {
"gpio105",
};
static const char * const qup13_groups[] = {
"gpio105", "gpio106", "gpio107", "gpio108",
};
-static const char * const reserved105_groups[] = {
- "gpio105",
-};
static const char * const uim2_clk_groups[] = {
"gpio106",
};
-static const char * const reserved106_groups[] = {
- "gpio106",
-};
static const char * const uim2_reset_groups[] = {
"gpio107",
};
-static const char * const reserved107_groups[] = {
- "gpio107",
-};
static const char * const uim2_present_groups[] = {
"gpio108",
};
-static const char * const reserved108_groups[] = {
- "gpio108",
-};
static const char * const uim1_data_groups[] = {
"gpio109",
};
-static const char * const reserved109_groups[] = {
- "gpio109",
-};
static const char * const uim1_clk_groups[] = {
"gpio110",
};
-static const char * const reserved110_groups[] = {
- "gpio110",
-};
static const char * const uim1_reset_groups[] = {
"gpio111",
};
-static const char * const reserved111_groups[] = {
- "gpio111",
-};
static const char * const uim1_present_groups[] = {
"gpio112",
};
-static const char * const reserved112_groups[] = {
- "gpio112",
-};
static const char * const uim_batt_groups[] = {
"gpio113",
};
static const char * const edp_hot_groups[] = {
"gpio113",
};
-static const char * const reserved113_groups[] = {
- "gpio113",
-};
static const char * const NAV_PPS_groups[] = {
"gpio114", "gpio114", "gpio115", "gpio115", "gpio128", "gpio128",
"gpio129", "gpio129", "gpio143", "gpio143",
@@ -1636,285 +1097,171 @@ static const char * const NAV_PPS_groups[] = {
static const char * const GPS_TX_groups[] = {
"gpio114", "gpio115", "gpio128", "gpio129", "gpio143", "gpio145",
};
-static const char * const reserved114_groups[] = {
- "gpio114",
-};
-static const char * const reserved115_groups[] = {
- "gpio115",
-};
-static const char * const reserved116_groups[] = {
- "gpio116",
-};
static const char * const atest_char_groups[] = {
"gpio117",
};
-static const char * const reserved117_groups[] = {
- "gpio117",
-};
static const char * const adsp_ext_groups[] = {
"gpio118",
};
static const char * const atest_char3_groups[] = {
"gpio118",
};
-static const char * const reserved118_groups[] = {
- "gpio118",
-};
static const char * const atest_char2_groups[] = {
"gpio119",
};
-static const char * const reserved119_groups[] = {
- "gpio119",
-};
static const char * const atest_char1_groups[] = {
"gpio120",
};
-static const char * const reserved120_groups[] = {
- "gpio120",
-};
static const char * const atest_char0_groups[] = {
"gpio121",
};
-static const char * const reserved121_groups[] = {
- "gpio121",
+static const char * const qlink_request_groups[] = {
+ "gpio130",
};
-static const char * const reserved122_groups[] = {
- "gpio122",
+static const char * const qlink_enable_groups[] = {
+ "gpio131",
};
-static const char * const reserved123_groups[] = {
- "gpio123",
+static const char * const pa_indicator_groups[] = {
+ "gpio135",
+};
+static const char * const phase_flag26_groups[] = {
+ "gpio137",
+};
+static const char * const phase_flag27_groups[] = {
+ "gpio138",
+};
+static const char * const phase_flag28_groups[] = {
+ "gpio139",
+};
+static const char * const phase_flag6_groups[] = {
+ "gpio140",
+};
+static const char * const phase_flag29_groups[] = {
+ "gpio141",
+};
+static const char * const phase_flag30_groups[] = {
+ "gpio142",
+};
+static const char * const phase_flag31_groups[] = {
+ "gpio143",
+};
+static const char * const mss_lte_groups[] = {
+ "gpio144", "gpio145",
};
static const struct msm_function sdm670_functions[] = {
FUNCTION(qup0),
FUNCTION(gpio),
- FUNCTION(reserved0),
- FUNCTION(reserved1),
- FUNCTION(reserved2),
- FUNCTION(reserved3),
FUNCTION(qup9),
FUNCTION(qdss_cti),
- FUNCTION(reserved4),
- FUNCTION(reserved5),
FUNCTION(ddr_pxi0),
- FUNCTION(reserved6),
FUNCTION(ddr_bist),
FUNCTION(atest_tsens2),
FUNCTION(vsense_trigger),
FUNCTION(atest_usb1),
- FUNCTION(reserved7),
FUNCTION(qup_l4),
FUNCTION(GP_PDM1),
- FUNCTION(reserved8),
FUNCTION(qup_l5),
- FUNCTION(reserved9),
FUNCTION(mdp_vsync),
FUNCTION(qup_l6),
FUNCTION(wlan2_adc1),
FUNCTION(atest_usb11),
FUNCTION(ddr_pxi2),
- FUNCTION(reserved10),
FUNCTION(edp_lcd),
FUNCTION(dbg_out),
FUNCTION(wlan2_adc0),
FUNCTION(atest_usb10),
- FUNCTION(reserved11),
FUNCTION(m_voc),
FUNCTION(tsif1_sync),
FUNCTION(ddr_pxi3),
- FUNCTION(reserved12),
FUNCTION(cam_mclk),
FUNCTION(pll_bypassnl),
FUNCTION(qdss_gpio0),
- FUNCTION(reserved13),
FUNCTION(pll_reset),
FUNCTION(qdss_gpio1),
- FUNCTION(reserved14),
FUNCTION(qdss_gpio2),
- FUNCTION(reserved15),
FUNCTION(qdss_gpio3),
- FUNCTION(reserved16),
FUNCTION(cci_i2c),
FUNCTION(qup1),
FUNCTION(qdss_gpio4),
- FUNCTION(reserved17),
FUNCTION(qdss_gpio5),
- FUNCTION(reserved18),
FUNCTION(qdss_gpio6),
- FUNCTION(reserved19),
FUNCTION(qdss_gpio7),
- FUNCTION(reserved20),
FUNCTION(cci_timer0),
FUNCTION(gcc_gp2),
FUNCTION(qdss_gpio8),
- FUNCTION(reserved21),
FUNCTION(cci_timer1),
FUNCTION(gcc_gp3),
FUNCTION(qdss_gpio),
- FUNCTION(reserved22),
FUNCTION(cci_timer2),
FUNCTION(qdss_gpio9),
- FUNCTION(reserved23),
FUNCTION(cci_timer3),
FUNCTION(cci_async),
FUNCTION(qdss_gpio10),
- FUNCTION(reserved24),
FUNCTION(cci_timer4),
FUNCTION(qdss_gpio11),
- FUNCTION(reserved25),
FUNCTION(qdss_gpio12),
FUNCTION(JITTER_BIST),
- FUNCTION(reserved26),
FUNCTION(qup2),
FUNCTION(qdss_gpio13),
FUNCTION(PLL_BIST),
- FUNCTION(reserved27),
FUNCTION(qdss_gpio14),
FUNCTION(AGERA_PLL),
- FUNCTION(reserved28),
FUNCTION(phase_flag1),
FUNCTION(qdss_gpio15),
FUNCTION(atest_tsens),
- FUNCTION(reserved29),
FUNCTION(phase_flag2),
- FUNCTION(reserved30),
FUNCTION(qup11),
FUNCTION(qup14),
- FUNCTION(reserved31),
- FUNCTION(reserved32),
- FUNCTION(reserved33),
- FUNCTION(reserved34),
FUNCTION(pci_e0),
FUNCTION(QUP_L4),
- FUNCTION(reserved35),
FUNCTION(QUP_L5),
- FUNCTION(reserved36),
FUNCTION(QUP_L6),
- FUNCTION(reserved37),
FUNCTION(usb_phy),
- FUNCTION(reserved38),
FUNCTION(lpass_slimbus),
- FUNCTION(reserved39),
FUNCTION(sd_write),
FUNCTION(tsif1_error),
- FUNCTION(reserved40),
FUNCTION(qup3),
- FUNCTION(reserved41),
- FUNCTION(reserved42),
- FUNCTION(reserved43),
- FUNCTION(reserved44),
- FUNCTION(bt_reset),
FUNCTION(qup6),
- FUNCTION(reserved45),
- FUNCTION(reserved46),
- FUNCTION(reserved47),
- FUNCTION(reserved124),
- FUNCTION(reserved125),
- FUNCTION(reserved126),
- FUNCTION(reserved127),
- FUNCTION(reserved128),
- FUNCTION(reserved129),
- FUNCTION(qlink_request),
- FUNCTION(reserved130),
- FUNCTION(qlink_enable),
- FUNCTION(reserved131),
- FUNCTION(reserved132),
- FUNCTION(reserved133),
- FUNCTION(reserved134),
- FUNCTION(pa_indicator),
- FUNCTION(reserved135),
- FUNCTION(reserved136),
- FUNCTION(phase_flag26),
- FUNCTION(reserved137),
- FUNCTION(phase_flag27),
- FUNCTION(reserved138),
- FUNCTION(phase_flag28),
- FUNCTION(reserved139),
- FUNCTION(phase_flag6),
- FUNCTION(reserved140),
- FUNCTION(phase_flag29),
- FUNCTION(reserved141),
- FUNCTION(phase_flag30),
- FUNCTION(reserved142),
- FUNCTION(phase_flag31),
- FUNCTION(reserved143),
- FUNCTION(mss_lte),
- FUNCTION(reserved144),
- FUNCTION(reserved145),
- FUNCTION(reserved146),
- FUNCTION(reserved147),
- FUNCTION(reserved148),
- FUNCTION(reserved149),
- FUNCTION(reserved48),
FUNCTION(qup12),
- FUNCTION(reserved49),
- FUNCTION(reserved50),
- FUNCTION(reserved51),
FUNCTION(phase_flag16),
- FUNCTION(reserved52),
FUNCTION(qup10),
FUNCTION(phase_flag11),
- FUNCTION(reserved53),
FUNCTION(GP_PDM0),
FUNCTION(phase_flag12),
FUNCTION(wlan1_adc1),
FUNCTION(atest_usb13),
FUNCTION(ddr_pxi1),
- FUNCTION(reserved54),
FUNCTION(phase_flag13),
FUNCTION(wlan1_adc0),
FUNCTION(atest_usb12),
- FUNCTION(reserved55),
FUNCTION(phase_flag17),
- FUNCTION(reserved56),
FUNCTION(qua_mi2s),
FUNCTION(gcc_gp1),
FUNCTION(phase_flag18),
- FUNCTION(reserved57),
FUNCTION(pri_mi2s),
FUNCTION(qup8),
FUNCTION(wsa_clk),
- FUNCTION(reserved65),
FUNCTION(pri_mi2s_ws),
FUNCTION(wsa_data),
- FUNCTION(reserved66),
- FUNCTION(wsa_en),
FUNCTION(atest_usb2),
- FUNCTION(reserved67),
FUNCTION(atest_usb23),
- FUNCTION(reserved68),
FUNCTION(ter_mi2s),
FUNCTION(phase_flag8),
FUNCTION(atest_usb22),
- FUNCTION(reserved75),
FUNCTION(phase_flag9),
FUNCTION(atest_usb21),
- FUNCTION(reserved76),
FUNCTION(phase_flag4),
FUNCTION(atest_usb20),
- FUNCTION(reserved77),
- FUNCTION(ssc_irq),
- FUNCTION(reserved78),
FUNCTION(sec_mi2s),
FUNCTION(GP_PDM2),
- FUNCTION(reserved79),
- FUNCTION(reserved80),
FUNCTION(qup15),
- FUNCTION(reserved81),
- FUNCTION(reserved82),
- FUNCTION(reserved83),
- FUNCTION(reserved84),
FUNCTION(qup5),
- FUNCTION(reserved85),
FUNCTION(copy_gp),
- FUNCTION(reserved86),
- FUNCTION(reserved87),
- FUNCTION(reserved88),
FUNCTION(tsif1_clk),
FUNCTION(qup4),
FUNCTION(tgu_ch3),
FUNCTION(phase_flag10),
- FUNCTION(reserved89),
FUNCTION(tsif1_en),
FUNCTION(mdp_vsync0),
FUNCTION(mdp_vsync1),
@@ -1922,326 +1269,320 @@ static const struct msm_function sdm670_functions[] = {
FUNCTION(mdp_vsync3),
FUNCTION(tgu_ch0),
FUNCTION(phase_flag0),
- FUNCTION(reserved90),
FUNCTION(tsif1_data),
FUNCTION(sdc4_cmd),
FUNCTION(tgu_ch1),
- FUNCTION(reserved91),
FUNCTION(tsif2_error),
FUNCTION(sdc43),
FUNCTION(vfr_1),
FUNCTION(tgu_ch2),
- FUNCTION(reserved92),
FUNCTION(tsif2_clk),
FUNCTION(sdc4_clk),
FUNCTION(qup7),
- FUNCTION(reserved93),
FUNCTION(tsif2_en),
FUNCTION(sdc42),
- FUNCTION(reserved94),
FUNCTION(tsif2_data),
FUNCTION(sdc41),
- FUNCTION(reserved95),
FUNCTION(tsif2_sync),
FUNCTION(sdc40),
FUNCTION(phase_flag3),
- FUNCTION(reserved96),
FUNCTION(ldo_en),
- FUNCTION(reserved97),
FUNCTION(ldo_update),
- FUNCTION(reserved98),
FUNCTION(phase_flag14),
FUNCTION(prng_rosc),
- FUNCTION(reserved99),
FUNCTION(phase_flag15),
- FUNCTION(reserved100),
FUNCTION(phase_flag5),
- FUNCTION(reserved101),
FUNCTION(pci_e1),
- FUNCTION(reserved102),
FUNCTION(COPY_PHASE),
- FUNCTION(reserved103),
FUNCTION(uim2_data),
FUNCTION(qup13),
- FUNCTION(reserved105),
FUNCTION(uim2_clk),
- FUNCTION(reserved106),
FUNCTION(uim2_reset),
- FUNCTION(reserved107),
FUNCTION(uim2_present),
- FUNCTION(reserved108),
FUNCTION(uim1_data),
- FUNCTION(reserved109),
FUNCTION(uim1_clk),
- FUNCTION(reserved110),
FUNCTION(uim1_reset),
- FUNCTION(reserved111),
FUNCTION(uim1_present),
- FUNCTION(reserved112),
FUNCTION(uim_batt),
FUNCTION(edp_hot),
- FUNCTION(reserved113),
FUNCTION(NAV_PPS),
FUNCTION(GPS_TX),
- FUNCTION(reserved114),
- FUNCTION(reserved115),
- FUNCTION(reserved116),
FUNCTION(atest_char),
- FUNCTION(reserved117),
FUNCTION(adsp_ext),
FUNCTION(atest_char3),
- FUNCTION(reserved118),
FUNCTION(atest_char2),
- FUNCTION(reserved119),
FUNCTION(atest_char1),
- FUNCTION(reserved120),
FUNCTION(atest_char0),
- FUNCTION(reserved121),
- FUNCTION(reserved122),
- FUNCTION(reserved123),
+ FUNCTION(qlink_request),
+ FUNCTION(qlink_enable),
+ FUNCTION(pa_indicator),
+ FUNCTION(phase_flag26),
+ FUNCTION(phase_flag27),
+ FUNCTION(phase_flag28),
+ FUNCTION(phase_flag6),
+ FUNCTION(phase_flag29),
+ FUNCTION(phase_flag30),
+ FUNCTION(phase_flag31),
+ FUNCTION(mss_lte),
};
+/* Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
static const struct msm_pingroup sdm670_groups[] = {
- PINGROUP(0, SOUTH, qup0, NA, reserved0, NA, NA, NA, NA, NA, NA),
- PINGROUP(1, SOUTH, qup0, NA, reserved1, NA, NA, NA, NA, NA, NA),
- PINGROUP(2, SOUTH, qup0, NA, reserved2, NA, NA, NA, NA, NA, NA),
- PINGROUP(3, SOUTH, qup0, NA, reserved3, NA, NA, NA, NA, NA, NA),
- PINGROUP(4, NORTH, qup9, qdss_cti, reserved4, NA, NA, NA, NA, NA, NA),
- PINGROUP(5, NORTH, qup9, qdss_cti, reserved5, NA, NA, NA, NA, NA, NA),
- PINGROUP(6, NORTH, qup9, NA, ddr_pxi0, reserved6, NA, NA, NA, NA, NA),
- PINGROUP(7, NORTH, qup9, ddr_bist, NA, atest_tsens2, vsense_trigger,
- atest_usb1, ddr_pxi0, reserved7, NA),
- PINGROUP(8, WEST, qup_l4, GP_PDM1, ddr_bist, NA, reserved8, NA, NA, NA,
- NA),
- PINGROUP(9, WEST, qup_l5, ddr_bist, reserved9, NA, NA, NA, NA, NA, NA),
- PINGROUP(10, NORTH, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1,
- atest_usb11, ddr_pxi2, reserved10, NA, NA),
- PINGROUP(11, NORTH, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0,
- atest_usb10, ddr_pxi2, reserved11, NA, NA),
- PINGROUP(12, SOUTH, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, reserved12,
- NA, NA, NA, NA),
- PINGROUP(13, WEST, cam_mclk, pll_bypassnl, qdss_gpio0, ddr_pxi3,
- reserved13, NA, NA, NA, NA),
- PINGROUP(14, WEST, cam_mclk, pll_reset, qdss_gpio1, reserved14, NA, NA,
- NA, NA, NA),
- PINGROUP(15, WEST, cam_mclk, qdss_gpio2, reserved15, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(16, WEST, cam_mclk, qdss_gpio3, reserved16, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(17, WEST, cci_i2c, qup1, qdss_gpio4, reserved17, NA, NA, NA,
- NA, NA),
- PINGROUP(18, WEST, cci_i2c, qup1, NA, qdss_gpio5, reserved18, NA, NA,
- NA, NA),
- PINGROUP(19, WEST, cci_i2c, qup1, NA, qdss_gpio6, reserved19, NA, NA,
- NA, NA),
- PINGROUP(20, WEST, cci_i2c, qup1, NA, qdss_gpio7, reserved20, NA, NA,
- NA, NA),
- PINGROUP(21, WEST, cci_timer0, gcc_gp2, qdss_gpio8, NA, reserved21, NA,
- NA, NA, NA),
- PINGROUP(22, WEST, cci_timer1, gcc_gp3, qdss_gpio, NA, reserved22, NA,
- NA, NA, NA),
- PINGROUP(23, WEST, cci_timer2, qdss_gpio9, NA, reserved23, NA, NA, NA,
- NA, NA),
- PINGROUP(24, WEST, cci_timer3, cci_async, qdss_gpio10, reserved24, NA,
- NA, NA, NA, NA),
- PINGROUP(25, WEST, cci_timer4, cci_async, qdss_gpio11, NA, reserved25,
- NA, NA, NA, NA),
- PINGROUP(26, WEST, cci_async, qdss_gpio12, JITTER_BIST, NA, reserved26,
- NA, NA, NA, NA),
- PINGROUP(27, WEST, qup2, qdss_gpio13, PLL_BIST, NA, reserved27, NA, NA,
- NA, NA),
- PINGROUP(28, WEST, qup2, qdss_gpio14, AGERA_PLL, NA, reserved28, NA,
- NA, NA, NA),
- PINGROUP(29, WEST, qup2, NA, phase_flag1, qdss_gpio15, atest_tsens,
- reserved29, NA, NA, NA),
- PINGROUP(30, WEST, qup2, phase_flag2, qdss_gpio, reserved30, NA, NA,
- NA, NA, NA),
- PINGROUP(31, WEST, qup11, qup14, reserved31, NA, NA, NA, NA, NA, NA),
- PINGROUP(32, WEST, qup11, qup14, NA, reserved32, NA, NA, NA, NA, NA),
- PINGROUP(33, WEST, qup11, qup14, NA, reserved33, NA, NA, NA, NA, NA),
- PINGROUP(34, WEST, qup11, qup14, NA, reserved34, NA, NA, NA, NA, NA),
- PINGROUP(35, NORTH, pci_e0, QUP_L4, JITTER_BIST, NA, reserved35, NA,
- NA, NA, NA),
- PINGROUP(36, NORTH, pci_e0, QUP_L5, PLL_BIST, NA, reserved36, NA, NA,
- NA, NA),
- PINGROUP(37, NORTH, QUP_L6, AGERA_PLL, NA, reserved37, NA, NA, NA, NA,
- NA),
- PINGROUP(38, NORTH, usb_phy, NA, reserved38, NA, NA, NA, NA, NA, NA),
- PINGROUP(39, NORTH, lpass_slimbus, NA, reserved39, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(40, NORTH, sd_write, tsif1_error, NA, reserved40, NA, NA, NA,
- NA, NA),
- PINGROUP(41, SOUTH, qup3, NA, qdss_gpio6, reserved41, NA, NA, NA, NA,
- NA),
- PINGROUP(42, SOUTH, qup3, NA, qdss_gpio7, reserved42, NA, NA, NA, NA,
- NA),
- PINGROUP(43, SOUTH, qup3, NA, qdss_gpio14, reserved43, NA, NA, NA, NA,
- NA),
- PINGROUP(44, SOUTH, qup3, NA, qdss_gpio15, reserved44, NA, NA, NA, NA,
- NA),
- PINGROUP(45, SOUTH, qup6, NA, reserved45, NA, NA, NA, NA, NA, NA),
- PINGROUP(46, SOUTH, qup6, NA, reserved46, NA, NA, NA, NA, NA, NA),
- PINGROUP(47, SOUTH, qup6, reserved47, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(48, SOUTH, qup6, reserved48, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(49, NORTH, qup12, reserved49, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(50, NORTH, qup12, reserved50, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(51, NORTH, qup12, qdss_cti, reserved51, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(52, NORTH, qup12, phase_flag16, qdss_cti, reserved52, NA, NA,
- NA, NA, NA),
- PINGROUP(53, NORTH, qup10, phase_flag11, reserved53, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(54, NORTH, qup10, GP_PDM0, phase_flag12, NA, wlan1_adc1,
- atest_usb13, ddr_pxi1, reserved54, NA),
- PINGROUP(55, NORTH, qup10, phase_flag13, NA, wlan1_adc0, atest_usb12,
- ddr_pxi1, reserved55, NA, NA),
- PINGROUP(56, NORTH, qup10, phase_flag17, reserved56, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(57, NORTH, qua_mi2s, gcc_gp1, phase_flag18, reserved57, NA,
- NA, NA, NA, NA),
- PINGROUP(65, NORTH, pri_mi2s, qup8, wsa_clk, NA, reserved65, NA, NA,
- NA, NA),
- PINGROUP(66, NORTH, pri_mi2s_ws, qup8, wsa_data, GP_PDM1, NA,
- reserved66, NA, NA, NA),
- PINGROUP(67, NORTH, pri_mi2s, qup8, NA, atest_usb2, reserved67, NA, NA,
- NA, NA),
- PINGROUP(68, NORTH, pri_mi2s, qup8, NA, atest_usb23, reserved68, NA,
- NA, NA, NA),
- PINGROUP(75, NORTH, ter_mi2s, phase_flag8, qdss_gpio8, atest_usb22,
- QUP_L4, reserved75, NA, NA, NA),
- PINGROUP(76, NORTH, ter_mi2s, phase_flag9, qdss_gpio9, atest_usb21,
- QUP_L5, reserved76, NA, NA, NA),
- PINGROUP(77, NORTH, ter_mi2s, phase_flag4, qdss_gpio10, atest_usb20,
- QUP_L6, reserved77, NA, NA, NA),
- PINGROUP(78, NORTH, ter_mi2s, gcc_gp1, NA, reserved78, NA, NA, NA, NA,
- NA),
- PINGROUP(79, NORTH, sec_mi2s, GP_PDM2, NA, qdss_gpio11, NA, reserved79,
- NA, NA, NA),
- PINGROUP(80, NORTH, sec_mi2s, NA, qdss_gpio12, reserved80, NA, NA, NA,
- NA, NA),
- PINGROUP(81, NORTH, sec_mi2s, qup15, NA, reserved81, NA, NA, NA, NA,
- NA),
- PINGROUP(82, NORTH, sec_mi2s, qup15, NA, reserved82, NA, NA, NA, NA,
- NA),
- PINGROUP(83, NORTH, sec_mi2s, qup15, NA, reserved83, NA, NA, NA, NA,
- NA),
- PINGROUP(84, NORTH, qup15, NA, reserved84, NA, NA, NA, NA, NA, NA),
- PINGROUP(85, SOUTH, qup5, NA, reserved85, NA, NA, NA, NA, NA, NA),
- PINGROUP(86, SOUTH, qup5, copy_gp, NA, reserved86, NA, NA, NA, NA, NA),
- PINGROUP(87, SOUTH, qup5, NA, reserved87, NA, NA, NA, NA, NA, NA),
- PINGROUP(88, SOUTH, qup5, NA, reserved88, NA, NA, NA, NA, NA, NA),
- PINGROUP(89, SOUTH, tsif1_clk, qup4, tgu_ch3, phase_flag10, reserved89,
- NA, NA, NA, NA),
- PINGROUP(90, SOUTH, tsif1_en, mdp_vsync0, qup4, mdp_vsync1, mdp_vsync2,
- mdp_vsync3, tgu_ch0, phase_flag0, qdss_cti),
- PINGROUP(91, SOUTH, tsif1_data, sdc4_cmd, qup4, tgu_ch1, NA, qdss_cti,
- reserved91, NA, NA),
- PINGROUP(92, SOUTH, tsif2_error, sdc43, qup4, vfr_1, tgu_ch2, NA,
- reserved92, NA, NA),
- PINGROUP(93, SOUTH, tsif2_clk, sdc4_clk, qup7, NA, qdss_gpio13,
- reserved93, NA, NA, NA),
- PINGROUP(94, SOUTH, tsif2_en, sdc42, qup7, NA, reserved94, NA, NA, NA,
- NA),
- PINGROUP(95, SOUTH, tsif2_data, sdc41, qup7, GP_PDM0, NA, reserved95,
- NA, NA, NA),
- PINGROUP(96, SOUTH, tsif2_sync, sdc40, qup7, phase_flag3, reserved96,
- NA, NA, NA, NA),
- PINGROUP(97, WEST, NA, NA, mdp_vsync, ldo_en, reserved97, NA, NA, NA,
- NA),
- PINGROUP(98, WEST, NA, mdp_vsync, ldo_update, reserved98, NA, NA, NA,
- NA, NA),
- PINGROUP(99, NORTH, phase_flag14, prng_rosc, reserved99, NA, NA, NA,
- NA, NA, NA),
- PINGROUP(100, WEST, phase_flag15, reserved100, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(101, WEST, NA, phase_flag5, reserved101, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(102, WEST, pci_e1, prng_rosc, reserved102, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(103, WEST, pci_e1, COPY_PHASE, reserved103, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(105, NORTH, uim2_data, qup13, qup_l4, NA, reserved105, NA, NA,
- NA, NA),
- PINGROUP(106, NORTH, uim2_clk, qup13, qup_l5, NA, reserved106, NA, NA,
- NA, NA),
- PINGROUP(107, NORTH, uim2_reset, qup13, qup_l6, reserved107, NA, NA,
- NA, NA, NA),
- PINGROUP(108, NORTH, uim2_present, qup13, reserved108, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(109, NORTH, uim1_data, reserved109, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(110, NORTH, uim1_clk, reserved110, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(111, NORTH, uim1_reset, reserved111, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(112, NORTH, uim1_present, reserved112, NA, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(113, NORTH, uim_batt, edp_hot, reserved113, NA, NA, NA, NA,
- NA, NA),
- PINGROUP(114, WEST, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, reserved114, NA,
- NA, NA),
- PINGROUP(115, WEST, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, reserved115, NA,
- NA, NA),
- PINGROUP(116, SOUTH, NA, reserved116, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(117, NORTH, NA, qdss_gpio0, atest_char, reserved117, NA, NA,
- NA, NA, NA),
- PINGROUP(118, NORTH, adsp_ext, NA, qdss_gpio1, atest_char3,
- reserved118, NA, NA, NA, NA),
- PINGROUP(119, NORTH, NA, qdss_gpio2, atest_char2, reserved119, NA, NA,
- NA, NA, NA),
- PINGROUP(120, NORTH, NA, qdss_gpio3, atest_char1, reserved120, NA, NA,
- NA, NA, NA),
- PINGROUP(121, NORTH, NA, qdss_gpio4, atest_char0, reserved121, NA, NA,
- NA, NA, NA),
- PINGROUP(122, NORTH, NA, qdss_gpio5, reserved122, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(123, NORTH, qup_l4, NA, qdss_gpio, reserved123, NA, NA, NA,
- NA, NA),
- PINGROUP(124, NORTH, qup_l5, NA, qdss_gpio, reserved124, NA, NA, NA,
- NA, NA),
- PINGROUP(125, NORTH, qup_l6, NA, reserved125, NA, NA, NA, NA, NA, NA),
- PINGROUP(126, NORTH, NA, reserved126, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(127, WEST, NA, NA, reserved127, NA, NA, NA, NA, NA, NA),
- PINGROUP(128, WEST, NAV_PPS, NAV_PPS, GPS_TX, NA, reserved128, NA, NA,
- NA, NA),
- PINGROUP(129, WEST, NAV_PPS, NAV_PPS, GPS_TX, NA, reserved129, NA, NA,
- NA, NA),
- PINGROUP(130, WEST, qlink_request, NA, reserved130, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(131, WEST, qlink_enable, NA, reserved131, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(132, WEST, NA, NA, reserved132, NA, NA, NA, NA, NA, NA),
- PINGROUP(133, NORTH, NA, reserved133, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(134, NORTH, NA, reserved134, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(135, WEST, NA, pa_indicator, NA, reserved135, NA, NA, NA, NA,
- NA),
- PINGROUP(136, WEST, NA, NA, reserved136, NA, NA, NA, NA, NA, NA),
- PINGROUP(137, WEST, NA, NA, phase_flag26, reserved137, NA, NA, NA, NA,
- NA),
- PINGROUP(138, WEST, NA, NA, phase_flag27, reserved138, NA, NA, NA, NA,
- NA),
- PINGROUP(139, WEST, NA, phase_flag28, reserved139, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(140, WEST, NA, NA, phase_flag6, reserved140, NA, NA, NA, NA,
- NA),
- PINGROUP(141, WEST, NA, phase_flag29, reserved141, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(142, WEST, NA, phase_flag30, reserved142, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(143, WEST, NA, NAV_PPS, NAV_PPS, GPS_TX, phase_flag31,
- reserved143, NA, NA, NA),
- PINGROUP(144, SOUTH, mss_lte, reserved144, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(145, SOUTH, mss_lte, GPS_TX, reserved145, NA, NA, NA, NA, NA,
- NA),
- PINGROUP(146, WEST, NA, NA, reserved146, NA, NA, NA, NA, NA, NA),
- PINGROUP(147, WEST, NA, NA, reserved147, NA, NA, NA, NA, NA, NA),
- PINGROUP(148, WEST, NA, reserved148, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(149, WEST, NA, reserved149, NA, NA, NA, NA, NA, NA, NA),
- SDC_QDSD_PINGROUP(sdc1_clk, 0x599000, 13, 6),
- SDC_QDSD_PINGROUP(sdc1_cmd, 0x599000, 11, 3),
- SDC_QDSD_PINGROUP(sdc1_data, 0x599000, 9, 0),
- SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6),
- SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3),
- SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0),
+ [0] = PINGROUP(0, SOUTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [1] = PINGROUP(1, SOUTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [2] = PINGROUP(2, SOUTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [3] = PINGROUP(3, SOUTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA),
+ [4] = PINGROUP(4, NORTH, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [5] = PINGROUP(5, NORTH, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [6] = PINGROUP(6, NORTH, qup9, NA, ddr_pxi0, NA, NA, NA, NA, NA, NA),
+ [7] = PINGROUP(7, NORTH, qup9, ddr_bist, NA, atest_tsens2,
+ vsense_trigger, atest_usb1, ddr_pxi0, NA, NA),
+ [8] = PINGROUP(8, WEST, qup_l4, GP_PDM1, ddr_bist, NA, NA, NA, NA, NA,
+ NA),
+ [9] = PINGROUP(9, WEST, qup_l5, ddr_bist, NA, NA, NA, NA, NA, NA, NA),
+ [10] = PINGROUP(10, NORTH, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1,
+ atest_usb11, ddr_pxi2, NA, NA, NA),
+ [11] = PINGROUP(11, NORTH, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0,
+ atest_usb10, ddr_pxi2, NA, NA, NA),
+ [12] = PINGROUP(12, SOUTH, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, NA,
+ NA, NA, NA, NA),
+ [13] = PINGROUP(13, WEST, cam_mclk, pll_bypassnl, qdss_gpio0, ddr_pxi3,
+ NA, NA, NA, NA, NA),
+ [14] = PINGROUP(14, WEST, cam_mclk, pll_reset, qdss_gpio1, NA, NA, NA,
+ NA, NA, NA),
+ [15] = PINGROUP(15, WEST, cam_mclk, qdss_gpio2, NA, NA, NA, NA, NA, NA,
+ NA),
+ [16] = PINGROUP(16, WEST, cam_mclk, qdss_gpio3, NA, NA, NA, NA, NA, NA,
+ NA),
+ [17] = PINGROUP(17, WEST, cci_i2c, qup1, qdss_gpio4, NA, NA, NA, NA,
+ NA, NA),
+ [18] = PINGROUP(18, WEST, cci_i2c, qup1, NA, qdss_gpio5, NA, NA, NA,
+ NA, NA),
+ [19] = PINGROUP(19, WEST, cci_i2c, qup1, NA, qdss_gpio6, NA, NA, NA,
+ NA, NA),
+ [20] = PINGROUP(20, WEST, cci_i2c, qup1, NA, qdss_gpio7, NA, NA, NA,
+ NA, NA),
+ [21] = PINGROUP(21, WEST, cci_timer0, gcc_gp2, qdss_gpio8, NA, NA, NA,
+ NA, NA, NA),
+ [22] = PINGROUP(22, WEST, cci_timer1, gcc_gp3, qdss_gpio, NA, NA, NA,
+ NA, NA, NA),
+ [23] = PINGROUP(23, WEST, cci_timer2, qdss_gpio9, NA, NA, NA, NA, NA,
+ NA, NA),
+ [24] = PINGROUP(24, WEST, cci_timer3, cci_async, qdss_gpio10, NA, NA,
+ NA, NA, NA, NA),
+ [25] = PINGROUP(25, WEST, cci_timer4, cci_async, qdss_gpio11, NA, NA,
+ NA, NA, NA, NA),
+ [26] = PINGROUP(26, WEST, cci_async, qdss_gpio12, JITTER_BIST, NA, NA,
+ NA, NA, NA, NA),
+ [27] = PINGROUP(27, WEST, qup2, qdss_gpio13, PLL_BIST, NA, NA, NA, NA,
+ NA, NA),
+ [28] = PINGROUP(28, WEST, qup2, qdss_gpio14, AGERA_PLL, NA, NA, NA, NA,
+ NA, NA),
+ [29] = PINGROUP(29, WEST, qup2, NA, phase_flag1, qdss_gpio15,
+ atest_tsens, NA, NA, NA, NA),
+ [30] = PINGROUP(30, WEST, qup2, phase_flag2, qdss_gpio, NA, NA, NA, NA,
+ NA, NA),
+ [31] = PINGROUP(31, WEST, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [32] = PINGROUP(32, WEST, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [33] = PINGROUP(33, WEST, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [34] = PINGROUP(34, WEST, qup11, qup14, NA, NA, NA, NA, NA, NA, NA),
+ [35] = PINGROUP(35, NORTH, pci_e0, QUP_L4, JITTER_BIST, NA, NA, NA, NA,
+ NA, NA),
+ [36] = PINGROUP(36, NORTH, pci_e0, QUP_L5, PLL_BIST, NA, NA, NA, NA,
+ NA, NA),
+ [37] = PINGROUP(37, NORTH, QUP_L6, AGERA_PLL, NA, NA, NA, NA, NA, NA,
+ NA),
+ [38] = PINGROUP(38, NORTH, usb_phy, NA, NA, NA, NA, NA, NA, NA, NA),
+ [39] = PINGROUP(39, NORTH, lpass_slimbus, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [40] = PINGROUP(40, NORTH, sd_write, tsif1_error, NA, NA, NA, NA, NA,
+ NA, NA),
+ [41] = PINGROUP(41, SOUTH, qup3, NA, qdss_gpio6, NA, NA, NA, NA, NA,
+ NA),
+ [42] = PINGROUP(42, SOUTH, qup3, NA, qdss_gpio7, NA, NA, NA, NA, NA,
+ NA),
+ [43] = PINGROUP(43, SOUTH, qup3, NA, qdss_gpio14, NA, NA, NA, NA, NA,
+ NA),
+ [44] = PINGROUP(44, SOUTH, qup3, NA, qdss_gpio15, NA, NA, NA, NA, NA,
+ NA),
+ [45] = PINGROUP(45, SOUTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [46] = PINGROUP(46, SOUTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [47] = PINGROUP(47, SOUTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [48] = PINGROUP(48, SOUTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [49] = PINGROUP(49, NORTH, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
+ [50] = PINGROUP(50, NORTH, qup12, NA, NA, NA, NA, NA, NA, NA, NA),
+ [51] = PINGROUP(51, NORTH, qup12, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ [52] = PINGROUP(52, NORTH, qup12, phase_flag16, qdss_cti, NA, NA, NA,
+ NA, NA, NA),
+ [53] = PINGROUP(53, NORTH, qup10, phase_flag11, NA, NA, NA, NA, NA, NA,
+ NA),
+ [54] = PINGROUP(54, NORTH, qup10, GP_PDM0, phase_flag12, NA,
+ wlan1_adc1, atest_usb13, ddr_pxi1, NA, NA),
+ [55] = PINGROUP(55, NORTH, qup10, phase_flag13, NA, wlan1_adc0,
+ atest_usb12, ddr_pxi1, NA, NA, NA),
+ [56] = PINGROUP(56, NORTH, qup10, phase_flag17, NA, NA, NA, NA, NA, NA,
+ NA),
+ [57] = PINGROUP(57, NORTH, qua_mi2s, gcc_gp1, phase_flag18, NA, NA, NA,
+ NA, NA, NA),
+ [58] = PINGROUP(58, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [59] = PINGROUP(59, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [60] = PINGROUP(60, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [61] = PINGROUP(61, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [62] = PINGROUP(62, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [63] = PINGROUP(63, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [64] = PINGROUP(64, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [65] = PINGROUP(65, NORTH, pri_mi2s, qup8, wsa_clk, NA, NA, NA, NA, NA,
+ NA),
+ [66] = PINGROUP(66, NORTH, pri_mi2s_ws, qup8, wsa_data, GP_PDM1, NA,
+ NA, NA, NA, NA),
+ [67] = PINGROUP(67, NORTH, pri_mi2s, qup8, NA, atest_usb2, NA, NA, NA,
+ NA, NA),
+ [68] = PINGROUP(68, NORTH, pri_mi2s, qup8, NA, atest_usb23, NA, NA, NA,
+ NA, NA),
+ [69] = PINGROUP(69, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [70] = PINGROUP(70, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [71] = PINGROUP(71, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [72] = PINGROUP(72, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [73] = PINGROUP(73, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [74] = PINGROUP(74, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [75] = PINGROUP(75, NORTH, ter_mi2s, phase_flag8, qdss_gpio8,
+ atest_usb22, QUP_L4, NA, NA, NA, NA),
+ [76] = PINGROUP(76, NORTH, ter_mi2s, phase_flag9, qdss_gpio9,
+ atest_usb21, QUP_L5, NA, NA, NA, NA),
+ [77] = PINGROUP(77, NORTH, ter_mi2s, phase_flag4, qdss_gpio10,
+ atest_usb20, QUP_L6, NA, NA, NA, NA),
+ [78] = PINGROUP(78, NORTH, ter_mi2s, gcc_gp1, NA, NA, NA, NA, NA, NA,
+ NA),
+ [79] = PINGROUP(79, NORTH, sec_mi2s, GP_PDM2, NA, qdss_gpio11, NA, NA,
+ NA, NA, NA),
+ [80] = PINGROUP(80, NORTH, sec_mi2s, NA, qdss_gpio12, NA, NA, NA, NA,
+ NA, NA),
+ [81] = PINGROUP(81, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [82] = PINGROUP(82, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [83] = PINGROUP(83, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA),
+ [84] = PINGROUP(84, NORTH, qup15, NA, NA, NA, NA, NA, NA, NA, NA),
+ [85] = PINGROUP(85, SOUTH, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [86] = PINGROUP(86, SOUTH, qup5, copy_gp, NA, NA, NA, NA, NA, NA, NA),
+ [87] = PINGROUP(87, SOUTH, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [88] = PINGROUP(88, SOUTH, qup5, NA, NA, NA, NA, NA, NA, NA, NA),
+ [89] = PINGROUP(89, SOUTH, tsif1_clk, qup4, tgu_ch3, phase_flag10, NA,
+ NA, NA, NA, NA),
+ [90] = PINGROUP(90, SOUTH, tsif1_en, mdp_vsync0, qup4, mdp_vsync1,
+ mdp_vsync2, mdp_vsync3, tgu_ch0, phase_flag0, qdss_cti),
+ [91] = PINGROUP(91, SOUTH, tsif1_data, sdc4_cmd, qup4, tgu_ch1, NA,
+ qdss_cti, NA, NA, NA),
+ [92] = PINGROUP(92, SOUTH, tsif2_error, sdc43, qup4, vfr_1, tgu_ch2,
+ NA, NA, NA, NA),
+ [93] = PINGROUP(93, SOUTH, tsif2_clk, sdc4_clk, qup7, NA, qdss_gpio13,
+ NA, NA, NA, NA),
+ [94] = PINGROUP(94, SOUTH, tsif2_en, sdc42, qup7, NA, NA, NA, NA, NA,
+ NA),
+ [95] = PINGROUP(95, SOUTH, tsif2_data, sdc41, qup7, GP_PDM0, NA, NA,
+ NA, NA, NA),
+ [96] = PINGROUP(96, SOUTH, tsif2_sync, sdc40, qup7, phase_flag3, NA,
+ NA, NA, NA, NA),
+ [97] = PINGROUP(97, WEST, NA, NA, mdp_vsync, ldo_en, NA, NA, NA, NA,
+ NA),
+ [98] = PINGROUP(98, WEST, NA, mdp_vsync, ldo_update, NA, NA, NA, NA,
+ NA, NA),
+ [99] = PINGROUP(99, NORTH, phase_flag14, prng_rosc, NA, NA, NA, NA, NA,
+ NA, NA),
+ [100] = PINGROUP(100, WEST, phase_flag15, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [101] = PINGROUP(101, WEST, NA, phase_flag5, NA, NA, NA, NA, NA, NA,
+ NA),
+ [102] = PINGROUP(102, WEST, pci_e1, prng_rosc, NA, NA, NA, NA, NA, NA,
+ NA),
+ [103] = PINGROUP(103, WEST, pci_e1, COPY_PHASE, NA, NA, NA, NA, NA, NA,
+ NA),
+ [104] = PINGROUP(104, DUMMY, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [105] = PINGROUP(105, NORTH, uim2_data, qup13, qup_l4, NA, NA, NA, NA,
+ NA, NA),
+ [106] = PINGROUP(106, NORTH, uim2_clk, qup13, qup_l5, NA, NA, NA, NA,
+ NA, NA),
+ [107] = PINGROUP(107, NORTH, uim2_reset, qup13, qup_l6, NA, NA, NA, NA,
+ NA, NA),
+ [108] = PINGROUP(108, NORTH, uim2_present, qup13, NA, NA, NA, NA, NA,
+ NA, NA),
+ [109] = PINGROUP(109, NORTH, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ [110] = PINGROUP(110, NORTH, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ [111] = PINGROUP(111, NORTH, uim1_reset, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [112] = PINGROUP(112, NORTH, uim1_present, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [113] = PINGROUP(113, NORTH, uim_batt, edp_hot, NA, NA, NA, NA, NA, NA,
+ NA),
+ [114] = PINGROUP(114, WEST, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA,
+ NA, NA),
+ [115] = PINGROUP(115, WEST, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA,
+ NA, NA),
+ [116] = PINGROUP(116, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [117] = PINGROUP(117, NORTH, NA, qdss_gpio0, atest_char, NA, NA, NA,
+ NA, NA, NA),
+ [118] = PINGROUP(118, NORTH, adsp_ext, NA, qdss_gpio1, atest_char3, NA,
+ NA, NA, NA, NA),
+ [119] = PINGROUP(119, NORTH, NA, qdss_gpio2, atest_char2, NA, NA, NA,
+ NA, NA, NA),
+ [120] = PINGROUP(120, NORTH, NA, qdss_gpio3, atest_char1, NA, NA, NA,
+ NA, NA, NA),
+ [121] = PINGROUP(121, NORTH, NA, qdss_gpio4, atest_char0, NA, NA, NA,
+ NA, NA, NA),
+ [122] = PINGROUP(122, NORTH, NA, qdss_gpio5, NA, NA, NA, NA, NA, NA,
+ NA),
+ [123] = PINGROUP(123, NORTH, qup_l4, NA, qdss_gpio, NA, NA, NA, NA, NA,
+ NA),
+ [124] = PINGROUP(124, NORTH, qup_l5, NA, qdss_gpio, NA, NA, NA, NA, NA,
+ NA),
+ [125] = PINGROUP(125, NORTH, qup_l6, NA, NA, NA, NA, NA, NA, NA, NA),
+ [126] = PINGROUP(126, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [127] = PINGROUP(127, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [128] = PINGROUP(128, WEST, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA, NA,
+ NA, NA),
+ [129] = PINGROUP(129, WEST, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA, NA,
+ NA, NA),
+ [130] = PINGROUP(130, WEST, qlink_request, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [131] = PINGROUP(131, WEST, qlink_enable, NA, NA, NA, NA, NA, NA, NA,
+ NA),
+ [132] = PINGROUP(132, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [133] = PINGROUP(133, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [134] = PINGROUP(134, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [135] = PINGROUP(135, WEST, NA, pa_indicator, NA, NA, NA, NA, NA, NA,
+ NA),
+ [136] = PINGROUP(136, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [137] = PINGROUP(137, WEST, NA, NA, phase_flag26, NA, NA, NA, NA, NA,
+ NA),
+ [138] = PINGROUP(138, WEST, NA, NA, phase_flag27, NA, NA, NA, NA, NA,
+ NA),
+ [139] = PINGROUP(139, WEST, NA, phase_flag28, NA, NA, NA, NA, NA, NA,
+ NA),
+ [140] = PINGROUP(140, WEST, NA, NA, phase_flag6, NA, NA, NA, NA, NA,
+ NA),
+ [141] = PINGROUP(141, WEST, NA, phase_flag29, NA, NA, NA, NA, NA, NA,
+ NA),
+ [142] = PINGROUP(142, WEST, NA, phase_flag30, NA, NA, NA, NA, NA, NA,
+ NA),
+ [143] = PINGROUP(143, WEST, NA, NAV_PPS, NAV_PPS, GPS_TX, phase_flag31,
+ NA, NA, NA, NA),
+ [144] = PINGROUP(144, SOUTH, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA),
+ [145] = PINGROUP(145, SOUTH, mss_lte, GPS_TX, NA, NA, NA, NA, NA, NA,
+ NA),
+ [146] = PINGROUP(146, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [147] = PINGROUP(147, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [148] = PINGROUP(148, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [149] = PINGROUP(149, WEST, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ [150] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x599000, 15, 0),
+ [151] = SDC_QDSD_PINGROUP(sdc1_clk, 0x599000, 13, 6),
+ [152] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x599000, 11, 3),
+ [153] = SDC_QDSD_PINGROUP(sdc1_data, 0x599000, 9, 0),
+ [154] = SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6),
+ [155] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3),
+ [156] = SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0),
+ [157] = UFS_RESET(ufs_reset, 0x99f000),
};
static const struct msm_pinctrl_soc_data sdm670_pinctrl = {
@@ -2251,7 +1592,7 @@ static const struct msm_pinctrl_soc_data sdm670_pinctrl = {
.nfunctions = ARRAY_SIZE(sdm670_functions),
.groups = sdm670_groups,
.ngroups = ARRAY_SIZE(sdm670_groups),
- .ngpios = 136,
+ .ngpios = 150,
};
static int sdm670_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c
index cf80ce1..4a5a0fe 100644
--- a/drivers/pinctrl/sh-pfc/core.c
+++ b/drivers/pinctrl/sh-pfc/core.c
@@ -586,6 +586,9 @@ static int sh_pfc_probe(struct platform_device *pdev)
ret = info->ops->init(pfc);
if (ret < 0)
return ret;
+
+ /* .init() may have overridden pfc->info */
+ info = pfc->info;
}
/* Enable dummy states for those platforms without pinctrl support */
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
index 7ca37c3..baa98d7 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
@@ -203,7 +203,7 @@ enum {
/* IPSR6 */
FN_AUDIO_CLKB, FN_STP_OPWM_0_B, FN_MSIOF1_SCK_B,
- FN_SCIF_CLK, FN_BPFCLK_E,
+ FN_SCIF_CLK, FN_DVC_MUTE, FN_BPFCLK_E,
FN_AUDIO_CLKC, FN_SCIFB0_SCK_C, FN_MSIOF1_SYNC_B, FN_RX2,
FN_SCIFA2_RXD, FN_FMIN_E,
FN_AUDIO_CLKOUT, FN_MSIOF1_SS1_B, FN_TX2, FN_SCIFA2_TXD,
@@ -573,7 +573,7 @@ enum {
/* IPSR6 */
AUDIO_CLKB_MARK, STP_OPWM_0_B_MARK, MSIOF1_SCK_B_MARK,
- SCIF_CLK_MARK, BPFCLK_E_MARK,
+ SCIF_CLK_MARK, DVC_MUTE_MARK, BPFCLK_E_MARK,
AUDIO_CLKC_MARK, SCIFB0_SCK_C_MARK, MSIOF1_SYNC_B_MARK, RX2_MARK,
SCIFA2_RXD_MARK, FMIN_E_MARK,
AUDIO_CLKOUT_MARK, MSIOF1_SS1_B_MARK, TX2_MARK, SCIFA2_TXD_MARK,
@@ -1010,14 +1010,17 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP4_12_10, SCL2, SEL_IIC2_0),
PINMUX_IPSR_MSEL(IP4_12_10, GPS_CLK_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP4_12_10, GLO_Q0_D, SEL_GPS_3),
+ PINMUX_IPSR_MSEL(IP4_12_10, HSCK1_E, SEL_HSCIF1_4),
PINMUX_IPSR_GPSR(IP4_15_13, SSI_WS2),
PINMUX_IPSR_MSEL(IP4_15_13, SDA2, SEL_IIC2_0),
PINMUX_IPSR_MSEL(IP4_15_13, GPS_SIGN_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP4_15_13, RX2_E, SEL_SCIF2_4),
PINMUX_IPSR_MSEL(IP4_15_13, GLO_Q1_D, SEL_GPS_3),
+ PINMUX_IPSR_MSEL(IP4_15_13, HCTS1_N_E, SEL_HSCIF1_4),
PINMUX_IPSR_GPSR(IP4_18_16, SSI_SDATA2),
PINMUX_IPSR_MSEL(IP4_18_16, GPS_MAG_B, SEL_GPS_1),
PINMUX_IPSR_MSEL(IP4_18_16, TX2_E, SEL_SCIF2_4),
+ PINMUX_IPSR_MSEL(IP4_18_16, HRTS1_N_E, SEL_HSCIF1_4),
PINMUX_IPSR_GPSR(IP4_19, SSI_SCK34),
PINMUX_IPSR_GPSR(IP4_20, SSI_WS34),
PINMUX_IPSR_GPSR(IP4_21, SSI_SDATA3),
@@ -1090,6 +1093,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP6_2_0, STP_OPWM_0_B, SEL_SSP_1),
PINMUX_IPSR_MSEL(IP6_2_0, MSIOF1_SCK_B, SEL_SOF1_1),
PINMUX_IPSR_MSEL(IP6_2_0, SCIF_CLK, SEL_SCIF_0),
+ PINMUX_IPSR_GPSR(IP6_2_0, DVC_MUTE),
PINMUX_IPSR_MSEL(IP6_2_0, BPFCLK_E, SEL_FM_4),
PINMUX_IPSR_GPSR(IP6_5_3, AUDIO_CLKC),
PINMUX_IPSR_MSEL(IP6_5_3, SCIFB0_SCK_C, SEL_SCIFB_2),
@@ -1099,7 +1103,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP6_5_3, FMIN_E, SEL_FM_4),
PINMUX_IPSR_GPSR(IP6_7_6, AUDIO_CLKOUT),
PINMUX_IPSR_MSEL(IP6_7_6, MSIOF1_SS1_B, SEL_SOF1_1),
- PINMUX_IPSR_MSEL(IP6_5_3, TX2, SEL_SCIF2_0),
+ PINMUX_IPSR_MSEL(IP6_7_6, TX2, SEL_SCIF2_0),
PINMUX_IPSR_MSEL(IP6_7_6, SCIFA2_TXD, SEL_SCIFA2_0),
PINMUX_IPSR_GPSR(IP6_9_8, IRQ0),
PINMUX_IPSR_MSEL(IP6_9_8, SCIFB1_RXD_D, SEL_SCIFB1_3),
@@ -5810,7 +5814,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
0, 0,
/* IP6_2_0 [3] */
FN_AUDIO_CLKB, FN_STP_OPWM_0_B, FN_MSIOF1_SCK_B,
- FN_SCIF_CLK, 0, FN_BPFCLK_E,
+ FN_SCIF_CLK, FN_DVC_MUTE, FN_BPFCLK_E,
0, 0, }
},
{ PINMUX_CFG_REG_VAR("IPSR7", 0xE606003C, 32,
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
index ed734f56..ef093ac 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
@@ -281,8 +281,8 @@ enum {
FN_AVB_AVTP_CAPTURE, FN_ETH_CRS_DV_B, FN_SSI_WS1, FN_SCIF1_TXD_B,
FN_IIC1_SDA_C, FN_VI1_DATA0, FN_CAN0_TX_D, FN_AVB_AVTP_MATCH,
FN_ETH_RX_ER_B, FN_SSI_SDATA1, FN_HSCIF1_HRX_B, FN_SDATA, FN_VI1_DATA1,
- FN_ATAG0_N, FN_ETH_RXD0_B, FN_SSI_SCK2, FN_HSCIF1_HTX_B, FN_VI1_DATA2,
- FN_MDATA, FN_ATAWR0_N, FN_ETH_RXD1_B,
+ FN_ATAWR0_N, FN_ETH_RXD0_B, FN_SSI_SCK2, FN_HSCIF1_HTX_B, FN_VI1_DATA2,
+ FN_MDATA, FN_ATAG0_N, FN_ETH_RXD1_B,
/* IPSR13 */
FN_SSI_WS2, FN_HSCIF1_HCTS_N_B, FN_SCIFA0_RXD_D, FN_VI1_DATA3, FN_SCKZ,
@@ -575,8 +575,8 @@ enum {
ETH_CRS_DV_B_MARK, SSI_WS1_MARK, SCIF1_TXD_B_MARK, IIC1_SDA_C_MARK,
VI1_DATA0_MARK, CAN0_TX_D_MARK, AVB_AVTP_MATCH_MARK, ETH_RX_ER_B_MARK,
SSI_SDATA1_MARK, HSCIF1_HRX_B_MARK, VI1_DATA1_MARK, SDATA_MARK,
- ATAG0_N_MARK, ETH_RXD0_B_MARK, SSI_SCK2_MARK, HSCIF1_HTX_B_MARK,
- VI1_DATA2_MARK, MDATA_MARK, ATAWR0_N_MARK, ETH_RXD1_B_MARK,
+ ATAWR0_N_MARK, ETH_RXD0_B_MARK, SSI_SCK2_MARK, HSCIF1_HTX_B_MARK,
+ VI1_DATA2_MARK, MDATA_MARK, ATAG0_N_MARK, ETH_RXD1_B_MARK,
/* IPSR13 */
SSI_WS2_MARK, HSCIF1_HCTS_N_B_MARK, SCIFA0_RXD_D_MARK, VI1_DATA3_MARK,
@@ -1413,13 +1413,13 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP12_26_24, HSCIF1_HRX_B, SEL_HSCIF1_1),
PINMUX_IPSR_GPSR(IP12_26_24, VI1_DATA1),
PINMUX_IPSR_MSEL(IP12_26_24, SDATA, SEL_FSN_0),
- PINMUX_IPSR_GPSR(IP12_26_24, ATAG0_N),
+ PINMUX_IPSR_GPSR(IP12_26_24, ATAWR0_N),
PINMUX_IPSR_MSEL(IP12_26_24, ETH_RXD0_B, SEL_ETH_1),
PINMUX_IPSR_MSEL(IP12_29_27, SSI_SCK2, SEL_SSI2_0),
PINMUX_IPSR_MSEL(IP12_29_27, HSCIF1_HTX_B, SEL_HSCIF1_1),
PINMUX_IPSR_GPSR(IP12_29_27, VI1_DATA2),
PINMUX_IPSR_MSEL(IP12_29_27, MDATA, SEL_FSN_0),
- PINMUX_IPSR_GPSR(IP12_29_27, ATAWR0_N),
+ PINMUX_IPSR_GPSR(IP12_29_27, ATAG0_N),
PINMUX_IPSR_MSEL(IP12_29_27, ETH_RXD1_B, SEL_ETH_1),
/* IPSR13 */
@@ -4938,10 +4938,10 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
0, 0, 0, 0,
/* IP12_29_27 [3] */
FN_SSI_SCK2, FN_HSCIF1_HTX_B, FN_VI1_DATA2, FN_MDATA,
- FN_ATAWR0_N, FN_ETH_RXD1_B, 0, 0,
+ FN_ATAG0_N, FN_ETH_RXD1_B, 0, 0,
/* IP12_26_24 [3] */
FN_SSI_SDATA1, FN_HSCIF1_HRX_B, FN_VI1_DATA1, FN_SDATA,
- FN_ATAG0_N, FN_ETH_RXD0_B, 0, 0,
+ FN_ATAWR0_N, FN_ETH_RXD0_B, 0, 0,
/* IP12_23_21 [3] */
FN_SSI_WS1, FN_SCIF1_TXD_B, FN_IIC1_SDA_C, FN_VI1_DATA0,
FN_CAN0_TX_D, FN_AVB_AVTP_MATCH, FN_ETH_RX_ER_B, 0,
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
index 84cee66..0acb0a7 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
@@ -2056,7 +2056,7 @@ static const unsigned int hscif2_clk_b_pins[] = {
RCAR_GP_PIN(6, 21),
};
static const unsigned int hscif2_clk_b_mux[] = {
- HSCK1_B_MARK,
+ HSCK2_B_MARK,
};
static const unsigned int hscif2_ctrl_b_pins[] = {
/* RTS, CTS */
@@ -2129,7 +2129,7 @@ static const unsigned int hscif4_ctrl_pins[] = {
RCAR_GP_PIN(1, 15), RCAR_GP_PIN(1, 14),
};
static const unsigned int hscif4_ctrl_mux[] = {
- HRTS4_N_MARK, HCTS3_N_MARK,
+ HRTS4_N_MARK, HCTS4_N_MARK,
};
static const unsigned int hscif4_data_b_pins[] = {
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
index efc4371..a36fd4b 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
@@ -798,7 +798,7 @@ static int stm32_pconf_parse_conf(struct pinctrl_dev *pctldev,
break;
case PIN_CONFIG_OUTPUT:
__stm32_gpio_set(bank, offset, arg);
- ret = stm32_pmx_gpio_set_direction(pctldev, NULL, pin, false);
+ ret = stm32_pmx_gpio_set_direction(pctldev, range, pin, false);
break;
default:
ret = -EINVAL;
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
index 90b973e..a7c81e9 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
@@ -394,7 +394,7 @@ static const struct sunxi_desc_pin sun8i_a83t_pins[] = {
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 18),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x3, "owa")), /* DOUT */
+ SUNXI_FUNCTION(0x3, "spdif")), /* DOUT */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 19),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out")),
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index 808391f..9f417bb 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -2971,6 +2971,25 @@ struct device *ipa_get_pdev(void)
}
EXPORT_SYMBOL(ipa_get_pdev);
+int ipa_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *user_data),
+ void *user_data)
+{
+ int ret;
+
+ IPA_API_DISPATCH_RETURN(ipa_ntn_uc_reg_rdyCB,
+ ipauc_ready_cb, user_data);
+
+ return ret;
+}
+EXPORT_SYMBOL(ipa_ntn_uc_reg_rdyCB);
+
+void ipa_ntn_uc_dereg_rdyCB(void)
+{
+ IPA_API_DISPATCH(ipa_ntn_uc_dereg_rdyCB);
+}
+EXPORT_SYMBOL(ipa_ntn_uc_dereg_rdyCB);
+
+
static const struct dev_pm_ops ipa_pm_ops = {
.suspend_noirq = ipa_ap_suspend,
.resume_noirq = ipa_ap_resume,
diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h
index d3d4178..133e058 100644
--- a/drivers/platform/msm/ipa/ipa_api.h
+++ b/drivers/platform/msm/ipa/ipa_api.h
@@ -378,6 +378,11 @@ struct ipa_api_controller {
int ipa_ep_idx_dl);
struct device *(*ipa_get_pdev)(void);
+
+ int (*ipa_ntn_uc_reg_rdyCB)(void (*ipauc_ready_cb)(void *user_data),
+ void *user_data);
+
+ void (*ipa_ntn_uc_dereg_rdyCB)(void);
};
#ifdef CONFIG_IPA
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 2dd82c1..a15a9d8 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c
@@ -620,3 +620,41 @@ int ipa_uc_offload_cleanup(u32 clnt_hdl)
return ret;
}
EXPORT_SYMBOL(ipa_uc_offload_cleanup);
+
+/**
+ * ipa_uc_offload_uc_rdyCB() - To register uC ready CB if uC not
+ * ready
+ * @inout: [in/out] input/output parameters
+ * from/to client
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ */
+int ipa_uc_offload_reg_rdyCB(struct ipa_uc_ready_params *inp)
+{
+ int ret = 0;
+
+ if (!inp) {
+ IPA_UC_OFFLOAD_ERR("Invalid input\n");
+ return -EINVAL;
+ }
+
+ if (inp->proto == IPA_UC_NTN)
+ ret = ipa_ntn_uc_reg_rdyCB(inp->notify, inp->priv);
+
+ if (ret == -EEXIST) {
+ inp->is_uC_ready = true;
+ ret = 0;
+ } else
+ inp->is_uC_ready = false;
+
+ return ret;
+}
+EXPORT_SYMBOL(ipa_uc_offload_reg_rdyCB);
+
+void ipa_uc_offload_dereg_rdyCB(enum ipa_uc_offload_proto proto)
+{
+ if (proto == IPA_UC_NTN)
+ ipa_ntn_uc_dereg_rdyCB();
+}
+EXPORT_SYMBOL(ipa_uc_offload_dereg_rdyCB);
diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h
index 69c83d4..07bca0c 100644
--- a/drivers/platform/msm/ipa/ipa_common_i.h
+++ b/drivers/platform/msm/ipa/ipa_common_i.h
@@ -374,13 +374,15 @@ int ipa_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in,
struct ipa_ntn_conn_out_params *outp);
int ipa_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl);
-
u8 *ipa_write_64(u64 w, u8 *dest);
u8 *ipa_write_32(u32 w, u8 *dest);
u8 *ipa_write_16(u16 hw, u8 *dest);
u8 *ipa_write_8(u8 b, u8 *dest);
u8 *ipa_pad_to_64(u8 *dest);
u8 *ipa_pad_to_32(u8 *dest);
+int ipa_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *user_data),
+ void *user_data);
+void ipa_ntn_uc_dereg_rdyCB(void);
const char *ipa_get_version_string(enum ipa_hw_type ver);
#endif /* _IPA_COMMON_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_uc_offload_common_i.h b/drivers/platform/msm/ipa/ipa_uc_offload_common_i.h
index ae6cfc4..0bc4b76 100644
--- a/drivers/platform/msm/ipa/ipa_uc_offload_common_i.h
+++ b/drivers/platform/msm/ipa/ipa_uc_offload_common_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -21,4 +21,7 @@ int ipa_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in,
struct ipa_ntn_conn_out_params *outp);
int ipa_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl);
+int ipa_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *user_data),
+ void *user_data);
+void ipa_ntn_uc_dereg_rdyCB(void);
#endif /* _IPA_UC_OFFLOAD_COMMON_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
index 3418896..8d9f0e0 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
@@ -1025,7 +1025,7 @@ static int __ipa_add_flt_rule(struct ipa_flt_tbl *tbl, enum ipa_ip_type ip,
goto error;
}
- if (rt_tbl->cookie != IPA_COOKIE) {
+ if (rt_tbl->cookie != IPA_RT_TBL_COOKIE) {
IPAERR("RT table cookie is invalid\n");
goto error;
}
@@ -1046,7 +1046,7 @@ static int __ipa_add_flt_rule(struct ipa_flt_tbl *tbl, enum ipa_ip_type ip,
}
INIT_LIST_HEAD(&entry->link);
entry->rule = *rule;
- entry->cookie = IPA_COOKIE;
+ entry->cookie = IPA_FLT_COOKIE;
entry->rt_tbl = rt_tbl;
entry->tbl = tbl;
if (add_rear) {
@@ -1065,13 +1065,19 @@ static int __ipa_add_flt_rule(struct ipa_flt_tbl *tbl, enum ipa_ip_type ip,
if (id < 0) {
IPAERR("failed to add to tree\n");
WARN_ON(1);
+ goto ipa_insert_failed;
}
*rule_hdl = id;
entry->id = id;
IPADBG("add flt rule rule_cnt=%d\n", tbl->rule_cnt);
return 0;
-
+ipa_insert_failed:
+ tbl->rule_cnt--;
+ if (entry->rt_tbl)
+ entry->rt_tbl->ref_cnt--;
+ list_del(&entry->link);
+ kmem_cache_free(ipa_ctx->flt_rule_cache, entry);
error:
return -EPERM;
}
@@ -1087,7 +1093,7 @@ static int __ipa_del_flt_rule(u32 rule_hdl)
return -EINVAL;
}
- if (entry->cookie != IPA_COOKIE) {
+ if (entry->cookie != IPA_FLT_COOKIE) {
IPAERR("bad params\n");
return -EINVAL;
}
@@ -1119,7 +1125,7 @@ static int __ipa_mdfy_flt_rule(struct ipa_flt_rule_mdfy *frule,
goto error;
}
- if (entry->cookie != IPA_COOKIE) {
+ if (entry->cookie != IPA_FLT_COOKIE) {
IPAERR("bad params\n");
goto error;
}
@@ -1140,7 +1146,7 @@ static int __ipa_mdfy_flt_rule(struct ipa_flt_rule_mdfy *frule,
goto error;
}
- if (rt_tbl->cookie != IPA_COOKIE) {
+ if (rt_tbl->cookie != IPA_RT_TBL_COOKIE) {
IPAERR("RT table cookie is invalid\n");
goto error;
}
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
index bb6f8ec..a6a7613 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
@@ -547,7 +547,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
{
struct ipa_hdr_entry *hdr_entry;
struct ipa_hdr_proc_ctx_entry *entry;
- struct ipa_hdr_proc_ctx_offset_entry *offset;
+ struct ipa_hdr_proc_ctx_offset_entry *offset = NULL;
u32 bin;
struct ipa_hdr_proc_ctx_tbl *htbl = &ipa_ctx->hdr_proc_ctx_tbl;
int id;
@@ -563,7 +563,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
}
hdr_entry = ipa_id_find(proc_ctx->hdr_hdl);
- if (!hdr_entry || (hdr_entry->cookie != IPA_COOKIE)) {
+ if (!hdr_entry || (hdr_entry->cookie != IPA_HDR_COOKIE)) {
IPAERR("hdr_hdl is invalid\n");
return -EINVAL;
}
@@ -580,7 +580,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
entry->hdr = hdr_entry;
if (add_ref_hdr)
hdr_entry->ref_cnt++;
- entry->cookie = IPA_COOKIE;
+ entry->cookie = IPA_PROC_HDR_COOKIE;
needed_len = (proc_ctx->type == IPA_HDR_PROC_NONE) ?
sizeof(struct ipa_hdr_proc_ctx_add_hdr_seq) :
@@ -640,6 +640,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
if (id < 0) {
IPAERR("failed to alloc id\n");
WARN_ON(1);
+ goto ipa_insert_failed;
}
entry->id = id;
proc_ctx->proc_ctx_hdl = id;
@@ -647,6 +648,14 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
return 0;
+ipa_insert_failed:
+ if (offset)
+ list_move(&offset->link,
+ &htbl->head_free_offset_list[offset->bin]);
+ entry->offset_entry = NULL;
+ list_del(&entry->link);
+ htbl->proc_ctx_cnt--;
+
bad_len:
if (add_ref_hdr)
hdr_entry->ref_cnt--;
@@ -659,7 +668,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
{
struct ipa_hdr_entry *entry;
- struct ipa_hdr_offset_entry *offset;
+ struct ipa_hdr_offset_entry *offset = NULL;
u32 bin;
struct ipa_hdr_tbl *htbl = &ipa_ctx->hdr_tbl;
int id;
@@ -691,7 +700,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
entry->type = hdr->type;
entry->is_eth2_ofst_valid = hdr->is_eth2_ofst_valid;
entry->eth2_ofst = hdr->eth2_ofst;
- entry->cookie = IPA_COOKIE;
+ entry->cookie = IPA_HDR_COOKIE;
if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN0])
bin = IPA_HDR_BIN0;
@@ -780,6 +789,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
if (id < 0) {
IPAERR("failed to alloc id\n");
WARN_ON(1);
+ goto ipa_insert_failed;
}
entry->id = id;
hdr->hdr_hdl = id;
@@ -804,10 +814,19 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
entry->ref_cnt--;
hdr->hdr_hdl = 0;
ipa_id_remove(id);
+ipa_insert_failed:
+ if (entry->is_hdr_proc_ctx) {
+ dma_unmap_single(ipa_ctx->pdev, entry->phys_base,
+ entry->hdr_len, DMA_TO_DEVICE);
+ } else {
+ if (offset)
+ list_move(&offset->link,
+ &htbl->head_free_offset_list[offset->bin]);
+ entry->offset_entry = NULL;
+ }
htbl->hdr_cnt--;
list_del(&entry->link);
- dma_unmap_single(ipa_ctx->pdev, entry->phys_base,
- entry->hdr_len, DMA_TO_DEVICE);
+
fail_dma_mapping:
entry->is_hdr_proc_ctx = false;
bad_hdr_len:
@@ -824,7 +843,7 @@ static int __ipa_del_hdr_proc_ctx(u32 proc_ctx_hdl,
struct ipa_hdr_proc_ctx_tbl *htbl = &ipa_ctx->hdr_proc_ctx_tbl;
entry = ipa_id_find(proc_ctx_hdl);
- if (!entry || (entry->cookie != IPA_COOKIE)) {
+ if (!entry || (entry->cookie != IPA_PROC_HDR_COOKIE)) {
IPAERR("bad parm\n");
return -EINVAL;
}
@@ -875,7 +894,7 @@ int __ipa_del_hdr(u32 hdr_hdl, bool by_user)
return -EINVAL;
}
- if (entry->cookie != IPA_COOKIE) {
+ if (entry->cookie != IPA_HDR_COOKIE) {
IPAERR("bad parm\n");
return -EINVAL;
}
@@ -1444,7 +1463,7 @@ int ipa2_put_hdr(u32 hdr_hdl)
goto bail;
}
- if (entry->cookie != IPA_COOKIE) {
+ if (entry->cookie != IPA_HDR_COOKIE) {
IPAERR("invalid header entry\n");
result = -EINVAL;
goto bail;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index 5568f8b..0c2410f 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -37,7 +37,15 @@
#define DRV_NAME "ipa"
#define NAT_DEV_NAME "ipaNatTable"
+
#define IPA_COOKIE 0x57831603
+#define IPA_RT_RULE_COOKIE 0x57831604
+#define IPA_RT_TBL_COOKIE 0x57831605
+#define IPA_FLT_COOKIE 0x57831606
+#define IPA_HDR_COOKIE 0x57831607
+#define IPA_PROC_HDR_COOKIE 0x57831608
+
+
#define MTU_BYTE 1500
#define IPA_MAX_NUM_PIPES 0x14
@@ -196,8 +204,8 @@ struct ipa_smmu_cb_ctx {
*/
struct ipa_flt_entry {
struct list_head link;
- struct ipa_flt_rule rule;
u32 cookie;
+ struct ipa_flt_rule rule;
struct ipa_flt_tbl *tbl;
struct ipa_rt_tbl *rt_tbl;
u32 hw_len;
@@ -222,13 +230,13 @@ struct ipa_flt_entry {
*/
struct ipa_rt_tbl {
struct list_head link;
+ u32 cookie;
struct list_head head_rt_rule_list;
char name[IPA_RESOURCE_NAME_MAX];
u32 idx;
u32 rule_cnt;
u32 ref_cnt;
struct ipa_rt_tbl_set *set;
- u32 cookie;
bool in_sys;
u32 sz;
struct ipa_mem_buffer curr_mem;
@@ -259,6 +267,7 @@ struct ipa_rt_tbl {
*/
struct ipa_hdr_entry {
struct list_head link;
+ u32 cookie;
u8 hdr[IPA_HDR_MAX_SIZE];
u32 hdr_len;
char name[IPA_RESOURCE_NAME_MAX];
@@ -268,7 +277,6 @@ struct ipa_hdr_entry {
dma_addr_t phys_base;
struct ipa_hdr_proc_ctx_entry *proc_ctx;
struct ipa_hdr_offset_entry *offset_entry;
- u32 cookie;
u32 ref_cnt;
int id;
u8 is_eth2_ofst_valid;
@@ -341,10 +349,10 @@ struct ipa_hdr_proc_ctx_add_hdr_cmd_seq {
*/
struct ipa_hdr_proc_ctx_entry {
struct list_head link;
+ u32 cookie;
enum ipa_hdr_proc_type type;
struct ipa_hdr_proc_ctx_offset_entry *offset_entry;
struct ipa_hdr_entry *hdr;
- u32 cookie;
u32 ref_cnt;
int id;
bool user_deleted;
@@ -400,8 +408,8 @@ struct ipa_flt_tbl {
*/
struct ipa_rt_entry {
struct list_head link;
- struct ipa_rt_rule rule;
u32 cookie;
+ struct ipa_rt_rule rule;
struct ipa_rt_tbl *tbl;
struct ipa_hdr_entry *hdr;
struct ipa_hdr_proc_ctx_entry *proc_ctx;
@@ -1512,6 +1520,8 @@ int ipa2_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *inp,
ipa_notify_cb notify, void *priv, u8 hdr_len,
struct ipa_ntn_conn_out_params *outp);
int ipa2_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl);
+int ipa2_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv);
+void ipa2_ntn_uc_dereg_rdyCB(void);
/*
* To retrieve doorbell physical address of
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
index dc27636..12b1a99 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
@@ -271,6 +271,14 @@ int ipa_query_intf_tx_props(struct ipa_ioc_query_intf_tx_props *tx)
mutex_lock(&ipa_ctx->lock);
list_for_each_entry(entry, &ipa_ctx->intf_list, link) {
if (!strcmp(entry->name, tx->name)) {
+ /* add the entry check */
+ if (entry->num_tx_props != tx->num_tx_props) {
+ IPAERR("invalid entry number(%u %u)\n",
+ entry->num_tx_props,
+ tx->num_tx_props);
+ mutex_unlock(&ipa_ctx->lock);
+ return result;
+ }
memcpy(tx->tx, entry->tx, entry->num_tx_props *
sizeof(struct ipa_ioc_tx_intf_prop));
result = 0;
@@ -304,6 +312,14 @@ int ipa_query_intf_rx_props(struct ipa_ioc_query_intf_rx_props *rx)
mutex_lock(&ipa_ctx->lock);
list_for_each_entry(entry, &ipa_ctx->intf_list, link) {
if (!strcmp(entry->name, rx->name)) {
+ /* add the entry check */
+ if (entry->num_rx_props != rx->num_rx_props) {
+ IPAERR("invalid entry number(%u %u)\n",
+ entry->num_rx_props,
+ rx->num_rx_props);
+ mutex_unlock(&ipa_ctx->lock);
+ return result;
+ }
memcpy(rx->rx, entry->rx, entry->num_rx_props *
sizeof(struct ipa_ioc_rx_intf_prop));
result = 0;
@@ -337,6 +353,14 @@ int ipa_query_intf_ext_props(struct ipa_ioc_query_intf_ext_props *ext)
mutex_lock(&ipa_ctx->lock);
list_for_each_entry(entry, &ipa_ctx->intf_list, link) {
if (!strcmp(entry->name, ext->name)) {
+ /* add the entry check */
+ if (entry->num_ext_props != ext->num_ext_props) {
+ IPAERR("invalid entry number(%u %u)\n",
+ entry->num_ext_props,
+ ext->num_ext_props);
+ mutex_unlock(&ipa_ctx->lock);
+ return result;
+ }
memcpy(ext->ext, entry->ext, entry->num_ext_props *
sizeof(struct ipa_ioc_ext_intf_prop));
result = 0;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 5b70853..1faa795 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -854,12 +854,16 @@ int ipa2_query_rt_index(struct ipa_ioc_get_rt_tbl_indx *in)
return -EINVAL;
}
+ mutex_lock(&ipa_ctx->lock);
/* check if this table exists */
entry = __ipa_find_rt_tbl(in->ip, in->name);
- if (!entry)
+ if (!entry) {
+ mutex_unlock(&ipa_ctx->lock);
return -EFAULT;
+ }
in->idx = entry->idx;
+ mutex_unlock(&ipa_ctx->lock);
return 0;
}
@@ -902,7 +906,7 @@ static struct ipa_rt_tbl *__ipa_add_rt_tbl(enum ipa_ip_type ip,
INIT_LIST_HEAD(&entry->link);
strlcpy(entry->name, name, IPA_RESOURCE_NAME_MAX);
entry->set = set;
- entry->cookie = IPA_COOKIE;
+ entry->cookie = IPA_RT_TBL_COOKIE;
entry->in_sys = (ip == IPA_IP_v4) ?
!ipa_ctx->ip4_rt_tbl_lcl : !ipa_ctx->ip6_rt_tbl_lcl;
set->tbl_cnt++;
@@ -915,12 +919,16 @@ static struct ipa_rt_tbl *__ipa_add_rt_tbl(enum ipa_ip_type ip,
if (id < 0) {
IPAERR("failed to add to tree\n");
WARN_ON(1);
+ goto ipa_insert_failed;
}
entry->id = id;
}
return entry;
+ipa_insert_failed:
+ set->tbl_cnt--;
+ list_del(&entry->link);
fail_rt_idx_alloc:
entry->cookie = 0;
kmem_cache_free(ipa_ctx->rt_tbl_cache, entry);
@@ -933,7 +941,7 @@ static int __ipa_del_rt_tbl(struct ipa_rt_tbl *entry)
enum ipa_ip_type ip = IPA_IP_MAX;
u32 id;
- if (entry == NULL || (entry->cookie != IPA_COOKIE)) {
+ if (entry == NULL || (entry->cookie != IPA_RT_TBL_COOKIE)) {
IPAERR("bad parms\n");
return -EINVAL;
}
@@ -947,8 +955,11 @@ static int __ipa_del_rt_tbl(struct ipa_rt_tbl *entry)
ip = IPA_IP_v4;
else if (entry->set == &ipa_ctx->rt_tbl_set[IPA_IP_v6])
ip = IPA_IP_v6;
- else
+ else {
WARN_ON(1);
+ return -EPERM;
+ }
+
if (!entry->in_sys) {
list_del(&entry->link);
@@ -987,13 +998,14 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
if (rule->hdr_hdl) {
hdr = ipa_id_find(rule->hdr_hdl);
- if ((hdr == NULL) || (hdr->cookie != IPA_COOKIE)) {
+ if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) {
IPAERR("rt rule does not point to valid hdr\n");
goto error;
}
} else if (rule->hdr_proc_ctx_hdl) {
proc_ctx = ipa_id_find(rule->hdr_proc_ctx_hdl);
- if ((proc_ctx == NULL) || (proc_ctx->cookie != IPA_COOKIE)) {
+ if ((proc_ctx == NULL) ||
+ (proc_ctx->cookie != IPA_PROC_HDR_COOKIE)) {
IPAERR("rt rule does not point to valid proc ctx\n");
goto error;
}
@@ -1001,7 +1013,7 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
tbl = __ipa_add_rt_tbl(ip, name);
- if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) {
+ if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) {
IPAERR("bad params\n");
goto error;
}
@@ -1022,7 +1034,7 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
goto error;
}
INIT_LIST_HEAD(&entry->link);
- entry->cookie = IPA_COOKIE;
+ entry->cookie = IPA_RT_RULE_COOKIE;
entry->rule = *rule;
entry->tbl = tbl;
entry->hdr = hdr;
@@ -1115,7 +1127,7 @@ int __ipa_del_rt_rule(u32 rule_hdl)
return -EINVAL;
}
- if (entry->cookie != IPA_COOKIE) {
+ if (entry->cookie != IPA_RT_RULE_COOKIE) {
IPAERR("bad params\n");
return -EINVAL;
}
@@ -1350,7 +1362,7 @@ int ipa2_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup)
}
mutex_lock(&ipa_ctx->lock);
entry = __ipa_find_rt_tbl(lookup->ip, lookup->name);
- if (entry && entry->cookie == IPA_COOKIE) {
+ if (entry && entry->cookie == IPA_RT_TBL_COOKIE) {
entry->ref_cnt++;
lookup->hdl = entry->id;
@@ -1387,7 +1399,7 @@ int ipa2_put_rt_tbl(u32 rt_tbl_hdl)
goto ret;
}
- if ((entry->cookie != IPA_COOKIE) || entry->ref_cnt == 0) {
+ if ((entry->cookie != IPA_RT_TBL_COOKIE) || entry->ref_cnt == 0) {
IPAERR("bad parms\n");
result = -EINVAL;
goto ret;
@@ -1397,8 +1409,11 @@ int ipa2_put_rt_tbl(u32 rt_tbl_hdl)
ip = IPA_IP_v4;
else if (entry->set == &ipa_ctx->rt_tbl_set[IPA_IP_v6])
ip = IPA_IP_v6;
- else
+ else {
WARN_ON(1);
+ result = -EINVAL;
+ goto ret;
+ }
entry->ref_cnt--;
if (entry->ref_cnt == 0 && entry->rule_cnt == 0) {
@@ -1425,7 +1440,7 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule)
if (rtrule->rule.hdr_hdl) {
hdr = ipa_id_find(rtrule->rule.hdr_hdl);
- if ((hdr == NULL) || (hdr->cookie != IPA_COOKIE)) {
+ if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) {
IPAERR("rt rule does not point to valid hdr\n");
goto error;
}
@@ -1437,7 +1452,7 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule)
goto error;
}
- if (entry->cookie != IPA_COOKIE) {
+ if (entry->cookie != IPA_RT_RULE_COOKIE) {
IPAERR("bad params\n");
goto error;
}
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c
index 6f59ebd..d4116eb 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c
@@ -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
@@ -165,6 +165,17 @@ int ipa2_register_ipa_ready_cb(void (*ipa_ready_cb)(void *), void *user_data)
return -EEXIST;
}
+int ipa2_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv)
+{
+ return ipa2_register_ipa_ready_cb(ipauc_ready_cb, priv);
+}
+
+void ipa2_ntn_uc_dereg_rdyCB(void)
+{
+ ipa_ctx->uc_ntn_ctx.uc_ready_cb = NULL;
+ ipa_ctx->uc_ntn_ctx.priv = NULL;
+}
+
static void ipa_uc_ntn_loaded_handler(void)
{
if (!ipa_ctx) {
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index 4652fc8..b133f9c 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -5086,6 +5086,8 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type,
api_ctrl->ipa_tear_down_uc_offload_pipes =
ipa2_tear_down_uc_offload_pipes;
api_ctrl->ipa_get_pdev = ipa2_get_pdev;
+ api_ctrl->ipa_ntn_uc_reg_rdyCB = ipa2_ntn_uc_reg_rdyCB;
+ api_ctrl->ipa_ntn_uc_dereg_rdyCB = ipa2_ntn_uc_dereg_rdyCB;
return 0;
}
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
index 11eeb2f..0bdfea9 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
@@ -2856,6 +2856,10 @@ int rmnet_ipa_query_tethering_stats_modem(
kfree(req);
kfree(resp);
return rc;
+ } else if (data == NULL) {
+ kfree(req);
+ kfree(resp);
+ return 0;
}
if (resp->dl_dst_pipe_stats_list_valid) {
@@ -3037,8 +3041,11 @@ int rmnet_ipa_query_tethering_stats_all(
int rmnet_ipa_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data)
{
enum ipa_upstream_type upstream_type;
+ struct wan_ioctl_query_tether_stats tether_stats;
int rc = 0;
+ memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats));
+
/* get IPA backhaul type */
upstream_type = find_upstream_type(data->upstreamIface);
@@ -3056,7 +3063,7 @@ int rmnet_ipa_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data)
} else {
IPAWANDBG(" reset modem-backhaul stats\n");
rc = rmnet_ipa_query_tethering_stats_modem(
- NULL, true);
+ &tether_stats, true);
if (rc) {
IPAWANERR("reset MODEM stats failed\n");
return rc;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index a5fb576..4b056f6c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -235,6 +235,10 @@ static void ipa_gsi_notify_cb(struct gsi_per_notify *notify);
static void ipa3_post_init_wq(struct work_struct *work);
static DECLARE_WORK(ipa3_post_init_work, ipa3_post_init_wq);
+static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work);
+static DECLARE_WORK(ipa_dec_clients_disable_clks_on_wq_work,
+ ipa_dec_clients_disable_clks_on_wq);
+
static struct ipa3_plat_drv_res ipa3_res = {0, };
struct msm_bus_scale_pdata *ipa3_bus_scale_table;
@@ -314,7 +318,7 @@ int ipa3_active_clients_log_print_table(char *buf, int size)
}
cnt += scnprintf(buf + cnt, size - cnt,
"\nTotal active clients count: %d\n",
- ipa3_ctx->ipa3_active_clients.cnt);
+ atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
return cnt;
}
@@ -322,11 +326,11 @@ int ipa3_active_clients_log_print_table(char *buf, int size)
static int ipa3_active_clients_panic_notifier(struct notifier_block *this,
unsigned long event, void *ptr)
{
- ipa3_active_clients_lock();
+ mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
ipa3_active_clients_log_print_table(active_clients_table_buf,
IPA3_ACTIVE_CLIENTS_TABLE_BUF_SIZE);
IPAERR("%s", active_clients_table_buf);
- ipa3_active_clients_unlock();
+ mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
return NOTIFY_DONE;
}
@@ -395,11 +399,11 @@ static int ipa3_active_clients_log_init(void)
void ipa3_active_clients_log_clear(void)
{
- ipa3_active_clients_lock();
+ mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
ipa3_ctx->ipa3_active_clients_logging.log_head = 0;
ipa3_ctx->ipa3_active_clients_logging.log_tail =
IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1;
- ipa3_active_clients_unlock();
+ mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
}
static void ipa3_active_clients_log_destroy(void)
@@ -3267,7 +3271,6 @@ void _ipa_enable_clks_v3_0(void)
}
ipa3_uc_notify_clk_state(true);
- ipa3_suspend_apps_pipes(false);
}
static unsigned int ipa3_get_bus_vote(void)
@@ -3466,13 +3469,33 @@ void ipa3_active_clients_log_inc(struct ipa_active_client_logging_info *id,
*/
void ipa3_inc_client_enable_clks(struct ipa_active_client_logging_info *id)
{
- ipa3_active_clients_lock();
+ int ret;
+
ipa3_active_clients_log_inc(id, false);
- ipa3_ctx->ipa3_active_clients.cnt++;
- if (ipa3_ctx->ipa3_active_clients.cnt == 1)
- ipa3_enable_clks();
- IPADBG_LOW("active clients = %d\n", ipa3_ctx->ipa3_active_clients.cnt);
- ipa3_active_clients_unlock();
+ ret = atomic_inc_not_zero(&ipa3_ctx->ipa3_active_clients.cnt);
+ if (ret) {
+ IPADBG_LOW("active clients = %d\n",
+ atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
+ return;
+ }
+
+ mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
+
+ /* somebody might voted to clocks meanwhile */
+ ret = atomic_inc_not_zero(&ipa3_ctx->ipa3_active_clients.cnt);
+ if (ret) {
+ mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
+ IPADBG_LOW("active clients = %d\n",
+ atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
+ return;
+ }
+
+ ipa3_enable_clks();
+ atomic_inc(&ipa3_ctx->ipa3_active_clients.cnt);
+ IPADBG_LOW("active clients = %d\n",
+ atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
+ ipa3_suspend_apps_pipes(false);
+ mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
}
/**
@@ -3486,23 +3509,57 @@ void ipa3_inc_client_enable_clks(struct ipa_active_client_logging_info *id)
int ipa3_inc_client_enable_clks_no_block(struct ipa_active_client_logging_info
*id)
{
- int res = 0;
- unsigned long flags;
+ int ret;
- if (ipa3_active_clients_trylock(&flags) == 0)
- return -EPERM;
-
- if (ipa3_ctx->ipa3_active_clients.cnt == 0) {
- res = -EPERM;
- goto bail;
+ ret = atomic_inc_not_zero(&ipa3_ctx->ipa3_active_clients.cnt);
+ if (ret) {
+ ipa3_active_clients_log_inc(id, true);
+ IPADBG_LOW("active clients = %d\n",
+ atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
+ return 0;
}
- ipa3_active_clients_log_inc(id, true);
- ipa3_ctx->ipa3_active_clients.cnt++;
- IPADBG_LOW("active clients = %d\n", ipa3_ctx->ipa3_active_clients.cnt);
-bail:
- ipa3_active_clients_trylock_unlock(&flags);
- return res;
+ return -EPERM;
+}
+
+static void __ipa3_dec_client_disable_clks(void)
+{
+ int ret;
+
+ if (!atomic_read(&ipa3_ctx->ipa3_active_clients.cnt)) {
+ IPAERR("trying to disable clocks with refcnt is 0!\n");
+ ipa_assert();
+ return;
+ }
+
+ ret = atomic_add_unless(&ipa3_ctx->ipa3_active_clients.cnt, -1, 1);
+ if (ret)
+ goto bail;
+
+ /* seems like this is the only client holding the clocks */
+ mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
+ if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) == 1 &&
+ ipa3_ctx->tag_process_before_gating) {
+ ipa3_ctx->tag_process_before_gating = false;
+ /*
+ * When TAG process ends, active clients will be
+ * decreased
+ */
+ queue_work(ipa3_ctx->power_mgmt_wq, &ipa3_tag_work);
+ goto unlock_mutex;
+ }
+
+ /* a different context might increase the clock reference meanwhile */
+ ret = atomic_sub_return(1, &ipa3_ctx->ipa3_active_clients.cnt);
+ if (ret > 0)
+ goto unlock_mutex;
+ ipa3_disable_clks();
+
+unlock_mutex:
+ mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
+bail:
+ IPADBG_LOW("active clients = %d\n",
+ atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
}
/**
@@ -3518,29 +3575,39 @@ int ipa3_inc_client_enable_clks_no_block(struct ipa_active_client_logging_info
*/
void ipa3_dec_client_disable_clks(struct ipa_active_client_logging_info *id)
{
- struct ipa_active_client_logging_info log_info;
-
- ipa3_active_clients_lock();
ipa3_active_clients_log_dec(id, false);
- ipa3_ctx->ipa3_active_clients.cnt--;
- IPADBG_LOW("active clients = %d\n", ipa3_ctx->ipa3_active_clients.cnt);
- if (ipa3_ctx->ipa3_active_clients.cnt == 0) {
- if (ipa3_ctx->tag_process_before_gating) {
- ipa3_ctx->tag_process_before_gating = false;
- /*
- * When TAG process ends, active clients will be
- * decreased
- */
- IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info,
- "TAG_PROCESS");
- ipa3_active_clients_log_inc(&log_info, false);
- ipa3_ctx->ipa3_active_clients.cnt = 1;
- queue_work(ipa3_ctx->power_mgmt_wq, &ipa3_tag_work);
- } else {
- ipa3_disable_clks();
- }
+ __ipa3_dec_client_disable_clks();
+}
+
+static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work)
+{
+ __ipa3_dec_client_disable_clks();
+}
+
+/**
+ * ipa3_dec_client_disable_clks_no_block() - Decrease active clients counter
+ * if possible without blocking. If this is the last client then the desrease
+ * will happen from work queue context.
+ *
+ * Return codes:
+ * None
+ */
+void ipa3_dec_client_disable_clks_no_block(
+ struct ipa_active_client_logging_info *id)
+{
+ int ret;
+
+ ipa3_active_clients_log_dec(id, true);
+ ret = atomic_add_unless(&ipa3_ctx->ipa3_active_clients.cnt, -1, 1);
+ if (ret) {
+ IPADBG_LOW("active clients = %d\n",
+ atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
+ return;
}
- ipa3_active_clients_unlock();
+
+ /* seems like this is the only client holding the clocks */
+ queue_work(ipa3_ctx->power_mgmt_wq,
+ &ipa_dec_clients_disable_clks_on_wq_work);
}
/**
@@ -3636,34 +3703,20 @@ int ipa3_set_required_perf_profile(enum ipa_voltage_level floor_voltage,
return 0;
}
- ipa3_active_clients_lock();
+ /* Hold the mutex to avoid race conditions with ipa3_enable_clocks() */
+ mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
ipa3_ctx->curr_ipa_clk_rate = clk_rate;
IPADBG_LOW("setting clock rate to %u\n", ipa3_ctx->curr_ipa_clk_rate);
- if (ipa3_ctx->ipa3_active_clients.cnt > 0) {
- struct ipa_active_client_logging_info log_info;
-
- /*
- * clk_set_rate should be called with unlocked lock to allow
- * clients to get a reference to IPA clock synchronously.
- * Hold a reference to IPA clock here to make sure clock
- * state does not change during set_rate.
- */
- IPA_ACTIVE_CLIENTS_PREP_SIMPLE(log_info);
- ipa3_ctx->ipa3_active_clients.cnt++;
- ipa3_active_clients_log_inc(&log_info, false);
- ipa3_active_clients_unlock();
-
+ 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()))
+ ipa3_get_bus_vote()))
WARN_ON(1);
- /* remove the vote added here */
- IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
} else {
IPADBG_LOW("clocks are gated, not setting rate\n");
- ipa3_active_clients_unlock();
}
+ mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
IPADBG_LOW("Done\n");
return 0;
@@ -4625,10 +4678,9 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
}
mutex_init(&ipa3_ctx->ipa3_active_clients.mutex);
- spin_lock_init(&ipa3_ctx->ipa3_active_clients.spinlock);
IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "PROXY_CLK_VOTE");
ipa3_active_clients_log_inc(&log_info, false);
- ipa3_ctx->ipa3_active_clients.cnt = 1;
+ atomic_set(&ipa3_ctx->ipa3_active_clients.cnt, 1);
/* Create workqueues for power management */
ipa3_ctx->power_mgmt_wq =
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index 24c3d62..f172dc4 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -363,14 +363,14 @@ static ssize_t ipa3_read_keep_awake(struct file *file, char __user *ubuf,
{
int nbytes;
- ipa3_active_clients_lock();
- if (ipa3_ctx->ipa3_active_clients.cnt)
+ mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
+ if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt))
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"IPA APPS power state is ON\n");
else
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"IPA APPS power state is OFF\n");
- ipa3_active_clients_unlock();
+ mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
}
@@ -1064,7 +1064,7 @@ static ssize_t ipa3_read_stats(struct file *file, char __user *ubuf,
ipa3_ctx->stats.stat_compl,
ipa3_ctx->stats.aggr_close,
ipa3_ctx->stats.wan_aggr_close,
- ipa3_ctx->ipa3_active_clients.cnt,
+ atomic_read(&ipa3_ctx->ipa3_active_clients.cnt),
connect,
ipa3_ctx->stats.wan_rx_empty,
ipa3_ctx->stats.wan_repl_rx_empty,
@@ -1257,8 +1257,6 @@ static ssize_t ipa3_read_ntn(struct file *file, char __user *ubuf,
if (!ipa3_get_ntn_stats(&stats)) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"TX num_pkts_processed=%u\n"
- "TX tail_ptr_val=%u\n"
- "TX num_db_fired=%u\n"
"TX ringFull=%u\n"
"TX ringEmpty=%u\n"
"TX ringUsageHigh=%u\n"
@@ -1270,27 +1268,25 @@ static ssize_t ipa3_read_ntn(struct file *file, char __user *ubuf,
"TX bamFifoUsageLow=%u\n"
"TX bamUtilCount=%u\n"
"TX num_db=%u\n"
- "TX num_qmb_int_handled=%u\n",
+ "TX num_qmb_int_handled=%u\n"
+ "TX ipa_pipe_number=%u\n",
TX_STATS(num_pkts_processed),
- TX_STATS(tail_ptr_val),
- TX_STATS(num_db_fired),
- TX_STATS(tx_comp_ring_stats.ringFull),
- TX_STATS(tx_comp_ring_stats.ringEmpty),
- TX_STATS(tx_comp_ring_stats.ringUsageHigh),
- TX_STATS(tx_comp_ring_stats.ringUsageLow),
- TX_STATS(tx_comp_ring_stats.RingUtilCount),
- TX_STATS(bam_stats.bamFifoFull),
- TX_STATS(bam_stats.bamFifoEmpty),
- TX_STATS(bam_stats.bamFifoUsageHigh),
- TX_STATS(bam_stats.bamFifoUsageLow),
- TX_STATS(bam_stats.bamUtilCount),
+ TX_STATS(ring_stats.ringFull),
+ TX_STATS(ring_stats.ringEmpty),
+ TX_STATS(ring_stats.ringUsageHigh),
+ TX_STATS(ring_stats.ringUsageLow),
+ TX_STATS(ring_stats.RingUtilCount),
+ TX_STATS(gsi_stats.bamFifoFull),
+ TX_STATS(gsi_stats.bamFifoEmpty),
+ TX_STATS(gsi_stats.bamFifoUsageHigh),
+ TX_STATS(gsi_stats.bamFifoUsageLow),
+ TX_STATS(gsi_stats.bamUtilCount),
TX_STATS(num_db),
- TX_STATS(num_qmb_int_handled));
+ TX_STATS(num_qmb_int_handled),
+ TX_STATS(ipa_pipe_number));
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
- "RX max_outstanding_pkts=%u\n"
"RX num_pkts_processed=%u\n"
- "RX rx_ring_rp_value=%u\n"
"RX ringFull=%u\n"
"RX ringEmpty=%u\n"
"RX ringUsageHigh=%u\n"
@@ -1301,21 +1297,23 @@ static ssize_t ipa3_read_ntn(struct file *file, char __user *ubuf,
"RX bamFifoUsageHigh=%u\n"
"RX bamFifoUsageLow=%u\n"
"RX bamUtilCount=%u\n"
- "RX num_db=%u\n",
- RX_STATS(max_outstanding_pkts),
+ "RX num_db=%u\n"
+ "RX num_qmb_int_handled=%u\n"
+ "RX ipa_pipe_number=%u\n",
RX_STATS(num_pkts_processed),
- RX_STATS(rx_ring_rp_value),
- RX_STATS(rx_ind_ring_stats.ringFull),
- RX_STATS(rx_ind_ring_stats.ringEmpty),
- RX_STATS(rx_ind_ring_stats.ringUsageHigh),
- RX_STATS(rx_ind_ring_stats.ringUsageLow),
- RX_STATS(rx_ind_ring_stats.RingUtilCount),
- RX_STATS(bam_stats.bamFifoFull),
- RX_STATS(bam_stats.bamFifoEmpty),
- RX_STATS(bam_stats.bamFifoUsageHigh),
- RX_STATS(bam_stats.bamFifoUsageLow),
- RX_STATS(bam_stats.bamUtilCount),
- RX_STATS(num_db));
+ RX_STATS(ring_stats.ringFull),
+ RX_STATS(ring_stats.ringEmpty),
+ RX_STATS(ring_stats.ringUsageHigh),
+ RX_STATS(ring_stats.ringUsageLow),
+ RX_STATS(ring_stats.RingUtilCount),
+ RX_STATS(gsi_stats.bamFifoFull),
+ RX_STATS(gsi_stats.bamFifoEmpty),
+ RX_STATS(gsi_stats.bamFifoUsageHigh),
+ RX_STATS(gsi_stats.bamFifoUsageLow),
+ RX_STATS(gsi_stats.bamUtilCount),
+ RX_STATS(num_db),
+ RX_STATS(num_qmb_int_handled),
+ RX_STATS(ipa_pipe_number));
cnt += nbytes;
} else {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
@@ -1785,12 +1783,12 @@ static ssize_t ipa3_print_active_clients_log(struct file *file,
return 0;
}
memset(active_clients_buf, 0, IPA_DBG_ACTIVE_CLIENT_BUF_SIZE);
- ipa3_active_clients_lock();
+ mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
cnt = ipa3_active_clients_log_print_buffer(active_clients_buf,
IPA_DBG_ACTIVE_CLIENT_BUF_SIZE - IPA_MAX_MSG_LEN);
table_size = ipa3_active_clients_log_print_table(active_clients_buf
+ cnt, IPA_MAX_MSG_LEN);
- ipa3_active_clients_unlock();
+ mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
return simple_read_from_buffer(ubuf, count, ppos,
active_clients_buf, cnt + table_size);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 4fb4da8..018467a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -759,6 +759,15 @@ static void ipa3_handle_rx(struct ipa3_sys_context *sys)
trace_idle_sleep_enter3(sys->ep->client);
usleep_range(POLLING_MIN_SLEEP_RX, POLLING_MAX_SLEEP_RX);
trace_idle_sleep_exit3(sys->ep->client);
+
+ /*
+ * if pipe is out of buffers there is no point polling for
+ * completed descs; release the worker so delayed work can
+ * run in a timely manner
+ */
+ if (sys->len - sys->len_pending_xfer == 0)
+ break;
+
} while (inactive_cycles <= POLLING_INACTIVITY_RX);
trace_poll_to_intr3(sys->ep->client);
@@ -775,8 +784,8 @@ static void ipa3_switch_to_intr_rx_work_func(struct work_struct *work)
sys = container_of(dwork, struct ipa3_sys_context, switch_to_intr_work);
if (sys->ep->napi_enabled) {
- ipa3_rx_switch_to_intr_mode(sys);
- IPA_ACTIVE_CLIENTS_DEC_SPECIAL("NAPI");
+ /* interrupt mode is done in ipa3_rx_poll context */
+ ipa_assert();
} else
ipa3_handle_rx(sys);
}
@@ -1549,6 +1558,8 @@ static void ipa3_cleanup_wlan_rx_common_cache(void)
struct ipa3_rx_pkt_wrapper *rx_pkt;
struct ipa3_rx_pkt_wrapper *tmp;
+ spin_lock_bh(&ipa3_ctx->wc_memb.wlan_spinlock);
+
list_for_each_entry_safe(rx_pkt, tmp,
&ipa3_ctx->wc_memb.wlan_comm_desc_list, link) {
list_del(&rx_pkt->link);
@@ -1569,6 +1580,8 @@ static void ipa3_cleanup_wlan_rx_common_cache(void)
IPAERR("wlan comm buff total cnt: %d\n",
ipa3_ctx->wc_memb.wlan_comm_total_cnt);
+ spin_unlock_bh(&ipa3_ctx->wc_memb.wlan_spinlock);
+
}
static void ipa3_alloc_wlan_rx_common_cache(u32 size)
@@ -1606,11 +1619,13 @@ static void ipa3_alloc_wlan_rx_common_cache(u32 size)
goto fail_dma_mapping;
}
+ spin_lock_bh(&ipa3_ctx->wc_memb.wlan_spinlock);
list_add_tail(&rx_pkt->link,
&ipa3_ctx->wc_memb.wlan_comm_desc_list);
rx_len_cached = ++ipa3_ctx->wc_memb.wlan_comm_total_cnt;
ipa3_ctx->wc_memb.wlan_comm_free_cnt++;
+ spin_unlock_bh(&ipa3_ctx->wc_memb.wlan_spinlock);
}
@@ -3255,6 +3270,7 @@ 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");
@@ -3286,7 +3302,20 @@ static void ipa_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify)
GSI_CHAN_MODE_POLL);
ipa3_inc_acquire_wakelock();
atomic_set(&sys->curr_polling_state, 1);
- queue_work(sys->wq, &sys->work);
+ 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);
+ }
}
break;
default:
@@ -3654,6 +3683,9 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight)
int cnt = 0;
struct ipa_mem_buffer mem_info = {0};
static int total_cnt;
+ struct ipa_active_client_logging_info log;
+
+ IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log, "NAPI");
if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
ipa3_ctx->ep[clnt_hdl].valid == 0) {
@@ -3666,6 +3698,7 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight)
while (cnt < weight &&
atomic_read(&ep->sys->curr_polling_state)) {
+ atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
ret = ipa_poll_gsi_pkt(ep->sys, &mem_info);
if (ret)
break;
@@ -3683,7 +3716,8 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight)
if (cnt < weight) {
ep->client_notify(ep->priv, IPA_CLIENT_COMP_NAPI, 0);
- queue_work(ep->sys->wq, &ep->sys->switch_to_intr_work.work);
+ ipa3_rx_switch_to_intr_mode(ep->sys);
+ ipa3_dec_client_disable_clks_no_block(&log);
}
return cnt;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
index bfcaa2b..b1e50ac 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
@@ -741,7 +741,7 @@ static int __ipa_validate_flt_rule(const struct ipa_flt_rule *rule,
goto error;
}
- if ((*rt_tbl)->cookie != IPA_COOKIE) {
+ if ((*rt_tbl)->cookie != IPA_RT_TBL_COOKIE) {
IPAERR("RT table cookie is invalid\n");
goto error;
}
@@ -800,7 +800,7 @@ static int __ipa_create_flt_entry(struct ipa3_flt_entry **entry,
}
INIT_LIST_HEAD(&((*entry)->link));
(*entry)->rule = *rule;
- (*entry)->cookie = IPA_COOKIE;
+ (*entry)->cookie = IPA_FLT_COOKIE;
(*entry)->rt_tbl = rt_tbl;
(*entry)->tbl = tbl;
if (rule->rule_id) {
@@ -835,12 +835,18 @@ static int __ipa_finish_flt_rule_add(struct ipa3_flt_tbl *tbl,
if (id < 0) {
IPAERR("failed to add to tree\n");
WARN_ON(1);
+ goto ipa_insert_failed;
}
*rule_hdl = id;
entry->id = id;
IPADBG_LOW("add flt rule rule_cnt=%d\n", tbl->rule_cnt);
return 0;
+ipa_insert_failed:
+ if (entry->rt_tbl)
+ entry->rt_tbl->ref_cnt--;
+ tbl->rule_cnt--;
+ return -EPERM;
}
static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip,
@@ -866,9 +872,16 @@ static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip,
list_add(&entry->link, &tbl->head_flt_rule_list);
}
- __ipa_finish_flt_rule_add(tbl, entry, rule_hdl);
+ if (__ipa_finish_flt_rule_add(tbl, entry, rule_hdl))
+ goto ipa_insert_failed;
return 0;
+ipa_insert_failed:
+ list_del(&entry->link);
+ /* if rule id was allocated from idr, remove it */
+ if (!(entry->rule_id & ipahal_get_rule_id_hi_bit()))
+ idr_remove(&entry->tbl->rule_ids, entry->rule_id);
+ kmem_cache_free(ipa3_ctx->flt_rule_cache, entry);
error:
return -EPERM;
@@ -900,7 +913,8 @@ static int __ipa_add_flt_rule_after(struct ipa3_flt_tbl *tbl,
list_add(&entry->link, &((*add_after_entry)->link));
- __ipa_finish_flt_rule_add(tbl, entry, rule_hdl);
+ if (__ipa_finish_flt_rule_add(tbl, entry, rule_hdl))
+ goto ipa_insert_failed;
/*
* prepare for next insertion
@@ -909,6 +923,13 @@ static int __ipa_add_flt_rule_after(struct ipa3_flt_tbl *tbl,
return 0;
+ipa_insert_failed:
+ list_del(&entry->link);
+ /* if rule id was allocated from idr, remove it */
+ if (!(entry->rule_id & ipahal_get_rule_id_hi_bit()))
+ idr_remove(&entry->tbl->rule_ids, entry->rule_id);
+ kmem_cache_free(ipa3_ctx->flt_rule_cache, entry);
+
error:
*add_after_entry = NULL;
return -EPERM;
@@ -925,7 +946,7 @@ static int __ipa_del_flt_rule(u32 rule_hdl)
return -EINVAL;
}
- if (entry->cookie != IPA_COOKIE) {
+ if (entry->cookie != IPA_FLT_COOKIE) {
IPAERR("bad params\n");
return -EINVAL;
}
@@ -962,7 +983,7 @@ static int __ipa_mdfy_flt_rule(struct ipa_flt_rule_mdfy *frule,
goto error;
}
- if (entry->cookie != IPA_COOKIE) {
+ if (entry->cookie != IPA_FLT_COOKIE) {
IPAERR("bad params\n");
goto error;
}
@@ -983,7 +1004,7 @@ static int __ipa_mdfy_flt_rule(struct ipa_flt_rule_mdfy *frule,
goto error;
}
- if (rt_tbl->cookie != IPA_COOKIE) {
+ if (rt_tbl->cookie != IPA_RT_TBL_COOKIE) {
IPAERR("RT table cookie is invalid\n");
goto error;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
index 14d776e..0c1832c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
@@ -336,7 +336,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
IPAERR("hdr_hdl is invalid\n");
return -EINVAL;
}
- if (hdr_entry->cookie != IPA_COOKIE) {
+ if (hdr_entry->cookie != IPA_HDR_COOKIE) {
IPAERR("Invalid header cookie %u\n", hdr_entry->cookie);
WARN_ON(1);
return -EINVAL;
@@ -357,7 +357,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
entry->l2tp_params = proc_ctx->l2tp_params;
if (add_ref_hdr)
hdr_entry->ref_cnt++;
- entry->cookie = IPA_COOKIE;
+ entry->cookie = IPA_PROC_HDR_COOKIE;
needed_len = ipahal_get_proc_ctx_needed_len(proc_ctx->type);
@@ -415,6 +415,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
if (id < 0) {
IPAERR("failed to alloc id\n");
WARN_ON(1);
+ goto ipa_insert_failed;
}
entry->id = id;
proc_ctx->proc_ctx_hdl = id;
@@ -422,6 +423,14 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
return 0;
+ipa_insert_failed:
+ if (offset)
+ list_move(&offset->link,
+ &htbl->head_free_offset_list[offset->bin]);
+ entry->offset_entry = NULL;
+ list_del(&entry->link);
+ htbl->proc_ctx_cnt--;
+
bad_len:
if (add_ref_hdr)
hdr_entry->ref_cnt--;
@@ -434,7 +443,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
{
struct ipa3_hdr_entry *entry;
- struct ipa_hdr_offset_entry *offset;
+ struct ipa_hdr_offset_entry *offset = NULL;
u32 bin;
struct ipa3_hdr_tbl *htbl = &ipa3_ctx->hdr_tbl;
int id;
@@ -465,7 +474,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
entry->type = hdr->type;
entry->is_eth2_ofst_valid = hdr->is_eth2_ofst_valid;
entry->eth2_ofst = hdr->eth2_ofst;
- entry->cookie = IPA_COOKIE;
+ entry->cookie = IPA_HDR_COOKIE;
if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN0])
bin = IPA_HDR_BIN0;
@@ -544,6 +553,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
if (id < 0) {
IPAERR("failed to alloc id\n");
WARN_ON(1);
+ goto ipa_insert_failed;
}
entry->id = id;
hdr->hdr_hdl = id;
@@ -568,10 +578,19 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
entry->ref_cnt--;
hdr->hdr_hdl = 0;
ipa3_id_remove(id);
+ipa_insert_failed:
+ if (entry->is_hdr_proc_ctx) {
+ dma_unmap_single(ipa3_ctx->pdev, entry->phys_base,
+ entry->hdr_len, DMA_TO_DEVICE);
+ } else {
+ if (offset)
+ list_move(&offset->link,
+ &htbl->head_free_offset_list[offset->bin]);
+ entry->offset_entry = NULL;
+ }
htbl->hdr_cnt--;
list_del(&entry->link);
- dma_unmap_single(ipa3_ctx->pdev, entry->phys_base,
- entry->hdr_len, DMA_TO_DEVICE);
+
fail_dma_mapping:
entry->is_hdr_proc_ctx = false;
@@ -589,7 +608,7 @@ static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl,
struct ipa3_hdr_proc_ctx_tbl *htbl = &ipa3_ctx->hdr_proc_ctx_tbl;
entry = ipa3_id_find(proc_ctx_hdl);
- if (!entry || (entry->cookie != IPA_COOKIE)) {
+ if (!entry || (entry->cookie != IPA_PROC_HDR_COOKIE)) {
IPAERR("bad parm\n");
return -EINVAL;
}
@@ -640,7 +659,7 @@ int __ipa3_del_hdr(u32 hdr_hdl, bool by_user)
return -EINVAL;
}
- if (entry->cookie != IPA_COOKIE) {
+ if (entry->cookie != IPA_HDR_COOKIE) {
IPAERR("bad parm\n");
return -EINVAL;
}
@@ -1186,7 +1205,7 @@ int ipa3_put_hdr(u32 hdr_hdl)
goto bail;
}
- if (entry->cookie != IPA_COOKIE) {
+ if (entry->cookie != IPA_HDR_COOKIE) {
IPAERR("invalid header entry\n");
result = -EINVAL;
goto bail;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index fcb7c72..1bed1c8 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -39,6 +39,12 @@
#define DRV_NAME "ipa"
#define NAT_DEV_NAME "ipaNatTable"
#define IPA_COOKIE 0x57831603
+#define IPA_RT_RULE_COOKIE 0x57831604
+#define IPA_RT_TBL_COOKIE 0x57831605
+#define IPA_FLT_COOKIE 0x57831606
+#define IPA_HDR_COOKIE 0x57831607
+#define IPA_PROC_HDR_COOKIE 0x57831608
+
#define MTU_BYTE 1500
#define IPA_EP_NOT_ALLOCATED (-1)
@@ -207,8 +213,8 @@ struct ipa_smmu_cb_ctx {
*/
struct ipa3_flt_entry {
struct list_head link;
- struct ipa_flt_rule rule;
u32 cookie;
+ struct ipa_flt_rule rule;
struct ipa3_flt_tbl *tbl;
struct ipa3_rt_tbl *rt_tbl;
u32 hw_len;
@@ -236,13 +242,13 @@ struct ipa3_flt_entry {
*/
struct ipa3_rt_tbl {
struct list_head link;
+ u32 cookie;
struct list_head head_rt_rule_list;
char name[IPA_RESOURCE_NAME_MAX];
u32 idx;
u32 rule_cnt;
u32 ref_cnt;
struct ipa3_rt_tbl_set *set;
- u32 cookie;
bool in_sys[IPA_RULE_TYPE_MAX];
u32 sz[IPA_RULE_TYPE_MAX];
struct ipa_mem_buffer curr_mem[IPA_RULE_TYPE_MAX];
@@ -274,6 +280,7 @@ struct ipa3_rt_tbl {
*/
struct ipa3_hdr_entry {
struct list_head link;
+ u32 cookie;
u8 hdr[IPA_HDR_MAX_SIZE];
u32 hdr_len;
char name[IPA_RESOURCE_NAME_MAX];
@@ -283,7 +290,6 @@ struct ipa3_hdr_entry {
dma_addr_t phys_base;
struct ipa3_hdr_proc_ctx_entry *proc_ctx;
struct ipa_hdr_offset_entry *offset_entry;
- u32 cookie;
u32 ref_cnt;
int id;
u8 is_eth2_ofst_valid;
@@ -333,11 +339,11 @@ struct ipa3_hdr_proc_ctx_offset_entry {
*/
struct ipa3_hdr_proc_ctx_entry {
struct list_head link;
+ u32 cookie;
enum ipa_hdr_proc_type type;
union ipa_l2tp_hdr_proc_ctx_params l2tp_params;
struct ipa3_hdr_proc_ctx_offset_entry *offset_entry;
struct ipa3_hdr_entry *hdr;
- u32 cookie;
u32 ref_cnt;
int id;
bool user_deleted;
@@ -399,8 +405,8 @@ struct ipa3_flt_tbl {
*/
struct ipa3_rt_entry {
struct list_head link;
- struct ipa_rt_rule rule;
u32 cookie;
+ struct ipa_rt_rule rule;
struct ipa3_rt_tbl *tbl;
struct ipa3_hdr_entry *hdr;
struct ipa3_hdr_proc_ctx_entry *proc_ctx;
@@ -844,9 +850,7 @@ struct ipa3_stats {
struct ipa3_active_clients {
struct mutex mutex;
- spinlock_t spinlock;
- bool mutex_locked;
- int cnt;
+ atomic_t cnt;
};
struct ipa3_wakelock_ref_cnt {
@@ -1675,6 +1679,8 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in,
ipa_notify_cb notify, void *priv, u8 hdr_len,
struct ipa_ntn_conn_out_params *outp);
int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl);
+int ipa3_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv);
+void ipa3_ntn_uc_dereg_rdyCB(void);
/*
* To retrieve doorbell physical address of
@@ -1845,6 +1851,8 @@ void ipa3_inc_client_enable_clks(struct ipa_active_client_logging_info *id);
int ipa3_inc_client_enable_clks_no_block(struct ipa_active_client_logging_info
*id);
void ipa3_dec_client_disable_clks(struct ipa_active_client_logging_info *id);
+void ipa3_dec_client_disable_clks_no_block(
+ struct ipa_active_client_logging_info *id);
void ipa3_active_clients_log_dec(struct ipa_active_client_logging_info *id,
bool int_ctx);
void ipa3_active_clients_log_inc(struct ipa_active_client_logging_info *id,
@@ -1921,10 +1929,7 @@ int ipa3_resume_resource(enum ipa_rm_resource_name name);
bool ipa3_should_pipe_be_suspended(enum ipa_client_type client);
int ipa3_tag_aggr_force_close(int pipe_num);
-void ipa3_active_clients_lock(void);
-int ipa3_active_clients_trylock(unsigned long *flags);
void ipa3_active_clients_unlock(void);
-void ipa3_active_clients_trylock_unlock(unsigned long *flags);
int ipa3_wdi_init(void);
int ipa3_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id);
int ipa3_tag_process(struct ipa3_desc *desc, int num_descs,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c b/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c
index e7f8acd..6d82da2 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c
@@ -322,27 +322,21 @@ static void ipa3_interrupt_defer(struct work_struct *work)
static irqreturn_t ipa3_isr(int irq, void *ctxt)
{
- unsigned long flags;
+ struct ipa_active_client_logging_info log_info;
+ IPA_ACTIVE_CLIENTS_PREP_SIMPLE(log_info);
IPADBG_LOW("Enter\n");
/* defer interrupt handling in case IPA is not clocked on */
- if (ipa3_active_clients_trylock(&flags) == 0) {
+ if (ipa3_inc_client_enable_clks_no_block(&log_info)) {
IPADBG("defer interrupt processing\n");
queue_work(ipa3_ctx->power_mgmt_wq, &ipa3_interrupt_defer_work);
return IRQ_HANDLED;
}
- if (ipa3_ctx->ipa3_active_clients.cnt == 0) {
- IPADBG("defer interrupt processing\n");
- queue_work(ipa3_ctx->power_mgmt_wq, &ipa3_interrupt_defer_work);
- goto bail;
- }
-
ipa3_process_interrupts(true);
IPADBG_LOW("Exit\n");
-bail:
- ipa3_active_clients_trylock_unlock(&flags);
+ ipa3_dec_client_disable_clks(&log_info);
return IRQ_HANDLED;
}
/**
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c
index fe6d245..38e8d4e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c
@@ -275,6 +275,14 @@ int ipa3_query_intf_tx_props(struct ipa_ioc_query_intf_tx_props *tx)
mutex_lock(&ipa3_ctx->lock);
list_for_each_entry(entry, &ipa3_ctx->intf_list, link) {
if (!strcmp(entry->name, tx->name)) {
+ /* add the entry check */
+ if (entry->num_tx_props != tx->num_tx_props) {
+ IPAERR("invalid entry number(%u %u)\n",
+ entry->num_tx_props,
+ tx->num_tx_props);
+ mutex_unlock(&ipa3_ctx->lock);
+ return result;
+ }
memcpy(tx->tx, entry->tx, entry->num_tx_props *
sizeof(struct ipa_ioc_tx_intf_prop));
result = 0;
@@ -314,6 +322,14 @@ int ipa3_query_intf_rx_props(struct ipa_ioc_query_intf_rx_props *rx)
mutex_lock(&ipa3_ctx->lock);
list_for_each_entry(entry, &ipa3_ctx->intf_list, link) {
if (!strcmp(entry->name, rx->name)) {
+ /* add the entry check */
+ if (entry->num_rx_props != rx->num_rx_props) {
+ IPAERR("invalid entry number(%u %u)\n",
+ entry->num_rx_props,
+ rx->num_rx_props);
+ mutex_unlock(&ipa3_ctx->lock);
+ return result;
+ }
memcpy(rx->rx, entry->rx, entry->num_rx_props *
sizeof(struct ipa_ioc_rx_intf_prop));
result = 0;
@@ -348,6 +364,14 @@ int ipa3_query_intf_ext_props(struct ipa_ioc_query_intf_ext_props *ext)
mutex_lock(&ipa3_ctx->lock);
list_for_each_entry(entry, &ipa3_ctx->intf_list, link) {
if (!strcmp(entry->name, ext->name)) {
+ /* add the entry check */
+ if (entry->num_ext_props != ext->num_ext_props) {
+ IPAERR("invalid entry number(%u %u)\n",
+ entry->num_ext_props,
+ ext->num_ext_props);
+ mutex_unlock(&ipa3_ctx->lock);
+ return result;
+ }
memcpy(ext->ext, entry->ext, entry->num_ext_props *
sizeof(struct ipa_ioc_ext_intf_prop));
result = 0;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index cf28986..234b945 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -724,12 +724,15 @@ int ipa3_query_rt_index(struct ipa_ioc_get_rt_tbl_indx *in)
return -EINVAL;
}
+ mutex_lock(&ipa3_ctx->lock);
/* check if this table exists */
entry = __ipa3_find_rt_tbl(in->ip, in->name);
- if (!entry)
+ if (!entry) {
+ mutex_unlock(&ipa3_ctx->lock);
return -EFAULT;
-
+ }
in->idx = entry->idx;
+ mutex_unlock(&ipa3_ctx->lock);
return 0;
}
@@ -790,7 +793,7 @@ static struct ipa3_rt_tbl *__ipa_add_rt_tbl(enum ipa_ip_type ip,
INIT_LIST_HEAD(&entry->link);
strlcpy(entry->name, name, IPA_RESOURCE_NAME_MAX);
entry->set = set;
- entry->cookie = IPA_COOKIE;
+ entry->cookie = IPA_RT_TBL_COOKIE;
entry->in_sys[IPA_RULE_HASHABLE] = (ip == IPA_IP_v4) ?
!ipa3_ctx->ip4_rt_tbl_hash_lcl :
!ipa3_ctx->ip6_rt_tbl_hash_lcl;
@@ -808,12 +811,16 @@ static struct ipa3_rt_tbl *__ipa_add_rt_tbl(enum ipa_ip_type ip,
if (id < 0) {
IPAERR("failed to add to tree\n");
WARN_ON(1);
+ goto ipa_insert_failed;
}
entry->id = id;
}
return entry;
-
+ipa_insert_failed:
+ set->tbl_cnt--;
+ list_del(&entry->link);
+ idr_destroy(&entry->rule_ids);
fail_rt_idx_alloc:
entry->cookie = 0;
kmem_cache_free(ipa3_ctx->rt_tbl_cache, entry);
@@ -827,7 +834,7 @@ static int __ipa_del_rt_tbl(struct ipa3_rt_tbl *entry)
u32 id;
struct ipa3_rt_tbl_set *rset;
- if (entry == NULL || (entry->cookie != IPA_COOKIE)) {
+ if (entry == NULL || (entry->cookie != IPA_RT_TBL_COOKIE)) {
IPAERR("bad parms\n");
return -EINVAL;
}
@@ -841,8 +848,10 @@ static int __ipa_del_rt_tbl(struct ipa3_rt_tbl *entry)
ip = IPA_IP_v4;
else if (entry->set == &ipa3_ctx->rt_tbl_set[IPA_IP_v6])
ip = IPA_IP_v6;
- else
+ else {
WARN_ON(1);
+ return -EPERM;
+ }
rset = &ipa3_ctx->reap_rt_tbl_set[ip];
@@ -879,14 +888,14 @@ static int __ipa_rt_validate_hndls(const struct ipa_rt_rule *rule,
if (rule->hdr_hdl) {
*hdr = ipa3_id_find(rule->hdr_hdl);
- if ((*hdr == NULL) || ((*hdr)->cookie != IPA_COOKIE)) {
+ if ((*hdr == NULL) || ((*hdr)->cookie != IPA_HDR_COOKIE)) {
IPAERR("rt rule does not point to valid hdr\n");
return -EPERM;
}
} else if (rule->hdr_proc_ctx_hdl) {
*proc_ctx = ipa3_id_find(rule->hdr_proc_ctx_hdl);
if ((*proc_ctx == NULL) ||
- ((*proc_ctx)->cookie != IPA_COOKIE)) {
+ ((*proc_ctx)->cookie != IPA_PROC_HDR_COOKIE)) {
IPAERR("rt rule does not point to valid proc ctx\n");
return -EPERM;
@@ -909,7 +918,7 @@ static int __ipa_create_rt_entry(struct ipa3_rt_entry **entry,
goto error;
}
INIT_LIST_HEAD(&(*entry)->link);
- (*(entry))->cookie = IPA_COOKIE;
+ (*(entry))->cookie = IPA_RT_RULE_COOKIE;
(*(entry))->rule = *rule;
(*(entry))->tbl = tbl;
(*(entry))->hdr = hdr;
@@ -977,7 +986,7 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
tbl = __ipa_add_rt_tbl(ip, name);
- if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) {
+ if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) {
IPAERR("failed adding rt tbl name = %s\n",
name ? name : "");
goto error;
@@ -1112,7 +1121,7 @@ int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules)
mutex_lock(&ipa3_ctx->lock);
tbl = __ipa3_find_rt_tbl(rules->ip, rules->rt_tbl_name);
- if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) {
+ if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) {
IPAERR("failed finding rt tbl name = %s\n",
rules->rt_tbl_name ? rules->rt_tbl_name : "");
ret = -EINVAL;
@@ -1196,7 +1205,7 @@ int __ipa3_del_rt_rule(u32 rule_hdl)
return -EINVAL;
}
- if (entry->cookie != IPA_COOKIE) {
+ if (entry->cookie != IPA_RT_RULE_COOKIE) {
IPAERR("bad params\n");
return -EINVAL;
}
@@ -1434,7 +1443,7 @@ int ipa3_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup)
}
mutex_lock(&ipa3_ctx->lock);
entry = __ipa3_find_rt_tbl(lookup->ip, lookup->name);
- if (entry && entry->cookie == IPA_COOKIE) {
+ if (entry && entry->cookie == IPA_RT_TBL_COOKIE) {
entry->ref_cnt++;
lookup->hdl = entry->id;
@@ -1471,7 +1480,7 @@ int ipa3_put_rt_tbl(u32 rt_tbl_hdl)
goto ret;
}
- if ((entry->cookie != IPA_COOKIE) || entry->ref_cnt == 0) {
+ if ((entry->cookie != IPA_RT_TBL_COOKIE) || entry->ref_cnt == 0) {
IPAERR("bad parms\n");
result = -EINVAL;
goto ret;
@@ -1481,8 +1490,11 @@ int ipa3_put_rt_tbl(u32 rt_tbl_hdl)
ip = IPA_IP_v4;
else if (entry->set == &ipa3_ctx->rt_tbl_set[IPA_IP_v6])
ip = IPA_IP_v6;
- else
+ else {
WARN_ON(1);
+ result = -EINVAL;
+ goto ret;
+ }
entry->ref_cnt--;
if (entry->ref_cnt == 0 && entry->rule_cnt == 0) {
@@ -1512,13 +1524,14 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule)
if (rtrule->rule.hdr_hdl) {
hdr = ipa3_id_find(rtrule->rule.hdr_hdl);
- if ((hdr == NULL) || (hdr->cookie != IPA_COOKIE)) {
+ if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) {
IPAERR("rt rule does not point to valid hdr\n");
goto error;
}
} else if (rtrule->rule.hdr_proc_ctx_hdl) {
proc_ctx = ipa3_id_find(rtrule->rule.hdr_proc_ctx_hdl);
- if ((proc_ctx == NULL) || (proc_ctx->cookie != IPA_COOKIE)) {
+ if ((proc_ctx == NULL) ||
+ (proc_ctx->cookie != IPA_PROC_HDR_COOKIE)) {
IPAERR("rt rule does not point to valid proc ctx\n");
goto error;
}
@@ -1530,7 +1543,7 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule)
goto error;
}
- if (entry->cookie != IPA_COOKIE) {
+ if (entry->cookie != IPA_RT_RULE_COOKIE) {
IPAERR("bad params\n");
goto error;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c
index ce47623..b6427d0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c
@@ -104,41 +104,83 @@ int ipa3_get_ntn_stats(struct Ipa3HwStatsNTNInfoData_t *stats)
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
TX_STATS(num_pkts_processed);
- TX_STATS(tail_ptr_val);
- TX_STATS(num_db_fired);
- TX_STATS(tx_comp_ring_stats.ringFull);
- TX_STATS(tx_comp_ring_stats.ringEmpty);
- TX_STATS(tx_comp_ring_stats.ringUsageHigh);
- TX_STATS(tx_comp_ring_stats.ringUsageLow);
- TX_STATS(tx_comp_ring_stats.RingUtilCount);
- TX_STATS(bam_stats.bamFifoFull);
- TX_STATS(bam_stats.bamFifoEmpty);
- TX_STATS(bam_stats.bamFifoUsageHigh);
- TX_STATS(bam_stats.bamFifoUsageLow);
- TX_STATS(bam_stats.bamUtilCount);
+ TX_STATS(ring_stats.ringFull);
+ TX_STATS(ring_stats.ringEmpty);
+ TX_STATS(ring_stats.ringUsageHigh);
+ TX_STATS(ring_stats.ringUsageLow);
+ TX_STATS(ring_stats.RingUtilCount);
+ TX_STATS(gsi_stats.bamFifoFull);
+ TX_STATS(gsi_stats.bamFifoEmpty);
+ TX_STATS(gsi_stats.bamFifoUsageHigh);
+ TX_STATS(gsi_stats.bamFifoUsageLow);
+ TX_STATS(gsi_stats.bamUtilCount);
TX_STATS(num_db);
TX_STATS(num_qmb_int_handled);
+ TX_STATS(ipa_pipe_number);
- RX_STATS(max_outstanding_pkts);
RX_STATS(num_pkts_processed);
- RX_STATS(rx_ring_rp_value);
- RX_STATS(rx_ind_ring_stats.ringFull);
- RX_STATS(rx_ind_ring_stats.ringEmpty);
- RX_STATS(rx_ind_ring_stats.ringUsageHigh);
- RX_STATS(rx_ind_ring_stats.ringUsageLow);
- RX_STATS(rx_ind_ring_stats.RingUtilCount);
- RX_STATS(bam_stats.bamFifoFull);
- RX_STATS(bam_stats.bamFifoEmpty);
- RX_STATS(bam_stats.bamFifoUsageHigh);
- RX_STATS(bam_stats.bamFifoUsageLow);
- RX_STATS(bam_stats.bamUtilCount);
+ RX_STATS(ring_stats.ringFull);
+ RX_STATS(ring_stats.ringEmpty);
+ RX_STATS(ring_stats.ringUsageHigh);
+ RX_STATS(ring_stats.ringUsageLow);
+ RX_STATS(ring_stats.RingUtilCount);
+ RX_STATS(gsi_stats.bamFifoFull);
+ RX_STATS(gsi_stats.bamFifoEmpty);
+ RX_STATS(gsi_stats.bamFifoUsageHigh);
+ RX_STATS(gsi_stats.bamFifoUsageLow);
+ RX_STATS(gsi_stats.bamUtilCount);
RX_STATS(num_db);
+ RX_STATS(num_qmb_int_handled);
+ RX_STATS(ipa_pipe_number);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return 0;
}
+
+int ipa3_ntn_uc_reg_rdyCB(void (*ipa_ready_cb)(void *), void *user_data)
+{
+ int ret;
+
+ if (!ipa3_ctx) {
+ IPAERR("IPA ctx is null\n");
+ return -ENXIO;
+ }
+
+ ret = ipa3_uc_state_check();
+ if (ret) {
+ ipa3_ctx->uc_ntn_ctx.uc_ready_cb = ipa_ready_cb;
+ ipa3_ctx->uc_ntn_ctx.priv = user_data;
+ return 0;
+ }
+
+ return -EEXIST;
+}
+
+void ipa3_ntn_uc_dereg_rdyCB(void)
+{
+ ipa3_ctx->uc_ntn_ctx.uc_ready_cb = NULL;
+ ipa3_ctx->uc_ntn_ctx.priv = NULL;
+}
+
+static void ipa3_uc_ntn_loaded_handler(void)
+{
+ if (!ipa3_ctx) {
+ IPAERR("IPA ctx is null\n");
+ return;
+ }
+
+ if (ipa3_ctx->uc_ntn_ctx.uc_ready_cb) {
+ ipa3_ctx->uc_ntn_ctx.uc_ready_cb(
+ ipa3_ctx->uc_ntn_ctx.priv);
+
+ ipa3_ctx->uc_ntn_ctx.uc_ready_cb =
+ NULL;
+ ipa3_ctx->uc_ntn_ctx.priv = NULL;
+ }
+}
+
int ipa3_ntn_init(void)
{
struct ipa3_uc_hdlrs uc_ntn_cbs = { 0 };
@@ -146,6 +188,8 @@ int ipa3_ntn_init(void)
uc_ntn_cbs.ipa_uc_event_hdlr = ipa3_uc_ntn_event_handler;
uc_ntn_cbs.ipa_uc_event_log_info_hdlr =
ipa3_uc_ntn_event_log_info_handler;
+ uc_ntn_cbs.ipa_uc_loaded_hdlr =
+ ipa3_uc_ntn_loaded_handler;
ipa3_uc_register_handlers(IPA_HW_FEATURE_NTN, &uc_ntn_cbs);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h
index 79f0973..2e5a832 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h
@@ -383,22 +383,21 @@ union Ipa3HwNTNErrorEventData_t {
* struct NTN3RxInfoData_t - NTN Structure holding the Rx pipe
* information
*
- *@max_outstanding_pkts: Number of outstanding packets in Rx
- * Ring
*@num_pkts_processed: Number of packets processed - cumulative
- *@rx_ring_rp_value: Read pointer last advertized to the WLAN FW
*
- *@rx_ind_ring_stats:
- *@bam_stats:
+ *@ring_stats:
+ *@gsi_stats:
*@num_db: Number of times the doorbell was rung
+ *@num_qmb_int_handled: Number of QMB interrupts handled
+ *@ipa_pipe_number: The IPA Rx/Tx pipe number.
*/
struct NTN3RxInfoData_t {
- u32 max_outstanding_pkts;
u32 num_pkts_processed;
- u32 rx_ring_rp_value;
- struct IpaHwRingStats_t rx_ind_ring_stats;
- struct IpaHwBamStats_t bam_stats;
- u32 num_db;
+ struct IpaHwRingStats_t ring_stats;
+ struct IpaHwBamStats_t gsi_stats;
+ u32 num_db;
+ u32 num_qmb_int_handled;
+ u32 ipa_pipe_number;
} __packed;
@@ -417,12 +416,11 @@ struct NTN3RxInfoData_t {
*/
struct NTN3TxInfoData_t {
u32 num_pkts_processed;
- u32 tail_ptr_val;
- u32 num_db_fired;
- struct IpaHwRingStats_t tx_comp_ring_stats;
- struct IpaHwBamStats_t bam_stats;
- u32 num_db;
- u32 num_qmb_int_handled;
+ struct IpaHwRingStats_t ring_stats;
+ struct IpaHwBamStats_t gsi_stats;
+ u32 num_db;
+ u32 num_qmb_int_handled;
+ u32 ipa_pipe_number;
} __packed;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 11da6b3..a251359 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -26,6 +26,15 @@
#define IPA_V3_0_CLK_RATE_SVS (75 * 1000 * 1000UL)
#define IPA_V3_0_CLK_RATE_NOMINAL (150 * 1000 * 1000UL)
#define IPA_V3_0_CLK_RATE_TURBO (200 * 1000 * 1000UL)
+
+#define IPA_V3_5_CLK_RATE_SVS (200 * 1000 * 1000UL)
+#define IPA_V3_5_CLK_RATE_NOMINAL (400 * 1000 * 1000UL)
+#define IPA_V3_5_CLK_RATE_TURBO (42640 * 10 * 1000UL)
+
+#define IPA_V4_0_CLK_RATE_SVS (125 * 1000 * 1000UL)
+#define IPA_V4_0_CLK_RATE_NOMINAL (220 * 1000 * 1000UL)
+#define IPA_V4_0_CLK_RATE_TURBO (250 * 1000 * 1000UL)
+
#define IPA_V3_0_MAX_HOLB_TMR_VAL (4294967296 - 1)
#define IPA_V3_0_BW_THRESHOLD_TURBO_MBPS (1000)
@@ -1538,43 +1547,6 @@ static struct msm_bus_scale_pdata ipa_bus_client_pdata_v3_0 = {
.name = "ipa",
};
-void ipa3_active_clients_lock(void)
-{
- unsigned long flags;
-
- mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
- spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients.spinlock, flags);
- ipa3_ctx->ipa3_active_clients.mutex_locked = true;
- spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients.spinlock, flags);
-}
-
-int ipa3_active_clients_trylock(unsigned long *flags)
-{
- spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients.spinlock, *flags);
- if (ipa3_ctx->ipa3_active_clients.mutex_locked) {
- spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients.spinlock,
- *flags);
- return 0;
- }
-
- return 1;
-}
-
-void ipa3_active_clients_trylock_unlock(unsigned long *flags)
-{
- spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients.spinlock, *flags);
-}
-
-void ipa3_active_clients_unlock(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ipa3_ctx->ipa3_active_clients.spinlock, flags);
- ipa3_ctx->ipa3_active_clients.mutex_locked = false;
- spin_unlock_irqrestore(&ipa3_ctx->ipa3_active_clients.spinlock, flags);
- mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
-}
-
/**
* ipa3_get_clients_from_rm_resource() - get IPA clients which are related to an
* IPA_RM resource
@@ -1818,16 +1790,8 @@ int ipa3_suspend_resource_no_block(enum ipa_rm_resource_name resource)
enum ipa_client_type client;
struct ipa_ep_cfg_ctrl suspend;
int ipa_ep_idx;
- unsigned long flags;
struct ipa_active_client_logging_info log_info;
- if (ipa3_active_clients_trylock(&flags) == 0)
- return -EPERM;
- if (ipa3_ctx->ipa3_active_clients.cnt == 1) {
- res = -EPERM;
- goto bail;
- }
-
memset(&clients, 0, sizeof(clients));
res = ipa3_get_clients_from_rm_resource(resource, &clients);
if (res) {
@@ -1866,14 +1830,11 @@ int ipa3_suspend_resource_no_block(enum ipa_rm_resource_name resource)
if (res == 0) {
IPA_ACTIVE_CLIENTS_PREP_RESOURCE(log_info,
ipa_rm_resource_str(resource));
- ipa3_active_clients_log_dec(&log_info, true);
- ipa3_ctx->ipa3_active_clients.cnt--;
- IPADBG("active clients = %d\n",
- ipa3_ctx->ipa3_active_clients.cnt);
+ /* before gating IPA clocks do TAG process */
+ ipa3_ctx->tag_process_before_gating = true;
+ ipa3_dec_client_disable_clks_no_block(&log_info);
}
bail:
- ipa3_active_clients_trylock_unlock(&flags);
-
return res;
}
@@ -3767,13 +3728,24 @@ int ipa3_init_mem_partition(struct device_node *node)
int ipa3_controller_static_bind(struct ipa3_controller *ctrl,
enum ipa_hw_type hw_type)
{
+ if (hw_type >= IPA_HW_v4_0) {
+ ctrl->ipa_clk_rate_turbo = IPA_V4_0_CLK_RATE_TURBO;
+ ctrl->ipa_clk_rate_nominal = IPA_V4_0_CLK_RATE_NOMINAL;
+ ctrl->ipa_clk_rate_svs = IPA_V4_0_CLK_RATE_SVS;
+ } else if (hw_type >= IPA_HW_v3_5) {
+ ctrl->ipa_clk_rate_turbo = IPA_V3_5_CLK_RATE_TURBO;
+ ctrl->ipa_clk_rate_nominal = IPA_V3_5_CLK_RATE_NOMINAL;
+ ctrl->ipa_clk_rate_svs = IPA_V3_5_CLK_RATE_SVS;
+ } else {
+ ctrl->ipa_clk_rate_turbo = IPA_V3_0_CLK_RATE_TURBO;
+ ctrl->ipa_clk_rate_nominal = IPA_V3_0_CLK_RATE_NOMINAL;
+ ctrl->ipa_clk_rate_svs = IPA_V3_0_CLK_RATE_SVS;
+ }
+
ctrl->ipa_init_rt4 = _ipa_init_rt4_v3;
ctrl->ipa_init_rt6 = _ipa_init_rt6_v3;
ctrl->ipa_init_flt4 = _ipa_init_flt4_v3;
ctrl->ipa_init_flt6 = _ipa_init_flt6_v3;
- ctrl->ipa_clk_rate_turbo = IPA_V3_0_CLK_RATE_TURBO;
- ctrl->ipa_clk_rate_nominal = IPA_V3_0_CLK_RATE_NOMINAL;
- ctrl->ipa_clk_rate_svs = IPA_V3_0_CLK_RATE_SVS;
ctrl->ipa3_read_ep_reg = _ipa_read_ep_reg_v3_0;
ctrl->ipa3_commit_flt = __ipa_commit_flt_v3;
ctrl->ipa3_commit_rt = __ipa_commit_rt_v3;
@@ -4502,6 +4474,8 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
api_ctrl->ipa_tear_down_uc_offload_pipes =
ipa3_tear_down_uc_offload_pipes;
api_ctrl->ipa_get_pdev = ipa3_get_pdev;
+ api_ctrl->ipa_ntn_uc_reg_rdyCB = ipa3_ntn_uc_reg_rdyCB;
+ api_ctrl->ipa_ntn_uc_dereg_rdyCB = ipa3_ntn_uc_dereg_rdyCB;
return 0;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index 16585a2..b19c71a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -2966,6 +2966,10 @@ static int rmnet_ipa3_query_tethering_stats_modem(
kfree(req);
kfree(resp);
return rc;
+ } else if (data == NULL) {
+ kfree(req);
+ kfree(resp);
+ return 0;
}
if (resp->dl_dst_pipe_stats_list_valid) {
@@ -3149,8 +3153,11 @@ int rmnet_ipa3_query_tethering_stats_all(
int rmnet_ipa3_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data)
{
enum ipa_upstream_type upstream_type;
+ struct wan_ioctl_query_tether_stats tether_stats;
int rc = 0;
+ memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats));
+
/* get IPA backhaul type */
upstream_type = find_upstream_type(data->upstreamIface);
@@ -3168,7 +3175,7 @@ int rmnet_ipa3_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data)
} else {
IPAWANERR(" reset modem-backhaul stats\n");
rc = rmnet_ipa3_query_tethering_stats_modem(
- NULL, true);
+ &tether_stats, true);
if (rc) {
IPAWANERR("reset MODEM stats failed\n");
return rc;
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 8641a45..486e8c3 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -41,6 +41,7 @@
#define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER"
#define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER"
#define USBIN_I_VOTER "USBIN_I_VOTER"
+#define FCC_CHANGE_VOTER "FCC_CHANGE_VOTER"
struct pl_data {
int pl_mode;
@@ -288,69 +289,11 @@ static struct class_attribute pl_attributes[] = {
__ATTR_NULL,
};
-/***********
- * TAPER *
- ************/
-#define MINIMUM_PARALLEL_FCC_UA 500000
-#define PL_TAPER_WORK_DELAY_MS 100
-#define TAPER_RESIDUAL_PCT 75
-static void pl_taper_work(struct work_struct *work)
-{
- struct pl_data *chip = container_of(work, struct pl_data,
- pl_taper_work.work);
- union power_supply_propval pval = {0, };
- int rc;
-
- /* exit immediately if parallel is disabled */
- if (get_effective_result(chip->pl_disable_votable)) {
- pl_dbg(chip, PR_PARALLEL, "terminating parallel not in progress\n");
- goto done;
- }
-
- pl_dbg(chip, PR_PARALLEL, "entering parallel taper work slave_fcc = %d\n",
- chip->slave_fcc_ua);
- if (chip->slave_fcc_ua < MINIMUM_PARALLEL_FCC_UA) {
- pl_dbg(chip, PR_PARALLEL, "terminating parallel's share lower than 500mA\n");
- vote(chip->pl_disable_votable, TAPER_END_VOTER, true, 0);
- goto done;
- }
-
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
- if (rc < 0) {
- pr_err("Couldn't get batt charge type rc=%d\n", rc);
- goto done;
- }
-
- chip->charge_type = pval.intval;
- if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
- pl_dbg(chip, PR_PARALLEL, "master is taper charging; reducing slave FCC\n");
-
- vote(chip->pl_awake_votable, TAPER_END_VOTER, true, 0);
- /* Reduce the taper percent by 25 percent */
- chip->taper_pct = chip->taper_pct * TAPER_RESIDUAL_PCT / 100;
- rerun_election(chip->fcc_votable);
- pl_dbg(chip, PR_PARALLEL, "taper entry scheduling work after %d ms\n",
- PL_TAPER_WORK_DELAY_MS);
- schedule_delayed_work(&chip->pl_taper_work,
- msecs_to_jiffies(PL_TAPER_WORK_DELAY_MS));
- return;
- }
-
- /*
- * Master back to Fast Charge, get out of this round of taper reduction
- */
- pl_dbg(chip, PR_PARALLEL, "master is fast charging; waiting for next taper\n");
-
-done:
- vote(chip->pl_awake_votable, TAPER_END_VOTER, false, 0);
-}
-
/*********
* FCC *
**********/
#define EFFICIENCY_PCT 80
-static void split_fcc(struct pl_data *chip, int total_ua,
+static void get_fcc_split(struct pl_data *chip, int total_ua,
int *master_ua, int *slave_ua)
{
int rc, effective_total_ua, slave_limited_ua, hw_cc_delta_ua = 0,
@@ -389,7 +332,7 @@ static void split_fcc(struct pl_data *chip, int total_ua,
effective_total_ua = max(0, total_ua + hw_cc_delta_ua);
slave_limited_ua = min(effective_total_ua, bcl_ua);
*slave_ua = (slave_limited_ua * chip->slave_pct) / 100;
- *slave_ua = (*slave_ua * chip->taper_pct) / 100;
+
/*
* In USBIN_USBIN configuration with internal rsense parallel
* charger's current goes through main charger's BATFET, keep
@@ -399,14 +342,75 @@ static void split_fcc(struct pl_data *chip, int total_ua,
*master_ua = max(0, total_ua);
else
*master_ua = max(0, total_ua - *slave_ua);
+
+ /* further reduce slave's share in accordance with taper reductions */
+ *slave_ua = (*slave_ua * chip->taper_pct) / 100;
+}
+
+#define MINIMUM_PARALLEL_FCC_UA 500000
+#define PL_TAPER_WORK_DELAY_MS 100
+#define TAPER_RESIDUAL_PCT 90
+static void pl_taper_work(struct work_struct *work)
+{
+ struct pl_data *chip = container_of(work, struct pl_data,
+ pl_taper_work.work);
+ union power_supply_propval pval = {0, };
+ int total_fcc_ua, master_fcc_ua, slave_fcc_ua;
+ int rc;
+
+ /* exit immediately if parallel is disabled */
+ if (get_effective_result(chip->pl_disable_votable)) {
+ pl_dbg(chip, PR_PARALLEL, "terminating parallel not in progress\n");
+ goto done;
+ }
+
+ total_fcc_ua = get_effective_result_locked(chip->fcc_votable);
+ get_fcc_split(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua);
+ if (slave_fcc_ua < MINIMUM_PARALLEL_FCC_UA) {
+ pl_dbg(chip, PR_PARALLEL, "terminating parallel's share lower than 500mA\n");
+ vote(chip->pl_disable_votable, TAPER_END_VOTER, true, 0);
+ goto done;
+ }
+
+ pl_dbg(chip, PR_PARALLEL, "entering parallel taper work slave_fcc = %d\n",
+ slave_fcc_ua);
+
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get batt charge type rc=%d\n", rc);
+ goto done;
+ }
+
+ chip->charge_type = pval.intval;
+ if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
+ pl_dbg(chip, PR_PARALLEL, "master is taper charging; reducing slave FCC\n");
+
+ vote(chip->pl_awake_votable, TAPER_END_VOTER, true, 0);
+ /* Reduce the taper percent by 10 percent */
+ chip->taper_pct = chip->taper_pct * TAPER_RESIDUAL_PCT / 100;
+ rerun_election(chip->fcc_votable);
+ pl_dbg(chip, PR_PARALLEL, "taper entry scheduling work after %d ms\n",
+ PL_TAPER_WORK_DELAY_MS);
+ schedule_delayed_work(&chip->pl_taper_work,
+ msecs_to_jiffies(PL_TAPER_WORK_DELAY_MS));
+ return;
+ }
+
+ /*
+ * Master back to Fast Charge, get out of this round of taper reduction
+ */
+ pl_dbg(chip, PR_PARALLEL, "master is fast charging; waiting for next taper\n");
+
+done:
+ vote(chip->pl_awake_votable, TAPER_END_VOTER, false, 0);
}
static int pl_fcc_vote_callback(struct votable *votable, void *data,
int total_fcc_ua, const char *client)
{
struct pl_data *chip = data;
- union power_supply_propval pval = {0, };
- int rc, master_fcc_ua = total_fcc_ua, slave_fcc_ua = 0;
+ int master_fcc_ua = total_fcc_ua, slave_fcc_ua = 0;
if (total_fcc_ua < 0)
return 0;
@@ -414,41 +418,23 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
if (!chip->main_psy)
return 0;
- if (chip->pl_mode == POWER_SUPPLY_PL_NONE
- || get_effective_result_locked(chip->pl_disable_votable)) {
- pval.intval = total_fcc_ua;
- rc = power_supply_set_property(chip->main_psy,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
- &pval);
- if (rc < 0)
- pr_err("Couldn't set main fcc, rc=%d\n", rc);
- return rc;
- }
-
if (chip->pl_mode != POWER_SUPPLY_PL_NONE) {
- split_fcc(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua);
+ get_fcc_split(chip, total_fcc_ua, &master_fcc_ua,
+ &slave_fcc_ua);
- pval.intval = slave_fcc_ua;
- rc = power_supply_set_property(chip->pl_psy,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
- &pval);
- if (rc < 0) {
- pr_err("Couldn't set parallel fcc, rc=%d\n", rc);
- return rc;
- }
-
- chip->slave_fcc_ua = slave_fcc_ua;
-
- pval.intval = master_fcc_ua;
- rc = power_supply_set_property(chip->main_psy,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
- &pval);
- if (rc < 0) {
- pr_err("Could not set main fcc, rc=%d\n", rc);
- return rc;
+ if (slave_fcc_ua > 500000) {
+ chip->slave_fcc_ua = slave_fcc_ua;
+ vote(chip->pl_disable_votable, FCC_CHANGE_VOTER,
+ false, 0);
+ } else {
+ chip->slave_fcc_ua = 0;
+ vote(chip->pl_disable_votable, FCC_CHANGE_VOTER,
+ true, 0);
}
}
+ rerun_election(chip->pl_disable_votable);
+
pl_dbg(chip, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
master_fcc_ua, slave_fcc_ua,
(master_fcc_ua * 100) / total_fcc_ua,
@@ -577,18 +563,34 @@ static void pl_disable_forever_work(struct work_struct *work)
vote(chip->hvdcp_hw_inov_dis_votable, PL_VOTER, false, 0);
}
+static bool is_main_available(struct pl_data *chip)
+{
+ if (chip->main_psy)
+ return true;
+
+ chip->main_psy = power_supply_get_by_name("main");
+
+ return !!chip->main_psy;
+}
+
static int pl_disable_vote_callback(struct votable *votable,
void *data, int pl_disable, const char *client)
{
struct pl_data *chip = data;
union power_supply_propval pval = {0, };
+ int master_fcc_ua, total_fcc_ua, slave_fcc_ua;
int rc;
- chip->taper_pct = 100;
chip->total_settled_ua = 0;
chip->pl_settled_ua = 0;
- if (!pl_disable) { /* enable */
+ if (!is_main_available(chip))
+ return -ENODEV;
+
+ total_fcc_ua = get_effective_result_locked(chip->fcc_votable);
+
+ if (chip->pl_mode != POWER_SUPPLY_PL_NONE && !pl_disable) {
+ /* enable parallel charging */
rc = power_supply_get_property(chip->pl_psy,
POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
if (rc == -ENODEV) {
@@ -602,7 +604,30 @@ static int pl_disable_vote_callback(struct votable *votable,
}
rerun_election(chip->fv_votable);
- rerun_election(chip->fcc_votable);
+
+ get_fcc_split(chip, total_fcc_ua, &master_fcc_ua,
+ &slave_fcc_ua);
+
+ chip->slave_fcc_ua = slave_fcc_ua;
+
+ pval.intval = master_fcc_ua;
+ rc = power_supply_set_property(chip->main_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ &pval);
+ if (rc < 0) {
+ pr_err("Could not set main fcc, rc=%d\n", rc);
+ return rc;
+ }
+
+ pval.intval = slave_fcc_ua;
+ rc = power_supply_set_property(chip->pl_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ &pval);
+ if (rc < 0) {
+ pr_err("Couldn't set parallel fcc, rc=%d\n", rc);
+ return rc;
+ }
+
/*
* Enable will be called with a valid pl_psy always. The
* PARALLEL_PSY_VOTER keeps it disabled unless a pl_psy
@@ -647,7 +672,17 @@ static int pl_disable_vote_callback(struct votable *votable,
pr_err("Couldn't change slave suspend state rc=%d\n",
rc);
}
- rerun_election(chip->fcc_votable);
+
+ /* main psy gets all share */
+ pval.intval = total_fcc_ua;
+ rc = power_supply_set_property(chip->main_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ &pval);
+ if (rc < 0) {
+ pr_err("Could not set main fcc, rc=%d\n", rc);
+ return rc;
+ }
+
rerun_election(chip->fv_votable);
}
@@ -681,16 +716,6 @@ static int pl_awake_vote_callback(struct votable *votable,
return 0;
}
-static bool is_main_available(struct pl_data *chip)
-{
- if (chip->main_psy)
- return true;
-
- chip->main_psy = power_supply_get_by_name("main");
-
- return !!chip->main_psy;
-}
-
static bool is_batt_available(struct pl_data *chip)
{
if (!chip->batt_psy)
@@ -835,6 +860,7 @@ static void handle_settled_icl_change(struct pl_data *chip)
else
vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, true, 0);
+ rerun_election(chip->fcc_votable);
if (get_effective_result(chip->pl_disable_votable))
return;
@@ -856,8 +882,6 @@ static void handle_settled_icl_change(struct pl_data *chip)
if (abs(new_total_settled_ua - chip->total_settled_ua)
> MIN_ICL_CHANGE_DELTA_UA)
split_settled(chip);
- } else {
- rerun_election(chip->fcc_votable);
}
}
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index ae44f01..3f26e5e 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -3705,6 +3705,7 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
/* reset parallel voters */
vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
+ vote(chg->pl_disable_votable, FCC_CHANGE_VOTER, false, 0);
vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 5c7819e..c08d404 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -66,6 +66,7 @@ enum print_reason {
#define USBIN_I_VOTER "USBIN_I_VOTER"
#define WEAK_CHARGER_VOTER "WEAK_CHARGER_VOTER"
#define OTG_VOTER "OTG_VOTER"
+#define FCC_CHANGE_VOTER "FCC_CHANGE_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c
index b2c0059..4e1bb17 100644
--- a/drivers/power/supply/qcom/smb1355-charger.c
+++ b/drivers/power/supply/qcom/smb1355-charger.c
@@ -62,6 +62,10 @@
#define CHGR_BATTOV_CFG_REG (CHGR_BASE + 0x70)
#define BATTOV_SETTING_MASK GENMASK(7, 0)
+#define POWER_MODE_HICCUP_CFG (BATIF_BASE + 0x72)
+#define MAX_HICCUP_DUETO_BATDIS_MASK GENMASK(5, 2)
+#define HICCUP_TIMEOUT_CFG_MASK GENMASK(1, 0)
+
#define TEMP_COMP_STATUS_REG (MISC_BASE + 0x07)
#define SKIN_TEMP_RST_HOT_BIT BIT(6)
#define SKIN_TEMP_UB_HOT_BIT BIT(5)
@@ -580,6 +584,16 @@ static int smb1355_init_hw(struct smb1355 *chip)
return rc;
}
+ /* HICCUP setting, unlimited retry with 250ms interval */
+ rc = smb1355_masked_write(chip, POWER_MODE_HICCUP_CFG,
+ HICCUP_TIMEOUT_CFG_MASK | MAX_HICCUP_DUETO_BATDIS_MASK,
+ 0);
+ if (rc < 0) {
+ pr_err("Couldn't enable parallel current sensing rc=%d\n",
+ rc);
+ return rc;
+ }
+
/* enable parallel current sensing */
rc = smb1355_masked_write(chip, CFG_REG,
VCHG_EN_CFG_BIT, VCHG_EN_CFG_BIT);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a2b5ea0..370e092 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7833,6 +7833,11 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
ufshcd_set_auto_hibern8_timer(hba,
hba->hibern8_on_idle.delay_ms);
out:
+ if (ret) {
+ ufshcd_set_ufs_dev_poweroff(hba);
+ ufshcd_set_link_off(hba);
+ }
+
/*
* If we failed to initialize the device or the device is not
* present, turn off the power/clocks etc.
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index e6c2aa3..5be06ba 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -632,6 +632,14 @@
between MSM and WCD DSP over glink transport protocol. This driver
provides read and write interface via char device.
+config QCOM_SMCINVOKE
+ bool "Secure QSEE Support"
+ help
+ Enable SMCInvoke driver which supports capability based secure
+ communication between QTI Secure Execution Environment (QSEE)
+ and high level operating system. It exposes APIs for both
+ userspace and kernel clients.
+
config MSM_EVENT_TIMER
bool "Event timer"
help
@@ -735,4 +743,12 @@
kernel panic. On certain MSM SoCs, this provides us
additional debugging information.
+config QMP_DEBUGFS_CLIENT
+ bool "Debugfs Client to communicate with AOP using QMP protocol"
+ depends on DEBUG_FS
+ default n
+ help
+ This options enables a driver which allows clients to send messages
+ to Alway On processor using QMP transport.
+
source "drivers/soc/qcom/memshare/Kconfig"
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 64fb7a0..9736cdc 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -77,3 +77,5 @@
obj-$(CONFIG_APSS_CORE_EA) += msm-core.o debug_core.o
obj-$(CONFIG_QCOM_DCC_V2) += dcc_v2.o
obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpm_stats.o
+obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o
+obj-$(CONFIG_QMP_DEBUGFS_CLIENT) += qmp-debugfs-client.o
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index cded512..a0982bc 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -269,6 +269,7 @@ enum icnss_driver_state {
ICNSS_WLFW_EXISTS,
ICNSS_WDOG_BITE,
ICNSS_SHUTDOWN_DONE,
+ ICNSS_HOST_TRIGGERED_PDR,
};
struct ce_irq_list {
@@ -321,6 +322,13 @@ struct icnss_stats {
uint32_t disable;
} ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS];
+ struct {
+ uint32_t pdr_fw_crash;
+ uint32_t pdr_host_error;
+ uint32_t root_pd_crash;
+ uint32_t root_pd_shutdown;
+ } recovery;
+
uint32_t pm_suspend;
uint32_t pm_suspend_err;
uint32_t pm_resume;
@@ -358,10 +366,10 @@ struct icnss_stats {
uint32_t vbatt_req;
uint32_t vbatt_resp;
uint32_t vbatt_req_err;
+ u32 rejuvenate_ind;
uint32_t rejuvenate_ack_req;
uint32_t rejuvenate_ack_resp;
uint32_t rejuvenate_ack_err;
- uint32_t trigger_recovery;
};
#define MAX_NO_OF_MAC_ADDR 4
@@ -370,6 +378,20 @@ struct icnss_wlan_mac_addr {
uint32_t no_of_mac_addr_set;
};
+enum icnss_pdr_cause_index {
+ ICNSS_FW_CRASH,
+ ICNSS_ROOT_PD_CRASH,
+ ICNSS_ROOT_PD_SHUTDOWN,
+ ICNSS_HOST_ERROR,
+};
+
+static const char * const icnss_pdr_cause[] = {
+ [ICNSS_FW_CRASH] = "FW crash",
+ [ICNSS_ROOT_PD_CRASH] = "Root PD crashed",
+ [ICNSS_ROOT_PD_SHUTDOWN] = "Root PD shutdown",
+ [ICNSS_HOST_ERROR] = "Host error",
+};
+
struct service_notifier_context {
void *handle;
uint32_t instance_id;
@@ -435,6 +457,11 @@ static struct icnss_priv {
bool is_wlan_mac_set;
struct icnss_wlan_mac_addr wlan_mac_addr;
bool bypass_s1_smmu;
+ u8 cause_for_rejuvenation;
+ u8 requesting_sub_system;
+ u16 line_number;
+ char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1];
+ struct mutex dev_lock;
} *penv;
#ifdef CONFIG_ICNSS_DEBUG
@@ -1670,6 +1697,60 @@ static int wlfw_athdiag_write_send_sync_msg(struct icnss_priv *priv,
return ret;
}
+static int icnss_decode_rejuvenate_ind(void *msg, unsigned int msg_len)
+{
+ struct msg_desc ind_desc;
+ struct wlfw_rejuvenate_ind_msg_v01 ind_msg;
+ int ret = 0;
+
+ if (!penv || !penv->wlfw_clnt) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ memset(&ind_msg, 0, sizeof(ind_msg));
+
+ ind_desc.msg_id = QMI_WLFW_REJUVENATE_IND_V01;
+ ind_desc.max_msg_len = WLFW_REJUVENATE_IND_MSG_V01_MAX_MSG_LEN;
+ ind_desc.ei_array = wlfw_rejuvenate_ind_msg_v01_ei;
+
+ ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len);
+ if (ret < 0) {
+ icnss_pr_err("Failed to decode rejuvenate ind message: ret %d, msg_len %u\n",
+ ret, msg_len);
+ goto out;
+ }
+
+ if (ind_msg.cause_for_rejuvenation_valid)
+ penv->cause_for_rejuvenation = ind_msg.cause_for_rejuvenation;
+ else
+ penv->cause_for_rejuvenation = 0;
+ if (ind_msg.requesting_sub_system_valid)
+ penv->requesting_sub_system = ind_msg.requesting_sub_system;
+ else
+ penv->requesting_sub_system = 0;
+ if (ind_msg.line_number_valid)
+ penv->line_number = ind_msg.line_number;
+ else
+ penv->line_number = 0;
+ if (ind_msg.function_name_valid)
+ memcpy(penv->function_name, ind_msg.function_name,
+ QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1);
+ else
+ memset(penv->function_name, 0,
+ QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1);
+
+ icnss_pr_info("Cause for rejuvenation: 0x%x, requesting sub-system: 0x%x, line number: %u, function name: %s\n",
+ penv->cause_for_rejuvenation,
+ penv->requesting_sub_system,
+ penv->line_number,
+ penv->function_name);
+
+ penv->stats.rejuvenate_ind++;
+out:
+ return ret;
+}
+
static int wlfw_rejuvenate_ack_send_sync_msg(struct icnss_priv *priv)
{
int ret;
@@ -1863,6 +1944,7 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle,
msg_id, penv->state);
icnss_ignore_qmi_timeout(true);
+ icnss_decode_rejuvenate_ind(msg, msg_len);
event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
if (event_data == NULL)
return;
@@ -2400,6 +2482,11 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n",
priv->state, notif->crashed);
+ if (notif->crashed)
+ priv->stats.recovery.root_pd_crash++;
+ else
+ priv->stats.recovery.root_pd_shutdown++;
+
icnss_ignore_qmi_timeout(true);
event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
@@ -2479,6 +2566,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
enum pd_subsys_state *state = data;
struct icnss_event_pd_service_down_data *event_data;
struct icnss_uevent_fw_down_data fw_down_data;
+ enum icnss_pdr_cause_index cause = ICNSS_ROOT_PD_CRASH;
icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n",
notification, priv->state);
@@ -2493,26 +2581,40 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
if (state == NULL) {
event_data->crashed = true;
+ priv->stats.recovery.root_pd_crash++;
goto event_post;
}
- icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx\n",
- *state, priv->state);
-
switch (*state) {
case ROOT_PD_WDOG_BITE:
event_data->crashed = true;
event_data->wdog_bite = true;
+ priv->stats.recovery.root_pd_crash++;
break;
case ROOT_PD_SHUTDOWN:
+ cause = ICNSS_ROOT_PD_SHUTDOWN;
+ priv->stats.recovery.root_pd_shutdown++;
+ break;
+ case USER_PD_STATE_CHANGE:
+ if (test_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state)) {
+ cause = ICNSS_HOST_ERROR;
+ priv->stats.recovery.pdr_host_error++;
+ } else {
+ cause = ICNSS_FW_CRASH;
+ priv->stats.recovery.pdr_fw_crash++;
+ }
break;
default:
event_data->crashed = true;
+ priv->stats.recovery.root_pd_crash++;
break;
}
+ icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx: cause: %s\n",
+ *state, priv->state, icnss_pdr_cause[cause]);
event_post:
icnss_ignore_qmi_timeout(true);
+ clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state);
fw_down_data.crashed = event_data->crashed;
icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data);
@@ -3255,7 +3357,6 @@ int icnss_trigger_recovery(struct device *dev)
WARN_ON(1);
icnss_pr_warn("Initiate PD restart at WLAN FW, state: 0x%lx\n",
priv->state);
- priv->stats.trigger_recovery++;
/*
* Initiate PDR, required only for the first instance
@@ -3263,6 +3364,9 @@ int icnss_trigger_recovery(struct device *dev)
ret = service_notif_pd_restart(priv->service_notifier[0].name,
priv->service_notifier[0].instance_id);
+ if (!ret)
+ set_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state);
+
out:
return ret;
}
@@ -3274,6 +3378,7 @@ static int icnss_smmu_init(struct icnss_priv *priv)
struct dma_iommu_mapping *mapping;
int atomic_ctx = 1;
int s1_bypass = 1;
+ int fast = 1;
int ret = 0;
icnss_pr_dbg("Initializing SMMU\n");
@@ -3287,7 +3392,17 @@ static int icnss_smmu_init(struct icnss_priv *priv)
goto map_fail;
}
- if (!priv->bypass_s1_smmu) {
+ if (priv->bypass_s1_smmu) {
+ ret = iommu_domain_set_attr(mapping->domain,
+ DOMAIN_ATTR_S1_BYPASS,
+ &s1_bypass);
+ if (ret < 0) {
+ icnss_pr_err("Set s1_bypass attribute failed, err = %d\n",
+ ret);
+ goto set_attr_fail;
+ }
+ icnss_pr_dbg("SMMU S1 BYPASS\n");
+ } else {
ret = iommu_domain_set_attr(mapping->domain,
DOMAIN_ATTR_ATOMIC,
&atomic_ctx);
@@ -3296,14 +3411,17 @@ static int icnss_smmu_init(struct icnss_priv *priv)
ret);
goto set_attr_fail;
}
- }
+ icnss_pr_dbg("SMMU ATTR ATOMIC\n");
- ret = iommu_domain_set_attr(mapping->domain,
- DOMAIN_ATTR_S1_BYPASS,
- &s1_bypass);
- if (ret < 0) {
- icnss_pr_err("Set s1_bypass attribute failed, err = %d\n", ret);
- goto set_attr_fail;
+ ret = iommu_domain_set_attr(mapping->domain,
+ DOMAIN_ATTR_FAST,
+ &fast);
+ if (ret < 0) {
+ icnss_pr_err("Set fast map attribute failed, err = %d\n",
+ ret);
+ goto set_attr_fail;
+ }
+ icnss_pr_dbg("SMMU FAST map set\n");
}
ret = arm_iommu_attach_device(&priv->pdev->dev, mapping);
@@ -3617,9 +3735,6 @@ static ssize_t icnss_fw_debug_write(struct file *fp,
if (ret)
return ret;
- if (ret == 0)
- memset(&priv->stats, 0, sizeof(priv->stats));
-
return count;
}
@@ -3713,6 +3828,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
case ICNSS_SHUTDOWN_DONE:
seq_puts(s, "SHUTDOWN DONE");
continue;
+ case ICNSS_HOST_TRIGGERED_PDR:
+ seq_puts(s, "HOST TRIGGERED PDR");
+ continue;
}
seq_printf(s, "UNKNOWN-%d", i);
@@ -3743,6 +3861,26 @@ static int icnss_stats_show_capability(struct seq_file *s,
return 0;
}
+static int icnss_stats_show_rejuvenate_info(struct seq_file *s,
+ struct icnss_priv *priv)
+{
+ if (priv->stats.rejuvenate_ind) {
+ seq_puts(s, "\n<---------------- Rejuvenate Info ----------------->\n");
+ seq_printf(s, "Number of Rejuvenations: %u\n",
+ priv->stats.rejuvenate_ind);
+ seq_printf(s, "Cause for Rejuvenation: 0x%x\n",
+ priv->cause_for_rejuvenation);
+ seq_printf(s, "Requesting Sub-System: 0x%x\n",
+ priv->requesting_sub_system);
+ seq_printf(s, "Line Number: %u\n",
+ priv->line_number);
+ seq_printf(s, "Function Name: %s\n",
+ priv->function_name);
+ }
+
+ return 0;
+}
+
static int icnss_stats_show_events(struct seq_file *s, struct icnss_priv *priv)
{
int i;
@@ -3808,10 +3946,14 @@ static int icnss_stats_show(struct seq_file *s, void *data)
ICNSS_STATS_DUMP(s, priv, vbatt_req);
ICNSS_STATS_DUMP(s, priv, vbatt_resp);
ICNSS_STATS_DUMP(s, priv, vbatt_req_err);
+ ICNSS_STATS_DUMP(s, priv, rejuvenate_ind);
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req);
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp);
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err);
- ICNSS_STATS_DUMP(s, priv, trigger_recovery);
+ ICNSS_STATS_DUMP(s, priv, recovery.pdr_fw_crash);
+ ICNSS_STATS_DUMP(s, priv, recovery.pdr_host_error);
+ ICNSS_STATS_DUMP(s, priv, recovery.root_pd_crash);
+ ICNSS_STATS_DUMP(s, priv, recovery.root_pd_shutdown);
seq_puts(s, "\n<------------------ PM stats ------------------->\n");
ICNSS_STATS_DUMP(s, priv, pm_suspend);
@@ -3829,6 +3971,8 @@ static int icnss_stats_show(struct seq_file *s, void *data)
icnss_stats_show_capability(s, priv);
+ icnss_stats_show_rejuvenate_info(s, priv);
+
icnss_stats_show_events(s, priv);
icnss_stats_show_state(s, priv);
@@ -3940,12 +4084,14 @@ static int icnss_regread_show(struct seq_file *s, void *data)
{
struct icnss_priv *priv = s->private;
+ mutex_lock(&priv->dev_lock);
if (!priv->diag_reg_read_buf) {
seq_puts(s, "Usage: echo <mem_type> <offset> <data_len> > <debugfs>/icnss/reg_read\n");
if (!test_bit(ICNSS_FW_READY, &priv->state))
seq_puts(s, "Firmware is not ready yet!, wait for FW READY\n");
+ mutex_unlock(&priv->dev_lock);
return 0;
}
@@ -3959,6 +4105,7 @@ static int icnss_regread_show(struct seq_file *s, void *data)
priv->diag_reg_read_len = 0;
kfree(priv->diag_reg_read_buf);
priv->diag_reg_read_buf = NULL;
+ mutex_unlock(&priv->dev_lock);
return 0;
}
@@ -4019,18 +4166,22 @@ static ssize_t icnss_regread_write(struct file *fp, const char __user *user_buf,
data_len > QMI_WLFW_MAX_DATA_SIZE_V01)
return -EINVAL;
+ mutex_lock(&priv->dev_lock);
kfree(priv->diag_reg_read_buf);
priv->diag_reg_read_buf = NULL;
reg_buf = kzalloc(data_len, GFP_KERNEL);
- if (!reg_buf)
+ if (!reg_buf) {
+ mutex_unlock(&priv->dev_lock);
return -ENOMEM;
+ }
ret = wlfw_athdiag_read_send_sync_msg(priv, reg_offset,
mem_type, data_len,
reg_buf);
if (ret) {
kfree(reg_buf);
+ mutex_unlock(&priv->dev_lock);
return ret;
}
@@ -4038,6 +4189,7 @@ static ssize_t icnss_regread_write(struct file *fp, const char __user *user_buf,
priv->diag_reg_read_mem_type = mem_type;
priv->diag_reg_read_len = data_len;
priv->diag_reg_read_buf = reg_buf;
+ mutex_unlock(&priv->dev_lock);
return count;
}
@@ -4317,6 +4469,7 @@ static int icnss_probe(struct platform_device *pdev)
spin_lock_init(&priv->event_lock);
spin_lock_init(&priv->on_off_lock);
+ mutex_init(&priv->dev_lock);
priv->event_wq = alloc_workqueue("icnss_driver_event", WQ_UNBOUND, 1);
if (!priv->event_wq) {
diff --git a/drivers/soc/qcom/llcc-sdm845.c b/drivers/soc/qcom/llcc-sdm845.c
index be2b7da..739c053 100644
--- a/drivers/soc/qcom/llcc-sdm845.c
+++ b/drivers/soc/qcom/llcc-sdm845.c
@@ -57,23 +57,23 @@
}
static struct llcc_slice_config sdm845_data[] = {
- SCT_ENTRY("cpuss", 1, 1, 3072, 1, 0, 0xFFF, 0x0, 0, 0, 0, 1, 1),
- SCT_ENTRY("vidsc0", 2, 2, 512, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("vidsc1", 3, 3, 512, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("rotator", 4, 4, 563, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("voice", 5, 5, 3072, 1, 0, 0xFFF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("audio", 6, 6, 3072, 1, 0, 0xFFF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("modemhp_grow", 7, 7, 1024, 2, 0, 0xFFF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("modem", 8, 8, 3072, 1, 0, 0xFFF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("compute", 10, 10, 3072, 1, 0, 0xFFF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("gpuhtw", 11, 11, 515, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("gpu", 12, 12, 2560, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("mmuhwt", 13, 13, 3072, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1),
- SCT_ENTRY("compute_dma", 15, 15, 3072, 1, 0, 0xFFF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("display", 16, 16, 3072, 1, 0, 0xFFF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("modemhp_fix", 20, 20, 1024, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("modem_paging", 21, 21, 1024, 0, 1, 0xF, 0x0, 0, 0, 0, 1, 0),
- SCT_ENTRY("audiohw", 22, 22, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0),
+ SCT_ENTRY("cpuss", 1, 1, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 1),
+ SCT_ENTRY("vidsc0", 2, 2, 512, 2, 1, 0x0, 0x0F0, 0, 0, 1, 1, 0),
+ SCT_ENTRY("vidsc1", 3, 3, 512, 2, 1, 0x0, 0x0F0, 0, 0, 1, 1, 0),
+ SCT_ENTRY("rotator", 4, 4, 563, 2, 1, 0x0, 0x00F, 2, 0, 1, 1, 0),
+ SCT_ENTRY("voice", 5, 5, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
+ SCT_ENTRY("audio", 6, 6, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
+ SCT_ENTRY("modemhp_grow", 7, 7, 1024, 2, 0, 0x0F0, 0xF0F, 0, 0, 1, 1, 0),
+ SCT_ENTRY("modem", 8, 8, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
+ SCT_ENTRY("compute", 10, 10, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
+ SCT_ENTRY("gpuhtw", 11, 11, 512, 1, 1, 0x0, 0xC, 0, 0, 1, 1, 0),
+ SCT_ENTRY("gpu", 12, 12, 2560, 1, 0, 0xFF0, 0x3, 0, 0, 1, 1, 0),
+ SCT_ENTRY("mmuhwt", 13, 13, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 0, 1),
+ SCT_ENTRY("compute_dma", 15, 15, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
+ SCT_ENTRY("display", 16, 16, 3072, 1, 0, 0xFF0, 0xF, 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("audiohw", 22, 22, 1024, 1, 1, 0xFF0, 0xF, 0, 0, 1, 1, 0),
};
static int sdm845_qcom_llcc_probe(struct platform_device *pdev)
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
index e90012d..aa6c5d7 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
@@ -40,8 +40,6 @@ struct handle_type {
};
static struct handle_type handle_list;
-static LIST_HEAD(input_list);
-static LIST_HEAD(apply_list);
static LIST_HEAD(commit_list);
static LIST_HEAD(late_init_clist);
static LIST_HEAD(query_list);
@@ -780,77 +778,9 @@ static void aggregate_bus_query_req(struct msm_bus_node_device_type *bus_dev,
return;
}
-static void del_inp_list(struct list_head *list)
-{
- struct rule_update_path_info *rule_node;
- struct rule_update_path_info *rule_node_tmp;
-
- list_for_each_entry_safe(rule_node, rule_node_tmp, list, link) {
- list_del(&rule_node->link);
- rule_node->added = false;
- }
-}
-
-static void del_op_list(struct list_head *list)
-{
- struct rule_apply_rcm_info *rule;
- struct rule_apply_rcm_info *rule_tmp;
-
- list_for_each_entry_safe(rule, rule_tmp, list, link)
- list_del(&rule->link);
-}
-
-static int msm_bus_apply_rules(struct list_head *list, bool after_clk_commit)
-{
- struct rule_apply_rcm_info *rule;
- struct device *dev = NULL;
- struct msm_bus_node_device_type *dev_info = NULL;
- int ret = 0;
-
- list_for_each_entry(rule, list, link) {
- if (!rule)
- continue;
-
- if (rule && (rule->after_clk_commit != after_clk_commit))
- continue;
-
- dev = bus_find_device(&msm_bus_type, NULL,
- (void *) &rule->id,
- msm_bus_device_match_adhoc);
-
- if (!dev) {
- MSM_BUS_ERR("Can't find dev node for %d", rule->id);
- continue;
- }
- dev_info = to_msm_bus_node(dev);
-
- ret = msm_bus_enable_limiter(dev_info, rule->throttle,
- rule->lim_bw);
- if (ret)
- MSM_BUS_ERR("Failed to set limiter for %d", rule->id);
- }
-
- return ret;
-}
-
static void commit_data(void)
{
- bool rules_registered = msm_rule_are_rules_registered();
-
- if (rules_registered) {
- msm_rules_update_path(&input_list, &apply_list);
- msm_bus_apply_rules(&apply_list, false);
- }
-
msm_bus_commit_data(&commit_list);
-
- if (rules_registered) {
- msm_bus_apply_rules(&apply_list, true);
- del_inp_list(&input_list);
- del_op_list(&apply_list);
- }
- INIT_LIST_HEAD(&input_list);
- INIT_LIST_HEAD(&apply_list);
INIT_LIST_HEAD(&commit_list);
}
@@ -909,8 +839,6 @@ static int update_path(struct device *src_dev, int dest, uint64_t act_req_ib,
struct msm_bus_node_device_type *dev_info = NULL;
int curr_idx;
int ret = 0;
- struct rule_update_path_info *rule_node;
- bool rules_registered = msm_rule_are_rules_registered();
if (IS_ERR_OR_NULL(src_dev)) {
MSM_BUS_ERR("%s: No source device", __func__);
@@ -958,19 +886,6 @@ static int update_path(struct device *src_dev, int dest, uint64_t act_req_ib,
add_node_to_clist(dev_info);
- if (rules_registered) {
- rule_node = &dev_info->node_info->rule;
- rule_node->id = dev_info->node_info->id;
- rule_node->ib = dev_info->node_bw[ACTIVE_CTX].max_ib;
- rule_node->ab = dev_info->node_bw[ACTIVE_CTX].sum_ab;
- rule_node->clk =
- dev_info->node_bw[ACTIVE_CTX].cur_clk_hz;
- if (!rule_node->added) {
- list_add_tail(&rule_node->link, &input_list);
- rule_node->added = true;
- }
- }
-
next_dev = lnode->next_dev;
curr_idx = lnode->next;
}
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 36c0154..185d862 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -596,8 +596,16 @@ int msm_bus_commit_data(struct list_head *clist)
}
n_active = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
+ if (!n_active)
+ return -ENOMEM;
+
n_wake = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
+ if (!n_wake)
+ return -ENOMEM;
+
n_sleep = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
+ if (!n_sleep)
+ return -ENOMEM;
if (cnt_active)
cmdlist_active = kcalloc(cnt_active, sizeof(struct tcs_cmd),
@@ -612,18 +620,32 @@ int msm_bus_commit_data(struct list_head *clist)
cmdlist_wake, cmdlist_sleep, cur_bcm_clist);
ret = rpmh_invalidate(cur_mbox);
+ if (ret)
+ MSM_BUS_ERR("%s: Error invalidating mbox: %d\n",
+ __func__, ret);
+
if (cur_rsc->rscdev->req_state == RPMH_AWAKE_STATE)
ret = rpmh_write(cur_mbox, cur_rsc->rscdev->req_state,
cmdlist_active, cnt_active);
else
ret = rpmh_write_passthru(cur_mbox, cur_rsc->rscdev->req_state,
cmdlist_active, n_active);
+ if (ret)
+ MSM_BUS_ERR("%s: error sending active/awake sets: %d\n",
+ __func__, ret);
+
ret = rpmh_write_passthru(cur_mbox, RPMH_WAKE_ONLY_STATE,
cmdlist_wake, n_wake);
+ if (ret)
+ MSM_BUS_ERR("%s: error sending wake sets: %d\n",
+ __func__, ret);
ret = rpmh_write_passthru(cur_mbox, RPMH_SLEEP_STATE,
cmdlist_sleep, n_sleep);
+ if (ret)
+ MSM_BUS_ERR("%s: error sending sleep sets: %d\n",
+ __func__, ret);
list_for_each_entry_safe(node, node_tmp, clist, link) {
bcm_clist_clean(node);
@@ -746,18 +768,16 @@ static void msm_bus_fab_init_noc_ops(struct msm_bus_node_device_type *bus_dev)
static int msm_bus_disable_node_qos_clk(struct msm_bus_node_device_type *node)
{
- struct msm_bus_node_device_type *bus_node = NULL;
int i;
int ret = 0;
- if (!node || (!to_msm_bus_node(node->node_info->bus_device))) {
+ if (!node) {
ret = -ENXIO;
goto exit_disable_node_qos_clk;
}
- bus_node = to_msm_bus_node(node->node_info->bus_device);
- for (i = 0; i < bus_node->num_node_qos_clks; i++)
- ret = disable_nodeclk(&bus_node->node_qos_clks[i]);
+ for (i = 0; i < node->num_node_qos_clks; i++)
+ ret = disable_nodeclk(&node->node_qos_clks[i]);
exit_disable_node_qos_clk:
return ret;
@@ -766,7 +786,7 @@ static int msm_bus_disable_node_qos_clk(struct msm_bus_node_device_type *node)
static int msm_bus_enable_node_qos_clk(struct msm_bus_node_device_type *node)
{
int i;
- int ret;
+ int ret = 0;
long rounded_rate;
for (i = 0; i < node->num_node_qos_clks; i++) {
@@ -1345,7 +1365,7 @@ static int msm_bus_copy_node_info(struct msm_bus_node_device_type *pdata,
node_info->bcm_dev_ids = devm_kzalloc(bus_dev,
sizeof(int) * pdata_node_info->num_bcm_devs,
GFP_KERNEL);
- if (!node_info->bcm_devs) {
+ if (!node_info->bcm_dev_ids) {
MSM_BUS_ERR("%s:Bus connections alloc failed\n", __func__);
devm_kfree(bus_dev, node_info->bcm_devs);
ret = -ENOMEM;
@@ -1369,7 +1389,7 @@ static int msm_bus_copy_node_info(struct msm_bus_node_device_type *pdata,
node_info->rsc_dev_ids = devm_kzalloc(bus_dev,
sizeof(int) * pdata_node_info->num_rsc_devs,
GFP_KERNEL);
- if (!node_info->rsc_devs) {
+ if (!node_info->rsc_dev_ids) {
MSM_BUS_ERR("%s:Bus connections alloc failed\n", __func__);
devm_kfree(bus_dev, node_info->rsc_devs);
ret = -ENOMEM;
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
index 42a6f58..77cbbf1 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
@@ -47,7 +47,7 @@ static int *get_arr(struct platform_device *pdev,
}
arr = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
- if ((size > 0) && ZERO_OR_NULL_PTR(arr)) {
+ if (ZERO_OR_NULL_PTR(arr)) {
dev_err(&pdev->dev, "Error: Failed to alloc mem for %s\n",
prop);
return NULL;
diff --git a/drivers/soc/qcom/qmp-debugfs-client.c b/drivers/soc/qcom/qmp-debugfs-client.c
new file mode 100644
index 0000000..578e7f0
--- /dev/null
+++ b/drivers/soc/qcom/qmp-debugfs-client.c
@@ -0,0 +1,105 @@
+/* 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mailbox_client.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/mailbox/qmp.h>
+#include <linux/uaccess.h>
+
+#define MAX_MSG_SIZE 96 /* Imposed by the remote*/
+
+static struct mbox_chan *chan;
+static struct mbox_client *cl;
+
+static ssize_t aop_msg_write(struct file *file, const char __user *userstr,
+ size_t len, loff_t *pos)
+{
+ char buf[MAX_MSG_SIZE + 1] = {0};
+ struct qmp_pkt pkt;
+ int rc;
+
+ if (!len || (len > MAX_MSG_SIZE))
+ return len;
+
+ rc = copy_from_user(buf, userstr, len);
+ if (rc) {
+ pr_err("%s copy from user failed, rc=%d\n", __func__, rc);
+ return len;
+ }
+
+ /*
+ * Controller expects a 4 byte aligned buffer
+ */
+ pkt.size = (len + 0x3) & ~0x3;
+ pkt.data = buf;
+
+ if (mbox_send_message(chan, &pkt) < 0)
+ pr_err("Failed to send qmp request\n");
+
+ return len;
+}
+
+static const struct file_operations aop_msg_fops = {
+ .write = aop_msg_write,
+};
+
+static int qmp_msg_probe(struct platform_device *pdev)
+{
+ struct dentry *file;
+
+ cl = devm_kzalloc(&pdev->dev, sizeof(*cl), GFP_KERNEL);
+ if (!cl)
+ return -ENOMEM;
+
+ cl->dev = &pdev->dev;
+ cl->tx_block = true;
+ cl->tx_tout = 100;
+ cl->knows_txdone = false;
+
+ chan = mbox_request_channel(cl, 0);
+ if (IS_ERR(chan)) {
+ dev_err(&pdev->dev, "Failed to mbox channel\n");
+ return PTR_ERR(chan);
+ }
+
+ file = debugfs_create_file("aop_send_message", 0220, NULL, NULL,
+ &aop_msg_fops);
+ if (!file)
+ goto err;
+ return 0;
+err:
+ mbox_free_channel(chan);
+ chan = NULL;
+ return -ENOMEM;
+}
+
+static const struct of_device_id aop_qmp_match_tbl[] = {
+ {.compatible = "qcom,debugfs-qmp-client"},
+ {},
+};
+
+static struct platform_driver aop_qmp_msg_driver = {
+ .probe = qmp_msg_probe,
+ .driver = {
+ .name = "debugfs-qmp-client",
+ .owner = THIS_MODULE,
+ .of_match_table = aop_qmp_match_tbl,
+ },
+};
+
+builtin_platform_driver(aop_qmp_msg_driver);
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 9a98063..17e0a4c 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -32,6 +32,7 @@
#define RPMH_MAX_MBOXES 2
#define RPMH_MAX_FAST_RES 32
#define RPMH_MAX_REQ_IN_BATCH 10
+#define RPMH_TIMEOUT msecs_to_jiffies(10000)
#define DEFINE_RPMH_MSG_ONSTACK(rc, s, q, c, name) \
struct rpmh_msg name = { \
@@ -166,6 +167,41 @@ static void rpmh_tx_done(struct mbox_client *cl, void *msg, int r)
complete(compl);
}
+/**
+ * wait_for_tx_done: Wait forever until the response is received.
+ *
+ * @rc: The RPMH client
+ * @compl: The completion object
+ * @addr: An addr that we sent in that request
+ * @data: The data for the address in that request
+ *
+ */
+static inline void wait_for_tx_done(struct rpmh_client *rc,
+ struct completion *compl, u32 addr, u32 data)
+{
+ int ret;
+ int count = 4;
+
+ do {
+ ret = wait_for_completion_timeout(compl, RPMH_TIMEOUT);
+ if (ret) {
+ if (count != 4)
+ dev_notice(rc->dev,
+ "RPMH response received addr=0x%x data=0x%x\n",
+ addr, data);
+ return;
+ }
+ if (!count) {
+ mbox_chan_debug(rc->chan);
+ } else {
+ dev_err(rc->dev,
+ "RPMH response timeout (%d) addr=0x%x,data=0x%x\n",
+ count, addr, data);
+ count--;
+ }
+ } while (true);
+}
+
static struct rpmh_req *__find_req(struct rpmh_client *rc, u32 addr)
{
struct rpmh_req *p, *req = NULL;
@@ -365,7 +401,7 @@ int rpmh_write_single(struct rpmh_client *rc, enum rpmh_state state,
if (ret < 0)
return ret;
- wait_for_completion(&compl);
+ wait_for_tx_done(rc, &compl, addr, data);
return rpm_msg.err;
}
@@ -469,7 +505,7 @@ int rpmh_write(struct rpmh_client *rc, enum rpmh_state state,
if (ret)
return ret;
- wait_for_completion(&compl);
+ wait_for_tx_done(rc, &compl, cmd[0].addr, cmd[0].data);
return rpm_msg.err;
}
@@ -500,6 +536,7 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state,
int count = 0;
int ret, i, j, k;
bool complete_set;
+ u32 addr, data;
if (IS_ERR_OR_NULL(rc) || !cmd || !n)
return -EINVAL;
@@ -537,6 +574,8 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state,
}
}
+ addr = cmd[0].addr;
+ data = cmd[0].data;
/* Create async request batches */
for (i = 0; i < count; i++) {
rpm_msg[i] = __get_rpmh_msg_async(rc, state, cmd, n[i]);
@@ -566,7 +605,7 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state,
/* For those unsent requests, spoof tx_done */
for (j = i; j < count; j++)
rpmh_tx_done(&rc->client, &rpm_msg[j]->msg, ret);
- wait_for_completion(&compl);
+ wait_for_tx_done(rc, &compl, addr, data);
} else {
/* Send Sleep requests to the controller, expect no response */
for (i = 0; i < count; i++) {
@@ -719,7 +758,7 @@ int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp)
return ret;
/* Wait until the response is received from RPMH */
- wait_for_completion(&compl);
+ wait_for_tx_done(rc, &compl, addr, 0);
/* Read the data back from the tcs_mbox_msg structrure */
*resp = rpm_msg.cmd[0].data;
diff --git a/drivers/soc/qcom/secure_buffer.c b/drivers/soc/qcom/secure_buffer.c
index 63cce5c..49fd7fe 100644
--- a/drivers/soc/qcom/secure_buffer.c
+++ b/drivers/soc/qcom/secure_buffer.c
@@ -380,6 +380,7 @@ int hyp_assign_phys(phys_addr_t addr, u64 size, u32 *source_vm_list,
sg_free_table(&table);
return ret;
}
+EXPORT_SYMBOL(hyp_assign_phys);
const char *msm_secure_vmid_to_string(int secure_vmid)
{
@@ -416,6 +417,8 @@ const char *msm_secure_vmid_to_string(int secure_vmid)
return "VMID_CP_SPSS_SP";
case VMID_CP_SPSS_SP_SHARED:
return "VMID_CP_SPSS_SP_SHARED";
+ case VMID_CP_SPSS_HLOS_SHARED:
+ return "VMID_CP_SPSS_HLOS_SHARED";
case VMID_INVAL:
return "VMID_INVAL";
default:
diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c
new file mode 100644
index 0000000..3f31fb1
--- /dev/null
+++ b/drivers/soc/qcom/smcinvoke.c
@@ -0,0 +1,575 @@
+/*
+ * SMC Invoke driver
+ *
+ * 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
+ * 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/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/anon_inodes.h>
+#include <linux/smcinvoke.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+
+#include <soc/qcom/scm.h>
+#include <asm/cacheflush.h>
+#include <soc/qcom/qseecomi.h>
+
+#include "smcinvoke_object.h"
+#include "../../misc/qseecom_kernel.h"
+
+#define SMCINVOKE_DEV "smcinvoke"
+#define SMCINVOKE_TZ_PARAM_ID 0x224
+#define SMCINVOKE_TZ_CMD 0x32000600
+#define SMCINVOKE_TZ_ROOT_OBJ 1
+#define SMCINVOKE_TZ_MIN_BUF_SIZE 4096
+#define SMCINVOKE_ARGS_ALIGN_SIZE (sizeof(uint64_t))
+#define SMCINVOKE_TZ_OBJ_NULL 0
+
+#define FOR_ARGS(ndxvar, counts, section) \
+ for (ndxvar = object_counts_index_##section(counts); \
+ ndxvar < (object_counts_index_##section(counts) \
+ + object_counts_num_##section(counts)); \
+ ++ndxvar)
+
+static long smcinvoke_ioctl(struct file *, unsigned int, unsigned long);
+static int smcinvoke_open(struct inode *, struct file *);
+static int smcinvoke_release(struct inode *, struct file *);
+
+static const struct file_operations smcinvoke_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = smcinvoke_ioctl,
+ .compat_ioctl = smcinvoke_ioctl,
+ .open = smcinvoke_open,
+ .release = smcinvoke_release,
+};
+
+struct smcinvoke_buf_hdr {
+ uint32_t offset;
+ uint32_t size;
+};
+
+union smcinvoke_tz_args {
+ struct smcinvoke_buf_hdr b;
+ uint32_t tzhandle;
+};
+struct smcinvoke_msg_hdr {
+ uint32_t tzhandle;
+ uint32_t op;
+ uint32_t counts;
+};
+
+struct smcinvoke_tzobj_context {
+ uint32_t tzhandle;
+};
+
+static dev_t smcinvoke_device_no;
+struct cdev smcinvoke_cdev;
+struct class *driver_class;
+struct device *class_dev;
+
+/*
+ * size_add saturates at SIZE_MAX. If integer overflow is detected,
+ * this function would return SIZE_MAX otherwise normal a+b is returned.
+ */
+static inline size_t size_add(size_t a, size_t b)
+{
+ return (b > (SIZE_MAX - a)) ? SIZE_MAX : a + b;
+}
+
+/*
+ * pad_size is used along with size_align to define a buffer overflow
+ * protected version of ALIGN
+ */
+static inline size_t pad_size(size_t a, size_t b)
+{
+ return (~a + 1) % b;
+}
+
+/*
+ * size_align saturates at SIZE_MAX. If integer overflow is detected, this
+ * function would return SIZE_MAX otherwise next aligned size is returned.
+ */
+static inline size_t size_align(size_t a, size_t b)
+{
+ return size_add(a, pad_size(a, b));
+}
+
+/*
+ * This function retrieves file pointer corresponding to FD provided. It stores
+ * retrived file pointer until IOCTL call is concluded. Once call is completed,
+ * all stored file pointers are released. file pointers are stored to prevent
+ * other threads from releasing that FD while IOCTL is in progress.
+ */
+static int get_tzhandle_from_fd(int64_t fd, struct file **filp,
+ uint32_t *tzhandle)
+{
+ int ret = -EBADF;
+ struct file *tmp_filp = NULL;
+ struct smcinvoke_tzobj_context *tzobj = NULL;
+
+ if (fd == SMCINVOKE_USERSPACE_OBJ_NULL) {
+ *tzhandle = SMCINVOKE_TZ_OBJ_NULL;
+ ret = 0;
+ goto out;
+ } else if (fd < SMCINVOKE_USERSPACE_OBJ_NULL) {
+ goto out;
+ }
+
+ tmp_filp = fget(fd);
+ if (!tmp_filp)
+ goto out;
+
+ /* Verify if filp is smcinvoke device's file pointer */
+ if (!tmp_filp->f_op || !tmp_filp->private_data ||
+ (tmp_filp->f_op != &smcinvoke_fops)) {
+ fput(tmp_filp);
+ goto out;
+ }
+
+ tzobj = tmp_filp->private_data;
+ *tzhandle = tzobj->tzhandle;
+ *filp = tmp_filp;
+ ret = 0;
+out:
+ return ret;
+}
+
+static int get_fd_from_tzhandle(uint32_t tzhandle, int64_t *fd)
+{
+ int unused_fd = -1, ret = -1;
+ struct file *f = NULL;
+ struct smcinvoke_tzobj_context *cxt = NULL;
+
+ if (tzhandle == SMCINVOKE_TZ_OBJ_NULL) {
+ *fd = SMCINVOKE_USERSPACE_OBJ_NULL;
+ ret = 0;
+ goto out;
+ }
+
+ cxt = kzalloc(sizeof(*cxt), GFP_KERNEL);
+ if (!cxt) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ unused_fd = get_unused_fd_flags(O_RDWR);
+ if (unused_fd < 0)
+ goto out;
+
+ f = anon_inode_getfile(SMCINVOKE_DEV, &smcinvoke_fops, cxt, O_RDWR);
+ if (IS_ERR(f))
+ goto out;
+
+ *fd = unused_fd;
+ fd_install(*fd, f);
+ ((struct smcinvoke_tzobj_context *)
+ (f->private_data))->tzhandle = tzhandle;
+ return 0;
+out:
+ if (unused_fd >= 0)
+ put_unused_fd(unused_fd);
+ kfree(cxt);
+
+ return ret;
+}
+
+static int prepare_send_scm_msg(const uint8_t *in_buf, size_t in_buf_len,
+ const uint8_t *out_buf, size_t out_buf_len,
+ int32_t *smcinvoke_result)
+{
+ int ret = 0;
+ struct scm_desc desc = {0};
+ size_t inbuf_flush_size = (1UL << get_order(in_buf_len)) * PAGE_SIZE;
+ size_t outbuf_flush_size = (1UL << get_order(out_buf_len)) * PAGE_SIZE;
+
+ desc.arginfo = SMCINVOKE_TZ_PARAM_ID;
+ desc.args[0] = (uint64_t)virt_to_phys(in_buf);
+ desc.args[1] = inbuf_flush_size;
+ desc.args[2] = (uint64_t)virt_to_phys(out_buf);
+ desc.args[3] = outbuf_flush_size;
+
+ dmac_flush_range(in_buf, in_buf + inbuf_flush_size);
+ dmac_flush_range(out_buf, out_buf + outbuf_flush_size);
+
+ ret = scm_call2(SMCINVOKE_TZ_CMD, &desc);
+
+ /* process listener request */
+ if (!ret && (desc.ret[0] == QSEOS_RESULT_INCOMPLETE ||
+ desc.ret[0] == QSEOS_RESULT_BLOCKED_ON_LISTENER))
+ ret = qseecom_process_listener_from_smcinvoke(&desc);
+
+ *smcinvoke_result = (int32_t)desc.ret[1];
+ if (ret || desc.ret[1] || desc.ret[2] || desc.ret[0])
+ pr_err("SCM call failed with ret val = %d %d %d %d\n",
+ ret, (int)desc.ret[0],
+ (int)desc.ret[1], (int)desc.ret[2]);
+
+ dmac_inv_range(in_buf, in_buf + inbuf_flush_size);
+ dmac_inv_range(out_buf, out_buf + outbuf_flush_size);
+ return ret;
+}
+
+static int marshal_out(void *buf, uint32_t buf_size,
+ struct smcinvoke_cmd_req *req,
+ union smcinvoke_arg *args_buf)
+{
+ int ret = -EINVAL, i = 0;
+ union smcinvoke_tz_args *tz_args = NULL;
+ size_t offset = sizeof(struct smcinvoke_msg_hdr) +
+ object_counts_total(req->counts) *
+ sizeof(union smcinvoke_tz_args);
+
+ if (offset > buf_size)
+ goto out;
+
+ tz_args = (union smcinvoke_tz_args *)
+ (buf + sizeof(struct smcinvoke_msg_hdr));
+
+ tz_args += object_counts_num_BI(req->counts);
+
+ FOR_ARGS(i, req->counts, BO) {
+ args_buf[i].b.size = tz_args->b.size;
+ if ((buf_size - tz_args->b.offset < tz_args->b.size) ||
+ tz_args->b.offset > buf_size) {
+ pr_err("%s: buffer overflow detected\n", __func__);
+ goto out;
+ }
+ if (copy_to_user((void __user *)(uintptr_t)(args_buf[i].b.addr),
+ (uint8_t *)(buf) + tz_args->b.offset,
+ tz_args->b.size)) {
+ pr_err("Error %d copying ctxt to user\n", ret);
+ goto out;
+ }
+ tz_args++;
+ }
+ tz_args += object_counts_num_OI(req->counts);
+
+ FOR_ARGS(i, req->counts, OO) {
+ /*
+ * create a new FD and assign to output object's
+ * context
+ */
+ ret = get_fd_from_tzhandle(tz_args->tzhandle,
+ &(args_buf[i].o.fd));
+ if (ret)
+ goto out;
+ tz_args++;
+ }
+ ret = 0;
+out:
+ return ret;
+}
+
+/*
+ * SMC expects arguments in following format
+ * ---------------------------------------------------------------------------
+ * | cxt | op | counts | ptr|size |ptr|size...|ORef|ORef|...| rest of payload |
+ * ---------------------------------------------------------------------------
+ * cxt: target, op: operation, counts: total arguments
+ * offset: offset is from beginning of buffer i.e. cxt
+ * size: size is 8 bytes aligned value
+ */
+static size_t compute_in_msg_size(const struct smcinvoke_cmd_req *req,
+ const union smcinvoke_arg *args_buf)
+{
+ uint32_t i = 0;
+
+ size_t total_size = sizeof(struct smcinvoke_msg_hdr) +
+ object_counts_total(req->counts) *
+ sizeof(union smcinvoke_tz_args);
+
+ /* Computed total_size should be 8 bytes aligned from start of buf */
+ total_size = ALIGN(total_size, SMCINVOKE_ARGS_ALIGN_SIZE);
+
+ /* each buffer has to be 8 bytes aligned */
+ while (i < object_counts_num_buffers(req->counts))
+ total_size = size_add(total_size,
+ size_align(args_buf[i++].b.size, SMCINVOKE_ARGS_ALIGN_SIZE));
+
+ /* Since we're using get_free_pages, no need for explicit PAGE align */
+ return total_size;
+}
+
+static int marshal_in(const struct smcinvoke_cmd_req *req,
+ const union smcinvoke_arg *args_buf, uint32_t tzhandle,
+ uint8_t *buf, size_t buf_size, struct file **arr_filp)
+{
+ int ret = -EINVAL, i = 0;
+ union smcinvoke_tz_args *tz_args = NULL;
+ struct smcinvoke_msg_hdr msg_hdr = {tzhandle, req->op, req->counts};
+ uint32_t offset = sizeof(struct smcinvoke_msg_hdr) +
+ sizeof(union smcinvoke_tz_args) *
+ object_counts_total(req->counts);
+
+ if (buf_size < offset)
+ goto out;
+
+ *(struct smcinvoke_msg_hdr *)buf = msg_hdr;
+ tz_args = (union smcinvoke_tz_args *)
+ (buf + sizeof(struct smcinvoke_msg_hdr));
+
+ FOR_ARGS(i, req->counts, BI) {
+ offset = size_align(offset, SMCINVOKE_ARGS_ALIGN_SIZE);
+ if ((offset > buf_size) ||
+ (args_buf[i].b.size > (buf_size - offset)))
+ goto out;
+
+ tz_args->b.offset = offset;
+ tz_args->b.size = args_buf[i].b.size;
+ tz_args++;
+
+ if (copy_from_user(buf+offset,
+ (void __user *)(uintptr_t)(args_buf[i].b.addr),
+ args_buf[i].b.size))
+ goto out;
+
+ offset += args_buf[i].b.size;
+ }
+ FOR_ARGS(i, req->counts, BO) {
+ offset = size_align(offset, SMCINVOKE_ARGS_ALIGN_SIZE);
+ if ((offset > buf_size) ||
+ (args_buf[i].b.size > (buf_size - offset)))
+ goto out;
+
+ tz_args->b.offset = offset;
+ tz_args->b.size = args_buf[i].b.size;
+ tz_args++;
+
+ offset += args_buf[i].b.size;
+ }
+ FOR_ARGS(i, req->counts, OI) {
+ if (get_tzhandle_from_fd(args_buf[i].o.fd,
+ &arr_filp[i], &(tz_args->tzhandle)))
+ goto out;
+ tz_args++;
+ }
+ ret = 0;
+out:
+ return ret;
+}
+
+long smcinvoke_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int ret = -1, i = 0, nr_args = 0;
+ struct smcinvoke_cmd_req req = {0};
+ void *in_msg = NULL;
+ size_t inmsg_size = 0;
+ void *out_msg = NULL;
+ union smcinvoke_arg *args_buf = NULL;
+ struct file *filp_to_release[object_counts_max_OO] = {NULL};
+ struct smcinvoke_tzobj_context *tzobj = filp->private_data;
+
+ switch (cmd) {
+ case SMCINVOKE_IOCTL_INVOKE_REQ:
+ if (_IOC_SIZE(cmd) != sizeof(req)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = copy_from_user(&req, (void __user *)arg, sizeof(req));
+ if (ret) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ nr_args = object_counts_num_buffers(req.counts) +
+ object_counts_num_objects(req.counts);
+
+ if (req.argsize != sizeof(union smcinvoke_arg)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (nr_args) {
+
+ args_buf = kzalloc(nr_args * req.argsize, GFP_KERNEL);
+ if (!args_buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = copy_from_user(args_buf,
+ (void __user *)(uintptr_t)(req.args),
+ nr_args * req.argsize);
+
+ if (ret) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+
+ inmsg_size = compute_in_msg_size(&req, args_buf);
+ in_msg = (void *)__get_free_pages(GFP_KERNEL,
+ get_order(inmsg_size));
+ if (!in_msg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ out_msg = (void *)__get_free_page(GFP_KERNEL);
+ if (!out_msg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = marshal_in(&req, args_buf, tzobj->tzhandle, in_msg,
+ inmsg_size, filp_to_release);
+ if (ret)
+ goto out;
+
+ ret = prepare_send_scm_msg(in_msg, inmsg_size, out_msg,
+ SMCINVOKE_TZ_MIN_BUF_SIZE, &req.result);
+ if (ret)
+ goto out;
+
+ /*
+ * if invoke op results in an err, no need to marshal_out and
+ * copy args buf to user space
+ */
+ if (!req.result) {
+ ret = marshal_out(in_msg, inmsg_size, &req, args_buf);
+
+ ret |= copy_to_user(
+ (void __user *)(uintptr_t)(req.args),
+ args_buf, nr_args * req.argsize);
+ }
+ ret |= copy_to_user((void __user *)arg, &req, sizeof(req));
+ if (ret)
+ goto out;
+
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+out:
+ free_page((long)out_msg);
+ free_pages((long)in_msg, get_order(inmsg_size));
+ kfree(args_buf);
+ for (i = 0; i < object_counts_max_OO; i++) {
+ if (filp_to_release[i])
+ fput(filp_to_release[i]);
+ }
+
+ return ret;
+}
+
+static int smcinvoke_open(struct inode *nodp, struct file *filp)
+{
+ struct smcinvoke_tzobj_context *tzcxt = NULL;
+
+ tzcxt = kzalloc(sizeof(*tzcxt), GFP_KERNEL);
+ if (!tzcxt)
+ return -ENOMEM;
+
+ tzcxt->tzhandle = SMCINVOKE_TZ_ROOT_OBJ;
+ filp->private_data = tzcxt;
+
+ return 0;
+}
+
+static int smcinvoke_release(struct inode *nodp, struct file *filp)
+{
+ int ret = 0, smcinvoke_result = 0;
+ uint8_t *in_buf = NULL;
+ uint8_t *out_buf = NULL;
+ struct smcinvoke_msg_hdr hdr = {0};
+ struct smcinvoke_tzobj_context *tzobj = filp->private_data;
+ uint32_t tzhandle = tzobj->tzhandle;
+
+ /* Root object is special in sense it is indestructible */
+ if (!tzhandle || tzhandle == SMCINVOKE_TZ_ROOT_OBJ)
+ goto out;
+
+ in_buf = (uint8_t *)__get_free_page(GFP_KERNEL);
+ out_buf = (uint8_t *)__get_free_page(GFP_KERNEL);
+ if (!in_buf || !out_buf)
+ goto out;
+
+ hdr.tzhandle = tzhandle;
+ hdr.op = object_op_RELEASE;
+ hdr.counts = 0;
+ *(struct smcinvoke_msg_hdr *)in_buf = hdr;
+
+ ret = prepare_send_scm_msg(in_buf, SMCINVOKE_TZ_MIN_BUF_SIZE,
+ out_buf, SMCINVOKE_TZ_MIN_BUF_SIZE, &smcinvoke_result);
+out:
+ kfree(filp->private_data);
+ free_page((long)in_buf);
+ free_page((long)out_buf);
+
+ return ret;
+}
+
+static int __init smcinvoke_init(void)
+{
+ unsigned int baseminor = 0;
+ unsigned int count = 1;
+ int rc = 0;
+
+ rc = alloc_chrdev_region(&smcinvoke_device_no, baseminor, count,
+ SMCINVOKE_DEV);
+ if (rc < 0) {
+ pr_err("chrdev_region failed %d for %s\n", rc, SMCINVOKE_DEV);
+ return rc;
+ }
+ driver_class = class_create(THIS_MODULE, SMCINVOKE_DEV);
+ if (IS_ERR(driver_class)) {
+ rc = -ENOMEM;
+ pr_err("class_create failed %d\n", rc);
+ goto exit_unreg_chrdev_region;
+ }
+ class_dev = device_create(driver_class, NULL, smcinvoke_device_no,
+ NULL, SMCINVOKE_DEV);
+ if (!class_dev) {
+ pr_err("class_device_create failed %d\n", rc);
+ rc = -ENOMEM;
+ goto exit_destroy_class;
+ }
+
+ cdev_init(&smcinvoke_cdev, &smcinvoke_fops);
+ smcinvoke_cdev.owner = THIS_MODULE;
+
+ rc = cdev_add(&smcinvoke_cdev, MKDEV(MAJOR(smcinvoke_device_no), 0),
+ count);
+ if (rc < 0) {
+ pr_err("cdev_add failed %d for %s\n", rc, SMCINVOKE_DEV);
+ goto exit_destroy_device;
+ }
+ return 0;
+
+exit_destroy_device:
+ device_destroy(driver_class, smcinvoke_device_no);
+exit_destroy_class:
+ class_destroy(driver_class);
+exit_unreg_chrdev_region:
+ unregister_chrdev_region(smcinvoke_device_no, count);
+
+ return rc;
+}
+
+static void __exit smcinvoke_exit(void)
+{
+ int count = 1;
+
+ cdev_del(&smcinvoke_cdev);
+ device_destroy(driver_class, smcinvoke_device_no);
+ class_destroy(driver_class);
+ unregister_chrdev_region(smcinvoke_device_no, count);
+}
+device_initcall(smcinvoke_init);
+module_exit(smcinvoke_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SMC Invoke driver");
diff --git a/drivers/soc/qcom/smcinvoke_object.h b/drivers/soc/qcom/smcinvoke_object.h
new file mode 100644
index 0000000..670b425
--- /dev/null
+++ b/drivers/soc/qcom/smcinvoke_object.h
@@ -0,0 +1,51 @@
+/* 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
+ * 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 __SMCINVOKE_OBJECT_H
+#define __SMCINVOKE_OBJECT_H
+
+#include <linux/types.h>
+
+#define object_op_METHOD_MASK ((uint32_t)0x0000FFFFu)
+#define object_op_RELEASE (object_op_METHOD_MASK - 0)
+#define object_op_RETAIN (object_op_METHOD_MASK - 1)
+
+#define object_counts_max_BI 0xF
+#define object_counts_max_BO 0xF
+#define object_counts_max_OI 0xF
+#define object_counts_max_OO 0xF
+
+/* unpack counts */
+
+#define object_counts_num_BI(k) ((size_t) (((k) >> 0) & object_counts_max_BI))
+#define object_counts_num_BO(k) ((size_t) (((k) >> 4) & object_counts_max_BO))
+#define object_counts_num_OI(k) ((size_t) (((k) >> 8) & object_counts_max_OI))
+#define object_counts_num_OO(k) ((size_t) (((k) >> 12) & object_counts_max_OO))
+#define object_counts_num_buffers(k) \
+ (object_counts_num_BI(k) + object_counts_num_BO(k))
+
+#define object_counts_num_objects(k) \
+ (object_counts_num_OI(k) + object_counts_num_OO(k))
+
+/* Indices into args[] */
+
+#define object_counts_index_BI(k) 0
+#define object_counts_index_BO(k) \
+ (object_counts_index_BI(k) + object_counts_num_BI(k))
+#define object_counts_index_OI(k) \
+ (object_counts_index_BO(k) + object_counts_num_BO(k))
+#define object_counts_index_OO(k) \
+ (object_counts_index_OI(k) + object_counts_num_OI(k))
+#define object_counts_total(k) \
+ (object_counts_index_OO(k) + object_counts_num_OO(k))
+
+
+#endif /* __SMCINVOKE_OBJECT_H */
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index c252040..31760ee 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -47,6 +47,7 @@
#define SMEM_IMAGE_VERSION_OEM_OFFSET 96
#define SMEM_IMAGE_VERSION_PARTITION_APPS 10
+static DECLARE_RWSEM(current_image_rwsem);
enum {
HW_PLATFORM_UNKNOWN = 0,
HW_PLATFORM_SURF = 1,
@@ -1047,7 +1048,9 @@ msm_get_image_version(struct device *dev,
pr_err("Failed to get image version base address");
return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "Unknown");
}
+ down_read(¤t_image_rwsem);
string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(¤t_image_rwsem);
return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s\n",
string_address);
}
@@ -1060,14 +1063,19 @@ msm_set_image_version(struct device *dev,
{
char *store_address;
- if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+ down_read(¤t_image_rwsem);
+ if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) {
+ up_read(¤t_image_rwsem);
return count;
+ }
store_address = socinfo_get_image_version_base_address();
if (IS_ERR_OR_NULL(store_address)) {
pr_err("Failed to get image version base address");
+ up_read(¤t_image_rwsem);
return count;
}
store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(¤t_image_rwsem);
snprintf(store_address, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s", buf);
return count;
}
@@ -1085,7 +1093,9 @@ msm_get_image_variant(struct device *dev,
return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE,
"Unknown");
}
+ down_read(¤t_image_rwsem);
string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(¤t_image_rwsem);
string_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET;
return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s\n",
string_address);
@@ -1099,14 +1109,19 @@ msm_set_image_variant(struct device *dev,
{
char *store_address;
- if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+ down_read(¤t_image_rwsem);
+ if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) {
+ up_read(¤t_image_rwsem);
return count;
+ }
store_address = socinfo_get_image_version_base_address();
if (IS_ERR_OR_NULL(store_address)) {
pr_err("Failed to get image version base address");
+ up_read(¤t_image_rwsem);
return count;
}
store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(¤t_image_rwsem);
store_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET;
snprintf(store_address, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s", buf);
return count;
@@ -1124,7 +1139,9 @@ msm_get_image_crm_version(struct device *dev,
pr_err("Failed to get image version base address");
return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "Unknown");
}
+ down_read(¤t_image_rwsem);
string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(¤t_image_rwsem);
string_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s\n",
string_address);
@@ -1138,14 +1155,19 @@ msm_set_image_crm_version(struct device *dev,
{
char *store_address;
- if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+ down_read(¤t_image_rwsem);
+ if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) {
+ up_read(¤t_image_rwsem);
return count;
+ }
store_address = socinfo_get_image_version_base_address();
if (IS_ERR_OR_NULL(store_address)) {
pr_err("Failed to get image version base address");
+ up_read(¤t_image_rwsem);
return count;
}
store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(¤t_image_rwsem);
store_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s", buf);
return count;
@@ -1156,8 +1178,14 @@ msm_get_image_number(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ int ret;
+
+ down_read(¤t_image_rwsem);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n",
current_image);
+ up_read(¤t_image_rwsem);
+ return ret;
+
}
static ssize_t
@@ -1169,10 +1197,12 @@ msm_select_image(struct device *dev, struct device_attribute *attr,
ret = kstrtoint(buf, 10, &digit);
if (ret)
return ret;
+ down_write(¤t_image_rwsem);
if (digit >= 0 && digit < SMEM_IMAGE_VERSION_BLOCKS_COUNT)
current_image = digit;
else
current_image = 0;
+ up_write(¤t_image_rwsem);
return count;
}
diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h
index ba92ed9..aa2d2d7 100644
--- a/drivers/staging/android/ion/ion_priv.h
+++ b/drivers/staging/android/ion/ion_priv.h
@@ -293,6 +293,7 @@ long msm_ion_custom_ioctl(struct ion_client *client,
int ion_heap_is_system_secure_heap_type(enum ion_heap_type type);
int get_secure_vmid(unsigned long flags);
+int get_vmid(unsigned long flags);
bool is_secure_vmid_valid(int vmid);
unsigned int count_set_bits(unsigned long val);
int populate_vm_list(unsigned long flags, unsigned int *vm_list, int nelems);
diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c
index 52926f0..c7b58ce 100644
--- a/drivers/staging/android/ion/msm/msm_ion.c
+++ b/drivers/staging/android/ion/msm/msm_ion.c
@@ -621,7 +621,8 @@ bool is_secure_vmid_valid(int vmid)
vmid == VMID_CP_APP ||
vmid == VMID_CP_CAMERA_PREVIEW ||
vmid == VMID_CP_SPSS_SP ||
- vmid == VMID_CP_SPSS_SP_SHARED);
+ vmid == VMID_CP_SPSS_SP_SHARED ||
+ vmid == VMID_CP_SPSS_HLOS_SHARED);
}
unsigned int count_set_bits(unsigned long val)
@@ -637,7 +638,7 @@ int populate_vm_list(unsigned long flags, unsigned int *vm_list,
flags = flags & ION_FLAGS_CP_MASK;
for_each_set_bit(itr, &flags, BITS_PER_LONG) {
- vmid = get_secure_vmid(0x1UL << itr);
+ vmid = get_vmid(0x1UL << itr);
if (vmid < 0 || !nelems)
return -EINVAL;
@@ -669,8 +670,23 @@ int get_secure_vmid(unsigned long flags)
return VMID_CP_SPSS_SP;
if (flags & ION_FLAG_CP_SPSS_SP_SHARED)
return VMID_CP_SPSS_SP_SHARED;
+ if (flags & ION_FLAG_CP_SPSS_HLOS_SHARED)
+ return VMID_CP_SPSS_HLOS_SHARED;
return -EINVAL;
}
+
+int get_vmid(unsigned long flags)
+{
+ int vmid;
+
+ vmid = get_secure_vmid(flags);
+ if (vmid < 0) {
+ if (flags & ION_FLAG_CP_HLOS)
+ vmid = VMID_HLOS;
+ }
+ return vmid;
+}
+
/* fix up the cases where the ioctl direction bits are incorrect */
static unsigned int msm_ion_ioctl_dir(unsigned int cmd)
{
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 9846c51..c0cda28 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -42,6 +42,21 @@
#include <linux/rcupdate.h>
#include <linux/profile.h>
#include <linux/notifier.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/swap.h>
+#include <linux/fs.h>
+#include <linux/cpuset.h>
+#include <linux/vmpressure.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/almk.h>
+
+#ifdef CONFIG_HIGHMEM
+#define _ZONE ZONE_HIGHMEM
+#else
+#define _ZONE ZONE_NORMAL
+#endif
#define CREATE_TRACE_POINTS
#include "trace/lowmemorykiller.h"
@@ -63,6 +78,7 @@ static int lowmem_minfree[6] = {
};
static int lowmem_minfree_size = 4;
+static int lmk_fast_run = 1;
static unsigned long lowmem_deathpending_timeout;
@@ -81,6 +97,314 @@ static unsigned long lowmem_count(struct shrinker *s,
global_node_page_state(NR_INACTIVE_FILE);
}
+static atomic_t shift_adj = ATOMIC_INIT(0);
+static short adj_max_shift = 353;
+module_param_named(adj_max_shift, adj_max_shift, short, 0644);
+
+/* User knob to enable/disable adaptive lmk feature */
+static int enable_adaptive_lmk;
+module_param_named(enable_adaptive_lmk, enable_adaptive_lmk, int, 0644);
+
+/*
+ * This parameter controls the behaviour of LMK when vmpressure is in
+ * the range of 90-94. Adaptive lmk triggers based on number of file
+ * pages wrt vmpressure_file_min, when vmpressure is in the range of
+ * 90-94. Usually this is a pseudo minfree value, higher than the
+ * highest configured value in minfree array.
+ */
+static int vmpressure_file_min;
+module_param_named(vmpressure_file_min, vmpressure_file_min, int, 0644);
+
+enum {
+ VMPRESSURE_NO_ADJUST = 0,
+ VMPRESSURE_ADJUST_ENCROACH,
+ VMPRESSURE_ADJUST_NORMAL,
+};
+
+static int adjust_minadj(short *min_score_adj)
+{
+ int ret = VMPRESSURE_NO_ADJUST;
+
+ if (!enable_adaptive_lmk)
+ return 0;
+
+ if (atomic_read(&shift_adj) &&
+ (*min_score_adj > adj_max_shift)) {
+ if (*min_score_adj == OOM_SCORE_ADJ_MAX + 1)
+ ret = VMPRESSURE_ADJUST_ENCROACH;
+ else
+ ret = VMPRESSURE_ADJUST_NORMAL;
+ *min_score_adj = adj_max_shift;
+ }
+ atomic_set(&shift_adj, 0);
+
+ return ret;
+}
+
+static int lmk_vmpressure_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ int other_free, other_file;
+ unsigned long pressure = action;
+ int array_size = ARRAY_SIZE(lowmem_adj);
+
+ if (!enable_adaptive_lmk)
+ return 0;
+
+ if (pressure >= 95) {
+ other_file = global_node_page_state(NR_FILE_PAGES) -
+ global_node_page_state(NR_SHMEM) -
+ total_swapcache_pages();
+ other_free = global_page_state(NR_FREE_PAGES);
+
+ atomic_set(&shift_adj, 1);
+ trace_almk_vmpressure(pressure, other_free, other_file);
+ } else if (pressure >= 90) {
+ if (lowmem_adj_size < array_size)
+ array_size = lowmem_adj_size;
+ if (lowmem_minfree_size < array_size)
+ array_size = lowmem_minfree_size;
+
+ other_file = global_node_page_state(NR_FILE_PAGES) -
+ global_node_page_state(NR_SHMEM) -
+ total_swapcache_pages();
+
+ other_free = global_page_state(NR_FREE_PAGES);
+
+ if ((other_free < lowmem_minfree[array_size - 1]) &&
+ (other_file < vmpressure_file_min)) {
+ atomic_set(&shift_adj, 1);
+ trace_almk_vmpressure(pressure, other_free, other_file);
+ }
+ } else if (atomic_read(&shift_adj)) {
+ other_file = global_node_page_state(NR_FILE_PAGES) -
+ global_node_page_state(NR_SHMEM) -
+ total_swapcache_pages();
+
+ other_free = global_page_state(NR_FREE_PAGES);
+ /*
+ * shift_adj would have been set by a previous invocation
+ * of notifier, which is not followed by a lowmem_shrink yet.
+ * Since vmpressure has improved, reset shift_adj to avoid
+ * false adaptive LMK trigger.
+ */
+ trace_almk_vmpressure(pressure, other_free, other_file);
+ atomic_set(&shift_adj, 0);
+ }
+
+ return 0;
+}
+
+static struct notifier_block lmk_vmpr_nb = {
+ .notifier_call = lmk_vmpressure_notifier,
+};
+
+static int test_task_flag(struct task_struct *p, int flag)
+{
+ struct task_struct *t;
+
+ for_each_thread(p, t) {
+ task_lock(t);
+ if (test_tsk_thread_flag(t, flag)) {
+ task_unlock(t);
+ return 1;
+ }
+ task_unlock(t);
+ }
+
+ return 0;
+}
+
+static int test_task_lmk_waiting(struct task_struct *p)
+{
+ struct task_struct *t;
+
+ for_each_thread(p, t) {
+ task_lock(t);
+ if (task_lmk_waiting(t)) {
+ task_unlock(t);
+ return 1;
+ }
+ task_unlock(t);
+ }
+
+ return 0;
+}
+
+static DEFINE_MUTEX(scan_mutex);
+
+static int can_use_cma_pages(gfp_t gfp_mask)
+{
+ int can_use = 0;
+ int mtype = gfpflags_to_migratetype(gfp_mask);
+ int i = 0;
+ int *mtype_fallbacks = get_migratetype_fallbacks(mtype);
+
+ if (is_migrate_cma(mtype)) {
+ can_use = 1;
+ } else {
+ for (i = 0;; i++) {
+ int fallbacktype = mtype_fallbacks[i];
+
+ if (is_migrate_cma(fallbacktype)) {
+ can_use = 1;
+ break;
+ }
+
+ if (fallbacktype == MIGRATE_TYPES)
+ break;
+ }
+ }
+ return can_use;
+}
+
+void tune_lmk_zone_param(struct zonelist *zonelist, int classzone_idx,
+ int *other_free, int *other_file,
+ int use_cma_pages)
+{
+ struct zone *zone;
+ struct zoneref *zoneref;
+ int zone_idx;
+
+ for_each_zone_zonelist(zone, zoneref, zonelist, MAX_NR_ZONES) {
+ zone_idx = zonelist_zone_idx(zoneref);
+ if (zone_idx == ZONE_MOVABLE) {
+ if (!use_cma_pages && other_free)
+ *other_free -=
+ zone_page_state(zone, NR_FREE_CMA_PAGES);
+ continue;
+ }
+
+ if (zone_idx > classzone_idx) {
+ if (other_free != NULL)
+ *other_free -= zone_page_state(zone,
+ NR_FREE_PAGES);
+ if (other_file != NULL)
+ *other_file -= zone_page_state(zone,
+ NR_ZONE_INACTIVE_FILE) +
+ zone_page_state(zone,
+ NR_ZONE_ACTIVE_FILE);
+ } else if (zone_idx < classzone_idx) {
+ if (zone_watermark_ok(zone, 0, 0, classzone_idx, 0) &&
+ other_free) {
+ if (!use_cma_pages) {
+ *other_free -= min(
+ zone->lowmem_reserve[classzone_idx] +
+ zone_page_state(
+ zone, NR_FREE_CMA_PAGES),
+ zone_page_state(
+ zone, NR_FREE_PAGES));
+ } else {
+ *other_free -=
+ zone->lowmem_reserve[classzone_idx];
+ }
+ } else {
+ if (other_free)
+ *other_free -=
+ zone_page_state(zone, NR_FREE_PAGES);
+ }
+ }
+ }
+}
+
+#ifdef CONFIG_HIGHMEM
+static void adjust_gfp_mask(gfp_t *gfp_mask)
+{
+ struct zone *preferred_zone;
+ struct zoneref *zref;
+ struct zonelist *zonelist;
+ enum zone_type high_zoneidx;
+
+ if (current_is_kswapd()) {
+ zonelist = node_zonelist(0, *gfp_mask);
+ high_zoneidx = gfp_zone(*gfp_mask);
+ zref = first_zones_zonelist(zonelist, high_zoneidx, NULL);
+ preferred_zone = zref->zone;
+
+ if (high_zoneidx == ZONE_NORMAL) {
+ if (zone_watermark_ok_safe(
+ preferred_zone, 0,
+ high_wmark_pages(preferred_zone), 0))
+ *gfp_mask |= __GFP_HIGHMEM;
+ } else if (high_zoneidx == ZONE_HIGHMEM) {
+ *gfp_mask |= __GFP_HIGHMEM;
+ }
+ }
+}
+#else
+static void adjust_gfp_mask(gfp_t *unused)
+{
+}
+#endif
+
+void tune_lmk_param(int *other_free, int *other_file, struct shrink_control *sc)
+{
+ gfp_t gfp_mask;
+ struct zone *preferred_zone;
+ struct zoneref *zref;
+ struct zonelist *zonelist;
+ enum zone_type high_zoneidx, classzone_idx;
+ unsigned long balance_gap;
+ int use_cma_pages;
+
+ gfp_mask = sc->gfp_mask;
+ adjust_gfp_mask(&gfp_mask);
+
+ zonelist = node_zonelist(0, gfp_mask);
+ high_zoneidx = gfp_zone(gfp_mask);
+ zref = first_zones_zonelist(zonelist, high_zoneidx, NULL);
+ preferred_zone = zref->zone;
+ classzone_idx = zone_idx(preferred_zone);
+ use_cma_pages = can_use_cma_pages(gfp_mask);
+
+ balance_gap = min(low_wmark_pages(preferred_zone),
+ (preferred_zone->present_pages +
+ 100-1) /
+ 100);
+
+ if (likely(current_is_kswapd() && zone_watermark_ok(preferred_zone, 0,
+ high_wmark_pages(preferred_zone) + SWAP_CLUSTER_MAX +
+ balance_gap, 0, 0))) {
+ if (lmk_fast_run)
+ tune_lmk_zone_param(zonelist, classzone_idx, other_free,
+ other_file, use_cma_pages);
+ else
+ tune_lmk_zone_param(zonelist, classzone_idx, other_free,
+ NULL, use_cma_pages);
+
+ if (zone_watermark_ok(preferred_zone, 0, 0, _ZONE, 0)) {
+ if (!use_cma_pages) {
+ *other_free -= min(
+ preferred_zone->lowmem_reserve[_ZONE]
+ + zone_page_state(
+ preferred_zone, NR_FREE_CMA_PAGES),
+ zone_page_state(
+ preferred_zone, NR_FREE_PAGES));
+ } else {
+ *other_free -=
+ preferred_zone->lowmem_reserve[_ZONE];
+ }
+ } else {
+ *other_free -= zone_page_state(preferred_zone,
+ NR_FREE_PAGES);
+ }
+
+ lowmem_print(4, "lowmem_shrink of kswapd tunning for highmem "
+ "ofree %d, %d\n", *other_free, *other_file);
+ } else {
+ tune_lmk_zone_param(zonelist, classzone_idx, other_free,
+ other_file, use_cma_pages);
+
+ if (!use_cma_pages) {
+ *other_free -=
+ zone_page_state(preferred_zone, NR_FREE_CMA_PAGES);
+ }
+
+ lowmem_print(4, "lowmem_shrink tunning for others ofree %d, "
+ "%d\n", *other_free, *other_file);
+ }
+}
+
static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
{
struct task_struct *tsk;
@@ -88,16 +412,31 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
unsigned long rem = 0;
int tasksize;
int i;
+ int ret = 0;
short min_score_adj = OOM_SCORE_ADJ_MAX + 1;
int minfree = 0;
int selected_tasksize = 0;
short selected_oom_score_adj;
int array_size = ARRAY_SIZE(lowmem_adj);
- int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
- int other_file = global_node_page_state(NR_FILE_PAGES) -
- global_node_page_state(NR_SHMEM) -
- global_node_page_state(NR_UNEVICTABLE) -
- total_swapcache_pages();
+ int other_free;
+ int other_file;
+
+ if (mutex_lock_interruptible(&scan_mutex) < 0)
+ return 0;
+
+ other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
+
+ if (global_node_page_state(NR_SHMEM) + total_swapcache_pages() +
+ global_node_page_state(NR_UNEVICTABLE) <
+ global_node_page_state(NR_FILE_PAGES))
+ other_file = global_node_page_state(NR_FILE_PAGES) -
+ global_node_page_state(NR_SHMEM) -
+ global_node_page_state(NR_UNEVICTABLE) -
+ total_swapcache_pages();
+ else
+ other_file = 0;
+
+ tune_lmk_param(&other_free, &other_file, sc);
if (lowmem_adj_size < array_size)
array_size = lowmem_adj_size;
@@ -111,13 +450,17 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
}
}
+ ret = adjust_minadj(&min_score_adj);
+
lowmem_print(3, "lowmem_scan %lu, %x, ofree %d %d, ma %hd\n",
sc->nr_to_scan, sc->gfp_mask, other_free,
other_file, min_score_adj);
if (min_score_adj == OOM_SCORE_ADJ_MAX + 1) {
+ trace_almk_shrink(0, ret, other_free, other_file, 0);
lowmem_print(5, "lowmem_scan %lu, %x, return 0\n",
sc->nr_to_scan, sc->gfp_mask);
+ mutex_unlock(&scan_mutex);
return 0;
}
@@ -131,16 +474,24 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
if (tsk->flags & PF_KTHREAD)
continue;
+ /* if task no longer has any memory ignore it */
+ if (test_task_flag(tsk, TIF_MM_RELEASED))
+ continue;
+
+ if (time_before_eq(jiffies, lowmem_deathpending_timeout)) {
+ if (test_task_lmk_waiting(tsk)) {
+ rcu_read_unlock();
+ /* give the system time to free up the memory */
+ msleep_interruptible(20);
+ mutex_unlock(&scan_mutex);
+ return 0;
+ }
+ }
+
p = find_lock_task_mm(tsk);
if (!p)
continue;
- if (task_lmk_waiting(p) &&
- time_before_eq(jiffies, lowmem_deathpending_timeout)) {
- task_unlock(p);
- rcu_read_unlock();
- return 0;
- }
oom_score_adj = p->signal->oom_score_adj;
if (oom_score_adj < min_score_adj) {
task_unlock(p);
@@ -160,7 +511,7 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
selected = p;
selected_tasksize = tasksize;
selected_oom_score_adj = oom_score_adj;
- lowmem_print(2, "select '%s' (%d), adj %hd, size %d, to kill\n",
+ lowmem_print(3, "select '%s' (%d), adj %hd, size %d, to kill\n",
p->comm, p->pid, oom_score_adj, tasksize);
}
if (selected) {
@@ -175,23 +526,51 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
task_unlock(selected);
trace_lowmemory_kill(selected, cache_size, cache_limit, free);
lowmem_print(1, "Killing '%s' (%d), adj %hd,\n"
- " to free %ldkB on behalf of '%s' (%d) because\n"
- " cache %ldkB is below limit %ldkB for oom_score_adj %hd\n"
- " Free memory is %ldkB above reserved\n",
- selected->comm, selected->pid,
- selected_oom_score_adj,
- selected_tasksize * (long)(PAGE_SIZE / 1024),
- current->comm, current->pid,
- cache_size, cache_limit,
- min_score_adj,
- free);
+ "to free %ldkB on behalf of '%s' (%d) because\n"
+ "cache %ldkB is below limit %ldkB for oom score %hd\n"
+ "Free memory is %ldkB above reserved.\n"
+ "Free CMA is %ldkB\n"
+ "Total reserve is %ldkB\n"
+ "Total free pages is %ldkB\n"
+ "Total file cache is %ldkB\n"
+ "GFP mask is 0x%x\n",
+ selected->comm, selected->pid,
+ selected_oom_score_adj,
+ selected_tasksize * (long)(PAGE_SIZE / 1024),
+ current->comm, current->pid,
+ cache_size, cache_limit,
+ min_score_adj,
+ free,
+ global_page_state(NR_FREE_CMA_PAGES) *
+ (long)(PAGE_SIZE / 1024),
+ totalreserve_pages * (long)(PAGE_SIZE / 1024),
+ global_page_state(NR_FREE_PAGES) *
+ (long)(PAGE_SIZE / 1024),
+ global_node_page_state(NR_FILE_PAGES) *
+ (long)(PAGE_SIZE / 1024),
+ sc->gfp_mask);
+
+ if (lowmem_debug_level >= 2 && selected_oom_score_adj == 0) {
+ show_mem(SHOW_MEM_FILTER_NODES);
+ dump_tasks(NULL, NULL);
+ }
+
lowmem_deathpending_timeout = jiffies + HZ;
rem += selected_tasksize;
+ rcu_read_unlock();
+ /* give the system time to free up the memory */
+ msleep_interruptible(20);
+ trace_almk_shrink(selected_tasksize, ret,
+ other_free, other_file,
+ selected_oom_score_adj);
+ } else {
+ trace_almk_shrink(1, ret, other_free, other_file, 0);
+ rcu_read_unlock();
}
lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n",
sc->nr_to_scan, sc->gfp_mask, rem);
- rcu_read_unlock();
+ mutex_unlock(&scan_mutex);
return rem;
}
@@ -204,6 +583,7 @@ static struct shrinker lowmem_shrinker = {
static int __init lowmem_init(void)
{
register_shrinker(&lowmem_shrinker);
+ vmpressure_notifier_register(&lmk_vmpr_nb);
return 0;
}
device_initcall(lowmem_init);
@@ -299,6 +679,7 @@ __MODULE_PARM_TYPE(adj, "array of short");
module_param_array_named(adj, lowmem_adj, short, &lowmem_adj_size, 0644);
#endif
module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size,
- 0644);
-module_param_named(debug_level, lowmem_debug_level, uint, 0644);
+ S_IRUGO | S_IWUSR);
+module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR);
+module_param_named(lmk_fast_run, lmk_fast_run, int, S_IRUGO | S_IWUSR);
diff --git a/drivers/staging/android/uapi/msm_ion.h b/drivers/staging/android/uapi/msm_ion.h
index 7381ee9..84598db 100644
--- a/drivers/staging/android/uapi/msm_ion.h
+++ b/drivers/staging/android/uapi/msm_ion.h
@@ -89,6 +89,7 @@ enum cp_mem_usage {
#define ION_FLAG_CP_SEC_DISPLAY ION_BIT(25)
#define ION_FLAG_CP_APP ION_BIT(26)
#define ION_FLAG_CP_CAMERA_PREVIEW ION_BIT(27)
+#define ION_FLAG_CP_SPSS_HLOS_SHARED ION_BIT(30)
/**
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 64b3966..a34fd5a 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -2908,6 +2908,7 @@ static int __init comedi_init(void)
dev = comedi_alloc_board_minor(NULL);
if (IS_ERR(dev)) {
comedi_cleanup_board_minors();
+ class_destroy(comedi_class);
cdev_del(&comedi_cdev);
unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
COMEDI_NUM_MINORS);
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index 0594828..b195537 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -522,6 +522,9 @@ static int vnt_start(struct ieee80211_hw *hw)
goto free_all;
}
+ if (vnt_key_init_table(priv))
+ goto free_all;
+
priv->int_interval = 1; /* bInterval is set to 1 */
vnt_int_start_interrupt(priv);
diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c
index 1ab5b0c..a04ddae 100644
--- a/drivers/thermal/msm-tsens.c
+++ b/drivers/thermal/msm-tsens.c
@@ -79,6 +79,9 @@ static const struct of_device_id tsens_table[] = {
{ .compatible = "qcom,sdm845-tsens",
.data = &data_tsens24xx,
},
+ { .compatible = "qcom,tsens24xx",
+ .data = &data_tsens24xx,
+ },
{}
};
MODULE_DEVICE_TABLE(of, tsens_table);
diff --git a/drivers/thermal/qcom/lmh_dbg.c b/drivers/thermal/qcom/lmh_dbg.c
index 74ffeda..d027bd9 100644
--- a/drivers/thermal/qcom/lmh_dbg.c
+++ b/drivers/thermal/qcom/lmh_dbg.c
@@ -315,11 +315,12 @@ static int lmh_get_recurssive_data(struct scm_desc *desc_arg, uint32_t cmd_idx,
pr_err("No LMH device supported.\n");
return -ENODEV;
}
- if (!dest_buf)
+ if (!dest_buf) {
dest_buf = devm_kcalloc(lmh_data->dev, *size,
sizeof(*dest_buf), GFP_KERNEL);
if (!dest_buf)
return -ENOMEM;
+ }
for (idx = next;
idx < min((next + LMH_SCM_PAYLOAD_SIZE), *size);
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index 94ba2c3e..17cdac4 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -469,6 +469,9 @@ static void msm_geni_serial_poll_cancel_tx(struct uart_port *uport)
int done = 0;
unsigned int irq_clear = M_CMD_DONE_EN;
+ if (!uart_console(uport))
+ return;
+
done = msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
M_CMD_DONE_EN, true);
if (!done) {
@@ -686,17 +689,22 @@ static void msm_geni_serial_start_tx(struct uart_port *uport)
{
unsigned int geni_m_irq_en;
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
-
- if (!msm_geni_serial_tx_empty(uport))
- return;
+ unsigned int geni_status;
if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) {
dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
return;
}
+ geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
+ if (geni_status & M_GENI_CMD_ACTIVE)
+ return;
+
+ if (!msm_geni_serial_tx_empty(uport))
+ return;
+
geni_m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
- geni_m_irq_en |= M_TX_FIFO_WATERMARK_EN;
+ geni_m_irq_en |= (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN);
geni_write_reg_nolog(msm_port->tx_wm, uport->membase,
SE_GENI_TX_WATERMARK_REG);
@@ -868,6 +876,7 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport)
unsigned int xmit_size;
unsigned int fifo_width_bytes =
(uart_console(uport) ? 1 : (msm_port->tx_fifo_width >> 3));
+ unsigned int geni_m_irq_en;
tx_fifo_status = geni_read_reg_nolog(uport->membase,
SE_GENI_TX_FIFO_STATUS);
@@ -876,6 +885,16 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport)
goto exit_handle_tx;
}
+ if (!uart_console(uport)) {
+ geni_m_irq_en = geni_read_reg_nolog(uport->membase,
+ SE_GENI_M_IRQ_EN);
+ geni_m_irq_en &= ~(M_TX_FIFO_WATERMARK_EN);
+ geni_write_reg_nolog(0, uport->membase,
+ SE_GENI_TX_WATERMARK_REG);
+ geni_write_reg_nolog(geni_m_irq_en, uport->membase,
+ SE_GENI_M_IRQ_EN);
+ }
+
avail_fifo_bytes = (msm_port->tx_fifo_depth - msm_port->tx_wm) *
fifo_width_bytes;
xmit_size = uart_circ_chars_pending(xmit);
@@ -923,6 +942,7 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev)
unsigned int s_irq_status;
struct uart_port *uport = dev;
unsigned long flags;
+ unsigned int m_irq_en;
spin_lock_irqsave(&uport->lock, flags);
if (uart_console(uport) && uport->suspended)
@@ -937,6 +957,7 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev)
SE_GENI_M_IRQ_CLEAR);
geni_write_reg_nolog(s_irq_status, uport->membase,
SE_GENI_S_IRQ_CLEAR);
+ m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
if ((m_irq_status & M_ILLEGAL_CMD_EN)) {
WARN_ON(1);
@@ -948,7 +969,8 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev)
msm_geni_serial_handle_rx(uport);
}
- if ((m_irq_status & M_TX_FIFO_WATERMARK_EN))
+ if ((m_irq_status & m_irq_en) &
+ (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
msm_geni_serial_handle_tx(uport);
exit_geni_serial_isr:
@@ -1069,6 +1091,14 @@ static int msm_geni_serial_port_setup(struct uart_port *uport)
SE_GENI_TX_PACKING_CFG0);
geni_write_reg_nolog(cfg1, uport->membase,
SE_GENI_TX_PACKING_CFG1);
+ msm_port->handle_rx = handle_rx_hs;
+ msm_port->rx_fifo = devm_kzalloc(uport->dev,
+ sizeof(msm_port->rx_fifo_depth * sizeof(u32)),
+ GFP_KERNEL);
+ if (!msm_port->rx_fifo) {
+ ret = -ENOMEM;
+ goto exit_portsetup;
+ }
} else {
/*
* Make an unconditional cancel on the main sequencer to reset
@@ -1166,12 +1196,12 @@ static int msm_geni_serial_startup(struct uart_port *uport)
goto exit_startup;
}
+ get_tx_fifo_size(msm_port);
if (!msm_port->port_setup) {
if (msm_geni_serial_port_setup(uport))
goto exit_startup;
}
- get_tx_fifo_size(msm_port);
msm_geni_serial_start_rx(uport);
/*
* Ensure that all the port configuration writes complete
@@ -1360,6 +1390,9 @@ static void msm_geni_serial_set_termios(struct uart_port *uport,
tx_trans_cfg |= UART_CTS_MASK;
/* status bits to ignore */
+ if (likely(baud))
+ uart_update_timeout(uport, termios->c_cflag, baud);
+
geni_serial_write_term_regs(uport, port->loopback, tx_trans_cfg,
tx_parity_cfg, rx_trans_cfg, rx_parity_cfg, bits_per_char,
stop_bit_len, ser_clk_cfg);
@@ -1790,10 +1823,6 @@ static int msm_geni_serial_probe(struct platform_device *pdev)
dev_port->rx_fifo = devm_kzalloc(uport->dev, sizeof(u32),
GFP_KERNEL);
} else {
- dev_port->handle_rx = handle_rx_hs;
- dev_port->rx_fifo = devm_kzalloc(uport->dev,
- sizeof(dev_port->rx_fifo_depth * sizeof(u32)),
- GFP_KERNEL);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_enable(&pdev->dev);
}
@@ -1882,7 +1911,8 @@ static int msm_geni_serial_sys_resume_noirq(struct device *dev)
struct msm_geni_serial_port *port = platform_get_drvdata(pdev);
struct uart_port *uport = &port->uport;
- if (uart_console(uport)) {
+ if (uart_console(uport) &&
+ console_suspend_enabled && uport->suspended) {
se_geni_resources_on(&port->serial_rsc);
uart_resume_port((struct uart_driver *)uport->private_data,
uport);
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 96b21b0..3116edf 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -223,6 +223,10 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Blackmagic Design UltraStudio SDI */
{ USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM },
+ /* Hauppauge HVR-950q */
+ { USB_DEVICE(0x2040, 0x7200), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
/* INTEL VALUE SSD */
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 7272f9a..92e5d13 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -279,6 +279,8 @@ static void usb_release_dev(struct device *dev)
usb_destroy_configuration(udev);
usb_release_bos_descriptor(udev);
+ if (udev->parent)
+ of_node_put(dev->of_node);
usb_put_hcd(hcd);
kfree(udev->product);
kfree(udev->manufacturer);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 81f3384..3e9d233 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1768,9 +1768,10 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event)
/*
* Below sequence is used when controller is working without
- * having ssphy and only USB high speed is supported.
+ * having ssphy and only USB high/full speed is supported.
*/
- if (dwc->maximum_speed == USB_SPEED_HIGH) {
+ if (dwc->maximum_speed == USB_SPEED_HIGH ||
+ dwc->maximum_speed == USB_SPEED_FULL) {
dwc3_msm_write_reg(mdwc->base, QSCRATCH_GENERAL_CFG,
dwc3_msm_read_reg(mdwc->base,
QSCRATCH_GENERAL_CFG)
@@ -3763,20 +3764,9 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)
platform_device_del(dwc->xhci);
usb_unregister_notify(&mdwc->host_nb);
- /*
- * Perform USB hardware RESET (both core reset and DBM reset)
- * when moving from host to peripheral. This is required for
- * peripheral mode to work.
- */
- dwc3_msm_block_reset(mdwc, true);
-
dwc3_usb3_phy_suspend(dwc, false);
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
-
mdwc->in_host_mode = false;
- /* re-init core and OTG registers as block reset clears these */
- dwc3_post_host_reset_core_init(dwc);
pm_runtime_mark_last_busy(mdwc->dev);
pm_runtime_put_sync_autosuspend(mdwc->dev);
dbg_event(0xFF, "StopHost psync",
diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c
index aaaf256..4cf5381 100644
--- a/drivers/usb/dwc3/dwc3-st.c
+++ b/drivers/usb/dwc3/dwc3-st.c
@@ -231,7 +231,7 @@ static int st_dwc3_probe(struct platform_device *pdev)
dwc3_data->syscfg_reg_off = res->start;
- dev_vdbg(&pdev->dev, "glue-logic addr 0x%p, syscfg-reg offset 0x%x\n",
+ dev_vdbg(&pdev->dev, "glue-logic addr 0x%pK, syscfg-reg offset 0x%x\n",
dwc3_data->glue_base, dwc3_data->syscfg_reg_off);
dwc3_data->rstc_pwrdn =
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 7d8566f..edd000b 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1211,9 +1211,9 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
return -ESHUTDOWN;
}
- if (WARN(req->dep != dep, "request %p belongs to '%s'\n",
+ if (WARN(req->dep != dep, "request %pK belongs to '%s'\n",
&req->request, req->dep->name)) {
- dwc3_trace(trace_dwc3_gadget, "request %p belongs to '%s'",
+ dwc3_trace(trace_dwc3_gadget, "request %pK belongs to '%s'",
&req->request, req->dep->name);
return -EINVAL;
}
@@ -1405,7 +1405,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
dwc3_stop_active_transfer(dwc, dep->number, true);
goto out1;
}
- dev_err(dwc->dev, "request %p was not queued to %s\n",
+ dev_err(dwc->dev, "request %pK was not queued to %s\n",
request, ep->name);
ret = -EINVAL;
goto out0;
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index e9e8f46..af3ce4f 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -19,6 +19,39 @@
#include "core.h"
+static int dwc3_host_get_irq(struct dwc3 *dwc)
+{
+ struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
+ int irq;
+
+ irq = platform_get_irq_byname(dwc3_pdev, "host");
+ if (irq > 0)
+ goto out;
+
+ if (irq == -EPROBE_DEFER)
+ goto out;
+
+ irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3");
+ if (irq > 0)
+ goto out;
+
+ if (irq == -EPROBE_DEFER)
+ goto out;
+
+ irq = platform_get_irq(dwc3_pdev, 0);
+ if (irq > 0)
+ goto out;
+
+ if (irq != -EPROBE_DEFER)
+ dev_err(dwc->dev, "missing host IRQ\n");
+
+ if (!irq)
+ irq = -EINVAL;
+
+out:
+ return irq;
+}
+
int dwc3_host_init(struct dwc3 *dwc)
{
struct property_entry props[3];
@@ -28,39 +61,18 @@ int dwc3_host_init(struct dwc3 *dwc)
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
int prop_idx = 0;
- irq = platform_get_irq_byname(dwc3_pdev, "host");
- if (irq == -EPROBE_DEFER)
+ irq = dwc3_host_get_irq(dwc);
+ if (irq < 0)
return irq;
- if (irq <= 0) {
- irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3");
- if (irq == -EPROBE_DEFER)
- return irq;
-
- if (irq <= 0) {
- irq = platform_get_irq(dwc3_pdev, 0);
- if (irq <= 0) {
- if (irq != -EPROBE_DEFER) {
- dev_err(dwc->dev,
- "missing host IRQ\n");
- }
- if (!irq)
- irq = -EINVAL;
- return irq;
- } else {
- res = platform_get_resource(dwc3_pdev,
- IORESOURCE_IRQ, 0);
- }
- } else {
- res = platform_get_resource_byname(dwc3_pdev,
- IORESOURCE_IRQ,
- "dwc_usb3");
- }
-
- } else {
+ res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ, "host");
+ if (!res)
res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ,
- "host");
- }
+ "dwc_usb3");
+ if (!res)
+ res = platform_get_resource(dwc3_pdev, IORESOURCE_IRQ, 0);
+ if (!res)
+ return -ENOMEM;
dwc->xhci_resources[1].start = irq;
dwc->xhci_resources[1].end = irq;
diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c
index 46df732..a7cb586 100644
--- a/drivers/usb/gadget/function/f_accessory.c
+++ b/drivers/usb/gadget/function/f_accessory.c
@@ -346,6 +346,7 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req)
struct acc_dev *dev = ep->driver_data;
char *string_dest = NULL;
int length = req->actual;
+ unsigned long flags;
if (req->status != 0) {
pr_err("acc_complete_set_string, err %d\n", req->status);
@@ -371,22 +372,26 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req)
case ACCESSORY_STRING_SERIAL:
string_dest = dev->serial;
break;
- }
- if (string_dest) {
- unsigned long flags;
-
- if (length >= ACC_STRING_SIZE)
- length = ACC_STRING_SIZE - 1;
-
- spin_lock_irqsave(&dev->lock, flags);
- memcpy(string_dest, req->buf, length);
- /* ensure zero termination */
- string_dest[length] = 0;
- spin_unlock_irqrestore(&dev->lock, flags);
- } else {
+ default:
pr_err("unknown accessory string index %d\n",
- dev->string_index);
+ dev->string_index);
+ return;
}
+
+ if (!length) {
+ pr_debug("zero length for accessory string index %d\n",
+ dev->string_index);
+ return;
+ }
+
+ if (length >= ACC_STRING_SIZE)
+ length = ACC_STRING_SIZE - 1;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ memcpy(string_dest, req->buf, length);
+ /* ensure zero termination */
+ string_dest[length] = 0;
+ spin_unlock_irqrestore(&dev->lock, flags);
}
static void acc_complete_set_hid_report_desc(struct usb_ep *ep,
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index ea17164..102003d 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -1545,7 +1545,7 @@ static int debug_mtp_read_stats(struct seq_file *s, void *unused)
}
seq_printf(s, "vfs_write(time in usec) min:%d\t max:%d\t avg:%d\n",
- min, max, sum / iteration);
+ min, max, (iteration ? (sum / iteration) : 0));
min = max = sum = iteration = 0;
seq_puts(s, "\n=======================\n");
seq_puts(s, "USB MTP IN related VFS read stats:\n");
@@ -1567,7 +1567,7 @@ static int debug_mtp_read_stats(struct seq_file *s, void *unused)
}
seq_printf(s, "vfs_read(time in usec) min:%d\t max:%d\t avg:%d\n",
- min, max, sum / iteration);
+ min, max, (iteration ? (sum / iteration) : 0));
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 32aa45e..b0c4f12 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1535,6 +1535,9 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
t2 |= PORT_WKOC_E | PORT_WKCONN_E;
t2 &= ~PORT_WKDISC_E;
}
+ if ((xhci->quirks & XHCI_U2_DISABLE_WAKE) &&
+ (hcd->speed < HCD_USB3))
+ t2 &= ~PORT_WAKE_BITS;
} else
t2 &= ~PORT_WAKE_BITS;
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 69864ba..672751e 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -54,6 +54,11 @@
#define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8
#define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_2 0x43bb
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_1 0x43bc
+
static const char hcd_name[] = "xhci_hcd";
static struct hc_driver __read_mostly xhci_pci_hc_driver;
@@ -135,6 +140,13 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
if (pdev->vendor == PCI_VENDOR_ID_AMD)
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+ if ((pdev->vendor == PCI_VENDOR_ID_AMD) &&
+ ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) ||
+ (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_3) ||
+ (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2) ||
+ (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_1)))
+ xhci->quirks |= XHCI_U2_DISABLE_WAKE;
+
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
xhci->quirks |= XHCI_LPM_SUPPORT;
xhci->quirks |= XHCI_INTEL_HOST;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 86d578e..3a7fb29 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1668,6 +1668,7 @@ struct xhci_hcd {
/* For controller with a broken Port Disable implementation */
#define XHCI_BROKEN_PORT_PED (1 << 25)
#define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
+#define XHCI_U2_DISABLE_WAKE (1 << 27)
unsigned int num_active_eps;
unsigned int limit_active_eps;
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 2682d29..1fad512 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -182,7 +182,7 @@ static void *usbpd_ipc_log;
#define PS_HARD_RESET_TIME 25
#define PS_SOURCE_ON 400
#define PS_SOURCE_OFF 750
-#define SWAP_SOURCE_START_TIME 20
+#define FIRST_SOURCE_CAP_TIME 200
#define VDM_BUSY_TIME 50
#define VCONN_ON_TIME 100
@@ -796,17 +796,27 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->pd_phy_opened = true;
}
- pd->current_state = PE_SRC_SEND_CAPABILITIES;
if (pd->in_pr_swap) {
- kick_sm(pd, SWAP_SOURCE_START_TIME);
pd->in_pr_swap = false;
val.intval = 0;
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PR_SWAP, &val);
- break;
}
- /* fall-through */
+ /*
+ * A sink might remove its terminations (during some Type-C
+ * compliance tests or a sink attempting to do Try.SRC)
+ * at this point just after we enabled VBUS. Sending PD
+ * messages now would delay detecting the detach beyond the
+ * required timing. Instead, delay sending out the first
+ * source capabilities to allow for the other side to
+ * completely settle CC debounce and allow HW to detect detach
+ * sooner in the meantime. PD spec allows up to
+ * tFirstSourceCap (250ms).
+ */
+ pd->current_state = PE_SRC_SEND_CAPABILITIES;
+ kick_sm(pd, FIRST_SOURCE_CAP_TIME);
+ break;
case PE_SRC_SEND_CAPABILITIES:
kick_sm(pd, 0);
@@ -1604,7 +1614,6 @@ static void usbpd_sm(struct work_struct *w)
else if (pd->current_dr == DR_DFP)
stop_usb_host(pd);
- pd->current_pr = PR_NONE;
pd->current_dr = DR_NONE;
if (pd->current_state == PE_ERROR_RECOVERY)
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 675e50e..37d904f 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -79,6 +79,7 @@ enum qusb_phy_reg {
struct qusb_phy {
struct usb_phy phy;
+ struct mutex lock;
void __iomem *base;
void __iomem *efuse_reg;
@@ -103,11 +104,11 @@ struct qusb_phy {
int efuse_bit_pos;
int efuse_num_of_bits;
- bool power_enabled;
+ int power_enabled_ref;
bool clocks_enabled;
bool cable_connected;
bool suspended;
- bool rm_pulldown;
+ bool dpdm_enable;
struct regulator_desc dpdm_rdesc;
struct regulator_dev *dpdm_rdev;
@@ -171,35 +172,47 @@ static int qusb_phy_config_vdd(struct qusb_phy *qphy, int high)
return ret;
}
-static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on,
- bool toggle_vdd)
+static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on)
{
int ret = 0;
- dev_dbg(qphy->phy.dev, "%s turn %s regulators. power_enabled:%d\n",
- __func__, on ? "on" : "off", qphy->power_enabled);
+ mutex_lock(&qphy->lock);
- if (toggle_vdd && qphy->power_enabled == on) {
- dev_dbg(qphy->phy.dev, "PHYs' regulators are already ON.\n");
- return 0;
+ dev_dbg(qphy->phy.dev,
+ "%s:req to turn %s regulators. power_enabled_ref:%d\n",
+ __func__, on ? "on" : "off", qphy->power_enabled_ref);
+
+ if (on && ++qphy->power_enabled_ref > 1) {
+ dev_dbg(qphy->phy.dev, "PHYs' regulators are already on\n");
+ goto done;
}
- if (!on)
- goto disable_vdda33;
-
- if (toggle_vdd) {
- ret = qusb_phy_config_vdd(qphy, true);
- if (ret) {
- dev_err(qphy->phy.dev, "Unable to config VDD:%d\n",
- ret);
- goto err_vdd;
+ if (!on) {
+ if (on == qphy->power_enabled_ref) {
+ dev_dbg(qphy->phy.dev,
+ "PHYs' regulators are already off\n");
+ goto done;
}
- ret = regulator_enable(qphy->vdd);
- if (ret) {
- dev_err(qphy->phy.dev, "Unable to enable VDD\n");
- goto unconfig_vdd;
- }
+ qphy->power_enabled_ref--;
+ if (!qphy->power_enabled_ref)
+ goto disable_vdda33;
+
+ dev_dbg(qphy->phy.dev, "Skip turning off PHYs' regulators\n");
+ goto done;
+ }
+
+ ret = qusb_phy_config_vdd(qphy, true);
+ if (ret) {
+ dev_err(qphy->phy.dev, "Unable to config VDD:%d\n",
+ ret);
+ goto err_vdd;
+ }
+
+ ret = regulator_enable(qphy->vdd);
+ if (ret) {
+ dev_err(qphy->phy.dev, "Unable to enable VDD\n");
+ goto unconfig_vdd;
}
ret = regulator_set_load(qphy->vdda18, QUSB2PHY_1P8_HPM_LOAD);
@@ -242,10 +255,9 @@ static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on,
goto unset_vdd33;
}
- if (toggle_vdd)
- qphy->power_enabled = true;
-
pr_debug("%s(): QUSB PHY's regulators are turned ON.\n", __func__);
+
+ mutex_unlock(&qphy->lock);
return ret;
disable_vdda33:
@@ -281,22 +293,24 @@ static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on,
dev_err(qphy->phy.dev, "Unable to set LPM of vdda18\n");
disable_vdd:
- if (toggle_vdd) {
- ret = regulator_disable(qphy->vdd);
- if (ret)
- dev_err(qphy->phy.dev, "Unable to disable vdd:%d\n",
- ret);
+ ret = regulator_disable(qphy->vdd);
+ if (ret)
+ dev_err(qphy->phy.dev, "Unable to disable vdd:%d\n",
+ ret);
unconfig_vdd:
- ret = qusb_phy_config_vdd(qphy, false);
- if (ret)
- dev_err(qphy->phy.dev, "Unable unconfig VDD:%d\n",
- ret);
- }
+ ret = qusb_phy_config_vdd(qphy, false);
+ if (ret)
+ dev_err(qphy->phy.dev, "Unable unconfig VDD:%d\n",
+ ret);
err_vdd:
- if (toggle_vdd)
- qphy->power_enabled = false;
dev_dbg(qphy->phy.dev, "QUSB PHY's regulators are turned OFF.\n");
+
+ /* in case of error in turning on regulators */
+ if (qphy->power_enabled_ref)
+ qphy->power_enabled_ref--;
+done:
+ mutex_unlock(&qphy->lock);
return ret;
}
@@ -394,7 +408,7 @@ static int qusb_phy_init(struct usb_phy *phy)
dev_dbg(phy->dev, "%s\n", __func__);
- ret = qusb_phy_enable_power(qphy, true, true);
+ ret = qusb_phy_enable_power(qphy, true);
if (ret)
return ret;
@@ -576,7 +590,7 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
qphy->base + qphy->phy_reg[INTR_CTRL]);
qusb_phy_reset(qphy);
qusb_phy_enable_clocks(qphy, false);
- qusb_phy_enable_power(qphy, false, true);
+ qusb_phy_enable_power(qphy, false);
}
qphy->suspended = true;
} else {
@@ -595,7 +609,6 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
/* Makes sure that above write goes through */
wmb();
} else { /* Cable connect case */
- qusb_phy_enable_power(qphy, true, true);
qusb_phy_enable_clocks(qphy, true);
}
qphy->suspended = false;
@@ -636,15 +649,17 @@ static int qusb_phy_dpdm_regulator_enable(struct regulator_dev *rdev)
int ret = 0;
struct qusb_phy *qphy = rdev_get_drvdata(rdev);
- dev_dbg(qphy->phy.dev, "%s\n", __func__);
+ dev_dbg(qphy->phy.dev, "%s dpdm_enable:%d\n",
+ __func__, qphy->dpdm_enable);
- if (qphy->rm_pulldown) {
- ret = qusb_phy_enable_power(qphy, true, false);
- if (ret >= 0) {
- qphy->rm_pulldown = true;
- dev_dbg(qphy->phy.dev, "dpdm_enable:rm_pulldown:%d\n",
- qphy->rm_pulldown);
+ if (!qphy->dpdm_enable) {
+ ret = qusb_phy_enable_power(qphy, true);
+ if (ret < 0) {
+ dev_dbg(qphy->phy.dev,
+ "dpdm regulator enable failed:%d\n", ret);
+ return ret;
}
+ qphy->dpdm_enable = true;
}
return ret;
@@ -655,15 +670,17 @@ static int qusb_phy_dpdm_regulator_disable(struct regulator_dev *rdev)
int ret = 0;
struct qusb_phy *qphy = rdev_get_drvdata(rdev);
- dev_dbg(qphy->phy.dev, "%s\n", __func__);
+ dev_dbg(qphy->phy.dev, "%s dpdm_enable:%d\n",
+ __func__, qphy->dpdm_enable);
- if (!qphy->rm_pulldown) {
- ret = qusb_phy_enable_power(qphy, false, false);
- if (ret >= 0) {
- qphy->rm_pulldown = false;
- dev_dbg(qphy->phy.dev, "dpdm_disable:rm_pulldown:%d\n",
- qphy->rm_pulldown);
+ if (qphy->dpdm_enable) {
+ ret = qusb_phy_enable_power(qphy, false);
+ if (ret < 0) {
+ dev_dbg(qphy->phy.dev,
+ "dpdm regulator disable failed:%d\n", ret);
+ return ret;
}
+ qphy->dpdm_enable = false;
}
return ret;
@@ -673,9 +690,9 @@ static int qusb_phy_dpdm_regulator_is_enabled(struct regulator_dev *rdev)
{
struct qusb_phy *qphy = rdev_get_drvdata(rdev);
- dev_dbg(qphy->phy.dev, "%s qphy->rm_pulldown = %d\n", __func__,
- qphy->rm_pulldown);
- return qphy->rm_pulldown;
+ dev_dbg(qphy->phy.dev, "%s qphy->dpdm_enable = %d\n", __func__,
+ qphy->dpdm_enable);
+ return qphy->dpdm_enable;
}
static struct regulator_ops qusb_phy_dpdm_regulator_ops = {
@@ -964,6 +981,7 @@ static int qusb_phy_probe(struct platform_device *pdev)
return PTR_ERR(qphy->vdda18);
}
+ mutex_init(&qphy->lock);
platform_set_drvdata(pdev, qphy);
qphy->phy.label = "msm-qusb-phy-v2";
@@ -991,7 +1009,7 @@ static int qusb_phy_remove(struct platform_device *pdev)
usb_remove_phy(&qphy->phy);
qusb_phy_enable_clocks(qphy, false);
- qusb_phy_enable_power(qphy, false, true);
+ qusb_phy_enable_power(qphy, false);
return 0;
}
diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c
index 76b034e..e355e35 100644
--- a/drivers/usb/phy/phy-msm-qusb.c
+++ b/drivers/usb/phy/phy-msm-qusb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-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
@@ -130,7 +130,7 @@ struct qusb_phy {
bool cable_connected;
bool suspended;
bool ulpi_mode;
- bool rm_pulldown;
+ bool dpdm_enable;
bool is_se_clk;
struct regulator_desc dpdm_rdesc;
@@ -673,15 +673,17 @@ static int qusb_phy_dpdm_regulator_enable(struct regulator_dev *rdev)
int ret = 0;
struct qusb_phy *qphy = rdev_get_drvdata(rdev);
- dev_dbg(qphy->phy.dev, "%s\n", __func__);
+ dev_dbg(qphy->phy.dev, "%s dpdm_enable:%d\n",
+ __func__, qphy->dpdm_enable);
- if (qphy->rm_pulldown) {
+ if (!qphy->dpdm_enable) {
ret = qusb_phy_enable_power(qphy, true, false);
- if (ret >= 0) {
- qphy->rm_pulldown = true;
- dev_dbg(qphy->phy.dev, "dpdm_enable:rm_pulldown:%d\n",
- qphy->rm_pulldown);
+ if (ret < 0) {
+ dev_dbg(qphy->phy.dev,
+ "dpdm regulator enable failed:%d\n", ret);
+ return ret;
}
+ qphy->dpdm_enable = true;
}
return ret;
@@ -692,15 +694,17 @@ static int qusb_phy_dpdm_regulator_disable(struct regulator_dev *rdev)
int ret = 0;
struct qusb_phy *qphy = rdev_get_drvdata(rdev);
- dev_dbg(qphy->phy.dev, "%s\n", __func__);
+ dev_dbg(qphy->phy.dev, "%s dpdm_enable:%d\n",
+ __func__, qphy->dpdm_enable);
- if (!qphy->rm_pulldown) {
+ if (qphy->dpdm_enable) {
ret = qusb_phy_enable_power(qphy, false, false);
- if (ret >= 0) {
- qphy->rm_pulldown = false;
- dev_dbg(qphy->phy.dev, "dpdm_disable:rm_pulldown:%d\n",
- qphy->rm_pulldown);
+ if (ret < 0) {
+ dev_dbg(qphy->phy.dev,
+ "dpdm regulator disable failed:%d\n", ret);
+ return ret;
}
+ qphy->dpdm_enable = false;
}
return ret;
@@ -710,9 +714,9 @@ static int qusb_phy_dpdm_regulator_is_enabled(struct regulator_dev *rdev)
{
struct qusb_phy *qphy = rdev_get_drvdata(rdev);
- dev_dbg(qphy->phy.dev, "%s qphy->rm_pulldown = %d\n", __func__,
- qphy->rm_pulldown);
- return qphy->rm_pulldown;
+ dev_dbg(qphy->phy.dev, "%s qphy->dpdm_enable = %d\n", __func__,
+ qphy->dpdm_enable);
+ return qphy->dpdm_enable;
}
static struct regulator_ops qusb_phy_dpdm_regulator_ops = {
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 8bb4875..84b444f 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -135,6 +135,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x10C4, 0x8977) }, /* CEL MeshWorks DevKit Device */
{ 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, 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 3bf61ac..ebe51f11 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1877,6 +1877,10 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t)&four_g_w100_blacklist
},
{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) },
+ { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, 0x9801, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, 0x9803, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) },
{ USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index fd509ed6c..652b433 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -158,6 +158,7 @@ static const struct usb_device_id id_table[] = {
{DEVICE_SWI(0x1199, 0x9056)}, /* Sierra Wireless Modem */
{DEVICE_SWI(0x1199, 0x9060)}, /* Sierra Wireless Modem */
{DEVICE_SWI(0x1199, 0x9061)}, /* Sierra Wireless Modem */
+ {DEVICE_SWI(0x1199, 0x9063)}, /* Sierra Wireless EM7305 */
{DEVICE_SWI(0x1199, 0x9070)}, /* Sierra Wireless MC74xx */
{DEVICE_SWI(0x1199, 0x9071)}, /* Sierra Wireless MC74xx */
{DEVICE_SWI(0x1199, 0x9078)}, /* Sierra Wireless EM74xx */
diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c
index 44ab43f..af10f7b 100644
--- a/drivers/usb/usbip/stub_main.c
+++ b/drivers/usb/usbip/stub_main.c
@@ -262,7 +262,11 @@ void stub_device_cleanup_urbs(struct stub_device *sdev)
kmem_cache_free(stub_priv_cache, priv);
kfree(urb->transfer_buffer);
+ urb->transfer_buffer = NULL;
+
kfree(urb->setup_packet);
+ urb->setup_packet = NULL;
+
usb_free_urb(urb);
}
}
diff --git a/drivers/usb/usbip/stub_tx.c b/drivers/usb/usbip/stub_tx.c
index 6b1e8c3..be50cef 100644
--- a/drivers/usb/usbip/stub_tx.c
+++ b/drivers/usb/usbip/stub_tx.c
@@ -28,7 +28,11 @@ static void stub_free_priv_and_urb(struct stub_priv *priv)
struct urb *urb = priv->urb;
kfree(urb->setup_packet);
+ urb->setup_packet = NULL;
+
kfree(urb->transfer_buffer);
+ urb->transfer_buffer = NULL;
+
list_del(&priv->list);
kmem_cache_free(stub_priv_cache, priv);
usb_free_urb(urb);
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 1afa111..aca0d88 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -315,7 +315,7 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
struct ceph_mds_client *mdsc = fsc->mdsc;
int i;
int err;
- u32 ftype;
+ unsigned frag = -1;
struct ceph_mds_reply_info_parsed *rinfo;
dout("readdir %p file %p pos %llx\n", inode, file, ctx->pos);
@@ -362,7 +362,6 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
/* do we have the correct frag content buffered? */
if (need_send_readdir(fi, ctx->pos)) {
struct ceph_mds_request *req;
- unsigned frag;
int op = ceph_snap(inode) == CEPH_SNAPDIR ?
CEPH_MDS_OP_LSSNAP : CEPH_MDS_OP_READDIR;
@@ -373,8 +372,11 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
}
if (is_hash_order(ctx->pos)) {
- frag = ceph_choose_frag(ci, fpos_hash(ctx->pos),
- NULL, NULL);
+ /* fragtree isn't always accurate. choose frag
+ * based on previous reply when possible. */
+ if (frag == (unsigned)-1)
+ frag = ceph_choose_frag(ci, fpos_hash(ctx->pos),
+ NULL, NULL);
} else {
frag = fpos_frag(ctx->pos);
}
@@ -497,6 +499,7 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
struct ceph_mds_reply_dir_entry *rde = rinfo->dir_entries + i;
struct ceph_vino vino;
ino_t ino;
+ u32 ftype;
BUG_ON(rde->offset < ctx->pos);
@@ -519,15 +522,17 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
ctx->pos++;
}
+ ceph_mdsc_put_request(fi->last_readdir);
+ fi->last_readdir = NULL;
+
if (fi->next_offset > 2) {
- ceph_mdsc_put_request(fi->last_readdir);
- fi->last_readdir = NULL;
+ frag = fi->frag;
goto more;
}
/* more frags? */
if (!ceph_frag_is_rightmost(fi->frag)) {
- unsigned frag = ceph_frag_next(fi->frag);
+ frag = ceph_frag_next(fi->frag);
if (is_hash_order(ctx->pos)) {
loff_t new_pos = ceph_make_fpos(ceph_frag_value(frag),
fi->next_offset, true);
diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c
index 42145be..5dc655e 100644
--- a/fs/ext4/sysfs.c
+++ b/fs/ext4/sysfs.c
@@ -100,7 +100,7 @@ static ssize_t reserved_clusters_store(struct ext4_attr *a,
int ret;
ret = kstrtoull(skip_spaces(buf), 0, &val);
- if (!ret || val >= clusters)
+ if (ret || val >= clusters)
return -EINVAL;
atomic64_set(&sbi->s_resv_clusters, val);
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 350a2c8..1493ceb 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -741,16 +741,10 @@ static int __init fcntl_init(void)
* Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY
* is defined as O_NONBLOCK on some platforms and not on others.
*/
- BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
- O_RDONLY | O_WRONLY | O_RDWR |
- O_CREAT | O_EXCL | O_NOCTTY |
- O_TRUNC | O_APPEND | /* O_NONBLOCK | */
- __O_SYNC | O_DSYNC | FASYNC |
- O_DIRECT | O_LARGEFILE | O_DIRECTORY |
- O_NOFOLLOW | O_NOATIME | O_CLOEXEC |
- __FMODE_EXEC | O_PATH | __O_TMPFILE |
- __FMODE_NONOTIFY
- ));
+ BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ !=
+ HWEIGHT32(
+ (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) |
+ __FMODE_EXEC | __FMODE_NONOTIFY));
fasync_cache = kmem_cache_create("fasync_cache",
sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL);
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 6528724..7bff6f4 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -80,9 +80,9 @@ static struct rhashtable_params ht_parms = {
static struct rhashtable gl_hash_table;
-void gfs2_glock_free(struct gfs2_glock *gl)
+static void gfs2_glock_dealloc(struct rcu_head *rcu)
{
- struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
+ struct gfs2_glock *gl = container_of(rcu, struct gfs2_glock, gl_rcu);
if (gl->gl_ops->go_flags & GLOF_ASPACE) {
kmem_cache_free(gfs2_glock_aspace_cachep, gl);
@@ -90,6 +90,13 @@ void gfs2_glock_free(struct gfs2_glock *gl)
kfree(gl->gl_lksb.sb_lvbptr);
kmem_cache_free(gfs2_glock_cachep, gl);
}
+}
+
+void gfs2_glock_free(struct gfs2_glock *gl)
+{
+ struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
+
+ call_rcu(&gl->gl_rcu, gfs2_glock_dealloc);
if (atomic_dec_and_test(&sdp->sd_glock_disposal))
wake_up(&sdp->sd_glock_wait);
}
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 51519c2..a04bf95 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -370,6 +370,7 @@ struct gfs2_glock {
loff_t end;
} gl_vm;
};
+ struct rcu_head gl_rcu;
struct rhash_head gl_node;
};
diff --git a/fs/open.c b/fs/open.c
index 568749b..73b7d19 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -915,6 +915,12 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
int lookup_flags = 0;
int acc_mode = ACC_MODE(flags);
+ /*
+ * Clear out all open flags we don't know about so that we don't report
+ * them in fcntl(F_GETFD) or similar interfaces.
+ */
+ flags &= VALID_OPEN_FLAGS;
+
if (flags & (O_CREAT | __O_TMPFILE))
op->mode = (mode & S_IALLUGO) | S_IFREG;
else
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 45f75c4..18f7612 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1632,7 +1632,7 @@ static const struct file_operations proc_pid_sched_group_id_operations = {
.release = single_release,
};
-#endif /* CONFIG_SCHED_HMP */
+#endif /* CONFIG_SCHED_WALT */
#ifdef CONFIG_SCHED_AUTOGROUP
/*
@@ -3090,6 +3090,9 @@ static const struct pid_entry tgid_base_stuff[] = {
REG("mounts", S_IRUGO, proc_mounts_operations),
REG("mountinfo", S_IRUGO, proc_mountinfo_operations),
REG("mountstats", S_IRUSR, proc_mountstats_operations),
+#ifdef CONFIG_PROCESS_RECLAIM
+ REG("reclaim", S_IWUSR, proc_reclaim_operations),
+#endif
#ifdef CONFIG_PROC_PAGE_MONITOR
REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
REG("smaps", S_IRUGO, proc_pid_smaps_operations),
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 5378441..6dfb414 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -209,6 +209,7 @@ struct pde_opener {
extern const struct inode_operations proc_link_inode_operations;
extern const struct inode_operations proc_pid_link_inode_operations;
+extern const struct file_operations proc_reclaim_operations;
extern void proc_init_inodecache(void);
extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 9182f84..71b62b8 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -15,6 +15,8 @@
#include <linux/mmu_notifier.h>
#include <linux/page_idle.h>
#include <linux/shmem_fs.h>
+#include <linux/mm_inline.h>
+#include <linux/ctype.h>
#include <asm/elf.h>
#include <asm/uaccess.h>
@@ -1526,6 +1528,238 @@ const struct file_operations proc_pagemap_operations = {
};
#endif /* CONFIG_PROC_PAGE_MONITOR */
+#ifdef CONFIG_PROCESS_RECLAIM
+static int reclaim_pte_range(pmd_t *pmd, unsigned long addr,
+ unsigned long end, struct mm_walk *walk)
+{
+ struct reclaim_param *rp = walk->private;
+ struct vm_area_struct *vma = rp->vma;
+ pte_t *pte, ptent;
+ spinlock_t *ptl;
+ struct page *page;
+ LIST_HEAD(page_list);
+ int isolated;
+ int reclaimed;
+
+ split_huge_pmd(vma, addr, pmd);
+ if (pmd_trans_unstable(pmd) || !rp->nr_to_reclaim)
+ return 0;
+cont:
+ isolated = 0;
+ pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+ for (; addr != end; pte++, addr += PAGE_SIZE) {
+ ptent = *pte;
+ if (!pte_present(ptent))
+ continue;
+
+ page = vm_normal_page(vma, addr, ptent);
+ if (!page)
+ continue;
+
+ if (isolate_lru_page(page))
+ continue;
+
+ list_add(&page->lru, &page_list);
+ inc_node_page_state(page, NR_ISOLATED_ANON +
+ page_is_file_cache(page));
+ isolated++;
+ rp->nr_scanned++;
+ if ((isolated >= SWAP_CLUSTER_MAX) || !rp->nr_to_reclaim)
+ break;
+ }
+ pte_unmap_unlock(pte - 1, ptl);
+ reclaimed = reclaim_pages_from_list(&page_list, vma);
+ rp->nr_reclaimed += reclaimed;
+ rp->nr_to_reclaim -= reclaimed;
+ if (rp->nr_to_reclaim < 0)
+ rp->nr_to_reclaim = 0;
+
+ if (rp->nr_to_reclaim && (addr != end))
+ goto cont;
+
+ cond_resched();
+ return 0;
+}
+
+enum reclaim_type {
+ RECLAIM_FILE,
+ RECLAIM_ANON,
+ RECLAIM_ALL,
+ RECLAIM_RANGE,
+};
+
+struct reclaim_param reclaim_task_anon(struct task_struct *task,
+ int nr_to_reclaim)
+{
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ struct mm_walk reclaim_walk = {};
+ struct reclaim_param rp;
+
+ rp.nr_reclaimed = 0;
+ rp.nr_scanned = 0;
+ get_task_struct(task);
+ mm = get_task_mm(task);
+ if (!mm)
+ goto out;
+
+ reclaim_walk.mm = mm;
+ reclaim_walk.pmd_entry = reclaim_pte_range;
+
+ rp.nr_to_reclaim = nr_to_reclaim;
+ reclaim_walk.private = &rp;
+
+ down_read(&mm->mmap_sem);
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if (is_vm_hugetlb_page(vma))
+ continue;
+
+ if (vma->vm_file)
+ continue;
+
+ if (!rp.nr_to_reclaim)
+ break;
+
+ rp.vma = vma;
+ walk_page_range(vma->vm_start, vma->vm_end,
+ &reclaim_walk);
+ }
+
+ flush_tlb_mm(mm);
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+out:
+ put_task_struct(task);
+ return rp;
+}
+
+static ssize_t reclaim_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_struct *task;
+ char buffer[200];
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ enum reclaim_type type;
+ char *type_buf;
+ struct mm_walk reclaim_walk = {};
+ unsigned long start = 0;
+ unsigned long end = 0;
+ struct reclaim_param rp;
+
+ memset(buffer, 0, sizeof(buffer));
+ if (count > sizeof(buffer) - 1)
+ count = sizeof(buffer) - 1;
+
+ if (copy_from_user(buffer, buf, count))
+ return -EFAULT;
+
+ type_buf = strstrip(buffer);
+ if (!strcmp(type_buf, "file"))
+ type = RECLAIM_FILE;
+ else if (!strcmp(type_buf, "anon"))
+ type = RECLAIM_ANON;
+ else if (!strcmp(type_buf, "all"))
+ type = RECLAIM_ALL;
+ else if (isdigit(*type_buf))
+ type = RECLAIM_RANGE;
+ else
+ goto out_err;
+
+ if (type == RECLAIM_RANGE) {
+ char *token;
+ unsigned long long len, len_in, tmp;
+ token = strsep(&type_buf, " ");
+ if (!token)
+ goto out_err;
+ tmp = memparse(token, &token);
+ if (tmp & ~PAGE_MASK || tmp > ULONG_MAX)
+ goto out_err;
+ start = tmp;
+
+ token = strsep(&type_buf, " ");
+ if (!token)
+ goto out_err;
+ len_in = memparse(token, &token);
+ len = (len_in + ~PAGE_MASK) & PAGE_MASK;
+ if (len > ULONG_MAX)
+ goto out_err;
+ /*
+ * Check to see whether len was rounded up from small -ve
+ * to zero.
+ */
+ if (len_in && !len)
+ goto out_err;
+
+ end = start + len;
+ if (end < start)
+ goto out_err;
+ }
+
+ task = get_proc_task(file->f_path.dentry->d_inode);
+ if (!task)
+ return -ESRCH;
+
+ mm = get_task_mm(task);
+ if (!mm)
+ goto out;
+
+ reclaim_walk.mm = mm;
+ reclaim_walk.pmd_entry = reclaim_pte_range;
+
+ rp.nr_to_reclaim = INT_MAX;
+ rp.nr_reclaimed = 0;
+ reclaim_walk.private = &rp;
+
+ down_read(&mm->mmap_sem);
+ if (type == RECLAIM_RANGE) {
+ vma = find_vma(mm, start);
+ while (vma) {
+ if (vma->vm_start > end)
+ break;
+ if (is_vm_hugetlb_page(vma))
+ continue;
+
+ rp.vma = vma;
+ walk_page_range(max(vma->vm_start, start),
+ min(vma->vm_end, end),
+ &reclaim_walk);
+ vma = vma->vm_next;
+ }
+ } else {
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if (is_vm_hugetlb_page(vma))
+ continue;
+
+ if (type == RECLAIM_ANON && vma->vm_file)
+ continue;
+
+ if (type == RECLAIM_FILE && !vma->vm_file)
+ continue;
+
+ rp.vma = vma;
+ walk_page_range(vma->vm_start, vma->vm_end,
+ &reclaim_walk);
+ }
+ }
+
+ flush_tlb_mm(mm);
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+out:
+ put_task_struct(task);
+ return count;
+
+out_err:
+ return -EINVAL;
+}
+
+const struct file_operations proc_reclaim_operations = {
+ .write = reclaim_write,
+ .llseek = noop_llseek,
+};
+#endif
+
#ifdef CONFIG_NUMA
struct numa_maps {
diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c
index 3c5b51d..80825b2 100644
--- a/fs/sdcardfs/main.c
+++ b/fs/sdcardfs/main.c
@@ -364,41 +364,34 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb,
return err;
}
-/* A feature which supports mount_nodev() with options */
-static struct dentry *mount_nodev_with_options(struct vfsmount *mnt,
- struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data,
- int (*fill_super)(struct vfsmount *, struct super_block *,
- const char *, void *, int))
+struct sdcardfs_mount_private {
+ struct vfsmount *mnt;
+ const char *dev_name;
+ void *raw_data;
+};
+static int __sdcardfs_fill_super(
+ struct super_block *sb,
+ void *_priv, int silent)
{
- int error;
- struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL);
+ struct sdcardfs_mount_private *priv = _priv;
- if (IS_ERR(s))
- return ERR_CAST(s);
-
- s->s_flags = flags;
-
- error = fill_super(mnt, s, dev_name, data, flags & MS_SILENT ? 1 : 0);
- if (error) {
- deactivate_locked_super(s);
- return ERR_PTR(error);
- }
- s->s_flags |= MS_ACTIVE;
- return dget(s->s_root);
+ return sdcardfs_read_super(priv->mnt,
+ sb, priv->dev_name, priv->raw_data, silent);
}
static struct dentry *sdcardfs_mount(struct vfsmount *mnt,
struct file_system_type *fs_type, int flags,
const char *dev_name, void *raw_data)
{
- /*
- * dev_name is a lower_path_name,
- * raw_data is a option string.
- */
- return mount_nodev_with_options(mnt, fs_type, flags, dev_name,
- raw_data, sdcardfs_read_super);
+ struct sdcardfs_mount_private priv = {
+ .mnt = mnt,
+ .dev_name = dev_name,
+ .raw_data = raw_data
+ };
+
+ return mount_nodev(fs_type, flags,
+ &priv, __sdcardfs_fill_super);
}
static struct dentry *sdcardfs_mount_wrn(struct file_system_type *fs_type,
@@ -423,7 +416,7 @@ void sdcardfs_kill_sb(struct super_block *sb)
list_del(&sbi->list);
mutex_unlock(&sdcardfs_super_list_lock);
}
- generic_shutdown_super(sb);
+ kill_anon_super(sb);
}
static struct file_system_type sdcardfs_fs_type = {
diff --git a/include/dt-bindings/clock/mdss-10nm-pll-clk.h b/include/dt-bindings/clock/mdss-10nm-pll-clk.h
index 75ddcfa..8108c98 100644
--- a/include/dt-bindings/clock/mdss-10nm-pll-clk.h
+++ b/include/dt-bindings/clock/mdss-10nm-pll-clk.h
@@ -17,23 +17,25 @@
/* DSI PLL clocks */
#define VCO_CLK_0 0
-#define BITCLK_SRC_0_CLK 1
-#define BYTECLK_SRC_0_CLK 2
-#define POST_BIT_DIV_0_CLK 3
-#define POST_VCO_DIV_0_CLK 4
-#define BYTECLK_MUX_0_CLK 5
-#define PCLK_SRC_MUX_0_CLK 6
-#define PCLK_SRC_0_CLK 7
-#define PCLK_MUX_0_CLK 8
-#define VCO_CLK_1 9
-#define BITCLK_SRC_1_CLK 10
-#define BYTECLK_SRC_1_CLK 11
-#define POST_BIT_DIV_1_CLK 12
-#define POST_VCO_DIV_1_CLK 13
-#define BYTECLK_MUX_1_CLK 14
-#define PCLK_SRC_MUX_1_CLK 15
-#define PCLK_SRC_1_CLK 16
-#define PCLK_MUX_1_CLK 17
+#define PLL_OUT_DIV_0_CLK 1
+#define BITCLK_SRC_0_CLK 2
+#define BYTECLK_SRC_0_CLK 3
+#define POST_BIT_DIV_0_CLK 4
+#define POST_VCO_DIV_0_CLK 5
+#define BYTECLK_MUX_0_CLK 6
+#define PCLK_SRC_MUX_0_CLK 7
+#define PCLK_SRC_0_CLK 8
+#define PCLK_MUX_0_CLK 9
+#define VCO_CLK_1 10
+#define PLL_OUT_DIV_1_CLK 11
+#define BITCLK_SRC_1_CLK 12
+#define BYTECLK_SRC_1_CLK 13
+#define POST_BIT_DIV_1_CLK 14
+#define POST_VCO_DIV_1_CLK 15
+#define BYTECLK_MUX_1_CLK 16
+#define PCLK_SRC_MUX_1_CLK 17
+#define PCLK_SRC_1_CLK 18
+#define PCLK_MUX_1_CLK 19
/* DP PLL clocks */
#define DP_VCO_CLK 0
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h
index 678a885..3d58645 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h
@@ -201,7 +201,16 @@
#define GCC_SDCC1_ICE_CORE_CLK 183
#define GCC_SDCC1_APPS_CLK_SRC 184
#define GCC_SDCC1_ICE_CORE_CLK_SRC 185
-
+#define GCC_APC_VS_CLK 186
+#define GCC_GPU_VS_CLK 187
+#define GCC_MSS_VS_CLK 188
+#define GCC_VDDA_VS_CLK 189
+#define GCC_VDDCX_VS_CLK 190
+#define GCC_VDDMX_VS_CLK 191
+#define GCC_VS_CTRL_AHB_CLK 192
+#define GCC_VS_CTRL_CLK 193
+#define GCC_VS_CTRL_CLK_SRC 194
+#define GCC_VSENSOR_CLK_SRC 195
/* GCC reset clocks */
#define GCC_MMSS_BCR 0
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index fb910c6..0693c3e 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -508,6 +508,7 @@ struct request_queue {
#define QUEUE_FLAG_FUA 24 /* device supports FUA writes */
#define QUEUE_FLAG_FLUSH_NQ 25 /* flush not queueuable */
#define QUEUE_FLAG_DAX 26 /* device supports DAX */
+#define QUEUE_FLAG_FAST 27 /* fast block device (e.g. ram based) */
#define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \
(1 << QUEUE_FLAG_STACKABLE) | \
@@ -598,6 +599,7 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q)
#define blk_queue_secure_erase(q) \
(test_bit(QUEUE_FLAG_SECERASE, &(q)->queue_flags))
#define blk_queue_dax(q) test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags)
+#define blk_queue_fast(q) test_bit(QUEUE_FLAG_FAST, &(q)->queue_flags)
#define blk_noretry_request(rq) \
((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \
diff --git a/include/linux/device.h b/include/linux/device.h
index d469121..f43db28 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -375,6 +375,7 @@ int subsys_virtual_register(struct bus_type *subsys,
* @suspend: Used to put the device to sleep mode, usually to a low power
* state.
* @resume: Used to bring the device from the sleep mode.
+ * @shutdown: Called at shut-down time to quiesce the device.
* @ns_type: Callbacks so sysfs can detemine namespaces.
* @namespace: Namespace of the device belongs to this class.
* @pm: The default device power management operations of this class.
@@ -403,6 +404,7 @@ struct class {
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
+ int (*shutdown)(struct device *dev);
const struct kobj_ns_type_operations *ns_type;
const void *(*namespace)(struct device *dev);
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
index b871c0c..a9a16f2 100644
--- a/include/linux/extcon.h
+++ b/include/linux/extcon.h
@@ -202,6 +202,7 @@ struct extcon_dev {
/* Internal data. Please do not set. */
struct device dev;
struct raw_notifier_head *nh;
+ struct blocking_notifier_head *bnh;
struct list_head entry;
int max_supported;
spinlock_t lock; /* could be called by irq handler */
@@ -289,6 +290,10 @@ extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
struct notifier_block *nb);
extern int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
struct notifier_block *nb);
+extern int extcon_register_blocking_notifier(struct extcon_dev *edev,
+ unsigned int id, struct notifier_block *nb);
+extern int extcon_unregister_blocking_notifier(struct extcon_dev *edev,
+ unsigned int id, struct notifier_block *nb);
extern int devm_extcon_register_notifier(struct device *dev,
struct extcon_dev *edev, unsigned int id,
struct notifier_block *nb);
@@ -306,7 +311,8 @@ extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
/* Following API to get information of extcon device */
extern const char *extcon_get_edev_name(struct extcon_dev *edev);
-
+extern int extcon_blocking_sync(struct extcon_dev *edev, unsigned int id,
+ bool val);
#else /* CONFIG_EXTCON */
static inline int extcon_dev_register(struct extcon_dev *edev)
{
@@ -413,6 +419,20 @@ static inline int extcon_unregister_notifier(struct extcon_dev *edev,
return 0;
}
+static inline int extcon_register_blocking_notifier(struct extcon_dev *edev,
+ unsigned int id,
+ struct notifier_block *nb)
+{
+ return 0;
+}
+
+static inline int extcon_unregister_blocking_notifier(struct extcon_dev *edev,
+ unsigned int id,
+ struct notifier_block *nb)
+{
+ return 0;
+}
+
static inline int devm_extcon_register_notifier(struct device *dev,
struct extcon_dev *edev, unsigned int id,
struct notifier_block *nb)
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index 76ce329..1b48d9c 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -3,6 +3,12 @@
#include <uapi/linux/fcntl.h>
+/* list of all valid flags for the open/openat flags argument: */
+#define VALID_OPEN_FLAGS \
+ (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \
+ O_APPEND | O_NDELAY | O_NONBLOCK | O_NDELAY | __O_SYNC | O_DSYNC | \
+ FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \
+ O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE)
#ifndef force_o_largefile
#define force_o_largefile() (BITS_PER_LONG != 32)
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index f8041f9de..46cd745 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -41,6 +41,7 @@ struct vm_area_struct;
#define ___GFP_OTHER_NODE 0x800000u
#define ___GFP_WRITE 0x1000000u
#define ___GFP_KSWAPD_RECLAIM 0x2000000u
+#define ___GFP_CMA 0x4000000u
/* If the above are modified, __GFP_BITS_SHIFT may need updating */
/*
@@ -54,8 +55,9 @@ struct vm_area_struct;
#define __GFP_HIGHMEM ((__force gfp_t)___GFP_HIGHMEM)
#define __GFP_DMA32 ((__force gfp_t)___GFP_DMA32)
#define __GFP_MOVABLE ((__force gfp_t)___GFP_MOVABLE) /* ZONE_MOVABLE allowed */
-#define GFP_ZONEMASK (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE)
-
+#define __GFP_CMA ((__force gfp_t)___GFP_CMA)
+#define GFP_ZONEMASK (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE| \
+ __GFP_CMA)
/*
* Page mobility and placement hints
*
@@ -274,7 +276,12 @@ static inline int gfpflags_to_migratetype(const gfp_t gfp_flags)
return MIGRATE_UNMOVABLE;
/* Group based on mobility */
+#ifndef CONFIG_CMA
return (gfp_flags & GFP_MOVABLE_MASK) >> GFP_MOVABLE_SHIFT;
+#else
+ return ((gfp_flags & GFP_MOVABLE_MASK) >> GFP_MOVABLE_SHIFT) |
+ ((gfp_flags & __GFP_CMA) != 0);
+#endif
}
#undef GFP_MOVABLE_MASK
#undef GFP_MOVABLE_SHIFT
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 4c70716..61aff32 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -187,9 +187,24 @@ static inline struct page *
alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
unsigned long vaddr)
{
+#ifndef CONFIG_CMA
return __alloc_zeroed_user_highpage(__GFP_MOVABLE, vma, vaddr);
+#else
+ return __alloc_zeroed_user_highpage(__GFP_MOVABLE|__GFP_CMA, vma,
+ vaddr);
+#endif
}
+#ifdef CONFIG_CMA
+static inline struct page *
+alloc_zeroed_user_highpage_movable_cma(struct vm_area_struct *vma,
+ unsigned long vaddr)
+{
+ return __alloc_zeroed_user_highpage(__GFP_MOVABLE|__GFP_CMA, vma,
+ vaddr);
+}
+#endif
+
static inline void clear_highpage(struct page *page)
{
void *kaddr = kmap_atomic(page);
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 7bdddb3..0b8aedf 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -141,6 +141,7 @@ enum iommu_attr {
DOMAIN_ATTR_EARLY_MAP,
DOMAIN_ATTR_PAGE_TABLE_IS_COHERENT,
DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT,
+ DOMAIN_ATTR_CB_STALL_DISABLE,
DOMAIN_ATTR_MAX,
};
diff --git a/include/linux/ipa_uc_offload.h b/include/linux/ipa_uc_offload.h
index 0277e87..85d0ce9 100644
--- a/include/linux/ipa_uc_offload.h
+++ b/include/linux/ipa_uc_offload.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
@@ -163,6 +163,20 @@ struct ipa_perf_profile {
u32 max_supported_bw_mbps;
};
+/**
+ * struct ipa_uc_ready_params - uC ready CB parameters
+ * @is_uC_ready: uC loaded or not
+ * @priv : callback cookie
+ * @notify: callback
+ * @proto: uC offload protocol type
+ */
+struct ipa_uc_ready_params {
+ bool is_uC_ready;
+ void *priv;
+ ipa_uc_ready_cb notify;
+ enum ipa_uc_offload_proto proto;
+};
+
#if defined CONFIG_IPA || defined CONFIG_IPA3
/**
@@ -223,6 +237,19 @@ int ipa_uc_offload_disconn_pipes(u32 clnt_hdl);
*/
int ipa_set_perf_profile(struct ipa_perf_profile *profile);
+
+/*
+ * To register uC ready callback if uC not ready
+ * and also check uC readiness
+ * if uC not ready only, register callback
+ */
+int ipa_uc_offload_reg_rdyCB(struct ipa_uc_ready_params *param);
+
+/*
+ * To de-register uC ready callback
+ */
+void ipa_uc_offload_dereg_rdyCB(enum ipa_uc_offload_proto proto);
+
#else /* (CONFIG_IPA || CONFIG_IPA3) */
static inline int ipa_uc_offload_reg_intf(
@@ -254,6 +281,15 @@ static inline int ipa_set_perf_profile(struct ipa_perf_profile *profile)
return -EPERM;
}
+static inline int ipa_uc_offload_reg_rdyCB(struct ipa_uc_ready_params *param)
+{
+ return -EPERM;
+}
+
+static void ipa_uc_offload_dereg_rdyCB(enum ipa_uc_offload_proto proto)
+{
+}
+
#endif /* CONFIG_IPA3 */
#endif /* _IPA_UC_OFFLOAD_H_ */
diff --git a/include/linux/mailbox_client.h b/include/linux/mailbox_client.h
index 78f01ea..86a2dc6 100644
--- a/include/linux/mailbox_client.h
+++ b/include/linux/mailbox_client.h
@@ -49,5 +49,6 @@ void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */
bool mbox_client_peek_data(struct mbox_chan *chan); /* atomic */
void mbox_free_channel(struct mbox_chan *chan); /* may sleep */
bool mbox_controller_is_idle(struct mbox_chan *chan); /* atomic */
+void mbox_chan_debug(struct mbox_chan *chan);
#endif /* __MAILBOX_CLIENT_H */
diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
index 30a4ed2..7827c68 100644
--- a/include/linux/mailbox_controller.h
+++ b/include/linux/mailbox_controller.h
@@ -49,6 +49,8 @@ struct mbox_chan;
* Used only if txdone_poll:=true && txdone_irq:=false
* @peek_data: Atomic check for any received data. Return true if controller
* has some data to push to the client. False otherwise.
+ * @debug: Allow chan to be debugged when the client detects a channel is
+ * locked up.
*/
struct mbox_chan_ops {
int (*send_data)(struct mbox_chan *chan, void *data);
@@ -90,6 +92,7 @@ struct mbox_controller {
struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox,
const struct of_phandle_args *sp);
bool (*is_idle)(struct mbox_controller *mbox);
+ void (*debug)(struct mbox_chan *chan);
/* Internal to API */
struct hrtimer poll_hrt;
struct list_head node;
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index d6ebc01..37e5178 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -415,6 +415,11 @@ static inline unsigned long memblock_region_reserved_end_pfn(const struct memblo
for (idx = 0, rgn = &memblock_type->regions[0]; \
idx < memblock_type->cnt; \
idx++, rgn = &memblock_type->regions[idx])
+#define for_each_memblock_rev(memblock_type, region) \
+ for (region = memblock.memblock_type.regions + \
+ memblock.memblock_type.cnt - 1; \
+ region >= memblock.memblock_type.regions; \
+ region--)
#ifdef CONFIG_MEMTEST
extern void early_memtest(phys_addr_t start, phys_addr_t end);
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index b4c1be4..b994010 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -350,7 +350,7 @@ struct wcd9xxx {
int (*post_reset)(struct wcd9xxx *wcd9xxx);
void *ssr_priv;
- bool dev_up;
+ unsigned long dev_up;
u32 num_of_supplies;
struct regulator_bulk_data *supplies;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 6a14034..2b423f7 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -478,16 +478,16 @@ unsigned long vmalloc_to_pfn(const void *addr);
* On nommu, vmalloc/vfree wrap through kmalloc/kfree directly, so there
* is no special casing required.
*/
-static inline bool is_vmalloc_addr(const void *x)
-{
-#ifdef CONFIG_MMU
- unsigned long addr = (unsigned long)x;
- return addr >= VMALLOC_START && addr < VMALLOC_END;
+#ifdef CONFIG_MMU
+extern int is_vmalloc_addr(const void *x);
#else
- return false;
-#endif
+static inline int is_vmalloc_addr(const void *x)
+{
+ return 0;
}
+#endif
+
#ifdef CONFIG_MMU
extern int is_vmalloc_or_module_addr(const void *x);
#else
@@ -2407,7 +2407,6 @@ extern void copy_user_huge_page(struct page *dst, struct page *src,
#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLBFS */
extern struct page_ext_operations debug_guardpage_ops;
-extern struct page_ext_operations page_poisoning_ops;
#ifdef CONFIG_DEBUG_PAGEALLOC
extern unsigned int _debug_guardpage_minorder;
@@ -2448,5 +2447,19 @@ void __init setup_nr_node_ids(void);
static inline void setup_nr_node_ids(void) {}
#endif
+#ifdef CONFIG_PROCESS_RECLAIM
+struct reclaim_param {
+ struct vm_area_struct *vma;
+ /* Number of pages scanned */
+ int nr_scanned;
+ /* max pages to reclaim */
+ int nr_to_reclaim;
+ /* pages reclaimed */
+ int nr_reclaimed;
+};
+extern struct reclaim_param reclaim_task_anon(struct task_struct *task,
+ int nr_to_reclaim);
+#endif
+
#endif /* __KERNEL__ */
#endif /* _LINUX_MM_H */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 6744eb4..ed0099c9 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -39,8 +39,6 @@ enum {
MIGRATE_UNMOVABLE,
MIGRATE_MOVABLE,
MIGRATE_RECLAIMABLE,
- MIGRATE_PCPTYPES, /* the number of types on the pcp lists */
- MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES,
#ifdef CONFIG_CMA
/*
* MIGRATE_CMA migration type is designed to mimic the way
@@ -57,6 +55,8 @@ enum {
*/
MIGRATE_CMA,
#endif
+ MIGRATE_PCPTYPES, /* the number of types on the pcp lists */
+ MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES,
#ifdef CONFIG_MEMORY_ISOLATION
MIGRATE_ISOLATE, /* can't allocate from here */
#endif
@@ -65,13 +65,22 @@ enum {
/* In mm/page_alloc.c; keep in sync also with show_migration_types() there */
extern char * const migratetype_names[MIGRATE_TYPES];
+/*
+ * Returns a list which contains the migrate types on to which
+ * an allocation falls back when the free list for the migrate
+ * type mtype is depleted.
+ * The end of the list is delimited by the type MIGRATE_TYPES.
+ */
+extern int *get_migratetype_fallbacks(int mtype);
#ifdef CONFIG_CMA
# define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
# define is_migrate_cma_page(_page) (get_pageblock_migratetype(_page) == MIGRATE_CMA)
+# define get_cma_migrate_type() MIGRATE_CMA
#else
# define is_migrate_cma(migratetype) false
# define is_migrate_cma_page(_page) false
+# define get_cma_migrate_type() MIGRATE_MOVABLE
#endif
#define for_each_migratetype_order(order, type) \
@@ -368,6 +377,10 @@ struct zone {
struct pglist_data *zone_pgdat;
struct per_cpu_pageset __percpu *pageset;
+#ifdef CONFIG_CMA
+ bool cma_alloc;
+#endif
+
#ifndef CONFIG_SPARSEMEM
/*
* Flags for a pageblock_nr_pages block. See pageblock-flags.h.
diff --git a/include/linux/oom.h b/include/linux/oom.h
index b4e36e9..b986840 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -79,6 +79,9 @@ extern void oom_killer_enable(void);
extern struct task_struct *find_lock_task_mm(struct task_struct *p);
+extern void dump_tasks(struct mem_cgroup *memcg,
+ const nodemask_t *nodemask);
+
/* sysctls */
extern int sysctl_oom_dump_tasks;
extern int sysctl_oom_kill_allocating_task;
diff --git a/include/linux/plist.h b/include/linux/plist.h
index 9788360..0ea3e1b 100644
--- a/include/linux/plist.h
+++ b/include/linux/plist.h
@@ -266,6 +266,9 @@ static inline int plist_node_empty(const struct plist_node *node)
#define plist_next(pos) \
list_next_entry(pos, node_list)
+#define plist_next_entry(pos, type, member) \
+ container_of(plist_next(pos), type, member)
+
/**
* plist_prev - get the prev entry in list
* @pos: the type * to cursor
diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h
index 6c9ddcd..2938206 100644
--- a/include/linux/qcom-geni-se.h
+++ b/include/linux/qcom-geni-se.h
@@ -64,11 +64,14 @@ struct se_geni_rsc {
struct pinctrl *geni_pinctrl;
struct pinctrl_state *geni_gpio_active;
struct pinctrl_state *geni_gpio_sleep;
+ int clk_freq_out;
};
#define PINCTRL_DEFAULT "default"
#define PINCTRL_SLEEP "sleep"
+#define KHz(freq) (1000 * (freq))
+
/* Common SE registers */
#define GENI_INIT_CFG_REVISION (0x0)
#define GENI_S_INIT_CFG_REVISION (0x4)
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index b46bb56..71fd2b3 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -10,6 +10,11 @@
#include <linux/rwsem.h>
#include <linux/memcontrol.h>
+extern int isolate_lru_page(struct page *page);
+extern void putback_lru_page(struct page *page);
+extern unsigned long reclaim_pages_from_list(struct list_head *page_list,
+ struct vm_area_struct *vma);
+
/*
* The anon_vma heads a list of private "related" vmas, to scan if
* an anonymous page pointing to this anon_vma needs to be unmapped:
@@ -186,7 +191,8 @@ int page_referenced(struct page *, int is_locked,
#define TTU_ACTION(x) ((x) & TTU_ACTION_MASK)
-int try_to_unmap(struct page *, enum ttu_flags flags);
+int try_to_unmap(struct page *, enum ttu_flags flags,
+ struct vm_area_struct *vma);
/*
* Used by uprobes to replace a userspace page safely
@@ -263,6 +269,7 @@ int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma);
*/
struct rmap_walk_control {
void *arg;
+ struct vm_area_struct *target_vma;
int (*rmap_one)(struct page *page, struct vm_area_struct *vma,
unsigned long addr, void *arg);
int (*done)(struct page *page);
@@ -287,7 +294,7 @@ static inline int page_referenced(struct page *page, int is_locked,
return 0;
}
-#define try_to_unmap(page, refs) SWAP_FAIL
+#define try_to_unmap(page, refs, vma) SWAP_FAIL
static inline int page_mkclean(struct page *page)
{
diff --git a/include/linux/sched.h b/include/linux/sched.h
index ff65b44..7627c76 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1503,9 +1503,6 @@ struct ravg {
u32 sum_history[RAVG_HIST_SIZE_MAX];
u32 *curr_window_cpu, *prev_window_cpu;
u32 curr_window, prev_window;
-#ifdef CONFIG_SCHED_HMP
- u64 curr_burst, avg_burst, avg_sleep_time;
-#endif
u16 active_windows;
u32 pred_demand;
u8 busy_buckets[NUM_BUSY_BUCKETS];
@@ -2653,38 +2650,10 @@ struct cpu_cycle_counter_cb {
#define MAX_NUM_CGROUP_COLOC_ID 20
-#ifdef CONFIG_SCHED_HMP
-extern int sched_set_window(u64 window_start, unsigned int window_size);
-extern unsigned long sched_get_busy(int cpu);
-extern void sched_get_cpus_busy(struct sched_load *busy,
- const struct cpumask *query_cpus);
-extern int sched_set_init_task_load(struct task_struct *p, int init_load_pct);
-extern u32 sched_get_init_task_load(struct task_struct *p);
-extern int sched_set_static_cpu_pwr_cost(int cpu, unsigned int cost);
-extern unsigned int sched_get_static_cpu_pwr_cost(int cpu);
-extern int sched_set_static_cluster_pwr_cost(int cpu, unsigned int cost);
-extern unsigned int sched_get_static_cluster_pwr_cost(int cpu);
-extern int sched_set_cluster_wake_idle(int cpu, unsigned int wake_idle);
-extern unsigned int sched_get_cluster_wake_idle(int cpu);
-extern int sched_update_freq_max_load(const cpumask_t *cpumask);
-extern void sched_update_cpu_freq_min_max(const cpumask_t *cpus,
- u32 fmin, u32 fmax);
-extern void sched_set_cpu_cstate(int cpu, int cstate,
- int wakeup_energy, int wakeup_latency);
-extern void sched_set_cluster_dstate(const cpumask_t *cluster_cpus, int dstate,
- int wakeup_energy, int wakeup_latency);
-extern int sched_set_group_id(struct task_struct *p, unsigned int group_id);
-extern unsigned int sched_get_group_id(struct task_struct *p);
-
-#else /* CONFIG_SCHED_HMP */
static inline int sched_set_window(u64 window_start, unsigned int window_size)
{
return -EINVAL;
}
-static inline unsigned long sched_get_busy(int cpu)
-{
- return 0;
-}
static inline void sched_get_cpus_busy(struct sched_load *busy,
const struct cpumask *query_cpus) {};
@@ -2698,12 +2667,6 @@ sched_set_cpu_cstate(int cpu, int cstate, int wakeup_energy, int wakeup_latency)
{
}
-static inline void sched_set_cluster_dstate(const cpumask_t *cluster_cpus,
- int dstate, int wakeup_energy, int wakeup_latency)
-{
-}
-#endif /* CONFIG_SCHED_HMP */
-
#ifdef CONFIG_SCHED_WALT
extern int register_cpu_cycle_counter_cb(struct cpu_cycle_counter_cb *cb);
extern void sched_set_io_is_busy(int val);
@@ -2731,10 +2694,8 @@ static inline void free_task_load_ptrs(struct task_struct *p) { }
#endif /* CONFIG_SCHED_WALT */
#ifndef CONFIG_SCHED_WALT
-#ifndef CONFIG_SCHED_HMP
static inline void sched_update_cpu_freq_min_max(const cpumask_t *cpus,
u32 fmin, u32 fmax) { }
-#endif /* CONFIG_SCHED_HMP */
#endif /* CONFIG_SCHED_WALT */
#ifdef CONFIG_NO_HZ_COMMON
@@ -2847,7 +2808,7 @@ extern unsigned long long
task_sched_runtime(struct task_struct *task);
/* sched_exec is called by processes performing an exec */
-#if defined(CONFIG_SMP) && !defined(CONFIG_SCHED_HMP)
+#ifdef CONFIG_SMP
extern void sched_exec(void);
#else
#define sched_exec() {}
@@ -2982,7 +2943,6 @@ extern void xtime_update(unsigned long ticks);
extern int wake_up_state(struct task_struct *tsk, unsigned int state);
extern int wake_up_process(struct task_struct *tsk);
-extern int wake_up_process_no_notif(struct task_struct *tsk);
extern void wake_up_new_task(struct task_struct *tsk);
#ifdef CONFIG_SMP
extern void kick_process(struct task_struct *tsk);
@@ -3217,7 +3177,7 @@ static inline bool mmget_not_zero(struct mm_struct *mm)
}
/* mmput gets rid of the mappings and all user-space */
-extern void mmput(struct mm_struct *);
+extern int mmput(struct mm_struct *mm);
#ifdef CONFIG_MMU
/* same as above but performs the slow path from the async context. Can
* be called from the atomic context as well
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
index f0ba8e6..322bc23 100644
--- a/include/linux/sched/sysctl.h
+++ b/include/linux/sched/sysctl.h
@@ -37,47 +37,13 @@ extern unsigned int sysctl_sched_use_walt_task_util;
extern unsigned int sysctl_sched_boost;
extern unsigned int sysctl_sched_group_upmigrate_pct;
extern unsigned int sysctl_sched_group_downmigrate_pct;
-#endif
-
-#ifdef CONFIG_SCHED_HMP
-
-enum freq_reporting_policy {
- FREQ_REPORT_MAX_CPU_LOAD_TOP_TASK,
- FREQ_REPORT_CPU_LOAD,
- FREQ_REPORT_TOP_TASK,
- FREQ_REPORT_INVALID_POLICY
-};
-
-extern int sysctl_sched_freq_inc_notify;
-extern int sysctl_sched_freq_dec_notify;
-extern unsigned int sysctl_sched_freq_reporting_policy;
-extern unsigned int sysctl_sched_window_stats_policy;
-extern unsigned int sysctl_sched_ravg_hist_size;
-extern unsigned int sysctl_sched_spill_nr_run;
-extern unsigned int sysctl_sched_spill_load_pct;
-extern unsigned int sysctl_sched_upmigrate_pct;
-extern unsigned int sysctl_sched_downmigrate_pct;
-extern unsigned int sysctl_early_detection_duration;
-extern unsigned int sysctl_sched_small_wakee_task_load_pct;
-extern unsigned int sysctl_sched_big_waker_task_load_pct;
-extern unsigned int sysctl_sched_select_prev_cpu_us;
-extern unsigned int sysctl_sched_restrict_cluster_spill;
-extern unsigned int sysctl_sched_pred_alert_freq;
-extern unsigned int sysctl_sched_freq_aggregate;
-extern unsigned int sysctl_sched_enable_thread_grouping;
-extern unsigned int sysctl_sched_freq_aggregate_threshold_pct;
-extern unsigned int sysctl_sched_prefer_sync_wakee_to_waker;
-extern unsigned int sysctl_sched_short_burst;
-extern unsigned int sysctl_sched_short_sleep;
-
-#elif defined(CONFIG_SCHED_WALT)
extern int
walt_proc_update_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
loff_t *ppos);
-#endif /* CONFIG_SCHED_HMP */
+#endif /* CONFIG_SCHED_WALT */
enum sched_tunable_scaling {
SCHED_TUNABLESCALING_NONE,
diff --git a/include/linux/sde_rsc.h b/include/linux/sde_rsc.h
index 1450caa..0320210 100644
--- a/include/linux/sde_rsc.h
+++ b/include/linux/sde_rsc.h
@@ -114,15 +114,16 @@ struct sde_rsc_event {
*
* @fps: panel te interval
* @vtotal: current vertical total (height + vbp + vfp)
- * @jitter: panel can set the jitter to wake up rsc/solver early
- * This value causes mdp core to exit certain mode
- * early. Default is 10% jitter
+ * @jitter_numer: panel jitter numerator value. This config causes rsc/solver
+ * early before te. Default is 0.8% jitter.
+ * @jitter_denom: panel jitter denominator.
* @prefill_lines: max prefill lines based on panel
*/
struct sde_rsc_cmd_config {
u32 fps;
u32 vtotal;
- u32 jitter;
+ u32 jitter_numer;
+ u32 jitter_denom;
u32 prefill_lines;
};
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 55ff559..92d1fde 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -151,12 +151,14 @@ enum {
SWP_AREA_DISCARD = (1 << 8), /* single-time swap area discards */
SWP_PAGE_DISCARD = (1 << 9), /* freed swap page-cluster discards */
SWP_STABLE_WRITES = (1 << 10), /* no overwrite PG_writeback pages */
+ SWP_FAST = (1 << 11), /* blkdev access is fast and cheap */
/* add others here before... */
- SWP_SCANNING = (1 << 11), /* refcount in scan_swap_map */
+ SWP_SCANNING = (1 << 12), /* refcount in scan_swap_map */
};
#define SWAP_CLUSTER_MAX 32UL
#define COMPACT_CLUSTER_MAX SWAP_CLUSTER_MAX
+#define SWAPFILE_CLUSTER 256
#define SWAP_MAP_MAX 0x3e /* Max duplication count, in first swap_map */
#define SWAP_MAP_BAD 0x3f /* Note pageblock is bad, in first swap_map */
@@ -241,6 +243,8 @@ struct swap_info_struct {
*/
struct work_struct discard_work; /* discard worker */
struct swap_cluster_list discard_clusters; /* discard clusters list */
+ unsigned int write_pending;
+ unsigned int max_writes;
};
/* linux/mm/workingset.c */
@@ -328,6 +332,8 @@ extern unsigned long mem_cgroup_shrink_node(struct mem_cgroup *mem,
unsigned long *nr_scanned);
extern unsigned long shrink_all_memory(unsigned long nr_pages);
extern int vm_swappiness;
+extern int sysctl_swap_ratio;
+extern int sysctl_swap_ratio_enable;
extern int remove_mapping(struct address_space *mapping, struct page *page);
extern unsigned long vm_total_pages;
@@ -389,10 +395,18 @@ extern struct page *swapin_readahead(swp_entry_t, gfp_t,
/* linux/mm/swapfile.c */
extern atomic_long_t nr_swap_pages;
extern long total_swap_pages;
+extern bool is_swap_fast(swp_entry_t entry);
/* Swap 50% full? Release swapcache more aggressively.. */
-static inline bool vm_swap_full(void)
+static inline bool vm_swap_full(struct swap_info_struct *si)
{
+ /*
+ * If the swap device is fast, return true
+ * not to delay swap free.
+ */
+ if (si->flags & SWP_FAST)
+ return true;
+
return atomic_long_read(&nr_swap_pages) * 2 < total_swap_pages;
}
@@ -428,7 +442,7 @@ struct backing_dev_info;
#define get_nr_swap_pages() 0L
#define total_swap_pages 0L
#define total_swapcache_pages() 0UL
-#define vm_swap_full() 0
+#define vm_swap_full(si) 0
#define si_swapinfo(val) \
do { (val)->freeswap = (val)->totalswap = 0; } while (0)
@@ -579,7 +593,7 @@ static inline long mem_cgroup_get_nr_swap_pages(struct mem_cgroup *memcg)
static inline bool mem_cgroup_swap_full(struct page *page)
{
- return vm_swap_full();
+ return vm_swap_full(page_swap_info(page));
}
#endif
diff --git a/include/linux/swapfile.h b/include/linux/swapfile.h
index 388293a..ed2a9c9 100644
--- a/include/linux/swapfile.h
+++ b/include/linux/swapfile.h
@@ -7,7 +7,12 @@
*/
extern spinlock_t swap_lock;
extern struct plist_head swap_active_head;
+extern spinlock_t swap_avail_lock;
+extern struct plist_head swap_avail_head;
extern struct swap_info_struct *swap_info[];
extern int try_to_unuse(unsigned int, bool, unsigned long);
+extern int swap_ratio(struct swap_info_struct **si);
+extern void setup_swap_ratio(struct swap_info_struct *p, int prio);
+extern bool is_swap_ratio_group(int prio);
#endif /* _LINUX_SWAPFILE_H */
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 56dde53..5f5107b 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -185,6 +185,9 @@ extern void add_timer_on(struct timer_list *timer, int cpu);
extern int del_timer(struct timer_list * timer);
extern int mod_timer(struct timer_list *timer, unsigned long expires);
extern int mod_timer_pending(struct timer_list *timer, unsigned long expires);
+#ifdef CONFIG_SMP
+extern bool check_pending_deferrable_timers(int cpu);
+#endif
/*
* The jiffies value which is added to now, when there is no timer
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 5c0b3fa..b305b0e 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -582,9 +582,9 @@ extern void usb_ep0_reinit(struct usb_device *);
((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
#define EndpointRequest \
- ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+ ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
#define EndpointOutRequest \
- ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+ ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
/* class requests from the USB 2.0 hub spec, table 11-15 */
/* GetBusState and SetHubDescriptor are optional, omitted */
diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h
index 4d6ec58..9cc195f 100644
--- a/include/linux/vm_event_item.h
+++ b/include/linux/vm_event_item.h
@@ -21,7 +21,7 @@
#define FOR_ALL_ZONES(xx) DMA_ZONE(xx) DMA32_ZONE(xx) xx##_NORMAL, HIGHMEM_ZONE(xx) xx##_MOVABLE
-enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
+enum vm_event_item { PGPGIN, PGPGOUT, PGPGOUTCLEAN, PSWPIN, PSWPOUT,
FOR_ALL_ZONES(PGALLOC),
FOR_ALL_ZONES(ALLOCSTALL),
FOR_ALL_ZONES(PGSCAN_SKIP),
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 3d9d786..826eef8 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -19,6 +19,8 @@ struct notifier_block; /* in notifier.h */
#define VM_UNINITIALIZED 0x00000020 /* vm_struct is not fully initialized */
#define VM_NO_GUARD 0x00000040 /* don't add guard page */
#define VM_KASAN 0x00000080 /* has allocated kasan shadow memory */
+#define VM_LOWMEM 0x00000100 /* Tracking of direct mapped lowmem */
+
/* bits [20..32] reserved for arch specific ioremap internals */
/*
@@ -159,6 +161,13 @@ extern long vwrite(char *buf, char *addr, unsigned long count);
extern struct list_head vmap_area_list;
extern __init void vm_area_add_early(struct vm_struct *vm);
extern __init void vm_area_register_early(struct vm_struct *vm, size_t align);
+extern __init int vm_area_check_early(struct vm_struct *vm);
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+extern void mark_vmalloc_reserved_area(void *addr, unsigned long size);
+#else
+static inline void mark_vmalloc_reserved_area(void *addr, unsigned long size)
+{ };
+#endif
#ifdef CONFIG_SMP
# ifdef CONFIG_MMU
@@ -184,7 +193,12 @@ pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms)
#endif
#ifdef CONFIG_MMU
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+extern unsigned long total_vmalloc_size;
+#define VMALLOC_TOTAL total_vmalloc_size
+#else
#define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START)
+#endif
#else
#define VMALLOC_TOTAL 0UL
#endif
diff --git a/include/linux/vmpressure.h b/include/linux/vmpressure.h
index 3347cc3..93000f5 100644
--- a/include/linux/vmpressure.h
+++ b/include/linux/vmpressure.h
@@ -15,6 +15,7 @@ struct vmpressure {
unsigned long tree_scanned;
unsigned long tree_reclaimed;
+ unsigned long stall;
/* The lock is used to keep the scanned/reclaimed above in sync. */
struct spinlock sr_lock;
@@ -28,11 +29,13 @@ struct vmpressure {
struct mem_cgroup;
-#ifdef CONFIG_MEMCG
+extern int vmpressure_notifier_register(struct notifier_block *nb);
+extern int vmpressure_notifier_unregister(struct notifier_block *nb);
extern void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
unsigned long scanned, unsigned long reclaimed);
extern void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio);
+#ifdef CONFIG_MEMCG
extern void vmpressure_init(struct vmpressure *vmpr);
extern void vmpressure_cleanup(struct vmpressure *vmpr);
extern struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg);
@@ -43,9 +46,9 @@ extern int vmpressure_register_event(struct mem_cgroup *memcg,
extern void vmpressure_unregister_event(struct mem_cgroup *memcg,
struct eventfd_ctx *eventfd);
#else
-static inline void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
- unsigned long scanned, unsigned long reclaimed) {}
-static inline void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg,
- int prio) {}
+static inline struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg)
+{
+ return NULL;
+}
#endif /* CONFIG_MEMCG */
#endif /* __LINUX_VMPRESSURE_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 6d27dae..45dbffb 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -772,6 +772,34 @@ struct cfg80211_csa_settings {
};
/**
+ * struct iface_combination_params - input parameters for interface combinations
+ *
+ * Used to pass interface combination parameters
+ *
+ * @num_different_channels: the number of different channels we want
+ * to use for verification
+ * @radar_detect: a bitmap where each bit corresponds to a channel
+ * width where radar detection is needed, as in the definition of
+ * &struct ieee80211_iface_combination.@radar_detect_widths
+ * @iftype_num: array with the number of interfaces of each interface
+ * type. The index is the interface type as specified in &enum
+ * nl80211_iftype.
+ * @beacon_int_gcd: a value specifying GCD of all beaconing interfaces,
+ * the GCD of a single value is considered the value itself, so for
+ * a single interface this should be set to that interface's beacon
+ * interval
+ * @beacon_int_different: a flag indicating whether or not all beacon
+ * intervals (of beaconing interfaces) are different or not.
+ */
+struct iface_combination_params {
+ int num_different_channels;
+ u8 radar_detect;
+ int iftype_num[NUM_NL80211_IFTYPES];
+ u32 beacon_int_gcd;
+ bool beacon_int_different;
+};
+
+/**
* enum station_parameters_apply_mask - station parameter values to apply
* @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
* @STATION_PARAM_APPLY_CAPABILITY: apply new capability
@@ -3082,6 +3110,12 @@ struct ieee80211_iface_limit {
* only in special cases.
* @radar_detect_widths: bitmap of channel widths supported for radar detection
* @radar_detect_regions: bitmap of regions supported for radar detection
+ * @beacon_int_min_gcd: This interface combination supports different
+ * beacon intervals.
+ * = 0 - all beacon intervals for different interface must be same.
+ * > 0 - any beacon interval for the interface part of this combination AND
+ * *GCD* of all beacon intervals from beaconing interfaces of this
+ * combination must be greater or equal to this value.
*
* With this structure the driver can describe which interface
* combinations it supports concurrently.
@@ -3147,6 +3181,7 @@ struct ieee80211_iface_combination {
bool beacon_int_infra_match;
u8 radar_detect_widths;
u8 radar_detect_regions;
+ u32 beacon_int_min_gcd;
};
struct ieee80211_txrx_stypes {
@@ -5644,36 +5679,20 @@ unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy);
* cfg80211_check_combinations - check interface combinations
*
* @wiphy: the wiphy
- * @num_different_channels: the number of different channels we want
- * to use for verification
- * @radar_detect: a bitmap where each bit corresponds to a channel
- * width where radar detection is needed, as in the definition of
- * &struct ieee80211_iface_combination.@radar_detect_widths
- * @iftype_num: array with the numbers of interfaces of each interface
- * type. The index is the interface type as specified in &enum
- * nl80211_iftype.
+ * @params: the interface combinations parameter
*
* This function can be called by the driver to check whether a
* combination of interfaces and their types are allowed according to
* the interface combinations.
*/
int cfg80211_check_combinations(struct wiphy *wiphy,
- const int num_different_channels,
- const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES]);
+ struct iface_combination_params *params);
/**
* cfg80211_iter_combinations - iterate over matching combinations
*
* @wiphy: the wiphy
- * @num_different_channels: the number of different channels we want
- * to use for verification
- * @radar_detect: a bitmap where each bit corresponds to a channel
- * width where radar detection is needed, as in the definition of
- * &struct ieee80211_iface_combination.@radar_detect_widths
- * @iftype_num: array with the numbers of interfaces of each interface
- * type. The index is the interface type as specified in &enum
- * nl80211_iftype.
+ * @params: the interface combinations parameter
* @iter: function to call for each matching combination
* @data: pointer to pass to iter function
*
@@ -5682,9 +5701,7 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
* purposes.
*/
int cfg80211_iter_combinations(struct wiphy *wiphy,
- const int num_different_channels,
- const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES],
+ struct iface_combination_params *params,
void (*iter)(const struct ieee80211_iface_combination *c,
void *data),
void *data);
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 2700f92..7b93ffd 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -140,6 +140,9 @@ void tcp_time_wait(struct sock *sk, int state, int timeo);
* most likely due to retrans in 3WHS.
*/
+/* Number of full MSS to receive before Acking RFC2581 */
+#define TCP_DELACK_SEG 1
+
#define TCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ/2U)) /* Maximal interval between probes
* for local resources.
*/
@@ -274,6 +277,11 @@ extern int sysctl_tcp_pacing_ca_ratio;
extern int sysctl_tcp_default_init_rwnd;
extern atomic_long_t tcp_memory_allocated;
+
+/* sysctl variables for controlling various tcp parameters */
+extern int sysctl_tcp_delack_seg;
+extern int sysctl_tcp_use_userconfig;
+
extern struct percpu_counter tcp_sockets_allocated;
extern int tcp_memory_pressure;
@@ -364,6 +372,13 @@ ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags);
+/* sysctl master controller */
+extern int tcp_use_userconfig_sysctl_handler(struct ctl_table *table,
+ int write, void __user *buffer, size_t *length,
+ loff_t *ppos);
+extern int tcp_proc_delayed_ack_control(struct ctl_table *table, int write,
+ void __user *buffer, size_t *length,
+ loff_t *ppos);
static inline void tcp_dec_quickack_mode(struct sock *sk,
const unsigned int pkts)
{
diff --git a/include/soc/qcom/qseecomi.h b/include/soc/qcom/qseecomi.h
index 0efea04..a7d4190 100644
--- a/include/soc/qcom/qseecomi.h
+++ b/include/soc/qcom/qseecomi.h
@@ -336,7 +336,7 @@ __packed struct qseecom_client_send_fsm_key_req {
__packed struct qseecom_continue_blocked_request_ireq {
uint32_t qsee_cmd_id;
- uint32_t app_id;
+ uint32_t app_or_session_id; /*legacy: app_id; smcinvoke: session_id*/
};
@@ -682,6 +682,9 @@ __packed struct qseecom_continue_blocked_request_ireq {
#define TZ_OS_CONTINUE_BLOCKED_REQUEST_ID \
TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_LISTENER, 0x04)
+#define TZ_OS_CONTINUE_BLOCKED_REQUEST_SMCINVOKE_ID \
+ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_LISTENER, 0x07)
+
#define TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID \
TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL)
diff --git a/include/soc/qcom/secure_buffer.h b/include/soc/qcom/secure_buffer.h
index a08cfe1..665708d 100644
--- a/include/soc/qcom/secure_buffer.h
+++ b/include/soc/qcom/secure_buffer.h
@@ -40,6 +40,7 @@ enum vmid {
VMID_CP_SPSS_SP = 0x1A,
VMID_CP_CAMERA_PREVIEW = 0x1D,
VMID_CP_SPSS_SP_SHARED = 0x22,
+ VMID_CP_SPSS_HLOS_SHARED = 0x24,
VMID_LAST,
VMID_INVAL = -1
};
@@ -55,7 +56,7 @@ int hyp_assign_table(struct sg_table *table,
u32 *source_vm_list, int source_nelems,
int *dest_vmids, int *dest_perms,
int dest_nelems);
-int hyp_assign_phys(phys_addr_t addr, u64 size,
+extern int hyp_assign_phys(phys_addr_t addr, u64 size,
u32 *source_vmlist, int source_nelems,
int *dest_vmids, int *dest_perms, int dest_nelems);
bool msm_secure_v2_is_supported(void);
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 128da7b..f0da77a 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -466,8 +466,6 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
struct snd_kcontrol *kcontrol);
-struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
- const struct snd_kcontrol *kcontrol);
struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
struct snd_kcontrol *kcontrol);
diff --git a/include/trace/events/almk.h b/include/trace/events/almk.h
new file mode 100644
index 0000000..85d712d
--- /dev/null
+++ b/include/trace/events/almk.h
@@ -0,0 +1,84 @@
+/* Copyright (c) 2015, 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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM almk
+
+#if !defined(_TRACE_EVENT_ALMK_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EVENT_ALMK_H
+
+#include <linux/tracepoint.h>
+#include <linux/types.h>
+
+TRACE_EVENT(almk_vmpressure,
+
+ TP_PROTO(unsigned long pressure,
+ int other_free,
+ int other_file),
+
+ TP_ARGS(pressure, other_free, other_file),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, pressure)
+ __field(int, other_free)
+ __field(int, other_file)
+ ),
+
+ TP_fast_assign(
+ __entry->pressure = pressure;
+ __entry->other_free = other_free;
+ __entry->other_file = other_file;
+ ),
+
+ TP_printk("%lu, %d, %d",
+ __entry->pressure, __entry->other_free,
+ __entry->other_file)
+);
+
+TRACE_EVENT(almk_shrink,
+
+ TP_PROTO(int tsize,
+ int vmp,
+ int other_free,
+ int other_file,
+ short adj),
+
+ TP_ARGS(tsize, vmp, other_free, other_file, adj),
+
+ TP_STRUCT__entry(
+ __field(int, tsize)
+ __field(int, vmp)
+ __field(int, other_free)
+ __field(int, other_file)
+ __field(short, adj)
+ ),
+
+ TP_fast_assign(
+ __entry->tsize = tsize;
+ __entry->vmp = vmp;
+ __entry->other_free = other_free;
+ __entry->other_file = other_file;
+ __entry->adj = adj;
+ ),
+
+ TP_printk("%d, %d, %d, %d, %d",
+ __entry->tsize,
+ __entry->vmp,
+ __entry->other_free,
+ __entry->other_file,
+ __entry->adj)
+);
+
+#endif
+
+#include <trace/define_trace.h>
+
diff --git a/include/trace/events/process_reclaim.h b/include/trace/events/process_reclaim.h
new file mode 100644
index 0000000..6fcede7
--- /dev/null
+++ b/include/trace/events/process_reclaim.h
@@ -0,0 +1,85 @@
+/* Copyright (c) 2015, 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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM process_reclaim
+
+#if !defined(_TRACE_EVENT_PROCESSRECLAIM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EVENT_PROCESSRECLAIM_H
+
+#include <linux/tracepoint.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+
+TRACE_EVENT(process_reclaim,
+
+ TP_PROTO(int tasksize,
+ short oom_score_adj,
+ int nr_scanned, int nr_reclaimed,
+ int per_swap_size, int total_sz,
+ int nr_to_reclaim),
+
+ TP_ARGS(tasksize, oom_score_adj, nr_scanned,
+ nr_reclaimed, per_swap_size,
+ total_sz, nr_to_reclaim),
+
+ TP_STRUCT__entry(
+ __field(int, tasksize)
+ __field(short, oom_score_adj)
+ __field(int, nr_scanned)
+ __field(int, nr_reclaimed)
+ __field(int, per_swap_size)
+ __field(int, total_sz)
+ __field(int, nr_to_reclaim)
+ ),
+
+ TP_fast_assign(
+ __entry->tasksize = tasksize;
+ __entry->oom_score_adj = oom_score_adj;
+ __entry->nr_scanned = nr_scanned;
+ __entry->nr_reclaimed = nr_reclaimed;
+ __entry->per_swap_size = per_swap_size;
+ __entry->total_sz = total_sz;
+ __entry->nr_to_reclaim = nr_to_reclaim;
+ ),
+
+ TP_printk("%d, %hd, %d, %d, %d, %d, %d",
+ __entry->tasksize, __entry->oom_score_adj,
+ __entry->nr_scanned, __entry->nr_reclaimed,
+ __entry->per_swap_size, __entry->total_sz,
+ __entry->nr_to_reclaim)
+);
+
+TRACE_EVENT(process_reclaim_eff,
+
+ TP_PROTO(int efficiency, int reclaim_avg_efficiency),
+
+ TP_ARGS(efficiency, reclaim_avg_efficiency),
+
+ TP_STRUCT__entry(
+ __field(int, efficiency)
+ __field(int, reclaim_avg_efficiency)
+ ),
+
+ TP_fast_assign(
+ __entry->efficiency = efficiency;
+ __entry->reclaim_avg_efficiency = reclaim_avg_efficiency;
+ ),
+
+ TP_printk("%d, %d", __entry->efficiency,
+ __entry->reclaim_avg_efficiency)
+);
+
+#endif
+
+#include <trace/define_trace.h>
+
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index e94a82b..bbcb3d5 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -71,7 +71,7 @@ TRACE_EVENT(sched_enq_deq_task,
__field(unsigned long, cpu_load )
__field(unsigned int, rt_nr_running )
__field(unsigned int, cpus_allowed )
-#ifdef CONFIG_SCHED_HMP
+#ifdef CONFIG_SCHED_WALT
__field(unsigned int, demand )
__field(unsigned int, pred_demand )
#endif
@@ -87,22 +87,22 @@ TRACE_EVENT(sched_enq_deq_task,
__entry->cpu_load = task_rq(p)->cpu_load[0];
__entry->rt_nr_running = task_rq(p)->rt.rt_nr_running;
__entry->cpus_allowed = cpus_allowed;
-#ifdef CONFIG_SCHED_HMP
+#ifdef CONFIG_SCHED_WALT
__entry->demand = p->ravg.demand;
__entry->pred_demand = p->ravg.pred_demand;
#endif
),
TP_printk("cpu=%d %s comm=%s pid=%d prio=%d nr_running=%u cpu_load=%lu rt_nr_running=%u affine=%x"
-#ifdef CONFIG_SCHED_HMP
- " demand=%u pred_demand=%u"
+#ifdef CONFIG_SCHED_WALT
+ " demand=%u pred_demand=%u"
#endif
, __entry->cpu,
__entry->enqueue ? "enqueue" : "dequeue",
__entry->comm, __entry->pid,
__entry->prio, __entry->nr_running,
__entry->cpu_load, __entry->rt_nr_running, __entry->cpus_allowed
-#ifdef CONFIG_SCHED_HMP
+#ifdef CONFIG_SCHED_WALT
, __entry->demand, __entry->pred_demand
#endif
)
@@ -549,9 +549,9 @@ TRACE_EVENT(sched_set_boost,
#ifdef CONFIG_SCHED_WALT
DECLARE_EVENT_CLASS(sched_cpu_load,
- TP_PROTO(struct rq *rq, int idle, u64 irqload, unsigned int power_cost, int temp),
+ TP_PROTO(struct rq *rq, int idle, u64 irqload, unsigned int power_cost),
- TP_ARGS(rq, idle, irqload, power_cost, temp),
+ TP_ARGS(rq, idle, irqload, power_cost),
TP_STRUCT__entry(
__field(unsigned int, cpu )
@@ -566,7 +566,6 @@ DECLARE_EVENT_CLASS(sched_cpu_load,
__field(unsigned int, power_cost )
__field( int, cstate )
__field( int, dstate )
- __field( int, temp )
),
TP_fast_assign(
@@ -582,181 +581,64 @@ DECLARE_EVENT_CLASS(sched_cpu_load,
__entry->power_cost = power_cost;
__entry->cstate = rq->cstate;
__entry->dstate = rq->cluster->dstate;
- __entry->temp = temp;
),
- TP_printk("cpu %u idle %d nr_run %u nr_big %u lsf %u capacity %u cr_avg %llu irqload %llu fmax %u power_cost %u cstate %d dstate %d temp %d",
+ TP_printk("cpu %u idle %d nr_run %u nr_big %u lsf %u capacity %u cr_avg %llu irqload %llu fmax %u power_cost %u cstate %d dstate %d",
__entry->cpu, __entry->idle, __entry->nr_running, __entry->nr_big_tasks,
__entry->load_scale_factor, __entry->capacity,
__entry->cumulative_runnable_avg, __entry->irqload,
__entry->max_freq, __entry->power_cost, __entry->cstate,
- __entry->dstate, __entry->temp)
+ __entry->dstate)
);
DEFINE_EVENT(sched_cpu_load, sched_cpu_load_lb,
- TP_PROTO(struct rq *rq, int idle, u64 irqload, unsigned int power_cost, int temp),
- TP_ARGS(rq, idle, irqload, power_cost, temp)
+ TP_PROTO(struct rq *rq, int idle, u64 irqload, unsigned int power_cost),
+ TP_ARGS(rq, idle, irqload, power_cost)
+);
+
+TRACE_EVENT(sched_load_to_gov,
+
+ TP_PROTO(struct rq *rq, u64 aggr_grp_load, u32 tt_load, u64 freq_aggr_thresh, u64 load, int policy),
+ TP_ARGS(rq, aggr_grp_load, tt_load, freq_aggr_thresh, load, policy),
+
+ TP_STRUCT__entry(
+ __field( int, cpu )
+ __field( int, policy )
+ __field( int, ed_task_pid )
+ __field( u64, aggr_grp_load )
+ __field( u64, freq_aggr_thresh )
+ __field( u64, tt_load )
+ __field( u64, rq_ps )
+ __field( u64, grp_rq_ps )
+ __field( u64, nt_ps )
+ __field( u64, grp_nt_ps )
+ __field( u64, pl )
+ __field( u64, load )
+ ),
+
+ TP_fast_assign(
+ __entry->cpu = cpu_of(rq);
+ __entry->policy = policy;
+ __entry->ed_task_pid = rq->ed_task ? rq->ed_task->pid : -1;
+ __entry->aggr_grp_load = aggr_grp_load;
+ __entry->freq_aggr_thresh = freq_aggr_thresh;
+ __entry->tt_load = tt_load;
+ __entry->rq_ps = rq->prev_runnable_sum;
+ __entry->grp_rq_ps = rq->grp_time.prev_runnable_sum;
+ __entry->nt_ps = rq->nt_prev_runnable_sum;
+ __entry->grp_nt_ps = rq->grp_time.nt_prev_runnable_sum;
+ __entry->pl = rq->hmp_stats.pred_demands_sum;
+ __entry->load = load;
+ ),
+
+ TP_printk("cpu=%d policy=%d ed_task_pid=%d aggr_grp_load=%llu freq_aggr_thresh=%llu tt_load=%llu rq_ps=%llu grp_rq_ps=%llu nt_ps=%llu grp_nt_ps=%llu pl=%llu load=%llu",
+ __entry->cpu, __entry->policy, __entry->ed_task_pid,
+ __entry->aggr_grp_load, __entry->freq_aggr_thresh,
+ __entry->tt_load, __entry->rq_ps, __entry->grp_rq_ps,
+ __entry->nt_ps, __entry->grp_nt_ps, __entry->pl, __entry->load)
);
#endif
-#ifdef CONFIG_SCHED_HMP
-
-TRACE_EVENT(sched_task_load,
-
- TP_PROTO(struct task_struct *p, bool boost, int reason,
- bool sync, bool need_idle, u32 flags, int best_cpu),
-
- TP_ARGS(p, boost, reason, sync, need_idle, flags, best_cpu),
-
- TP_STRUCT__entry(
- __array( char, comm, TASK_COMM_LEN )
- __field( pid_t, pid )
- __field(unsigned int, demand )
- __field( bool, boost )
- __field( int, reason )
- __field( bool, sync )
- __field( bool, need_idle )
- __field( u32, flags )
- __field( int, best_cpu )
- __field( u64, latency )
- __field( int, grp_id )
- __field( u64, avg_burst )
- __field( u64, avg_sleep )
- ),
-
- TP_fast_assign(
- memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
- __entry->pid = p->pid;
- __entry->demand = p->ravg.demand;
- __entry->boost = boost;
- __entry->reason = reason;
- __entry->sync = sync;
- __entry->need_idle = need_idle;
- __entry->flags = flags;
- __entry->best_cpu = best_cpu;
- __entry->latency = p->state == TASK_WAKING ?
- sched_ktime_clock() -
- p->ravg.mark_start : 0;
- __entry->grp_id = p->grp ? p->grp->id : 0;
- __entry->avg_burst = p->ravg.avg_burst;
- __entry->avg_sleep = p->ravg.avg_sleep_time;
- ),
-
- TP_printk("%d (%s): demand=%u boost=%d reason=%d sync=%d need_idle=%d flags=%x grp=%d best_cpu=%d latency=%llu avg_burst=%llu avg_sleep=%llu",
- __entry->pid, __entry->comm, __entry->demand,
- __entry->boost, __entry->reason, __entry->sync,
- __entry->need_idle, __entry->flags, __entry->grp_id,
- __entry->best_cpu, __entry->latency, __entry->avg_burst,
- __entry->avg_sleep)
-);
-
-DEFINE_EVENT(sched_cpu_load, sched_cpu_load_wakeup,
- TP_PROTO(struct rq *rq, int idle, u64 irqload, unsigned int power_cost, int temp),
- TP_ARGS(rq, idle, irqload, power_cost, temp)
-);
-
-DEFINE_EVENT(sched_cpu_load, sched_cpu_load_cgroup,
- TP_PROTO(struct rq *rq, int idle, u64 irqload, unsigned int power_cost, int temp),
- TP_ARGS(rq, idle, irqload, power_cost, temp)
-);
-
-TRACE_EVENT(sched_reset_all_window_stats,
-
- TP_PROTO(u64 window_start, u64 window_size, u64 time_taken,
- int reason, unsigned int old_val, unsigned int new_val),
-
- TP_ARGS(window_start, window_size, time_taken,
- reason, old_val, new_val),
-
- TP_STRUCT__entry(
- __field( u64, window_start )
- __field( u64, window_size )
- __field( u64, time_taken )
- __field( int, reason )
- __field(unsigned int, old_val )
- __field(unsigned int, new_val )
- ),
-
- TP_fast_assign(
- __entry->window_start = window_start;
- __entry->window_size = window_size;
- __entry->time_taken = time_taken;
- __entry->reason = reason;
- __entry->old_val = old_val;
- __entry->new_val = new_val;
- ),
-
- TP_printk("time_taken %llu window_start %llu window_size %llu reason %s old_val %u new_val %u",
- __entry->time_taken, __entry->window_start,
- __entry->window_size,
- sched_window_reset_reasons[__entry->reason],
- __entry->old_val, __entry->new_val)
-);
-
-TRACE_EVENT(sched_get_busy,
-
- TP_PROTO(int cpu, u64 load, u64 nload, u64 pload, int early),
-
- TP_ARGS(cpu, load, nload, pload, early),
-
- TP_STRUCT__entry(
- __field( int, cpu )
- __field( u64, load )
- __field( u64, nload )
- __field( u64, pload )
- __field( int, early )
- ),
-
- TP_fast_assign(
- __entry->cpu = cpu;
- __entry->load = load;
- __entry->nload = nload;
- __entry->pload = pload;
- __entry->early = early;
- ),
-
- TP_printk("cpu %d load %lld new_task_load %lld predicted_load %lld early %d",
- __entry->cpu, __entry->load, __entry->nload,
- __entry->pload, __entry->early)
-);
-
-TRACE_EVENT(sched_freq_alert,
-
- TP_PROTO(int cpu, int pd_notif, int check_groups, struct rq *rq,
- u64 new_load),
-
- TP_ARGS(cpu, pd_notif, check_groups, rq, new_load),
-
- TP_STRUCT__entry(
- __field( int, cpu )
- __field( int, pd_notif )
- __field( int, check_groups )
- __field( u64, old_busy_time )
- __field( u64, ps )
- __field( u64, new_load )
- __field( u64, old_pred )
- __field( u64, new_pred )
- ),
-
- TP_fast_assign(
- __entry->cpu = cpu;
- __entry->pd_notif = pd_notif;
- __entry->check_groups = check_groups;
- __entry->old_busy_time = rq->old_busy_time;
- __entry->ps = rq->prev_runnable_sum;
- __entry->new_load = new_load;
- __entry->old_pred = rq->old_estimated_time;
- __entry->new_pred = rq->hmp_stats.pred_demands_sum;
- ),
-
- TP_printk("cpu %d pd_notif=%d check_groups %d old_busy_time=%llu prev_sum=%lld new_load=%llu old_pred=%llu new_pred=%llu",
- __entry->cpu, __entry->pd_notif, __entry->check_groups,
- __entry->old_busy_time, __entry->ps, __entry->new_load,
- __entry->old_pred, __entry->new_pred)
-);
-
-#endif /* CONFIG_SCHED_HMP */
-
#ifdef CONFIG_SMP
TRACE_EVENT(sched_cpu_util,
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index eb7e0c6..71c2c9e 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -322,6 +322,7 @@ struct drm_msm_event_resp {
#define DRM_EVENT_AD_BACKLIGHT 0x80000001
#define DRM_EVENT_CRTC_POWER 0x80000002
#define DRM_EVENT_SYS_BACKLIGHT 0x80000003
+#define DRM_EVENT_SDE_POWER 0x80000004
#define DRM_IOCTL_MSM_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GET_PARAM, struct drm_msm_param)
#define DRM_IOCTL_MSM_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_NEW, struct drm_msm_gem_new)
diff --git a/include/uapi/drm/msm_drm_pp.h b/include/uapi/drm/msm_drm_pp.h
index 7945af0..c7f2308 100644
--- a/include/uapi/drm/msm_drm_pp.h
+++ b/include/uapi/drm/msm_drm_pp.h
@@ -28,17 +28,35 @@ struct drm_msm_pcc_coeff {
/**
* struct drm_msm_pcc - pcc feature structure
- * flags: for customizing operations
- * r: red coefficients.
- * g: green coefficients.
- * b: blue coefficients.
+ * @flags: for customizing operations
+ * @r: red coefficients.
+ * @g: green coefficients.
+ * @b: blue coefficients.
+ * @r_rr: second order coefficients
+ * @r_gg: second order coefficients
+ * @r_bb: second order coefficients
+ * @g_rr: second order coefficients
+ * @g_gg: second order coefficients
+ * @g_bb: second order coefficients
+ * @b_rr: second order coefficients
+ * @b_gg: second order coefficients
+ * @b_bb: second order coefficients
*/
-
+#define DRM_MSM_PCC3
struct drm_msm_pcc {
__u64 flags;
struct drm_msm_pcc_coeff r;
struct drm_msm_pcc_coeff g;
struct drm_msm_pcc_coeff b;
+ __u32 r_rr;
+ __u32 r_gg;
+ __u32 r_bb;
+ __u32 g_rr;
+ __u32 g_gg;
+ __u32 g_bb;
+ __u32 b_rr;
+ __u32 b_gg;
+ __u32 b_bb;
};
/* struct drm_msm_pa_vlut - picture adjustment vLUT structure
@@ -135,6 +153,26 @@ struct drm_msm_pgc_lut {
__u32 c2[PGC_TBL_LEN];
};
+#define IGC_TBL_LEN 256
+#define IGC_DITHER_ENABLE (1 << 0)
+/**
+ * struct drm_msm_igc_lut - igc lut feature structure
+ * @flags: flags for the feature customization, values can be:
+ * - IGC_DITHER_ENABLE: Enable dither functionality
+ * @c0: color0 component lut
+ * @c1: color1 component lut
+ * @c2: color2 component lut
+ * @strength: dither strength, considered valid when IGC_DITHER_ENABLE
+ * is set in flags. Strength value based on source bit width.
+ */
+struct drm_msm_igc_lut {
+ __u64 flags;
+ __u32 c0[IGC_TBL_LEN];
+ __u32 c1[IGC_TBL_LEN];
+ __u32 c2[IGC_TBL_LEN];
+ __u32 strength;
+};
+
#define AD4_LUT_GRP0_SIZE 33
#define AD4_LUT_GRP1_SIZE 32
/*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index d3cbe48..7d1e3b2 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4285,6 +4285,9 @@ enum nl80211_iface_limit_attrs {
* of supported channel widths for radar detection.
* @NL80211_IFACE_COMB_RADAR_DETECT_REGIONS: u32 attribute containing the bitmap
* of supported regulatory regions for radar detection.
+ * @NL80211_IFACE_COMB_BI_MIN_GCD: u32 attribute specifying the minimum GCD of
+ * different beacon intervals supported by all the interface combinations
+ * in this group (if not present, all beacon intervals be identical).
* @NUM_NL80211_IFACE_COMB: number of attributes
* @MAX_NL80211_IFACE_COMB: highest attribute number
*
@@ -4292,8 +4295,8 @@ enum nl80211_iface_limit_attrs {
* limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2
* => allows an AP and a STA that must match BIs
*
- * numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8
- * => allows 8 of AP/GO
+ * numbers = [ #{AP, P2P-GO} <= 8 ], BI min gcd, channels = 1, max = 8,
+ * => allows 8 of AP/GO that can have BI gcd >= min gcd
*
* numbers = [ #{STA} <= 2 ], channels = 2, max = 2
* => allows two STAs on different channels
@@ -4319,6 +4322,7 @@ enum nl80211_if_combination_attrs {
NL80211_IFACE_COMB_NUM_CHANNELS,
NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
+ NL80211_IFACE_COMB_BI_MIN_GCD,
/* keep last */
NUM_NL80211_IFACE_COMB,
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index e5c4ddf..731b2f0 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -1074,6 +1074,11 @@ enum v4l2_mpeg_vidc_video_venc_iframesize_type {
V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_UNLIMITED,
};
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_8BIT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 109)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_10BIT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 110)
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h
index e6c1a45..e073c5c 100644
--- a/include/uapi/media/cam_req_mgr.h
+++ b/include/uapi/media/cam_req_mgr.h
@@ -43,6 +43,10 @@
#define V4L_EVENT_CAM_REQ_MGR_ERROR 1
#define V4L_EVENT_CAM_REQ_MGR_MAX 2
+/* SOF Event status */
+#define CAM_REQ_MGR_SOF_EVENT_SUCCESS 0
+#define CAM_REQ_MGR_SOF_EVENT_ERROR 1
+
/**
* Request Manager : flush_type
* @CAM_REQ_MGR_FLUSH_TYPE_ALL: Req mgr will remove all the pending
@@ -353,14 +357,18 @@ struct cam_req_mgr_error_msg {
/**
* struct cam_req_mgr_frame_msg
- * @request_id: request id of frame
- * @frame_count: running count of frames
- * @timestamp: timestamp of frame
+ * @request_id: request id of the frame
+ * @frame_id: frame id of the frame
+ * @timestamp: timestamp of the frame
+ * @link_hdl: link handle associated with this message
+ * @sof_status: sof status success or fail
*/
struct cam_req_mgr_frame_msg {
uint64_t request_id;
- uint64_t frame_count;
+ uint64_t frame_id;
uint64_t timestamp;
+ int32_t link_hdl;
+ uint32_t sof_status;
};
/**
diff --git a/include/uapi/sound/devdep_params.h b/include/uapi/sound/devdep_params.h
index 5061ec0..9e3133b 100644
--- a/include/uapi/sound/devdep_params.h
+++ b/include/uapi/sound/devdep_params.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015,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
@@ -66,4 +66,14 @@ struct dts_eagle_param_desc {
uint32_t device;
} __packed;
+#define HWDEP_FE_BASE 3000 /*unique base for FE hw dep nodes*/
+struct snd_pcm_mmap_fd {
+ int32_t dir;
+ int32_t fd;
+ int32_t size;
+ int32_t actual_size;
+};
+
+#define SNDRV_PCM_IOCTL_MMAP_DATA_FD _IOWR('U', 0xd2, struct snd_pcm_mmap_fd)
+
#endif
diff --git a/init/Kconfig b/init/Kconfig
index 954de19..af000c7 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1276,16 +1276,6 @@
endif # CGROUPS
-config SCHED_HMP
- bool "Scheduler support for heterogenous multi-processor systems"
- select SCHED_WALT
- depends on SMP && FAIR_GROUP_SCHED
- help
- This feature will let the scheduler optimize task placement on
- systems made of heterogeneous cpus i.e cpus that differ either
- in their instructions per-cycle capability or the maximum
- frequency they can attain.
-
config SCHED_WALT
bool "WALT"
depends on SMP && FAIR_GROUP_SCHED
@@ -1293,14 +1283,6 @@
Use Window-Assisted Load Tracking (WALT) as an alternative or
additional load tracking scheme in lieu of or along with PELT.
-config SCHED_HMP_CSTATE_AWARE
- bool "CPU C-state aware scheduler"
- depends on SCHED_HMP
- help
- This feature will let the HMP scheduler optimize task placement
- with CPUs C-state. If this is enabled, scheduler places tasks
- onto the shallowest C-state CPU among the most power efficient CPUs.
-
config SCHED_CORE_CTL
bool "QTI Core Control"
depends on SMP
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index a37a10b..02fb438 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -1249,8 +1249,10 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
timeo = MAX_SCHEDULE_TIMEOUT;
ret = netlink_attachskb(sock, nc, &timeo, NULL);
- if (ret == 1)
+ if (ret == 1) {
+ sock = NULL;
goto retry;
+ }
if (ret) {
sock = NULL;
nc = NULL;
diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config
index 301e1a6..80df048 100644
--- a/kernel/configs/android-base.config
+++ b/kernel/configs/android-base.config
@@ -17,7 +17,6 @@
CONFIG_BLK_DEV_INITRD=y
CONFIG_CGROUPS=y
CONFIG_CGROUP_CPUACCT=y
-CONFIG_CGROUP_DEBUG=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_SCHED=y
CONFIG_CGROUP_BPF=y
diff --git a/kernel/exit.c b/kernel/exit.c
index 83e8afa..35ff283 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -465,6 +465,7 @@ static void exit_mm(struct task_struct *tsk)
{
struct mm_struct *mm = tsk->mm;
struct core_state *core_state;
+ int mm_released;
mm_release(tsk, mm);
if (!mm)
@@ -511,9 +512,12 @@ static void exit_mm(struct task_struct *tsk)
enter_lazy_tlb(mm, current);
task_unlock(tsk);
mm_update_next_owner(mm);
- mmput(mm);
+
+ mm_released = mmput(mm);
if (test_thread_flag(TIF_MEMDIE))
exit_oom_victim();
+ if (mm_released)
+ set_tsk_thread_flag(tsk, TIF_MM_RELEASED);
}
static struct task_struct *find_alive_thread(struct task_struct *p)
diff --git a/kernel/fork.c b/kernel/fork.c
index 33663b0..f90327b 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -877,12 +877,17 @@ static inline void __mmput(struct mm_struct *mm)
/*
* Decrement the use count and release all resources for an mm.
*/
-void mmput(struct mm_struct *mm)
+int mmput(struct mm_struct *mm)
{
+ int mm_freed = 0;
might_sleep();
- if (atomic_dec_and_test(&mm->mm_users))
+ if (atomic_dec_and_test(&mm->mm_users)) {
__mmput(mm);
+ mm_freed = 1;
+ }
+
+ return mm_freed;
}
EXPORT_SYMBOL_GPL(mmput);
diff --git a/kernel/locking/rwsem-spinlock.c b/kernel/locking/rwsem-spinlock.c
index 2bef4ab..a608f7a 100644
--- a/kernel/locking/rwsem-spinlock.c
+++ b/kernel/locking/rwsem-spinlock.c
@@ -233,8 +233,8 @@ int __sched __down_write_common(struct rw_semaphore *sem, int state)
out_nolock:
list_del(&waiter.list);
- if (!list_empty(&sem->wait_list))
- __rwsem_do_wake(sem, 1);
+ if (!list_empty(&sem->wait_list) && sem->count >= 0)
+ __rwsem_do_wake(sem, 0);
raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
return -EINTR;
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 12fe782..009f788 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -588,7 +588,12 @@ void pm_qos_add_request(struct pm_qos_request *req,
if (irq_can_set_affinity(req->irq)) {
int ret = 0;
struct irq_desc *desc = irq_to_desc(req->irq);
- struct cpumask *mask = desc->irq_data.common->affinity;
+ struct cpumask *mask;
+
+ if (!desc)
+ break;
+
+ mask = desc->irq_data.common->affinity;
/* Get the current affinity */
cpumask_copy(&req->cpus_affine, mask);
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
index 3d12ce8..f6cce95 100644
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -18,7 +18,6 @@
obj-y += core.o loadavg.o clock.o cputime.o
obj-y += idle_task.o fair.o rt.o deadline.o stop_task.o
obj-y += wait.o swait.o completion.o idle.o
-obj-$(CONFIG_SCHED_HMP) += hmp.o boost.o
obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o energy.o sched_avg.o
obj-$(CONFIG_SCHED_WALT) += walt.o boost.o
obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index c2433b3..46e4643 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1074,7 +1074,6 @@ static int migration_cpu_stop(void *data)
struct migration_arg *arg = data;
struct task_struct *p = arg->task;
struct rq *rq = this_rq();
- int src_cpu = cpu_of(rq);
bool moved = false;
/*
@@ -1109,9 +1108,6 @@ static int migration_cpu_stop(void *data)
local_irq_enable();
- if (moved)
- notify_migration(src_cpu, arg->dest_cpu, false, p);
-
return 0;
}
@@ -1287,8 +1283,6 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
#endif
#endif
- trace_sched_migrate_task(p, new_cpu, pct_task_load(p));
-
if (task_cpu(p) != new_cpu) {
if (p->sched_class->migrate_task_rq)
p->sched_class->migrate_task_rq(p);
@@ -2091,12 +2085,9 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
struct related_thread_group *grp = NULL;
int src_cpu;
bool notif_required = false;
- bool freq_notif_allowed = !(wake_flags & WF_NO_NOTIFIER);
bool check_group = false;
#endif
- wake_flags &= ~WF_NO_NOTIFIER;
-
/*
* If we are going to wake up a thread waiting for CONDITION we
* need to ensure that CONDITION=1 done by the caller can not be
@@ -2208,19 +2199,6 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
out:
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
-#ifdef CONFIG_SMP
- if (freq_notif_allowed) {
- if (notif_required && !same_freq_domain(src_cpu, cpu)) {
- check_for_freq_change(cpu_rq(cpu),
- false, check_group);
- check_for_freq_change(cpu_rq(src_cpu),
- false, check_group);
- } else if (success) {
- check_for_freq_change(cpu_rq(cpu), true, false);
- }
- }
-#endif
-
return success;
}
@@ -2302,26 +2280,6 @@ int wake_up_process(struct task_struct *p)
}
EXPORT_SYMBOL(wake_up_process);
-/**
- * wake_up_process_no_notif - Wake up a specific process without notifying
- * governor
- * @p: The process to be woken up.
- *
- * Attempt to wake up the nominated process and move it to the set of runnable
- * processes.
- *
- * Return: 1 if the process was woken up, 0 if it was already running.
- *
- * It may be assumed that this function implies a write memory barrier before
- * changing the task state if and only if any tasks are woken up.
- */
-int wake_up_process_no_notif(struct task_struct *p)
-{
- WARN_ON(task_is_stopped_or_traced(p));
- return try_to_wake_up(p, TASK_NORMAL, WF_NO_NOTIFIER);
-}
-EXPORT_SYMBOL(wake_up_process_no_notif);
-
int wake_up_state(struct task_struct *p, unsigned int state)
{
return try_to_wake_up(p, state, 0);
@@ -3165,7 +3123,7 @@ void get_iowait_load(unsigned long *nr_waiters, unsigned long *load)
*load = rq->load.weight;
}
-#if defined(CONFIG_SMP) && !defined(CONFIG_SCHED_HMP)
+#ifdef CONFIG_SMP
/*
* sched_exec - execve() is a valuable balancing opportunity, because at
@@ -3692,15 +3650,10 @@ static void __sched notrace __schedule(bool preempt)
update_task_ravg(prev, rq, PUT_PREV_TASK, wallclock, 0);
update_task_ravg(next, rq, PICK_NEXT_TASK, wallclock, 0);
cpufreq_update_util(rq, 0);
- if (!is_idle_task(prev) && !prev->on_rq)
- update_avg_burst(prev);
-
rq->nr_switches++;
rq->curr = next;
++*switch_count;
- set_task_last_switch_out(prev, wallclock);
-
trace_sched_switch(preempt, prev, next);
rq = context_switch(rq, prev, next, cookie); /* unlocks the rq */
} else {
@@ -5953,7 +5906,6 @@ static void migrate_tasks(struct rq *dead_rq, bool migrate_pinned_tasks)
if (rq != dead_rq) {
raw_spin_unlock(&rq->lock);
raw_spin_unlock(&next->pi_lock);
- notify_migration(dead_rq->cpu, dest_cpu, true, next);
rq = dead_rq;
raw_spin_lock(&next->pi_lock);
raw_spin_lock(&rq->lock);
@@ -8236,9 +8188,6 @@ void __init sched_init(void)
for (i = 0; i < WAIT_TABLE_SIZE; i++)
init_waitqueue_head(bit_wait_table + i);
-#ifdef CONFIG_SCHED_HMP
- pr_info("HMP scheduling enabled.\n");
-#endif
sched_boost_parse_dt();
init_clusters();
@@ -8359,56 +8308,9 @@ void __init sched_init(void)
rq->avg_idle = 2*sysctl_sched_migration_cost;
rq->max_idle_balance_cost = sysctl_sched_migration_cost;
rq->push_task = NULL;
-#ifdef CONFIG_SCHED_WALT
- cpumask_set_cpu(i, &rq->freq_domain_cpumask);
- init_irq_work(&rq->irq_work, walt_irq_work);
- rq->hmp_stats.cumulative_runnable_avg = 0;
- rq->window_start = 0;
- rq->cum_window_start = 0;
- rq->hmp_stats.nr_big_tasks = 0;
- rq->hmp_flags = 0;
- rq->cur_irqload = 0;
- rq->avg_irqload = 0;
- rq->irqload_ts = 0;
- rq->static_cpu_pwr_cost = 0;
- rq->cc.cycles = 1;
- rq->cc.time = 1;
- rq->cstate = 0;
- rq->wakeup_latency = 0;
- rq->wakeup_energy = 0;
- /*
- * All cpus part of same cluster by default. This avoids the
- * need to check for rq->cluster being non-NULL in hot-paths
- * like select_best_cpu()
- */
- rq->cluster = &init_cluster;
- rq->curr_runnable_sum = rq->prev_runnable_sum = 0;
- rq->nt_curr_runnable_sum = rq->nt_prev_runnable_sum = 0;
- memset(&rq->grp_time, 0, sizeof(struct group_cpu_time));
- rq->old_busy_time = 0;
- rq->old_estimated_time = 0;
- rq->old_busy_time_group = 0;
- rq->hmp_stats.pred_demands_sum = 0;
- rq->ed_task = NULL;
- rq->curr_table = 0;
- rq->prev_top = 0;
- rq->curr_top = 0;
+ walt_sched_init(rq);
- for (j = 0; j < NUM_TRACKED_WINDOWS; j++) {
- memset(&rq->load_subs[j], 0,
- sizeof(struct load_subtractions));
-
- rq->top_tasks[j] = kcalloc(NUM_LOAD_INDICES,
- sizeof(u8), GFP_NOWAIT);
-
- /* No other choice */
- BUG_ON(!rq->top_tasks[j]);
-
- clear_top_tasks_bitmap(rq->top_tasks_bitmap[j]);
- }
- rq->cum_window_demand = 0;
-#endif
INIT_LIST_HEAD(&rq->cfs_tasks);
rq_attach_root(rq, &def_root_domain);
@@ -8427,8 +8329,6 @@ void __init sched_init(void)
i = alloc_related_thread_groups();
BUG_ON(i);
- set_hmp_defaults();
-
set_load_weight(&init_task);
/*
@@ -9552,13 +9452,6 @@ static u64 cpu_rt_period_read_uint(struct cgroup_subsys_state *css,
#endif /* CONFIG_RT_GROUP_SCHED */
static struct cftype cpu_files[] = {
-#ifdef CONFIG_SCHED_HMP
- {
- .name = "upmigrate_discourage",
- .read_u64 = cpu_upmigrate_discourage_read_u64,
- .write_u64 = cpu_upmigrate_discourage_write_u64,
- },
-#endif
#ifdef CONFIG_FAIR_GROUP_SCHED
{
.name = "shares",
diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c
index b140e55..4c3bf526 100644
--- a/kernel/sched/core_ctl.c
+++ b/kernel/sched/core_ctl.c
@@ -612,8 +612,7 @@ static void wake_up_core_ctl_thread(struct cluster_data *cluster)
spin_lock_irqsave(&cluster->pending_lock, flags);
cluster->pending = true;
spin_unlock_irqrestore(&cluster->pending_lock, flags);
-
- wake_up_process_no_notif(cluster->core_ctl_thread);
+ wake_up_process(cluster->core_ctl_thread);
}
static u64 core_ctl_check_timestamp;
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index b6a639b..dce76d1 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -404,12 +404,13 @@ static void sugov_update_shared(struct update_util_data *hook, u64 time,
static void sugov_work(struct kthread_work *work)
{
struct sugov_policy *sg_policy = container_of(work, struct sugov_policy, work);
+ unsigned long flags;
mutex_lock(&sg_policy->work_lock);
- raw_spin_lock(&sg_policy->update_lock);
+ raw_spin_lock_irqsave(&sg_policy->update_lock, flags);
sugov_track_cycles(sg_policy, sg_policy->policy->cur,
sched_ktime_clock());
- raw_spin_unlock(&sg_policy->update_lock);
+ raw_spin_unlock_irqrestore(&sg_policy->update_lock, flags);
__cpufreq_driver_target(sg_policy->policy, sg_policy->next_freq,
CPUFREQ_RELATION_L);
mutex_unlock(&sg_policy->work_lock);
@@ -488,18 +489,19 @@ static ssize_t hispeed_freq_store(struct gov_attr_set *attr_set,
unsigned int val;
struct sugov_policy *sg_policy;
unsigned long hs_util;
+ unsigned long flags;
if (kstrtouint(buf, 10, &val))
return -EINVAL;
tunables->hispeed_freq = val;
list_for_each_entry(sg_policy, &attr_set->policy_list, tunables_hook) {
- raw_spin_lock(&sg_policy->update_lock);
+ raw_spin_lock_irqsave(&sg_policy->update_lock, flags);
hs_util = freq_to_util(sg_policy,
sg_policy->tunables->hispeed_freq);
hs_util = mult_frac(hs_util, TARGET_LOAD, 100);
sg_policy->hispeed_util = hs_util;
- raw_spin_unlock(&sg_policy->update_lock);
+ raw_spin_unlock_irqrestore(&sg_policy->update_lock, flags);
}
return count;
@@ -784,13 +786,14 @@ static void sugov_stop(struct cpufreq_policy *policy)
static void sugov_limits(struct cpufreq_policy *policy)
{
struct sugov_policy *sg_policy = policy->governor_data;
+ unsigned long flags;
if (!policy->fast_switch_enabled) {
mutex_lock(&sg_policy->work_lock);
- raw_spin_lock(&sg_policy->update_lock);
+ raw_spin_lock_irqsave(&sg_policy->update_lock, flags);
sugov_track_cycles(sg_policy, sg_policy->policy->cur,
sched_ktime_clock());
- raw_spin_unlock(&sg_policy->update_lock);
+ raw_spin_unlock_irqrestore(&sg_policy->update_lock, flags);
cpufreq_policy_apply_limits(policy);
mutex_unlock(&sg_policy->work_lock);
}
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index ed9f6db..b520691 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -698,10 +698,6 @@ do { \
P(cpu_capacity);
#endif
#ifdef CONFIG_SCHED_WALT
-#ifdef CONFIG_SCHED_HMP
- P(static_cpu_pwr_cost);
- P(cluster->static_cluster_pwr_cost);
-#endif
P(cluster->load_scale_factor);
P(cluster->capacity);
P(cluster->max_possible_capacity);
@@ -794,10 +790,6 @@ static void sched_debug_header(struct seq_file *m)
P(sysctl_sched_child_runs_first);
P(sysctl_sched_features);
#ifdef CONFIG_SCHED_WALT
-#ifdef CONFIG_SCHED_HMP
- P(sched_upmigrate);
- P(sched_downmigrate);
-#endif
P(sched_init_task_load_windows);
P(min_capacity);
P(max_capacity);
@@ -965,9 +957,6 @@ static void sched_show_numa(struct task_struct *p, struct seq_file *m)
void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
{
unsigned long nr_switches;
- unsigned int load_avg;
-
- load_avg = pct_task_load(p);
SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, task_pid_nr(p),
get_nr_threads(p));
@@ -1025,12 +1014,9 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
P_SCHEDSTAT(se.statistics.nr_wakeups_affine_attempts);
P_SCHEDSTAT(se.statistics.nr_wakeups_passive);
P_SCHEDSTAT(se.statistics.nr_wakeups_idle);
-#if defined(CONFIG_SMP) && defined(CONFIG_FAIR_GROUP_SCHED)
- __P(load_avg);
-#ifdef CONFIG_SCHED_HMP
+#ifdef CONFIG_SCHED_WALT
P(ravg.demand);
#endif
-#endif
avg_atom = p->se.sum_exec_runtime;
if (nr_switches)
avg_atom = div64_ul(avg_atom, nr_switches);
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d06ac7d..e0ab4d6 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -48,52 +48,6 @@ static void fixup_hmp_sched_stats_fair(struct rq *rq, struct task_struct *p,
u32 new_task_load, u32 new_pred_demand);
#endif
-#ifdef CONFIG_SCHED_HMP
-#ifdef CONFIG_CFS_BANDWIDTH
-static void inc_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq,
- struct task_struct *p, int change_cra);
-static void dec_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq,
- struct task_struct *p, int change_cra);
-
-static inline void dec_throttled_cfs_rq_hmp_stats(
- struct hmp_sched_stats *stats,
- struct cfs_rq *cfs_rq);
-
-static inline void inc_throttled_cfs_rq_hmp_stats(
- struct hmp_sched_stats *stats,
- struct cfs_rq *cfs_rq);
-
-static inline void init_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq);
-
-#else /* CONFIG_CFS_BANDWIDTH */
-static inline void inc_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq,
- struct task_struct *p, int change_cra) { }
-static inline void dec_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq,
- struct task_struct *p, int change_cra) { }
-#endif /* CONFIG_CFS_BANDWIDTH */
-
-#ifdef CONFIG_SMP
-
-static struct rq *find_busiest_queue_hmp(struct lb_env *env,
- struct sched_group *group);
-static int
-bail_inter_cluster_balance(struct lb_env *env, struct sd_lb_stats *sds);
-
-static bool update_sd_pick_busiest_active_balance(struct lb_env *env,
- struct sd_lb_stats *sds,
- struct sched_group *sg,
- struct sg_lb_stats *sgs);
-
-static int select_best_cpu(struct task_struct *p, int target, int reason,
- int sync);
-
-#ifdef CONFIG_NO_HZ_COMMON
-static int find_new_hmp_ilb(int type);
-static int _nohz_kick_needed_hmp(struct rq *rq, int cpu, int *type);
-#endif /* CONFIG_NO_HZ_COMMON */
-#endif /* CONFIG_SMP */
-#else /* CONFIG_SCHED_HMP */
-
static inline void inc_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq,
struct task_struct *p, int change_cra) { }
static inline void dec_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq,
@@ -123,8 +77,6 @@ static inline bool update_sd_pick_busiest_active_balance(struct lb_env *env,
}
#endif /* CONFIG_SMP */
-#endif /* CONFIG_SCHED_HMP */
-
#ifdef CONFIG_SCHED_WALT
static inline bool task_fits_max(struct task_struct *p, int cpu);
#endif
@@ -4129,8 +4081,7 @@ static void throttle_cfs_rq(struct cfs_rq *cfs_rq)
/* Log effect on hmp stats after throttling */
trace_sched_cpu_load_cgroup(rq, idle_cpu(cpu_of(rq)),
sched_irqload(cpu_of(rq)),
- power_cost(cpu_of(rq), 0),
- cpu_temp(cpu_of(rq)));
+ power_cost(cpu_of(rq), 0));
}
void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
@@ -4186,8 +4137,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
/* Log effect on hmp stats after un-throttling */
trace_sched_cpu_load_cgroup(rq, idle_cpu(cpu_of(rq)),
sched_irqload(cpu_of(rq)),
- power_cost(cpu_of(rq), 0),
- cpu_temp(cpu_of(rq)));
+ power_cost(cpu_of(rq), 0));
}
static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b,
@@ -5407,10 +5357,13 @@ static inline int task_util(struct task_struct *p)
}
static inline bool
-bias_to_waker_cpu(struct task_struct *p, int cpu)
+bias_to_waker_cpu(struct task_struct *p, int cpu, struct cpumask *rtg_target)
{
+ int rtg_target_cpu = rtg_target ? cpumask_first(rtg_target) : cpu;
+
return cpumask_test_cpu(cpu, tsk_cpus_allowed(p)) &&
cpu_active(cpu) && !cpu_isolated(cpu) &&
+ capacity_orig_of(cpu) >= capacity_orig_of(rtg_target_cpu) &&
task_fits_max(p, cpu);
}
@@ -6730,6 +6683,7 @@ static int energy_aware_wake_cpu(struct task_struct *p, int target, int sync)
bool need_idle;
enum sched_boost_policy placement_boost = task_sched_boost(p) ?
sched_boost_policy() : SCHED_BOOST_NONE;
+ struct related_thread_group *grp;
sd = rcu_dereference(per_cpu(sd_ea, task_cpu(p)));
@@ -6745,22 +6699,17 @@ static int energy_aware_wake_cpu(struct task_struct *p, int target, int sync)
need_idle = wake_to_idle(p);
- if (sync && bias_to_waker_cpu(p, cpu)) {
+ grp = task_related_thread_group(p);
+ if (grp && grp->preferred_cluster)
+ rtg_target = &grp->preferred_cluster->cpus;
+
+ if (sync && bias_to_waker_cpu(p, cpu, rtg_target)) {
trace_sched_task_util_bias_to_waker(p, task_cpu(p),
task_util(p), cpu, cpu, 0, need_idle);
return cpu;
}
if (sysctl_sched_is_big_little) {
- struct related_thread_group *grp;
-
- rcu_read_lock();
- grp = task_related_thread_group(p);
- rcu_read_unlock();
-
- if (grp && grp->preferred_cluster)
- rtg_target = &grp->preferred_cluster->cpus;
-
task_util_boosted = boosted_task_util(p);
/*
@@ -7076,12 +7025,12 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f
int want_affine = 0;
int sync = wake_flags & WF_SYNC;
-#ifdef CONFIG_SCHED_HMP
- return select_best_cpu(p, prev_cpu, 0, sync);
-#endif
-
- if (energy_aware())
- return energy_aware_wake_cpu(p, prev_cpu, sync);
+ if (energy_aware()) {
+ rcu_read_lock();
+ new_cpu = energy_aware_wake_cpu(p, prev_cpu, sync);
+ rcu_read_unlock();
+ return new_cpu;
+ }
if (sd_flag & SD_BALANCE_WAKE) {
record_wakee(p);
@@ -7748,9 +7697,6 @@ struct lb_env {
enum fbq_type fbq_type;
enum group_type busiest_group_type;
struct list_head tasks;
-#ifdef CONFIG_SCHED_HMP
- enum sched_boost_policy boost_policy;
-#endif
};
/*
@@ -7848,9 +7794,6 @@ static
int can_migrate_task(struct task_struct *p, struct lb_env *env)
{
int tsk_cache_hot;
-#ifdef CONFIG_SCHED_HMP
- int twf, group_cpus;
-#endif
lockdep_assert_held(&env->src_rq->lock);
@@ -7921,37 +7864,6 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
return 0;
#endif
-#ifdef CONFIG_SCHED_HMP
- if (cpu_capacity(env->dst_cpu) > cpu_capacity(env->src_cpu)) {
- if (nr_big_tasks(env->src_rq) && !is_big_task(p))
- return 0;
-
- if (env->boost_policy == SCHED_BOOST_ON_BIG &&
- !task_sched_boost(p))
- return 0;
- }
-
- twf = task_will_fit(p, env->dst_cpu);
-
- /*
- * Attempt to not pull tasks that don't fit. We may get lucky and find
- * one that actually fits.
- */
- if (env->flags & LBF_IGNORE_BIG_TASKS && !twf)
- return 0;
-
- /*
- * Group imbalance can sometimes cause work to be pulled across groups
- * even though the group could have managed the imbalance on its own.
- * Prevent inter-cluster migrations for big tasks when the number of
- * tasks is lower than the capacity of the group.
- */
- group_cpus = DIV_ROUND_UP(env->busiest_grp_capacity,
- SCHED_CAPACITY_SCALE);
- if (!twf && env->busiest_nr_running <= group_cpus)
- return 0;
-#endif
-
if (task_running(env->src_rq, p)) {
schedstat_inc(p->se.statistics.nr_failed_migrations_running);
return 0;
@@ -8292,10 +8204,6 @@ struct sg_lb_stats {
unsigned long group_capacity;
unsigned long group_util; /* Total utilization of the group */
unsigned int sum_nr_running; /* Nr tasks running in the group */
-#ifdef CONFIG_SCHED_HMP
- unsigned long sum_nr_big_tasks;
- u64 group_cpu_load; /* Scaled load of all CPUs of the group */
-#endif
unsigned int idle_cpus;
unsigned int group_weight;
enum group_type group_type;
@@ -8339,10 +8247,6 @@ static inline void init_sd_lb_stats(struct sd_lb_stats *sds)
.avg_load = 0UL,
.sum_nr_running = 0,
.group_type = group_other,
-#ifdef CONFIG_SCHED_HMP
- .sum_nr_big_tasks = 0UL,
- .group_cpu_load = 0ULL,
-#endif
},
};
}
@@ -8673,8 +8577,7 @@ static inline void update_sg_lb_stats(struct lb_env *env,
trace_sched_cpu_load_lb(cpu_rq(i), idle_cpu(i),
sched_irqload(i),
- power_cost(i, 0),
- cpu_temp(i));
+ power_cost(i, 0));
if (cpu_isolated(i))
continue;
@@ -8693,11 +8596,6 @@ static inline void update_sg_lb_stats(struct lb_env *env,
if (nr_running > 1)
*overload = true;
-#ifdef CONFIG_SCHED_HMP
- sgs->sum_nr_big_tasks += rq->hmp_stats.nr_big_tasks;
- sgs->group_cpu_load += cpu_load(i);
-#endif
-
#ifdef CONFIG_NUMA_BALANCING
sgs->nr_numa_running += rq->nr_numa_running;
sgs->nr_preferred_running += rq->nr_preferred_running;
@@ -9306,10 +9204,6 @@ static struct rq *find_busiest_queue(struct lb_env *env,
unsigned long busiest_load = 0, busiest_capacity = 1;
int i;
-#ifdef CONFIG_SCHED_HMP
- return find_busiest_queue_hmp(env, group);
-#endif
-
for_each_cpu_and(i, sched_group_cpus(group), env->cpus) {
unsigned long capacity, wl;
enum fbq_type rt;
@@ -9515,9 +9409,6 @@ static int load_balance(int this_cpu, struct rq *this_rq,
.loop = 0,
.busiest_nr_running = 0,
.busiest_grp_capacity = 0,
-#ifdef CONFIG_SCHED_HMP
- .boost_policy = sched_boost_policy(),
-#endif
};
/*
@@ -9724,21 +9615,9 @@ static int load_balance(int this_cpu, struct rq *this_rq,
sd->nr_balance_failed = sd->cache_nice_tries +
NEED_ACTIVE_BALANCE_THRESHOLD - 1;
}
- } else {
+ } else
sd->nr_balance_failed = 0;
- /* Assumes one 'busiest' cpu that we pulled tasks from */
- if (!same_freq_domain(this_cpu, cpu_of(busiest))) {
- int check_groups = !!(env.flags &
- LBF_MOVED_RELATED_THREAD_GROUP_TASK);
-
- check_for_freq_change(this_rq, false, check_groups);
- check_for_freq_change(busiest, false, check_groups);
- } else {
- check_for_freq_change(this_rq, true, false);
- }
- }
-
if (likely(!active_balance)) {
/* We were unbalanced, so reset the balancing interval */
sd->balance_interval = sd->min_interval;
@@ -9973,9 +9852,6 @@ static int active_load_balance_cpu_stop(void *data)
.busiest_grp_capacity = 0,
.flags = 0,
.loop = 0,
-#ifdef CONFIG_SCHED_HMP
- .boost_policy = sched_boost_policy(),
-#endif
};
bool moved = false;
@@ -10060,15 +9936,6 @@ static int active_load_balance_cpu_stop(void *data)
local_irq_enable();
- if (moved && !same_freq_domain(busiest_cpu, target_cpu)) {
- int check_groups = !!(env.flags &
- LBF_MOVED_RELATED_THREAD_GROUP_TASK);
- check_for_freq_change(busiest_rq, false, check_groups);
- check_for_freq_change(target_rq, false, check_groups);
- } else if (moved) {
- check_for_freq_change(target_rq, true, false);
- }
-
return 0;
}
@@ -10098,10 +9965,6 @@ static inline int find_new_ilb(int type)
struct rq *rq = cpu_rq(cpu);
cpumask_t cpumask;
-#ifdef CONFIG_SCHED_HMP
- return find_new_hmp_ilb(type);
-#endif
-
rcu_read_lock();
sd = rcu_dereference_check_sched_domain(rq->sd);
if (sd) {
@@ -10437,11 +10300,9 @@ static void nohz_idle_balance(struct rq *this_rq, enum cpu_idle_type idle)
static inline bool nohz_kick_needed(struct rq *rq, int *type)
{
unsigned long now = jiffies;
-#ifndef CONFIG_SCHED_HMP
struct sched_domain_shared *sds;
struct sched_domain *sd;
int nr_busy;
-#endif
int cpu = rq->cpu;
bool kick = false;
@@ -10462,17 +10323,12 @@ static inline bool nohz_kick_needed(struct rq *rq, int *type)
if (likely(!atomic_read(&nohz.nr_cpus)))
return false;
-#ifdef CONFIG_SCHED_HMP
- return _nohz_kick_needed_hmp(rq, cpu, type);
-#endif
-
if (time_before(now, nohz.next_balance))
return false;
if (energy_aware())
return rq->nr_running >= 2 && cpu_overutilized(cpu);
-#ifndef CONFIG_SCHED_HMP
rcu_read_lock();
sds = rcu_dereference(per_cpu(sd_llc_shared, cpu));
if (sds && !energy_aware()) {
@@ -10506,7 +10362,6 @@ static inline bool nohz_kick_needed(struct rq *rq, int *type)
unlock:
rcu_read_unlock();
-#endif
return kick;
}
#else
@@ -11195,7 +11050,6 @@ static void fixup_hmp_sched_stats_fair(struct rq *rq, struct task_struct *p,
fixup_cumulative_runnable_avg(&cfs_rq->hmp_stats, p,
task_load_delta,
pred_demand_delta);
- fixup_nr_big_tasks(&cfs_rq->hmp_stats, p, task_load_delta);
if (cfs_rq_throttled(cfs_rq))
break;
}
@@ -11205,7 +11059,6 @@ static void fixup_hmp_sched_stats_fair(struct rq *rq, struct task_struct *p,
fixup_cumulative_runnable_avg(&rq->hmp_stats, p,
task_load_delta,
pred_demand_delta);
- fixup_nr_big_tasks(&rq->hmp_stats, p, task_load_delta);
}
}
@@ -11222,7 +11075,6 @@ fixup_hmp_sched_stats_fair(struct rq *rq, struct task_struct *p,
fixup_cumulative_runnable_avg(&rq->hmp_stats, p, task_load_delta,
pred_demand_delta);
- fixup_nr_big_tasks(&rq->hmp_stats, p, task_load_delta);
}
static inline int task_will_be_throttled(struct task_struct *p)
@@ -11265,1026 +11117,9 @@ static inline int task_will_be_throttled(struct task_struct *p)
#endif
-/* QHMP/Zone sched implementation begins here */
-
-#ifdef CONFIG_SCHED_HMP
-#ifdef CONFIG_SMP
-
-/* CPU selection flag */
-#define SBC_FLAG_PREV_CPU 0x1
-#define SBC_FLAG_BEST_CAP_CPU 0x2
-#define SBC_FLAG_CPU_COST 0x4
-#define SBC_FLAG_MIN_COST 0x8
-#define SBC_FLAG_IDLE_LEAST_LOADED 0x10
-#define SBC_FLAG_IDLE_CSTATE 0x20
-#define SBC_FLAG_COST_CSTATE_TIE_BREAKER 0x40
-#define SBC_FLAG_COST_CSTATE_PREV_CPU_TIE_BREAKER 0x80
-#define SBC_FLAG_CSTATE_LOAD 0x100
-#define SBC_FLAG_BEST_SIBLING 0x200
-#define SBC_FLAG_WAKER_CPU 0x400
-#define SBC_FLAG_PACK_TASK 0x800
-
-/* Cluster selection flag */
-#define SBC_FLAG_COLOC_CLUSTER 0x10000
-#define SBC_FLAG_WAKER_CLUSTER 0x20000
-#define SBC_FLAG_BACKUP_CLUSTER 0x40000
-#define SBC_FLAG_BOOST_CLUSTER 0x80000
-
-struct cpu_select_env {
- struct task_struct *p;
- struct related_thread_group *rtg;
- u8 reason;
- u8 need_idle:1;
- u8 need_waker_cluster:1;
- u8 sync:1;
- enum sched_boost_policy boost_policy;
- u8 pack_task:1;
- int prev_cpu;
- DECLARE_BITMAP(candidate_list, NR_CPUS);
- DECLARE_BITMAP(backup_list, NR_CPUS);
- u64 task_load;
- u64 cpu_load;
- u32 sbc_best_flag;
- u32 sbc_best_cluster_flag;
- struct cpumask search_cpus;
-};
-
-struct cluster_cpu_stats {
- int best_idle_cpu, least_loaded_cpu;
- int best_capacity_cpu, best_cpu, best_sibling_cpu;
- int min_cost, best_sibling_cpu_cost;
- int best_cpu_wakeup_latency;
- u64 min_load, best_load, best_sibling_cpu_load;
- s64 highest_spare_capacity;
-};
-
-static int spill_threshold_crossed(struct cpu_select_env *env, struct rq *rq)
-{
- u64 total_load;
-
- total_load = env->task_load + env->cpu_load;
-
- if (total_load > sched_spill_load ||
- (rq->nr_running + 1) > sysctl_sched_spill_nr_run)
- return 1;
-
- return 0;
-}
-
-static int skip_cpu(int cpu, struct cpu_select_env *env)
-{
- int tcpu = task_cpu(env->p);
- int skip = 0;
-
- if (!env->reason)
- return 0;
-
- if (is_reserved(cpu))
- return 1;
-
- switch (env->reason) {
- case UP_MIGRATION:
- skip = !idle_cpu(cpu);
- break;
- case IRQLOAD_MIGRATION:
- /* Purposely fall through */
- default:
- skip = (cpu == tcpu);
- break;
- }
-
- return skip;
-}
-
-static inline int
-acceptable_capacity(struct sched_cluster *cluster, struct cpu_select_env *env)
-{
- int tcpu;
-
- if (!env->reason)
- return 1;
-
- tcpu = task_cpu(env->p);
- switch (env->reason) {
- case UP_MIGRATION:
- return cluster->capacity > cpu_capacity(tcpu);
-
- case DOWN_MIGRATION:
- return cluster->capacity < cpu_capacity(tcpu);
-
- default:
- break;
- }
-
- return 1;
-}
-
-static int
-skip_cluster(struct sched_cluster *cluster, struct cpu_select_env *env)
-{
- if (!test_bit(cluster->id, env->candidate_list))
- return 1;
-
- if (!acceptable_capacity(cluster, env)) {
- __clear_bit(cluster->id, env->candidate_list);
- return 1;
- }
-
- return 0;
-}
-
-static struct sched_cluster *
-select_least_power_cluster(struct cpu_select_env *env)
-{
- struct sched_cluster *cluster;
-
- if (env->rtg) {
- int cpu = cluster_first_cpu(env->rtg->preferred_cluster);
-
- env->task_load = scale_load_to_cpu(task_load(env->p), cpu);
-
- if (task_load_will_fit(env->p, env->task_load,
- cpu, env->boost_policy)) {
- env->sbc_best_cluster_flag |= SBC_FLAG_COLOC_CLUSTER;
-
- if (env->boost_policy == SCHED_BOOST_NONE)
- return env->rtg->preferred_cluster;
-
- for_each_sched_cluster(cluster) {
- if (cluster != env->rtg->preferred_cluster) {
- __set_bit(cluster->id,
- env->backup_list);
- __clear_bit(cluster->id,
- env->candidate_list);
- }
- }
-
- return env->rtg->preferred_cluster;
- }
-
- /*
- * Since the task load does not fit on the preferred
- * cluster anymore, pretend that the task does not
- * have any preferred cluster. This allows the waking
- * task to get the appropriate CPU it needs as per the
- * non co-location placement policy without having to
- * wait until the preferred cluster is updated.
- */
- env->rtg = NULL;
- }
-
- for_each_sched_cluster(cluster) {
- if (!skip_cluster(cluster, env)) {
- int cpu = cluster_first_cpu(cluster);
-
- env->task_load = scale_load_to_cpu(task_load(env->p),
- cpu);
- if (task_load_will_fit(env->p, env->task_load, cpu,
- env->boost_policy))
- return cluster;
-
- __set_bit(cluster->id, env->backup_list);
- __clear_bit(cluster->id, env->candidate_list);
- }
- }
-
- return NULL;
-}
-
-static struct sched_cluster *
-next_candidate(const unsigned long *list, int start, int end)
-{
- int cluster_id;
-
- cluster_id = find_next_bit(list, end, start - 1 + 1);
- if (cluster_id >= end)
- return NULL;
-
- return sched_cluster[cluster_id];
-}
-
-static void
-update_spare_capacity(struct cluster_cpu_stats *stats,
- struct cpu_select_env *env, int cpu, int capacity,
- u64 cpu_load)
-{
- s64 spare_capacity = sched_ravg_window - cpu_load;
-
- if (spare_capacity > 0 &&
- (spare_capacity > stats->highest_spare_capacity ||
- (spare_capacity == stats->highest_spare_capacity &&
- ((!env->need_waker_cluster &&
- capacity > cpu_capacity(stats->best_capacity_cpu)) ||
- (env->need_waker_cluster &&
- cpu_rq(cpu)->nr_running <
- cpu_rq(stats->best_capacity_cpu)->nr_running))))) {
- /*
- * If sync waker is the only runnable of CPU, cr_avg of the
- * CPU is 0 so we have high chance to place the wakee on the
- * waker's CPU which likely causes preemtion of the waker.
- * This can lead migration of preempted waker. Place the
- * wakee on the real idle CPU when it's possible by checking
- * nr_running to avoid such preemption.
- */
- stats->highest_spare_capacity = spare_capacity;
- stats->best_capacity_cpu = cpu;
- }
-}
-
-static inline void find_backup_cluster(
-struct cpu_select_env *env, struct cluster_cpu_stats *stats)
-{
- struct sched_cluster *next = NULL;
- int i;
- struct cpumask search_cpus;
-
- while (!bitmap_empty(env->backup_list, num_clusters)) {
- next = next_candidate(env->backup_list, 0, num_clusters);
- __clear_bit(next->id, env->backup_list);
-
- cpumask_and(&search_cpus, &env->search_cpus, &next->cpus);
- for_each_cpu(i, &search_cpus) {
- trace_sched_cpu_load_wakeup(cpu_rq(i), idle_cpu(i),
- sched_irqload(i), power_cost(i, task_load(env->p) +
- cpu_cravg_sync(i, env->sync)), 0);
-
- update_spare_capacity(stats, env, i, next->capacity,
- cpu_load_sync(i, env->sync));
- }
- env->sbc_best_cluster_flag = SBC_FLAG_BACKUP_CLUSTER;
- }
-}
-
-struct sched_cluster *
-next_best_cluster(struct sched_cluster *cluster, struct cpu_select_env *env,
- struct cluster_cpu_stats *stats)
-{
- struct sched_cluster *next = NULL;
-
- __clear_bit(cluster->id, env->candidate_list);
-
- if (env->rtg && preferred_cluster(cluster, env->p))
- return NULL;
-
- do {
- if (bitmap_empty(env->candidate_list, num_clusters))
- return NULL;
-
- next = next_candidate(env->candidate_list, 0, num_clusters);
- if (next) {
- if (next->min_power_cost > stats->min_cost) {
- clear_bit(next->id, env->candidate_list);
- next = NULL;
- continue;
- }
-
- if (skip_cluster(next, env))
- next = NULL;
- }
- } while (!next);
-
- env->task_load = scale_load_to_cpu(task_load(env->p),
- cluster_first_cpu(next));
- return next;
-}
-
-#ifdef CONFIG_SCHED_HMP_CSTATE_AWARE
-static void __update_cluster_stats(int cpu, struct cluster_cpu_stats *stats,
- struct cpu_select_env *env, int cpu_cost)
-{
- int wakeup_latency;
- int prev_cpu = env->prev_cpu;
-
- wakeup_latency = cpu_rq(cpu)->wakeup_latency;
-
- if (env->need_idle) {
- stats->min_cost = cpu_cost;
- if (idle_cpu(cpu)) {
- if (wakeup_latency < stats->best_cpu_wakeup_latency ||
- (wakeup_latency == stats->best_cpu_wakeup_latency &&
- cpu == prev_cpu)) {
- stats->best_idle_cpu = cpu;
- stats->best_cpu_wakeup_latency = wakeup_latency;
- }
- } else {
- if (env->cpu_load < stats->min_load ||
- (env->cpu_load == stats->min_load &&
- cpu == prev_cpu)) {
- stats->least_loaded_cpu = cpu;
- stats->min_load = env->cpu_load;
- }
- }
-
- return;
- }
-
- if (cpu_cost < stats->min_cost) {
- stats->min_cost = cpu_cost;
- stats->best_cpu_wakeup_latency = wakeup_latency;
- stats->best_load = env->cpu_load;
- stats->best_cpu = cpu;
- env->sbc_best_flag = SBC_FLAG_CPU_COST;
- return;
- }
-
- /* CPU cost is the same. Start breaking the tie by C-state */
-
- if (wakeup_latency > stats->best_cpu_wakeup_latency)
- return;
-
- if (wakeup_latency < stats->best_cpu_wakeup_latency) {
- stats->best_cpu_wakeup_latency = wakeup_latency;
- stats->best_load = env->cpu_load;
- stats->best_cpu = cpu;
- env->sbc_best_flag = SBC_FLAG_COST_CSTATE_TIE_BREAKER;
- return;
- }
-
- /* C-state is the same. Use prev CPU to break the tie */
- if (cpu == prev_cpu) {
- stats->best_cpu = cpu;
- env->sbc_best_flag = SBC_FLAG_COST_CSTATE_PREV_CPU_TIE_BREAKER;
- return;
- }
-
- if (stats->best_cpu != prev_cpu &&
- ((wakeup_latency == 0 && env->cpu_load < stats->best_load) ||
- (wakeup_latency > 0 && env->cpu_load > stats->best_load))) {
- stats->best_load = env->cpu_load;
- stats->best_cpu = cpu;
- env->sbc_best_flag = SBC_FLAG_CSTATE_LOAD;
- }
-}
-#else /* CONFIG_SCHED_HMP_CSTATE_AWARE */
-static void __update_cluster_stats(int cpu, struct cluster_cpu_stats *stats,
- struct cpu_select_env *env, int cpu_cost)
-{
- int prev_cpu = env->prev_cpu;
-
- if (cpu != prev_cpu && cpus_share_cache(prev_cpu, cpu)) {
- if (stats->best_sibling_cpu_cost > cpu_cost ||
- (stats->best_sibling_cpu_cost == cpu_cost &&
- stats->best_sibling_cpu_load > env->cpu_load)) {
- stats->best_sibling_cpu_cost = cpu_cost;
- stats->best_sibling_cpu_load = env->cpu_load;
- stats->best_sibling_cpu = cpu;
- }
- }
-
- if ((cpu_cost < stats->min_cost) ||
- ((stats->best_cpu != prev_cpu &&
- stats->min_load > env->cpu_load) || cpu == prev_cpu)) {
- if (env->need_idle) {
- if (idle_cpu(cpu)) {
- stats->min_cost = cpu_cost;
- stats->best_idle_cpu = cpu;
- }
- } else {
- stats->min_cost = cpu_cost;
- stats->min_load = env->cpu_load;
- stats->best_cpu = cpu;
- env->sbc_best_flag = SBC_FLAG_MIN_COST;
- }
- }
-}
-#endif /* CONFIG_SCHED_HMP_CSTATE_AWARE */
-
-static void update_cluster_stats(int cpu, struct cluster_cpu_stats *stats,
- struct cpu_select_env *env)
-{
- int cpu_cost;
-
- /*
- * We try to find the least loaded *busy* CPU irrespective
- * of the power cost.
- */
- if (env->pack_task)
- cpu_cost = cpu_min_power_cost(cpu);
-
- else
- cpu_cost = power_cost(cpu, task_load(env->p) +
- cpu_cravg_sync(cpu, env->sync));
-
- if (cpu_cost <= stats->min_cost)
- __update_cluster_stats(cpu, stats, env, cpu_cost);
-}
-
-static void find_best_cpu_in_cluster(struct sched_cluster *c,
- struct cpu_select_env *env, struct cluster_cpu_stats *stats)
-{
- int i;
- struct cpumask search_cpus;
-
- cpumask_and(&search_cpus, &env->search_cpus, &c->cpus);
-
- env->need_idle = wake_to_idle(env->p) || c->wake_up_idle;
-
- for_each_cpu(i, &search_cpus) {
- env->cpu_load = cpu_load_sync(i, env->sync);
-
- trace_sched_cpu_load_wakeup(cpu_rq(i), idle_cpu(i),
- sched_irqload(i),
- power_cost(i, task_load(env->p) +
- cpu_cravg_sync(i, env->sync)), 0);
-
- if (skip_cpu(i, env))
- continue;
-
- update_spare_capacity(stats, env, i, c->capacity,
- env->cpu_load);
-
- /*
- * need_idle takes precedence over sched boost but when both
- * are set, idlest CPU with in all the clusters is selected
- * when boost_policy = BOOST_ON_ALL whereas idlest CPU in the
- * big cluster is selected within boost_policy = BOOST_ON_BIG.
- */
- if ((!env->need_idle &&
- env->boost_policy != SCHED_BOOST_NONE) ||
- env->need_waker_cluster ||
- sched_cpu_high_irqload(i) ||
- spill_threshold_crossed(env, cpu_rq(i)))
- continue;
-
- update_cluster_stats(i, stats, env);
- }
-}
-
-static inline void init_cluster_cpu_stats(struct cluster_cpu_stats *stats)
-{
- stats->best_cpu = stats->best_idle_cpu = -1;
- stats->best_capacity_cpu = stats->best_sibling_cpu = -1;
- stats->min_cost = stats->best_sibling_cpu_cost = INT_MAX;
- stats->min_load = stats->best_sibling_cpu_load = ULLONG_MAX;
- stats->highest_spare_capacity = 0;
- stats->least_loaded_cpu = -1;
- stats->best_cpu_wakeup_latency = INT_MAX;
- /* No need to initialize stats->best_load */
-}
-
-static inline bool env_has_special_flags(struct cpu_select_env *env)
-{
- if (env->need_idle || env->boost_policy != SCHED_BOOST_NONE ||
- env->reason)
- return true;
-
- return false;
-}
-
-static inline bool
-bias_to_prev_cpu(struct cpu_select_env *env, struct cluster_cpu_stats *stats)
-{
- int prev_cpu;
- struct task_struct *task = env->p;
- struct sched_cluster *cluster;
-
- if (!task->ravg.mark_start || !sched_short_sleep_task_threshold)
- return false;
-
- prev_cpu = env->prev_cpu;
- if (!cpumask_test_cpu(prev_cpu, &env->search_cpus))
- return false;
-
- if (task->ravg.mark_start - task->last_cpu_selected_ts >=
- sched_long_cpu_selection_threshold)
- return false;
-
- /*
- * This function should be used by task wake up path only as it's
- * assuming p->last_switch_out_ts as last sleep time.
- * p->last_switch_out_ts can denote last preemption time as well as
- * last sleep time.
- */
- if (task->ravg.mark_start - task->last_switch_out_ts >=
- sched_short_sleep_task_threshold)
- return false;
-
- env->task_load = scale_load_to_cpu(task_load(task), prev_cpu);
- cluster = cpu_rq(prev_cpu)->cluster;
-
- if (!task_load_will_fit(task, env->task_load, prev_cpu,
- sched_boost_policy())) {
-
- __set_bit(cluster->id, env->backup_list);
- __clear_bit(cluster->id, env->candidate_list);
- return false;
- }
-
- env->cpu_load = cpu_load_sync(prev_cpu, env->sync);
- if (sched_cpu_high_irqload(prev_cpu) ||
- spill_threshold_crossed(env, cpu_rq(prev_cpu))) {
- update_spare_capacity(stats, env, prev_cpu,
- cluster->capacity, env->cpu_load);
- cpumask_clear_cpu(prev_cpu, &env->search_cpus);
- return false;
- }
-
- return true;
-}
-
-static inline bool
-wake_to_waker_cluster(struct cpu_select_env *env)
-{
- return env->sync &&
- task_load(current) > sched_big_waker_task_load &&
- task_load(env->p) < sched_small_wakee_task_load;
-}
-
-static inline bool
-bias_to_waker_cpu(struct cpu_select_env *env, int cpu)
-{
- return sysctl_sched_prefer_sync_wakee_to_waker &&
- cpu_rq(cpu)->nr_running == 1 &&
- cpumask_test_cpu(cpu, &env->search_cpus);
-}
-
-static inline int
-cluster_allowed(struct cpu_select_env *env, struct sched_cluster *cluster)
-{
- return cpumask_intersects(&env->search_cpus, &cluster->cpus);
-}
-
-/* return cheapest cpu that can fit this task */
-static int select_best_cpu(struct task_struct *p, int target, int reason,
- int sync)
-{
- struct sched_cluster *cluster, *pref_cluster = NULL;
- struct cluster_cpu_stats stats;
- struct related_thread_group *grp;
- unsigned int sbc_flag = 0;
- int cpu = raw_smp_processor_id();
- bool special;
-
- struct cpu_select_env env = {
- .p = p,
- .reason = reason,
- .need_idle = wake_to_idle(p),
- .need_waker_cluster = 0,
- .sync = sync,
- .prev_cpu = target,
- .rtg = NULL,
- .sbc_best_flag = 0,
- .sbc_best_cluster_flag = 0,
- .pack_task = false,
- };
-
- env.boost_policy = task_sched_boost(p) ?
- sched_boost_policy() : SCHED_BOOST_NONE;
-
- bitmap_copy(env.candidate_list, all_cluster_ids, NR_CPUS);
- bitmap_zero(env.backup_list, NR_CPUS);
-
- cpumask_and(&env.search_cpus, tsk_cpus_allowed(p), cpu_active_mask);
- cpumask_andnot(&env.search_cpus, &env.search_cpus, cpu_isolated_mask);
-
- init_cluster_cpu_stats(&stats);
- special = env_has_special_flags(&env);
-
- rcu_read_lock();
-
- grp = task_related_thread_group(p);
-
- if (grp && grp->preferred_cluster) {
- pref_cluster = grp->preferred_cluster;
- if (!cluster_allowed(&env, pref_cluster))
- clear_bit(pref_cluster->id, env.candidate_list);
- else
- env.rtg = grp;
- } else if (!special) {
- cluster = cpu_rq(cpu)->cluster;
- if (wake_to_waker_cluster(&env)) {
- if (bias_to_waker_cpu(&env, cpu)) {
- target = cpu;
- sbc_flag = SBC_FLAG_WAKER_CLUSTER |
- SBC_FLAG_WAKER_CPU;
- goto out;
- } else if (cluster_allowed(&env, cluster)) {
- env.need_waker_cluster = 1;
- bitmap_zero(env.candidate_list, NR_CPUS);
- __set_bit(cluster->id, env.candidate_list);
- env.sbc_best_cluster_flag =
- SBC_FLAG_WAKER_CLUSTER;
- }
- } else if (bias_to_prev_cpu(&env, &stats)) {
- sbc_flag = SBC_FLAG_PREV_CPU;
- goto out;
- }
- }
-
- if (!special && is_short_burst_task(p)) {
- env.pack_task = true;
- sbc_flag = SBC_FLAG_PACK_TASK;
- }
-retry:
- cluster = select_least_power_cluster(&env);
-
- if (!cluster)
- goto out;
-
- /*
- * 'cluster' now points to the minimum power cluster which can satisfy
- * task's perf goals. Walk down the cluster list starting with that
- * cluster. For non-small tasks, skip clusters that don't have
- * mostly_idle/idle cpus
- */
-
- do {
- find_best_cpu_in_cluster(cluster, &env, &stats);
-
- } while ((cluster = next_best_cluster(cluster, &env, &stats)));
-
- if (env.need_idle) {
- if (stats.best_idle_cpu >= 0) {
- target = stats.best_idle_cpu;
- sbc_flag |= SBC_FLAG_IDLE_CSTATE;
- } else if (stats.least_loaded_cpu >= 0) {
- target = stats.least_loaded_cpu;
- sbc_flag |= SBC_FLAG_IDLE_LEAST_LOADED;
- }
- } else if (stats.best_cpu >= 0) {
- if (stats.best_cpu != task_cpu(p) &&
- stats.min_cost == stats.best_sibling_cpu_cost) {
- stats.best_cpu = stats.best_sibling_cpu;
- sbc_flag |= SBC_FLAG_BEST_SIBLING;
- }
- sbc_flag |= env.sbc_best_flag;
- target = stats.best_cpu;
- } else {
- if (env.rtg && env.boost_policy == SCHED_BOOST_NONE) {
- env.rtg = NULL;
- goto retry;
- }
-
- /*
- * With boost_policy == SCHED_BOOST_ON_BIG, we reach here with
- * backup_list = little cluster, candidate_list = none and
- * stats->best_capacity_cpu points the best spare capacity
- * CPU among the CPUs in the big cluster.
- */
- if (env.boost_policy == SCHED_BOOST_ON_BIG &&
- stats.best_capacity_cpu >= 0)
- sbc_flag |= SBC_FLAG_BOOST_CLUSTER;
- else
- find_backup_cluster(&env, &stats);
-
- if (stats.best_capacity_cpu >= 0) {
- target = stats.best_capacity_cpu;
- sbc_flag |= SBC_FLAG_BEST_CAP_CPU;
- }
- }
- p->last_cpu_selected_ts = sched_ktime_clock();
-out:
- sbc_flag |= env.sbc_best_cluster_flag;
- rcu_read_unlock();
- trace_sched_task_load(p, sched_boost_policy() && task_sched_boost(p),
- env.reason, env.sync, env.need_idle, sbc_flag, target);
- return target;
-}
-
-/*
- * Reset balance_interval at all sched_domain levels of given cpu, so that it
- * honors kick.
- */
-static inline void reset_balance_interval(int cpu)
-{
- struct sched_domain *sd;
-
- if (cpu >= nr_cpu_ids)
- return;
-
- rcu_read_lock();
- for_each_domain(cpu, sd)
- sd->balance_interval = 0;
- rcu_read_unlock();
-}
-
-/*
- * Check if a task is on the "wrong" cpu (i.e its current cpu is not the ideal
- * cpu as per its demand or priority)
- *
- * Returns reason why task needs to be migrated
- */
-static inline int migration_needed(struct task_struct *p, int cpu)
-{
- int nice;
- struct related_thread_group *grp;
-
- if (p->state != TASK_RUNNING || p->nr_cpus_allowed == 1)
- return 0;
-
- /* No need to migrate task that is about to be throttled */
- if (task_will_be_throttled(p))
- return 0;
-
- if (sched_boost_policy() == SCHED_BOOST_ON_BIG &&
- cpu_capacity(cpu) != max_capacity && task_sched_boost(p))
- return UP_MIGRATION;
-
- if (sched_cpu_high_irqload(cpu))
- return IRQLOAD_MIGRATION;
-
- nice = task_nice(p);
- rcu_read_lock();
- grp = task_related_thread_group(p);
- /*
- * Don't assume higher capacity means higher power. If the task
- * is running on the power efficient CPU, avoid migrating it
- * to a lower capacity cluster.
- */
- if (!grp && (nice > SCHED_UPMIGRATE_MIN_NICE ||
- upmigrate_discouraged(p)) &&
- cpu_capacity(cpu) > min_capacity &&
- cpu_max_power_cost(cpu) == max_power_cost) {
- rcu_read_unlock();
- return DOWN_MIGRATION;
- }
-
- if (!task_will_fit(p, cpu)) {
- rcu_read_unlock();
- return UP_MIGRATION;
- }
- rcu_read_unlock();
-
- return 0;
-}
+#if defined(CONFIG_SCHED_WALT)
static DEFINE_RAW_SPINLOCK(migration_lock);
-
-/*
- * Check if currently running task should be migrated to a better cpu.
- *
- * Todo: Effect this via changes to nohz_balancer_kick() and load balance?
- */
-void check_for_migration(struct rq *rq, struct task_struct *p)
-{
- int cpu = cpu_of(rq), new_cpu;
- int active_balance = 0, reason;
-
- reason = migration_needed(p, cpu);
- if (!reason)
- return;
-
- raw_spin_lock(&migration_lock);
- new_cpu = select_best_cpu(p, cpu, reason, 0);
-
- if (new_cpu != cpu) {
- active_balance = kick_active_balance(rq, p, new_cpu);
- if (active_balance)
- mark_reserved(new_cpu);
- }
-
- raw_spin_unlock(&migration_lock);
-
- if (active_balance)
- stop_one_cpu_nowait(cpu, active_load_balance_cpu_stop, rq,
- &rq->active_balance_work);
-}
-
-#ifdef CONFIG_CFS_BANDWIDTH
-static void init_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq)
-{
- cfs_rq->hmp_stats.nr_big_tasks = 0;
- cfs_rq->hmp_stats.cumulative_runnable_avg = 0;
- cfs_rq->hmp_stats.pred_demands_sum = 0;
-}
-
-static void inc_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq,
- struct task_struct *p, int change_cra)
-{
- inc_nr_big_task(&cfs_rq->hmp_stats, p);
- if (change_cra)
- inc_cumulative_runnable_avg(&cfs_rq->hmp_stats, p);
-}
-
-static void dec_cfs_rq_hmp_stats(struct cfs_rq *cfs_rq,
- struct task_struct *p, int change_cra)
-{
- dec_nr_big_task(&cfs_rq->hmp_stats, p);
- if (change_cra)
- dec_cumulative_runnable_avg(&cfs_rq->hmp_stats, p);
-}
-
-static void inc_throttled_cfs_rq_hmp_stats(struct hmp_sched_stats *stats,
- struct cfs_rq *cfs_rq)
-{
- stats->nr_big_tasks += cfs_rq->hmp_stats.nr_big_tasks;
- stats->cumulative_runnable_avg +=
- cfs_rq->hmp_stats.cumulative_runnable_avg;
- stats->pred_demands_sum += cfs_rq->hmp_stats.pred_demands_sum;
-}
-
-static void dec_throttled_cfs_rq_hmp_stats(struct hmp_sched_stats *stats,
- struct cfs_rq *cfs_rq)
-{
- stats->nr_big_tasks -= cfs_rq->hmp_stats.nr_big_tasks;
- stats->cumulative_runnable_avg -=
- cfs_rq->hmp_stats.cumulative_runnable_avg;
- stats->pred_demands_sum -= cfs_rq->hmp_stats.pred_demands_sum;
-
- BUG_ON(stats->nr_big_tasks < 0 ||
- (s64)stats->cumulative_runnable_avg < 0);
- BUG_ON((s64)stats->pred_demands_sum < 0);
-}
-#endif /* CONFIG_CFS_BANDWIDTH */
-
-static int
-bail_inter_cluster_balance(struct lb_env *env, struct sd_lb_stats *sds)
-{
- int local_cpu, busiest_cpu;
- int local_capacity, busiest_capacity;
- int local_pwr_cost, busiest_pwr_cost;
- int nr_cpus;
- int boost = sched_boost();
-
- if (!sysctl_sched_restrict_cluster_spill ||
- boost == FULL_THROTTLE_BOOST || boost == CONSERVATIVE_BOOST)
- return 0;
-
- local_cpu = group_first_cpu(sds->local);
- busiest_cpu = group_first_cpu(sds->busiest);
-
- local_capacity = cpu_max_possible_capacity(local_cpu);
- busiest_capacity = cpu_max_possible_capacity(busiest_cpu);
-
- local_pwr_cost = cpu_max_power_cost(local_cpu);
- busiest_pwr_cost = cpu_max_power_cost(busiest_cpu);
-
- if (local_pwr_cost <= busiest_pwr_cost)
- return 0;
-
- if (local_capacity > busiest_capacity &&
- sds->busiest_stat.sum_nr_big_tasks)
- return 0;
-
- nr_cpus = cpumask_weight(sched_group_cpus(sds->busiest));
- if ((sds->busiest_stat.group_cpu_load < nr_cpus * sched_spill_load) &&
- (sds->busiest_stat.sum_nr_running <
- nr_cpus * sysctl_sched_spill_nr_run))
- return 1;
-
- return 0;
-}
-
-static bool update_sd_pick_busiest_active_balance(struct lb_env *env,
- struct sd_lb_stats *sds,
- struct sched_group *sg,
- struct sg_lb_stats *sgs)
-{
- if (env->idle != CPU_NOT_IDLE &&
- cpu_capacity(env->dst_cpu) > group_rq_capacity(sg)) {
- if (sgs->sum_nr_big_tasks >
- sds->busiest_stat.sum_nr_big_tasks) {
- env->flags |= LBF_BIG_TASK_ACTIVE_BALANCE;
- return true;
- }
- }
-
- return false;
-}
-
-static struct rq *find_busiest_queue_hmp(struct lb_env *env,
- struct sched_group *group)
-{
- struct rq *busiest = NULL, *busiest_big = NULL;
- u64 max_runnable_avg = 0, max_runnable_avg_big = 0;
- int max_nr_big = 0, nr_big;
- bool find_big = !!(env->flags & LBF_BIG_TASK_ACTIVE_BALANCE);
- int i;
- cpumask_t cpus;
-
- cpumask_andnot(&cpus, sched_group_cpus(group), cpu_isolated_mask);
-
- for_each_cpu(i, &cpus) {
- struct rq *rq = cpu_rq(i);
- u64 cumulative_runnable_avg =
- rq->hmp_stats.cumulative_runnable_avg;
-
- if (!cpumask_test_cpu(i, env->cpus))
- continue;
-
-
- if (find_big) {
- nr_big = nr_big_tasks(rq);
- if (nr_big > max_nr_big ||
- (nr_big > 0 && nr_big == max_nr_big &&
- cumulative_runnable_avg > max_runnable_avg_big)) {
- max_runnable_avg_big = cumulative_runnable_avg;
- busiest_big = rq;
- max_nr_big = nr_big;
- continue;
- }
- }
-
- if (cumulative_runnable_avg > max_runnable_avg) {
- max_runnable_avg = cumulative_runnable_avg;
- busiest = rq;
- }
- }
-
- if (busiest_big)
- return busiest_big;
-
- env->flags &= ~LBF_BIG_TASK_ACTIVE_BALANCE;
- return busiest;
-}
-
-#ifdef CONFIG_NO_HZ_COMMON
-static inline int find_new_hmp_ilb(int type)
-{
- int call_cpu = raw_smp_processor_id();
- struct sched_domain *sd;
- int ilb;
-
- rcu_read_lock();
-
- /* Pick an idle cpu "closest" to call_cpu */
- for_each_domain(call_cpu, sd) {
- for_each_cpu_and(ilb, nohz.idle_cpus_mask,
- sched_domain_span(sd)) {
- if (idle_cpu(ilb) && (type != NOHZ_KICK_RESTRICT ||
- cpu_max_power_cost(ilb) <=
- cpu_max_power_cost(call_cpu))) {
- rcu_read_unlock();
- reset_balance_interval(ilb);
- return ilb;
- }
- }
- }
-
- rcu_read_unlock();
- return nr_cpu_ids;
-}
-
-static inline int _nohz_kick_needed_hmp(struct rq *rq, int cpu, int *type)
-{
- struct sched_domain *sd;
- int i;
-
- if (rq->nr_running < 2)
- return 0;
-
- if (!sysctl_sched_restrict_cluster_spill ||
- sched_boost_policy() == SCHED_BOOST_ON_ALL)
- return 1;
-
- if (cpu_max_power_cost(cpu) == max_power_cost)
- return 1;
-
- rcu_read_lock();
- sd = rcu_dereference_check_sched_domain(rq->sd);
- if (!sd) {
- rcu_read_unlock();
- return 0;
- }
-
- for_each_cpu(i, sched_domain_span(sd)) {
- if (cpu_load(i) < sched_spill_load &&
- cpu_rq(i)->nr_running <
- sysctl_sched_spill_nr_run) {
- /* Change the kick type to limit to CPUs that
- * are of equal or lower capacity.
- */
- *type = NOHZ_KICK_RESTRICT;
- break;
- }
- }
- rcu_read_unlock();
- return 1;
-}
-#endif /* CONFIG_NO_HZ_COMMON */
-#endif /* CONFIG_SMP */
-
-#ifdef CONFIG_CFS_BANDWIDTH
-/*
- * Check if task is part of a hierarchy where some cfs_rq does not have any
- * runtime left.
- *
- * We can't rely on throttled_hierarchy() to do this test, as
- * cfs_rq->throttle_count will not be updated yet when this function is called
- * from scheduler_tick()
- */
-static int task_will_be_throttled(struct task_struct *p)
-{
- struct sched_entity *se = &p->se;
- struct cfs_rq *cfs_rq;
-
- if (!cfs_bandwidth_used())
- return 0;
-
- for_each_sched_entity(se) {
- cfs_rq = cfs_rq_of(se);
- if (!cfs_rq->runtime_enabled)
- continue;
- if (cfs_rq->runtime_remaining <= 0)
- return 1;
- }
-
- return 0;
-}
-#endif /* CONFIG_CFS_BANDWIDTH */
-
-#elif defined(CONFIG_SCHED_WALT)
-
void check_for_migration(struct rq *rq, struct task_struct *p)
{
int new_cpu;
@@ -12296,17 +11131,23 @@ void check_for_migration(struct rq *rq, struct task_struct *p)
rq->curr->nr_cpus_allowed == 1)
return;
+ raw_spin_lock(&migration_lock);
+ rcu_read_lock();
new_cpu = energy_aware_wake_cpu(p, cpu, 0);
+ rcu_read_unlock();
if (capacity_orig_of(new_cpu) > capacity_orig_of(cpu)) {
active_balance = kick_active_balance(rq, p, new_cpu);
if (active_balance) {
mark_reserved(new_cpu);
+ raw_spin_unlock(&migration_lock);
stop_one_cpu_nowait(cpu,
active_load_balance_cpu_stop, rq,
&rq->active_balance_work);
+ return;
}
}
+ raw_spin_unlock(&migration_lock);
}
}
-#endif /* CONFIG_SCHED_HMP */
+#endif /* CONFIG_SCHED_WALT */
diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c
deleted file mode 100644
index 24b60d7..0000000
--- a/kernel/sched/hmp.c
+++ /dev/null
@@ -1,1639 +0,0 @@
-/* Copyright (c) 2012-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.
- *
- * Implementation credits: Srivatsa Vaddagiri, Steve Muckle
- * Syed Rameez Mustafa, Olav haugan, Joonwoo Park, Pavan Kumar Kondeti
- * and Vikram Mulukutla
- */
-
-#include <linux/cpufreq.h>
-#include <linux/list_sort.h>
-#include <linux/syscore_ops.h>
-
-#include "sched.h"
-#include "walt.h"
-
-#include <trace/events/sched.h>
-
-#define CSTATE_LATENCY_GRANULARITY_SHIFT (6)
-
-inline void clear_ed_task(struct task_struct *p, struct rq *rq)
-{
- if (p == rq->ed_task)
- rq->ed_task = NULL;
-}
-
-inline void set_task_last_switch_out(struct task_struct *p, u64 wallclock)
-{
- p->last_switch_out_ts = wallclock;
-}
-
-/*
- * Note C-state for (idle) cpus.
- *
- * @cstate = cstate index, 0 -> active state
- * @wakeup_energy = energy spent in waking up cpu
- * @wakeup_latency = latency to wakeup from cstate
- *
- */
-void
-sched_set_cpu_cstate(int cpu, int cstate, int wakeup_energy, int wakeup_latency)
-{
- struct rq *rq = cpu_rq(cpu);
-
- rq->cstate = cstate; /* C1, C2 etc */
- rq->wakeup_energy = wakeup_energy;
- /* disregard small latency delta (64 us). */
- rq->wakeup_latency = ((wakeup_latency >>
- CSTATE_LATENCY_GRANULARITY_SHIFT) <<
- CSTATE_LATENCY_GRANULARITY_SHIFT);
-}
-
-/*
- * Note D-state for (idle) cluster.
- *
- * @dstate = dstate index, 0 -> active state
- * @wakeup_energy = energy spent in waking up cluster
- * @wakeup_latency = latency to wakeup from cluster
- *
- */
-void sched_set_cluster_dstate(const cpumask_t *cluster_cpus, int dstate,
- int wakeup_energy, int wakeup_latency)
-{
- struct sched_cluster *cluster =
- cpu_rq(cpumask_first(cluster_cpus))->cluster;
- cluster->dstate = dstate;
- cluster->dstate_wakeup_energy = wakeup_energy;
- cluster->dstate_wakeup_latency = wakeup_latency;
-}
-
-u32 __weak get_freq_max_load(int cpu, u32 freq)
-{
- /* 100% by default */
- return 100;
-}
-
-struct freq_max_load_entry {
- /* The maximum load which has accounted governor's headroom. */
- u64 hdemand;
-};
-
-struct freq_max_load {
- struct rcu_head rcu;
- int length;
- struct freq_max_load_entry freqs[0];
-};
-
-static DEFINE_PER_CPU(struct freq_max_load *, freq_max_load);
-static DEFINE_SPINLOCK(freq_max_load_lock);
-
-struct cpu_pwr_stats __weak *get_cpu_pwr_stats(void)
-{
- return NULL;
-}
-
-int sched_update_freq_max_load(const cpumask_t *cpumask)
-{
- int i, cpu, ret;
- unsigned int freq;
- struct cpu_pstate_pwr *costs;
- struct cpu_pwr_stats *per_cpu_info = get_cpu_pwr_stats();
- struct freq_max_load *max_load, *old_max_load;
- struct freq_max_load_entry *entry;
- u64 max_demand_capacity, max_demand;
- unsigned long flags;
- u32 hfreq;
- int hpct;
-
- if (!per_cpu_info)
- return 0;
-
- spin_lock_irqsave(&freq_max_load_lock, flags);
- max_demand_capacity = div64_u64(max_task_load(), max_possible_capacity);
- for_each_cpu(cpu, cpumask) {
- if (!per_cpu_info[cpu].ptable) {
- ret = -EINVAL;
- goto fail;
- }
-
- old_max_load = rcu_dereference(per_cpu(freq_max_load, cpu));
-
- /*
- * allocate len + 1 and leave the last power cost as 0 for
- * power_cost() can stop iterating index when
- * per_cpu_info[cpu].len > len of max_load due to race between
- * cpu power stats update and get_cpu_pwr_stats().
- */
- max_load = kzalloc(sizeof(struct freq_max_load) +
- sizeof(struct freq_max_load_entry) *
- (per_cpu_info[cpu].len + 1), GFP_ATOMIC);
- if (unlikely(!max_load)) {
- ret = -ENOMEM;
- goto fail;
- }
-
- max_load->length = per_cpu_info[cpu].len;
-
- max_demand = max_demand_capacity *
- cpu_max_possible_capacity(cpu);
-
- i = 0;
- costs = per_cpu_info[cpu].ptable;
- while (costs[i].freq) {
- entry = &max_load->freqs[i];
- freq = costs[i].freq;
- hpct = get_freq_max_load(cpu, freq);
- if (hpct <= 0 || hpct > 100)
- hpct = 100;
- hfreq = div64_u64((u64)freq * hpct, 100);
- entry->hdemand =
- div64_u64(max_demand * hfreq,
- cpu_max_possible_freq(cpu));
- i++;
- }
-
- rcu_assign_pointer(per_cpu(freq_max_load, cpu), max_load);
- if (old_max_load)
- kfree_rcu(old_max_load, rcu);
- }
-
- spin_unlock_irqrestore(&freq_max_load_lock, flags);
- return 0;
-
-fail:
- for_each_cpu(cpu, cpumask) {
- max_load = rcu_dereference(per_cpu(freq_max_load, cpu));
- if (max_load) {
- rcu_assign_pointer(per_cpu(freq_max_load, cpu), NULL);
- kfree_rcu(max_load, rcu);
- }
- }
-
- spin_unlock_irqrestore(&freq_max_load_lock, flags);
- return ret;
-}
-
-unsigned long __weak arch_get_cpu_efficiency(int cpu)
-{
- return SCHED_CAPACITY_SCALE;
-}
-
-int sched_set_static_cpu_pwr_cost(int cpu, unsigned int cost)
-{
- struct rq *rq = cpu_rq(cpu);
-
- rq->static_cpu_pwr_cost = cost;
- return 0;
-}
-
-unsigned int sched_get_static_cpu_pwr_cost(int cpu)
-{
- return cpu_rq(cpu)->static_cpu_pwr_cost;
-}
-
-int sched_set_static_cluster_pwr_cost(int cpu, unsigned int cost)
-{
- struct sched_cluster *cluster = cpu_rq(cpu)->cluster;
-
- cluster->static_cluster_pwr_cost = cost;
- return 0;
-}
-
-unsigned int sched_get_static_cluster_pwr_cost(int cpu)
-{
- return cpu_rq(cpu)->cluster->static_cluster_pwr_cost;
-}
-
-int sched_set_cluster_wake_idle(int cpu, unsigned int wake_idle)
-{
- struct sched_cluster *cluster = cpu_rq(cpu)->cluster;
-
- cluster->wake_up_idle = !!wake_idle;
- return 0;
-}
-
-unsigned int sched_get_cluster_wake_idle(int cpu)
-{
- return cpu_rq(cpu)->cluster->wake_up_idle;
-}
-
-/*
- * Tasks that are runnable continuously for a period greather than
- * EARLY_DETECTION_DURATION can be flagged early as potential
- * high load tasks.
- */
-#define EARLY_DETECTION_DURATION 9500000
-
-/*
- * For increase, send notification if
- * freq_required - cur_freq > sysctl_sched_freq_inc_notify
- */
-__read_mostly int sysctl_sched_freq_inc_notify = 10 * 1024 * 1024; /* + 10GHz */
-
-/*
- * For decrease, send notification if
- * cur_freq - freq_required > sysctl_sched_freq_dec_notify
- */
-__read_mostly int sysctl_sched_freq_dec_notify = 10 * 1024 * 1024; /* - 10GHz */
-__read_mostly unsigned int sysctl_sched_pred_alert_freq = 10 * 1024 * 1024;
-
-/* Maximum allowed threshold before freq aggregation must be enabled */
-#define MAX_FREQ_AGGR_THRESH 1000
-
-#define for_each_related_thread_group(grp) \
- list_for_each_entry(grp, &active_related_thread_groups, list)
-
-/* Size of bitmaps maintained to track top tasks */
-static const unsigned int top_tasks_bitmap_size =
- BITS_TO_LONGS(NUM_LOAD_INDICES + 1) * sizeof(unsigned long);
-
-__read_mostly unsigned int sysctl_sched_freq_aggregate = 1;
-
-/* A cpu can no longer accommodate more tasks if:
- *
- * rq->nr_running > sysctl_sched_spill_nr_run ||
- * rq->hmp_stats.cumulative_runnable_avg > sched_spill_load
- */
-unsigned int __read_mostly sysctl_sched_spill_nr_run = 10;
-
-/*
- * Place sync wakee tasks those have less than configured demand to the waker's
- * cluster.
- */
-unsigned int __read_mostly sched_small_wakee_task_load;
-unsigned int __read_mostly sysctl_sched_small_wakee_task_load_pct = 10;
-
-unsigned int __read_mostly sched_big_waker_task_load;
-unsigned int __read_mostly sysctl_sched_big_waker_task_load_pct = 25;
-
-/*
- * CPUs with load greater than the sched_spill_load_threshold are not
- * eligible for task placement. When all CPUs in a cluster achieve a
- * load higher than this level, tasks becomes eligible for inter
- * cluster migration.
- */
-unsigned int __read_mostly sched_spill_load;
-unsigned int __read_mostly sysctl_sched_spill_load_pct = 100;
-
-/*
- * Prefer the waker CPU for sync wakee task, if the CPU has only 1 runnable
- * task. This eliminates the LPM exit latency associated with the idle
- * CPUs in the waker cluster.
- */
-unsigned int __read_mostly sysctl_sched_prefer_sync_wakee_to_waker;
-
-/*
- * Tasks whose bandwidth consumption on a cpu is more than
- * sched_upmigrate are considered "big" tasks. Big tasks will be
- * considered for "up" migration, i.e migrating to a cpu with better
- * capacity.
- */
-unsigned int __read_mostly sched_upmigrate;
-unsigned int __read_mostly sysctl_sched_upmigrate_pct = 80;
-
-/*
- * Big tasks, once migrated, will need to drop their bandwidth
- * consumption to less than sched_downmigrate before they are "down"
- * migrated.
- */
-unsigned int __read_mostly sched_downmigrate;
-unsigned int __read_mostly sysctl_sched_downmigrate_pct = 60;
-
-/*
- * The load scale factor of a CPU gets boosted when its max frequency
- * is restricted due to which the tasks are migrating to higher capacity
- * CPUs early. The sched_upmigrate threshold is auto-upgraded by
- * rq->max_possible_freq/rq->max_freq of a lower capacity CPU.
- */
-unsigned int up_down_migrate_scale_factor = 1024;
-
-/*
- * Scheduler selects and places task to its previous CPU if sleep time is
- * less than sysctl_sched_select_prev_cpu_us.
- */
-unsigned int __read_mostly
-sched_short_sleep_task_threshold = 2000 * NSEC_PER_USEC;
-
-unsigned int __read_mostly sysctl_sched_select_prev_cpu_us = 2000;
-
-unsigned int __read_mostly
-sched_long_cpu_selection_threshold = 100 * NSEC_PER_MSEC;
-
-unsigned int __read_mostly sysctl_sched_restrict_cluster_spill;
-
-/*
- * Scheduler tries to avoid waking up idle CPUs for tasks running
- * in short bursts. If the task average burst is less than
- * sysctl_sched_short_burst nanoseconds and it sleeps on an average
- * for more than sysctl_sched_short_sleep nanoseconds, then the
- * task is eligible for packing.
- */
-unsigned int __read_mostly sysctl_sched_short_burst;
-unsigned int __read_mostly sysctl_sched_short_sleep = 1 * NSEC_PER_MSEC;
-
-static void _update_up_down_migrate(unsigned int *up_migrate,
- unsigned int *down_migrate, bool is_group)
-{
- unsigned int delta;
-
- if (up_down_migrate_scale_factor == 1024)
- return;
-
- delta = *up_migrate - *down_migrate;
-
- *up_migrate /= NSEC_PER_USEC;
- *up_migrate *= up_down_migrate_scale_factor;
- *up_migrate >>= 10;
- *up_migrate *= NSEC_PER_USEC;
-
- if (!is_group)
- *up_migrate = min(*up_migrate, sched_ravg_window);
-
- *down_migrate /= NSEC_PER_USEC;
- *down_migrate *= up_down_migrate_scale_factor;
- *down_migrate >>= 10;
- *down_migrate *= NSEC_PER_USEC;
-
- *down_migrate = min(*down_migrate, *up_migrate - delta);
-}
-
-static void update_up_down_migrate(void)
-{
- unsigned int up_migrate = pct_to_real(sysctl_sched_upmigrate_pct);
- unsigned int down_migrate = pct_to_real(sysctl_sched_downmigrate_pct);
-
- _update_up_down_migrate(&up_migrate, &down_migrate, false);
- sched_upmigrate = up_migrate;
- sched_downmigrate = down_migrate;
-
- up_migrate = pct_to_real(sysctl_sched_group_upmigrate_pct);
- down_migrate = pct_to_real(sysctl_sched_group_downmigrate_pct);
-
- _update_up_down_migrate(&up_migrate, &down_migrate, true);
- sched_group_upmigrate = up_migrate;
- sched_group_downmigrate = down_migrate;
-}
-
-void set_hmp_defaults(void)
-{
- sched_spill_load =
- pct_to_real(sysctl_sched_spill_load_pct);
-
- update_up_down_migrate();
-
- sched_init_task_load_windows =
- div64_u64((u64)sysctl_sched_init_task_load_pct *
- (u64)sched_ravg_window, 100);
-
- sched_short_sleep_task_threshold = sysctl_sched_select_prev_cpu_us *
- NSEC_PER_USEC;
-
- sched_small_wakee_task_load =
- div64_u64((u64)sysctl_sched_small_wakee_task_load_pct *
- (u64)sched_ravg_window, 100);
-
- sched_big_waker_task_load =
- div64_u64((u64)sysctl_sched_big_waker_task_load_pct *
- (u64)sched_ravg_window, 100);
-
- sched_freq_aggregate_threshold =
- pct_to_real(sysctl_sched_freq_aggregate_threshold_pct);
-}
-
-#ifdef CONFIG_CGROUP_SCHED
-
-int upmigrate_discouraged(struct task_struct *p)
-{
- return task_group(p)->upmigrate_discouraged;
-}
-
-#else
-
-static inline int upmigrate_discouraged(struct task_struct *p)
-{
- return 0;
-}
-
-#endif
-
-/* Is a task "big" on its current cpu */
-static inline int __is_big_task(struct task_struct *p, u64 scaled_load)
-{
- int nice = task_nice(p);
-
- if (nice > SCHED_UPMIGRATE_MIN_NICE || upmigrate_discouraged(p))
- return 0;
-
- return scaled_load > sched_upmigrate;
-}
-
-int is_big_task(struct task_struct *p)
-{
- return __is_big_task(p, scale_load_to_cpu(task_load(p), task_cpu(p)));
-}
-
-u64 cpu_load(int cpu)
-{
- struct rq *rq = cpu_rq(cpu);
-
- return scale_load_to_cpu(rq->hmp_stats.cumulative_runnable_avg, cpu);
-}
-
-u64 cpu_load_sync(int cpu, int sync)
-{
- return scale_load_to_cpu(cpu_cravg_sync(cpu, sync), cpu);
-}
-
-/*
- * Task will fit on a cpu if it's bandwidth consumption on that cpu
- * will be less than sched_upmigrate. A big task that was previously
- * "up" migrated will be considered fitting on "little" cpu if its
- * bandwidth consumption on "little" cpu will be less than
- * sched_downmigrate. This will help avoid frequenty migrations for
- * tasks with load close to the upmigrate threshold
- */
-int task_load_will_fit(struct task_struct *p, u64 task_load, int cpu,
- enum sched_boost_policy boost_policy)
-{
- int upmigrate = sched_upmigrate;
-
- if (cpu_capacity(cpu) == max_capacity)
- return 1;
-
- if (cpu_capacity(task_cpu(p)) > cpu_capacity(cpu))
- upmigrate = sched_downmigrate;
-
- if (boost_policy != SCHED_BOOST_ON_BIG) {
- if (task_nice(p) > SCHED_UPMIGRATE_MIN_NICE ||
- upmigrate_discouraged(p))
- return 1;
-
- if (task_load < upmigrate)
- return 1;
- } else {
- if (task_sched_boost(p) || task_load >= upmigrate)
- return 0;
-
- return 1;
- }
-
- return 0;
-}
-
-int task_will_fit(struct task_struct *p, int cpu)
-{
- u64 tload = scale_load_to_cpu(task_load(p), cpu);
-
- return task_load_will_fit(p, tload, cpu, sched_boost_policy());
-}
-
-/*
- * Return the cost of running task p on CPU cpu. This function
- * currently assumes that task p is the only task which will run on
- * the CPU.
- */
-unsigned int power_cost(int cpu, u64 demand)
-{
- int first, mid, last;
- struct cpu_pwr_stats *per_cpu_info = get_cpu_pwr_stats();
- struct cpu_pstate_pwr *costs;
- struct freq_max_load *max_load;
- int total_static_pwr_cost = 0;
- struct rq *rq = cpu_rq(cpu);
- unsigned int pc;
-
- if (!per_cpu_info || !per_cpu_info[cpu].ptable)
- /*
- * When power aware scheduling is not in use, or CPU
- * power data is not available, just use the CPU
- * capacity as a rough stand-in for real CPU power
- * numbers, assuming bigger CPUs are more power
- * hungry.
- */
- return cpu_max_possible_capacity(cpu);
-
- rcu_read_lock();
- max_load = rcu_dereference(per_cpu(freq_max_load, cpu));
- if (!max_load) {
- pc = cpu_max_possible_capacity(cpu);
- goto unlock;
- }
-
- costs = per_cpu_info[cpu].ptable;
-
- if (demand <= max_load->freqs[0].hdemand) {
- pc = costs[0].power;
- goto unlock;
- } else if (demand > max_load->freqs[max_load->length - 1].hdemand) {
- pc = costs[max_load->length - 1].power;
- goto unlock;
- }
-
- first = 0;
- last = max_load->length - 1;
- mid = (last - first) >> 1;
- while (1) {
- if (demand <= max_load->freqs[mid].hdemand)
- last = mid;
- else
- first = mid;
-
- if (last - first == 1)
- break;
- mid = first + ((last - first) >> 1);
- }
-
- pc = costs[last].power;
-
-unlock:
- rcu_read_unlock();
-
- if (idle_cpu(cpu) && rq->cstate) {
- total_static_pwr_cost += rq->static_cpu_pwr_cost;
- if (rq->cluster->dstate)
- total_static_pwr_cost +=
- rq->cluster->static_cluster_pwr_cost;
- }
-
- return pc + total_static_pwr_cost;
-
-}
-
-struct sched_cluster *rq_cluster(struct rq *rq)
-{
- return rq->cluster;
-}
-
-/*
- * reset_cpu_hmp_stats - reset HMP stats for a cpu
- * nr_big_tasks
- * cumulative_runnable_avg (iff reset_cra is true)
- */
-void reset_cpu_hmp_stats(int cpu, int reset_cra)
-{
- reset_cfs_rq_hmp_stats(cpu, reset_cra);
- reset_hmp_stats(&cpu_rq(cpu)->hmp_stats, reset_cra);
-}
-
-void fixup_nr_big_tasks(struct hmp_sched_stats *stats,
- struct task_struct *p, s64 delta)
-{
- u64 new_task_load;
- u64 old_task_load;
-
- if (sched_disable_window_stats)
- return;
-
- old_task_load = scale_load_to_cpu(task_load(p), task_cpu(p));
- new_task_load = scale_load_to_cpu(delta + task_load(p), task_cpu(p));
-
- if (__is_big_task(p, old_task_load) && !__is_big_task(p, new_task_load))
- stats->nr_big_tasks--;
- else if (!__is_big_task(p, old_task_load) &&
- __is_big_task(p, new_task_load))
- stats->nr_big_tasks++;
-
- BUG_ON(stats->nr_big_tasks < 0);
-}
-
-/*
- * Walk runqueue of cpu and re-initialize 'nr_big_tasks' counters.
- */
-static void update_nr_big_tasks(int cpu)
-{
- struct rq *rq = cpu_rq(cpu);
- struct task_struct *p;
-
- /* Do not reset cumulative_runnable_avg */
- reset_cpu_hmp_stats(cpu, 0);
-
- list_for_each_entry(p, &rq->cfs_tasks, se.group_node)
- inc_hmp_sched_stats_fair(rq, p, 0);
-}
-
-/* Disable interrupts and grab runqueue lock of all cpus listed in @cpus */
-void pre_big_task_count_change(const struct cpumask *cpus)
-{
- int i;
-
- local_irq_disable();
-
- for_each_cpu(i, cpus)
- raw_spin_lock(&cpu_rq(i)->lock);
-}
-
-/*
- * Reinitialize 'nr_big_tasks' counters on all affected cpus
- */
-void post_big_task_count_change(const struct cpumask *cpus)
-{
- int i;
-
- /* Assumes local_irq_disable() keeps online cpumap stable */
- for_each_cpu(i, cpus)
- update_nr_big_tasks(i);
-
- for_each_cpu(i, cpus)
- raw_spin_unlock(&cpu_rq(i)->lock);
-
- local_irq_enable();
-}
-
-static inline int invalid_value_freq_input(unsigned int *data)
-{
- if (data == &sysctl_sched_freq_aggregate)
- return !(*data == 0 || *data == 1);
-
- return 0;
-}
-
-static inline int invalid_value(unsigned int *data)
-{
- unsigned int val = *data;
-
- if (data == &sysctl_sched_ravg_hist_size)
- return (val < 2 || val > RAVG_HIST_SIZE_MAX);
-
- if (data == &sysctl_sched_window_stats_policy)
- return val >= WINDOW_STATS_INVALID_POLICY;
-
- return invalid_value_freq_input(data);
-}
-
-/*
- * Handle "atomic" update of sysctl_sched_window_stats_policy,
- * sysctl_sched_ravg_hist_size variables.
- */
-int sched_window_update_handler(struct ctl_table *table, int write,
- void __user *buffer, size_t *lenp,
- loff_t *ppos)
-{
- int ret;
- unsigned int *data = (unsigned int *)table->data;
- unsigned int old_val;
-
- mutex_lock(&policy_mutex);
-
- old_val = *data;
-
- ret = proc_dointvec(table, write, buffer, lenp, ppos);
- if (ret || !write || (write && (old_val == *data)))
- goto done;
-
- if (invalid_value(data)) {
- *data = old_val;
- ret = -EINVAL;
- goto done;
- }
-
- reset_all_window_stats(0, 0);
-
-done:
- mutex_unlock(&policy_mutex);
-
- return ret;
-}
-
-/*
- * Convert percentage value into absolute form. This will avoid div() operation
- * in fast path, to convert task load in percentage scale.
- */
-int sched_hmp_proc_update_handler(struct ctl_table *table, int write,
- void __user *buffer, size_t *lenp,
- loff_t *ppos)
-{
- int ret;
- unsigned int old_val;
- unsigned int *data = (unsigned int *)table->data;
- int update_task_count = 0;
-
- /*
- * The policy mutex is acquired with cpu_hotplug.lock
- * held from cpu_up()->cpufreq_governor_interactive()->
- * sched_set_window(). So enforce the same order here.
- */
- if (write && (data == &sysctl_sched_upmigrate_pct)) {
- update_task_count = 1;
- get_online_cpus();
- }
-
- mutex_lock(&policy_mutex);
-
- old_val = *data;
-
- ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
-
- if (ret || !write)
- goto done;
-
- if (write && (old_val == *data))
- goto done;
-
- if (sysctl_sched_downmigrate_pct > sysctl_sched_upmigrate_pct ||
- sysctl_sched_group_downmigrate_pct >
- sysctl_sched_group_upmigrate_pct) {
- *data = old_val;
- ret = -EINVAL;
- goto done;
- }
-
- /*
- * Big task tunable change will need to re-classify tasks on
- * runqueue as big and set their counters appropriately.
- * sysctl interface affects secondary variables (*_pct), which is then
- * "atomically" carried over to the primary variables. Atomic change
- * includes taking runqueue lock of all online cpus and re-initiatizing
- * their big counter values based on changed criteria.
- */
- if (update_task_count)
- pre_big_task_count_change(cpu_online_mask);
-
- set_hmp_defaults();
-
- if (update_task_count)
- post_big_task_count_change(cpu_online_mask);
-
-done:
- mutex_unlock(&policy_mutex);
- if (update_task_count)
- put_online_cpus();
- return ret;
-}
-
-inline int nr_big_tasks(struct rq *rq)
-{
- return rq->hmp_stats.nr_big_tasks;
-}
-
-unsigned int cpu_temp(int cpu)
-{
- struct cpu_pwr_stats *per_cpu_info = get_cpu_pwr_stats();
-
- if (per_cpu_info)
- return per_cpu_info[cpu].temp;
- else
- return 0;
-}
-
-/* Return task demand in percentage scale */
-unsigned int pct_task_load(struct task_struct *p)
-{
- unsigned int load;
-
- load = div64_u64((u64)task_load(p) * 100, (u64)max_task_load());
-
- return load;
-}
-
-static int __init set_sched_ravg_window(char *str)
-{
- unsigned int window_size;
-
- get_option(&str, &window_size);
-
- if (window_size < MIN_SCHED_RAVG_WINDOW ||
- window_size > MAX_SCHED_RAVG_WINDOW) {
- WARN_ON(1);
- return -EINVAL;
- }
-
- sched_ravg_window = window_size;
- return 0;
-}
-
-early_param("sched_ravg_window", set_sched_ravg_window);
-
-#define DIV64_U64_ROUNDUP(X, Y) div64_u64((X) + (Y - 1), Y)
-
-static inline u64 scale_exec_time(u64 delta, struct rq *rq)
-{
- u32 freq;
-
- freq = cpu_cycles_to_freq(rq->cc.cycles, rq->cc.time);
- delta = DIV64_U64_ROUNDUP(delta * freq, max_possible_freq);
- delta *= rq->cluster->exec_scale_factor;
- delta >>= 10;
-
- return delta;
-}
-
-/* Does freq_required sufficiently exceed or fall behind cur_freq? */
-static inline int
-nearly_same_freq(unsigned int cur_freq, unsigned int freq_required)
-{
- int delta = freq_required - cur_freq;
-
- if (freq_required > cur_freq)
- return delta < sysctl_sched_freq_inc_notify;
-
- delta = -delta;
-
- return delta < sysctl_sched_freq_dec_notify;
-}
-
-/* Convert busy time to frequency equivalent */
-static inline unsigned int load_to_freq(struct rq *rq, u64 load)
-{
- unsigned int freq;
-
- load = scale_load_to_cpu(load, cpu_of(rq));
- load *= 128;
- load = div64_u64(load, max_task_load());
-
- freq = load * cpu_max_possible_freq(cpu_of(rq));
- freq /= 128;
-
- return freq;
-}
-
-/*
- * Return load from all related groups in given frequency domain.
- */
-static void group_load_in_freq_domain(struct cpumask *cpus,
- u64 *grp_load, u64 *new_grp_load)
-{
- int j;
-
- for_each_cpu(j, cpus) {
- struct rq *rq = cpu_rq(j);
-
- *grp_load += rq->grp_time.prev_runnable_sum;
- *new_grp_load += rq->grp_time.nt_prev_runnable_sum;
- }
-}
-
-/*
- * Should scheduler alert governor for changing frequency?
- *
- * @check_pred - evaluate frequency based on the predictive demand
- * @check_groups - add load from all related groups on given cpu
- *
- * check_groups is set to 1 if a "related" task movement/wakeup is triggering
- * the notification check. To avoid "re-aggregation" of demand in such cases,
- * we check whether the migrated/woken tasks demand (along with demand from
- * existing tasks on the cpu) can be met on target cpu
- *
- */
-
-static int send_notification(struct rq *rq, int check_pred, int check_groups)
-{
- unsigned int cur_freq, freq_required;
- unsigned long flags;
- int rc = 0;
- u64 group_load = 0, new_load = 0;
-
- if (check_pred) {
- u64 prev = rq->old_busy_time;
- u64 predicted = rq->hmp_stats.pred_demands_sum;
-
- if (rq->cluster->cur_freq == cpu_max_freq(cpu_of(rq)))
- return 0;
-
- prev = max(prev, rq->old_estimated_time);
- if (prev > predicted)
- return 0;
-
- cur_freq = load_to_freq(rq, prev);
- freq_required = load_to_freq(rq, predicted);
-
- if (freq_required < cur_freq + sysctl_sched_pred_alert_freq)
- return 0;
- } else {
- /*
- * Protect from concurrent update of rq->prev_runnable_sum and
- * group cpu load
- */
- raw_spin_lock_irqsave(&rq->lock, flags);
- if (check_groups)
- group_load = rq->grp_time.prev_runnable_sum;
-
- new_load = rq->prev_runnable_sum + group_load;
- new_load = freq_policy_load(rq, new_load);
-
- raw_spin_unlock_irqrestore(&rq->lock, flags);
-
- cur_freq = load_to_freq(rq, rq->old_busy_time);
- freq_required = load_to_freq(rq, new_load);
-
- if (nearly_same_freq(cur_freq, freq_required))
- return 0;
- }
-
- raw_spin_lock_irqsave(&rq->lock, flags);
- if (!rq->cluster->notifier_sent) {
- rq->cluster->notifier_sent = 1;
- rc = 1;
- trace_sched_freq_alert(cpu_of(rq), check_pred, check_groups, rq,
- new_load);
- }
- raw_spin_unlock_irqrestore(&rq->lock, flags);
-
- return rc;
-}
-
-/* Alert governor if there is a need to change frequency */
-void check_for_freq_change(struct rq *rq, bool check_pred, bool check_groups)
-{
- int cpu = cpu_of(rq);
-
- if (!send_notification(rq, check_pred, check_groups))
- return;
-
- atomic_notifier_call_chain(
- &load_alert_notifier_head, 0,
- (void *)(long)cpu);
-}
-
-void notify_migration(int src_cpu, int dest_cpu, bool src_cpu_dead,
- struct task_struct *p)
-{
- bool check_groups;
-
- rcu_read_lock();
- check_groups = task_in_related_thread_group(p);
- rcu_read_unlock();
-
- if (!same_freq_domain(src_cpu, dest_cpu)) {
- if (!src_cpu_dead)
- check_for_freq_change(cpu_rq(src_cpu), false,
- check_groups);
- check_for_freq_change(cpu_rq(dest_cpu), false, check_groups);
- } else {
- check_for_freq_change(cpu_rq(dest_cpu), true, check_groups);
- }
-}
-
-#define INC_STEP 8
-#define DEC_STEP 2
-#define CONSISTENT_THRES 16
-#define INC_STEP_BIG 16
-/*
- * bucket_increase - update the count of all buckets
- *
- * @buckets: array of buckets tracking busy time of a task
- * @idx: the index of bucket to be incremented
- *
- * Each time a complete window finishes, count of bucket that runtime
- * falls in (@idx) is incremented. Counts of all other buckets are
- * decayed. The rate of increase and decay could be different based
- * on current count in the bucket.
- */
-static inline void bucket_increase(u8 *buckets, int idx)
-{
- int i, step;
-
- for (i = 0; i < NUM_BUSY_BUCKETS; i++) {
- if (idx != i) {
- if (buckets[i] > DEC_STEP)
- buckets[i] -= DEC_STEP;
- else
- buckets[i] = 0;
- } else {
- step = buckets[i] >= CONSISTENT_THRES ?
- INC_STEP_BIG : INC_STEP;
- if (buckets[i] > U8_MAX - step)
- buckets[i] = U8_MAX;
- else
- buckets[i] += step;
- }
- }
-}
-
-static inline int busy_to_bucket(u32 normalized_rt)
-{
- int bidx;
-
- bidx = mult_frac(normalized_rt, NUM_BUSY_BUCKETS, max_task_load());
- bidx = min(bidx, NUM_BUSY_BUCKETS - 1);
-
- /*
- * Combine lowest two buckets. The lowest frequency falls into
- * 2nd bucket and thus keep predicting lowest bucket is not
- * useful.
- */
- if (!bidx)
- bidx++;
-
- return bidx;
-}
-
-/*
- * get_pred_busy - calculate predicted demand for a task on runqueue
- *
- * @rq: runqueue of task p
- * @p: task whose prediction is being updated
- * @start: starting bucket. returned prediction should not be lower than
- * this bucket.
- * @runtime: runtime of the task. returned prediction should not be lower
- * than this runtime.
- * Note: @start can be derived from @runtime. It's passed in only to
- * avoid duplicated calculation in some cases.
- *
- * A new predicted busy time is returned for task @p based on @runtime
- * passed in. The function searches through buckets that represent busy
- * time equal to or bigger than @runtime and attempts to find the bucket to
- * to use for prediction. Once found, it searches through historical busy
- * time and returns the latest that falls into the bucket. If no such busy
- * time exists, it returns the medium of that bucket.
- */
-static u32 get_pred_busy(struct rq *rq, struct task_struct *p,
- int start, u32 runtime)
-{
- int i;
- u8 *buckets = p->ravg.busy_buckets;
- u32 *hist = p->ravg.sum_history;
- u32 dmin, dmax;
- u64 cur_freq_runtime = 0;
- int first = NUM_BUSY_BUCKETS, final;
- u32 ret = runtime;
-
- /* skip prediction for new tasks due to lack of history */
- if (unlikely(is_new_task(p)))
- goto out;
-
- /* find minimal bucket index to pick */
- for (i = start; i < NUM_BUSY_BUCKETS; i++) {
- if (buckets[i]) {
- first = i;
- break;
- }
- }
- /* if no higher buckets are filled, predict runtime */
- if (first >= NUM_BUSY_BUCKETS)
- goto out;
-
- /* compute the bucket for prediction */
- final = first;
-
- /* determine demand range for the predicted bucket */
- if (final < 2) {
- /* lowest two buckets are combined */
- dmin = 0;
- final = 1;
- } else {
- dmin = mult_frac(final, max_task_load(), NUM_BUSY_BUCKETS);
- }
- dmax = mult_frac(final + 1, max_task_load(), NUM_BUSY_BUCKETS);
-
- /*
- * search through runtime history and return first runtime that falls
- * into the range of predicted bucket.
- */
- for (i = 0; i < sched_ravg_hist_size; i++) {
- if (hist[i] >= dmin && hist[i] < dmax) {
- ret = hist[i];
- break;
- }
- }
- /* no historical runtime within bucket found, use average of the bin */
- if (ret < dmin)
- ret = (dmin + dmax) / 2;
- /*
- * when updating in middle of a window, runtime could be higher
- * than all recorded history. Always predict at least runtime.
- */
- ret = max(runtime, ret);
-out:
- trace_sched_update_pred_demand(rq, p, runtime,
- mult_frac((unsigned int)cur_freq_runtime, 100,
- sched_ravg_window), ret);
- return ret;
-}
-
-static inline u32 calc_pred_demand(struct rq *rq, struct task_struct *p)
-{
- if (p->ravg.pred_demand >= p->ravg.curr_window)
- return p->ravg.pred_demand;
-
- return get_pred_busy(rq, p, busy_to_bucket(p->ravg.curr_window),
- p->ravg.curr_window);
-}
-
-static void reset_all_task_stats(void)
-{
- struct task_struct *g, *p;
-
- do_each_thread(g, p) {
- reset_task_stats(p);
- } while_each_thread(g, p);
-}
-
-enum reset_reason_code {
- WINDOW_CHANGE,
- POLICY_CHANGE,
- HIST_SIZE_CHANGE,
- FREQ_AGGREGATE_CHANGE,
-};
-
-const char *sched_window_reset_reasons[] = {
- "WINDOW_CHANGE",
- "POLICY_CHANGE",
- "HIST_SIZE_CHANGE",
-};
-
-/* Called with IRQs enabled */
-void reset_all_window_stats(u64 window_start, unsigned int window_size)
-{
- int cpu, i;
- unsigned long flags;
- u64 start_ts = sched_ktime_clock();
- int reason = WINDOW_CHANGE;
- unsigned int old = 0, new = 0;
-
- local_irq_save(flags);
-
- read_lock(&tasklist_lock);
-
- read_lock(&related_thread_group_lock);
-
- /* Taking all runqueue locks prevents race with sched_exit(). */
- for_each_possible_cpu(cpu)
- raw_spin_lock(&cpu_rq(cpu)->lock);
-
- sched_disable_window_stats = 1;
-
- reset_all_task_stats();
-
- read_unlock(&tasklist_lock);
-
- if (window_size) {
- sched_ravg_window = window_size * TICK_NSEC;
- set_hmp_defaults();
- sched_load_granule = sched_ravg_window / NUM_LOAD_INDICES;
- }
-
- sched_disable_window_stats = 0;
-
- for_each_possible_cpu(cpu) {
- struct rq *rq = cpu_rq(cpu);
-
- if (window_start)
- rq->window_start = window_start;
- rq->curr_runnable_sum = rq->prev_runnable_sum = 0;
- rq->nt_curr_runnable_sum = rq->nt_prev_runnable_sum = 0;
- memset(&rq->grp_time, 0, sizeof(struct group_cpu_time));
- for (i = 0; i < NUM_TRACKED_WINDOWS; i++) {
- memset(&rq->load_subs[i], 0,
- sizeof(struct load_subtractions));
- clear_top_tasks_table(rq->top_tasks[i]);
- clear_top_tasks_bitmap(rq->top_tasks_bitmap[i]);
- }
-
- rq->curr_table = 0;
- rq->curr_top = 0;
- rq->prev_top = 0;
- reset_cpu_hmp_stats(cpu, 1);
- }
-
- if (sched_window_stats_policy != sysctl_sched_window_stats_policy) {
- reason = POLICY_CHANGE;
- old = sched_window_stats_policy;
- new = sysctl_sched_window_stats_policy;
- sched_window_stats_policy = sysctl_sched_window_stats_policy;
- } else if (sched_ravg_hist_size != sysctl_sched_ravg_hist_size) {
- reason = HIST_SIZE_CHANGE;
- old = sched_ravg_hist_size;
- new = sysctl_sched_ravg_hist_size;
- sched_ravg_hist_size = sysctl_sched_ravg_hist_size;
- } else if (sched_freq_aggregate !=
- sysctl_sched_freq_aggregate) {
- reason = FREQ_AGGREGATE_CHANGE;
- old = sched_freq_aggregate;
- new = sysctl_sched_freq_aggregate;
- sched_freq_aggregate = sysctl_sched_freq_aggregate;
- }
-
- for_each_possible_cpu(cpu)
- raw_spin_unlock(&cpu_rq(cpu)->lock);
-
- read_unlock(&related_thread_group_lock);
-
- local_irq_restore(flags);
-
- trace_sched_reset_all_window_stats(window_start, window_size,
- sched_ktime_clock() - start_ts, reason, old, new);
-}
-
-void sched_get_cpus_busy(struct sched_load *busy,
- const struct cpumask *query_cpus)
-{
- unsigned long flags;
- struct rq *rq;
- const int cpus = cpumask_weight(query_cpus);
- u64 load[cpus], group_load[cpus];
- u64 nload[cpus], ngload[cpus];
- u64 pload[cpus];
- unsigned int max_freq[cpus];
- int notifier_sent = 0;
- int early_detection[cpus];
- int cpu, i = 0;
- unsigned int window_size;
- u64 max_prev_sum = 0;
- int max_busy_cpu = cpumask_first(query_cpus);
- u64 total_group_load = 0, total_ngload = 0;
- bool aggregate_load = false;
- struct sched_cluster *cluster = cpu_cluster(cpumask_first(query_cpus));
-
- if (unlikely(cpus == 0))
- return;
-
- local_irq_save(flags);
-
- /*
- * This function could be called in timer context, and the
- * current task may have been executing for a long time. Ensure
- * that the window stats are current by doing an update.
- */
-
- for_each_cpu(cpu, query_cpus)
- raw_spin_lock(&cpu_rq(cpu)->lock);
-
- window_size = sched_ravg_window;
-
- /*
- * We don't really need the cluster lock for this entire for loop
- * block. However, there is no advantage in optimizing this as rq
- * locks are held regardless and would prevent migration anyways
- */
- raw_spin_lock(&cluster->load_lock);
-
- for_each_cpu(cpu, query_cpus) {
- rq = cpu_rq(cpu);
-
- update_task_ravg(rq->curr, rq, TASK_UPDATE, sched_ktime_clock(),
- 0);
-
- /*
- * Ensure that we don't report load for 'cpu' again via the
- * cpufreq_update_util path in the window that started at
- * rq->window_start
- */
- rq->load_reported_window = rq->window_start;
-
- account_load_subtractions(rq);
- load[i] = rq->prev_runnable_sum;
- nload[i] = rq->nt_prev_runnable_sum;
- pload[i] = rq->hmp_stats.pred_demands_sum;
- rq->old_estimated_time = pload[i];
-
- if (load[i] > max_prev_sum) {
- max_prev_sum = load[i];
- max_busy_cpu = cpu;
- }
-
- /*
- * sched_get_cpus_busy() is called for all CPUs in a
- * frequency domain. So the notifier_sent flag per
- * cluster works even when a frequency domain spans
- * more than 1 cluster.
- */
- if (rq->cluster->notifier_sent) {
- notifier_sent = 1;
- rq->cluster->notifier_sent = 0;
- }
- early_detection[i] = (rq->ed_task != NULL);
- max_freq[i] = cpu_max_freq(cpu);
- i++;
- }
-
- raw_spin_unlock(&cluster->load_lock);
-
- group_load_in_freq_domain(
- &cpu_rq(max_busy_cpu)->freq_domain_cpumask,
- &total_group_load, &total_ngload);
- aggregate_load = !!(total_group_load > sched_freq_aggregate_threshold);
-
- i = 0;
- for_each_cpu(cpu, query_cpus) {
- group_load[i] = 0;
- ngload[i] = 0;
-
- if (early_detection[i])
- goto skip_early;
-
- rq = cpu_rq(cpu);
- if (aggregate_load) {
- if (cpu == max_busy_cpu) {
- group_load[i] = total_group_load;
- ngload[i] = total_ngload;
- }
- } else {
- group_load[i] = rq->grp_time.prev_runnable_sum;
- ngload[i] = rq->grp_time.nt_prev_runnable_sum;
- }
-
- load[i] += group_load[i];
- nload[i] += ngload[i];
-
- load[i] = freq_policy_load(rq, load[i]);
- rq->old_busy_time = load[i];
-
- /*
- * Scale load in reference to cluster max_possible_freq.
- *
- * Note that scale_load_to_cpu() scales load in reference to
- * the cluster max_freq.
- */
- load[i] = scale_load_to_cpu(load[i], cpu);
- nload[i] = scale_load_to_cpu(nload[i], cpu);
- pload[i] = scale_load_to_cpu(pload[i], cpu);
-skip_early:
- i++;
- }
-
- for_each_cpu(cpu, query_cpus)
- raw_spin_unlock(&(cpu_rq(cpu))->lock);
-
- local_irq_restore(flags);
-
- i = 0;
- for_each_cpu(cpu, query_cpus) {
- rq = cpu_rq(cpu);
-
- if (early_detection[i]) {
- busy[i].prev_load = div64_u64(sched_ravg_window,
- NSEC_PER_USEC);
- busy[i].new_task_load = 0;
- busy[i].predicted_load = 0;
- goto exit_early;
- }
-
- load[i] = scale_load_to_freq(load[i], max_freq[i],
- cpu_max_possible_freq(cpu));
- nload[i] = scale_load_to_freq(nload[i], max_freq[i],
- cpu_max_possible_freq(cpu));
-
- pload[i] = scale_load_to_freq(pload[i], max_freq[i],
- rq->cluster->max_possible_freq);
-
- busy[i].prev_load = div64_u64(load[i], NSEC_PER_USEC);
- busy[i].new_task_load = div64_u64(nload[i], NSEC_PER_USEC);
- busy[i].predicted_load = div64_u64(pload[i], NSEC_PER_USEC);
-
-exit_early:
- trace_sched_get_busy(cpu, busy[i].prev_load,
- busy[i].new_task_load,
- busy[i].predicted_load,
- early_detection[i]);
- i++;
- }
-}
-
-int sched_set_window(u64 window_start, unsigned int window_size)
-{
- u64 now, cur_jiffies, jiffy_ktime_ns;
- s64 ws;
- unsigned long flags;
-
- if (window_size * TICK_NSEC < MIN_SCHED_RAVG_WINDOW)
- return -EINVAL;
-
- mutex_lock(&policy_mutex);
-
- /*
- * Get a consistent view of ktime, jiffies, and the time
- * since the last jiffy (based on last_jiffies_update).
- */
- local_irq_save(flags);
- cur_jiffies = jiffy_to_ktime_ns(&now, &jiffy_ktime_ns);
- local_irq_restore(flags);
-
- /* translate window_start from jiffies to nanoseconds */
- ws = (window_start - cur_jiffies); /* jiffy difference */
- ws *= TICK_NSEC;
- ws += jiffy_ktime_ns;
-
- /*
- * Roll back calculated window start so that it is in
- * the past (window stats must have a current window).
- */
- while (ws > now)
- ws -= (window_size * TICK_NSEC);
-
- BUG_ON(sched_ktime_clock() < ws);
-
- reset_all_window_stats(ws, window_size);
-
- sched_update_freq_max_load(cpu_possible_mask);
-
- mutex_unlock(&policy_mutex);
-
- return 0;
-}
-
-static inline void create_subtraction_entry(struct rq *rq, u64 ws, int index)
-{
- rq->load_subs[index].window_start = ws;
- rq->load_subs[index].subs = 0;
- rq->load_subs[index].new_subs = 0;
-}
-
-#define sched_up_down_migrate_auto_update 1
-static void check_for_up_down_migrate_update(const struct cpumask *cpus)
-{
- int i = cpumask_first(cpus);
-
- if (!sched_up_down_migrate_auto_update)
- return;
-
- if (cpu_max_possible_capacity(i) == max_possible_capacity)
- return;
-
- if (cpu_max_possible_freq(i) == cpu_max_freq(i))
- up_down_migrate_scale_factor = 1024;
- else
- up_down_migrate_scale_factor = (1024 *
- cpu_max_possible_freq(i)) / cpu_max_freq(i);
-
- update_up_down_migrate();
-}
-
-void update_cpu_cluster_capacity(const cpumask_t *cpus)
-{
- int i;
- struct sched_cluster *cluster;
- struct cpumask cpumask;
-
- cpumask_copy(&cpumask, cpus);
- pre_big_task_count_change(cpu_possible_mask);
-
- for_each_cpu(i, &cpumask) {
- cluster = cpu_rq(i)->cluster;
- cpumask_andnot(&cpumask, &cpumask, &cluster->cpus);
-
- cluster->capacity = compute_capacity(cluster);
- cluster->load_scale_factor = compute_load_scale_factor(cluster);
-
- /* 'cpus' can contain cpumask more than one cluster */
- check_for_up_down_migrate_update(&cluster->cpus);
- }
-
- __update_min_max_capacity();
-
- post_big_task_count_change(cpu_possible_mask);
-}
-
-static DEFINE_SPINLOCK(cpu_freq_min_max_lock);
-void sched_update_cpu_freq_min_max(const cpumask_t *cpus, u32 fmin, u32 fmax)
-{
- struct cpumask cpumask;
- struct sched_cluster *cluster;
- int i, update_capacity = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&cpu_freq_min_max_lock, flags);
- cpumask_copy(&cpumask, cpus);
- for_each_cpu(i, &cpumask) {
- cluster = cpu_rq(i)->cluster;
- cpumask_andnot(&cpumask, &cpumask, &cluster->cpus);
-
- update_capacity += (cluster->max_mitigated_freq != fmax);
- cluster->max_mitigated_freq = fmax;
- }
- spin_unlock_irqrestore(&cpu_freq_min_max_lock, flags);
-
- if (update_capacity)
- update_cpu_cluster_capacity(cpus);
-}
-
-static int cpufreq_notifier_trans(struct notifier_block *nb,
- unsigned long val, void *data)
-{
- struct cpufreq_freqs *freq = (struct cpufreq_freqs *)data;
- unsigned int cpu = freq->cpu, new_freq = freq->new;
- unsigned long flags;
- struct sched_cluster *cluster;
- struct cpumask policy_cpus = cpu_rq(cpu)->freq_domain_cpumask;
- int i, j;
-
- if (val != CPUFREQ_POSTCHANGE)
- return 0;
-
- BUG_ON(!new_freq);
-
- if (cpu_cur_freq(cpu) == new_freq)
- return 0;
-
- for_each_cpu(i, &policy_cpus) {
- cluster = cpu_rq(i)->cluster;
-
- for_each_cpu(j, &cluster->cpus) {
- struct rq *rq = cpu_rq(j);
-
- raw_spin_lock_irqsave(&rq->lock, flags);
- update_task_ravg(rq->curr, rq, TASK_UPDATE,
- sched_ktime_clock(), 0);
- raw_spin_unlock_irqrestore(&rq->lock, flags);
- }
-
- cluster->cur_freq = new_freq;
- cpumask_andnot(&policy_cpus, &policy_cpus, &cluster->cpus);
- }
-
- return 0;
-}
-
-static int pwr_stats_ready_notifier(struct notifier_block *nb,
- unsigned long cpu, void *data)
-{
- cpumask_t mask = CPU_MASK_NONE;
-
- cpumask_set_cpu(cpu, &mask);
- sched_update_freq_max_load(&mask);
-
- mutex_lock(&cluster_lock);
- sort_clusters();
- mutex_unlock(&cluster_lock);
-
- return 0;
-}
-
-static struct notifier_block notifier_trans_block = {
- .notifier_call = cpufreq_notifier_trans
-};
-
-static struct notifier_block notifier_pwr_stats_ready = {
- .notifier_call = pwr_stats_ready_notifier
-};
-
-int __weak register_cpu_pwr_stats_ready_notifier(struct notifier_block *nb)
-{
- return -EINVAL;
-}
-
-static int register_sched_callback(void)
-{
- cpufreq_register_notifier(¬ifier_trans_block,
- CPUFREQ_TRANSITION_NOTIFIER);
-
- register_cpu_pwr_stats_ready_notifier(¬ifier_pwr_stats_ready);
-
- return 0;
-}
-
-/*
- * cpufreq callbacks can be registered at core_initcall or later time.
- * Any registration done prior to that is "forgotten" by cpufreq. See
- * initialization of variable init_cpufreq_transition_notifier_list_called
- * for further information.
- */
-core_initcall(register_sched_callback);
-
-void update_avg_burst(struct task_struct *p)
-{
- update_avg(&p->ravg.avg_burst, p->ravg.curr_burst);
- p->ravg.curr_burst = 0;
-}
-
-void note_task_waking(struct task_struct *p, u64 wallclock)
-{
- u64 sleep_time = wallclock - p->last_switch_out_ts;
-
- p->last_wake_ts = wallclock;
- update_avg(&p->ravg.avg_sleep_time, sleep_time);
-}
-
-#ifdef CONFIG_CGROUP_SCHED
-u64 cpu_upmigrate_discourage_read_u64(struct cgroup_subsys_state *css,
- struct cftype *cft)
-{
- struct task_group *tg = css_tg(css);
-
- return tg->upmigrate_discouraged;
-}
-
-int cpu_upmigrate_discourage_write_u64(struct cgroup_subsys_state *css,
- struct cftype *cft, u64 upmigrate_discourage)
-{
- struct task_group *tg = css_tg(css);
- int discourage = upmigrate_discourage > 0;
-
- if (tg->upmigrate_discouraged == discourage)
- return 0;
-
- /*
- * Revisit big-task classification for tasks of this cgroup. It would
- * have been efficient to walk tasks of just this cgroup in running
- * state, but we don't have easy means to do that. Walk all tasks in
- * running state on all cpus instead and re-visit their big task
- * classification.
- */
- get_online_cpus();
- pre_big_task_count_change(cpu_online_mask);
-
- tg->upmigrate_discouraged = discourage;
-
- post_big_task_count_change(cpu_online_mask);
- put_online_cpus();
-
- return 0;
-}
-#endif /* CONFIG_CGROUP_SCHED */
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 65b34b4..2b556d0 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -39,21 +39,6 @@ fixup_hmp_sched_stats_rt(struct rq *rq, struct task_struct *p,
#ifdef CONFIG_SMP
static int find_lowest_rq(struct task_struct *task);
-#ifdef CONFIG_SCHED_HMP
-static int
-select_task_rq_rt_hmp(struct task_struct *p, int cpu, int sd_flag, int flags)
-{
- int target;
-
- rcu_read_lock();
- target = find_lowest_rq(p);
- if (target != -1)
- cpu = target;
- rcu_read_unlock();
-
- return cpu;
-}
-#endif /* CONFIG_SCHED_HMP */
#endif /* CONFIG_SMP */
#else /* CONFIG_SCHED_WALT */
@@ -63,7 +48,7 @@ inc_hmp_sched_stats_rt(struct rq *rq, struct task_struct *p) { }
static inline void
dec_hmp_sched_stats_rt(struct rq *rq, struct task_struct *p) { }
-#endif /* CONFIG_SCHED_HMP */
+#endif /* CONFIG_SCHED_WALT */
#include "walt.h"
@@ -1515,10 +1500,6 @@ select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags)
struct rq *rq;
bool may_not_preempt;
-#ifdef CONFIG_SCHED_HMP
- return select_task_rq_rt_hmp(p, cpu, sd_flag, flags);
-#endif
-
/* For anything but wake ups, just return the task_cpu */
if (sd_flag != SD_BALANCE_WAKE && sd_flag != SD_BALANCE_FORK)
goto out;
@@ -1771,93 +1752,6 @@ static struct task_struct *pick_highest_pushable_task(struct rq *rq, int cpu)
static DEFINE_PER_CPU(cpumask_var_t, local_cpu_mask);
-#ifdef CONFIG_SCHED_HMP
-static int find_lowest_rq_hmp(struct task_struct *task)
-{
- struct cpumask *lowest_mask = *this_cpu_ptr(&local_cpu_mask);
- struct cpumask candidate_mask = CPU_MASK_NONE;
- struct sched_cluster *cluster;
- int best_cpu = -1;
- int prev_cpu = task_cpu(task);
- u64 cpu_load, min_load = ULLONG_MAX;
- int i;
- int restrict_cluster;
- int boost_on_big;
- int pack_task, wakeup_latency, least_wakeup_latency = INT_MAX;
-
- boost_on_big = sched_boost() == FULL_THROTTLE_BOOST &&
- sched_boost_policy() == SCHED_BOOST_ON_BIG;
-
- restrict_cluster = sysctl_sched_restrict_cluster_spill;
-
- /* Make sure the mask is initialized first */
- if (unlikely(!lowest_mask))
- return best_cpu;
-
- if (task->nr_cpus_allowed == 1)
- return best_cpu; /* No other targets possible */
-
- if (!cpupri_find(&task_rq(task)->rd->cpupri, task, lowest_mask))
- return best_cpu; /* No targets found */
-
- pack_task = is_short_burst_task(task);
-
- /*
- * At this point we have built a mask of cpus representing the
- * lowest priority tasks in the system. Now we want to elect
- * the best one based on our affinity and topology.
- */
-
- for_each_sched_cluster(cluster) {
- if (boost_on_big && cluster->capacity != max_possible_capacity)
- continue;
-
- cpumask_and(&candidate_mask, &cluster->cpus, lowest_mask);
- cpumask_andnot(&candidate_mask, &candidate_mask,
- cpu_isolated_mask);
-
- if (cpumask_empty(&candidate_mask))
- continue;
-
- for_each_cpu(i, &candidate_mask) {
- if (sched_cpu_high_irqload(i))
- continue;
-
- cpu_load = cpu_rq(i)->hmp_stats.cumulative_runnable_avg;
- if (!restrict_cluster)
- cpu_load = scale_load_to_cpu(cpu_load, i);
-
- if (pack_task) {
- wakeup_latency = cpu_rq(i)->wakeup_latency;
-
- if (wakeup_latency > least_wakeup_latency)
- continue;
-
- if (wakeup_latency < least_wakeup_latency) {
- least_wakeup_latency = wakeup_latency;
- min_load = cpu_load;
- best_cpu = i;
- continue;
- }
- }
-
- if (cpu_load < min_load ||
- (cpu_load == min_load &&
- (i == prev_cpu || (best_cpu != prev_cpu &&
- cpus_share_cache(prev_cpu, i))))) {
- min_load = cpu_load;
- best_cpu = i;
- }
- }
-
- if (restrict_cluster && best_cpu != -1)
- break;
- }
-
- return best_cpu;
-}
-#endif /* CONFIG_SCHED_HMP */
-
static inline unsigned long task_util(struct task_struct *p)
{
#ifdef CONFIG_SCHED_WALT
@@ -1888,10 +1782,6 @@ static int find_lowest_rq(struct task_struct *task)
long max_spare_cap = -LONG_MAX;
bool placement_boost;
-#ifdef CONFIG_SCHED_HMP
- return find_lowest_rq_hmp(task);
-#endif
-
/* Make sure the mask is initialized first */
if (unlikely(!lowest_mask))
return -1;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 2524954..07d7731 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -318,10 +318,6 @@ struct cfs_bandwidth {
struct task_group {
struct cgroup_subsys_state css;
-#ifdef CONFIG_SCHED_HMP
- bool upmigrate_discouraged;
-#endif
-
#ifdef CONFIG_FAIR_GROUP_SCHED
/* schedulable entities of this group on each cpu */
struct sched_entity **se;
@@ -801,7 +797,6 @@ struct rq {
u8 curr_table;
int prev_top;
int curr_top;
- struct irq_work irq_work;
#endif
#ifdef CONFIG_IRQ_TIME_ACCOUNTING
@@ -1312,7 +1307,6 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
#define WF_SYNC 0x01 /* waker goes to sleep after wakeup */
#define WF_FORK 0x02 /* child wakeup after fork */
#define WF_MIGRATED 0x4 /* internal use, task got migrated */
-#define WF_NO_NOTIFIER 0x08 /* do not notify governor */
/*
* To aid in avoiding the subversion of "niceness" due to uneven distribution
@@ -2211,11 +2205,15 @@ static inline u64 irq_time_read(int cpu)
#ifdef CONFIG_SCHED_WALT
u64 sched_ktime_clock(void);
+void note_task_waking(struct task_struct *p, u64 wallclock);
+extern void update_avg_burst(struct task_struct *p);
#else /* CONFIG_SCHED_WALT */
static inline u64 sched_ktime_clock(void)
{
return 0;
}
+static inline void note_task_waking(struct task_struct *p, u64 wallclock) { }
+static inline void update_avg_burst(struct task_struct *p) { }
#endif /* CONFIG_SCHED_WALT */
#ifdef CONFIG_CPU_FREQ
@@ -2709,14 +2707,10 @@ extern void sched_boost_parse_dt(void);
extern void clear_ed_task(struct task_struct *p, struct rq *rq);
extern bool early_detection_notify(struct rq *rq, u64 wallclock);
-#ifdef CONFIG_SCHED_HMP
-extern unsigned int power_cost(int cpu, u64 demand);
-#else
static inline unsigned int power_cost(int cpu, u64 demand)
{
return cpu_max_possible_capacity(cpu);
}
-#endif
#else /* CONFIG_SCHED_WALT */
@@ -2879,88 +2873,7 @@ static inline unsigned int power_cost(int cpu, u64 demand)
#endif /* CONFIG_SCHED_WALT */
-#ifdef CONFIG_SCHED_HMP
-#define energy_aware() false
-
-extern int is_big_task(struct task_struct *p);
-extern unsigned int pct_task_load(struct task_struct *p);
-extern void notify_migration(int src_cpu, int dest_cpu,
- bool src_cpu_dead, struct task_struct *p);
-extern void note_task_waking(struct task_struct *p, u64 wallclock);
-extern void
-check_for_freq_change(struct rq *rq, bool check_pred, bool check_groups);
-extern void fixup_nr_big_tasks(struct hmp_sched_stats *stats,
- struct task_struct *p, s64 delta);
-extern unsigned int cpu_temp(int cpu);
-extern void pre_big_task_count_change(const struct cpumask *cpus);
-extern void post_big_task_count_change(const struct cpumask *cpus);
-extern void set_hmp_defaults(void);
-extern void update_avg_burst(struct task_struct *p);
-extern void set_task_last_switch_out(struct task_struct *p, u64 wallclock);
-
-extern unsigned int nr_eligible_big_tasks(int cpu);
-
-static inline void
-inc_nr_big_task(struct hmp_sched_stats *stats, struct task_struct *p)
-{
- if (sched_disable_window_stats)
- return;
-
- if (is_big_task(p))
- stats->nr_big_tasks++;
-}
-
-static inline void
-dec_nr_big_task(struct hmp_sched_stats *stats, struct task_struct *p)
-{
- if (sched_disable_window_stats)
- return;
-
- if (is_big_task(p))
- stats->nr_big_tasks--;
-
- BUG_ON(stats->nr_big_tasks < 0);
-}
-
-static inline bool is_short_burst_task(struct task_struct *p)
-{
- return p->ravg.avg_burst < sysctl_sched_short_burst &&
- p->ravg.avg_sleep_time > sysctl_sched_short_sleep;
-}
-
-#else
static inline bool energy_aware(void)
{
return sched_feat(ENERGY_AWARE);
}
-
-static inline int pct_task_load(struct task_struct *p) { return 0; }
-
-static inline void notify_migration(int src_cpu, int dest_cpu,
- bool src_cpu_dead, struct task_struct *p) { }
-
-static inline void note_task_waking(struct task_struct *p, u64 wallclock) { }
-
-static inline void
-check_for_freq_change(struct rq *rq, bool check_pred, bool check_groups) { }
-
-static inline void fixup_nr_big_tasks(struct hmp_sched_stats *stats,
- struct task_struct *p, s64 delta) { }
-
-static inline unsigned int cpu_temp(int cpu)
-{
- return 0;
-}
-
-static inline void pre_big_task_count_change(const struct cpumask *cpus) { }
-
-static inline void post_big_task_count_change(const struct cpumask *cpus) { }
-
-static inline void set_hmp_defaults(void) { }
-
-static inline void update_avg_burst(struct task_struct *p) { }
-
-static inline void set_task_last_switch_out(struct task_struct *p,
- u64 wallclock) { }
-
-#endif /* CONFIG_SCHED_HMP */
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index 69bbce2..6f7d34d 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -49,6 +49,9 @@ static bool use_cycle_counter;
DEFINE_MUTEX(cluster_lock);
static atomic64_t walt_irq_work_lastq_ws;
+static struct irq_work walt_cpufreq_irq_work;
+static struct irq_work walt_migration_irq_work;
+
u64 sched_ktime_clock(void)
{
if (unlikely(sched_ktime_suspended))
@@ -471,24 +474,28 @@ static u32 top_task_load(struct rq *rq)
u64 freq_policy_load(struct rq *rq)
{
unsigned int reporting_policy = sysctl_sched_freq_reporting_policy;
+ int freq_aggr_thresh = sched_freq_aggregate_threshold;
struct sched_cluster *cluster = rq->cluster;
u64 aggr_grp_load = cluster->aggr_grp_load;
- u64 load;
+ u64 load, tt_load = 0;
- if (rq->ed_task != NULL)
- return sched_ravg_window;
+ if (rq->ed_task != NULL) {
+ load = sched_ravg_window;
+ goto done;
+ }
- if (aggr_grp_load > sched_freq_aggregate_threshold)
+ if (aggr_grp_load > freq_aggr_thresh)
load = rq->prev_runnable_sum + aggr_grp_load;
else
load = rq->prev_runnable_sum + rq->grp_time.prev_runnable_sum;
+ tt_load = top_task_load(rq);
switch (reporting_policy) {
case FREQ_REPORT_MAX_CPU_LOAD_TOP_TASK:
- load = max_t(u64, load, top_task_load(rq));
+ load = max_t(u64, load, tt_load);
break;
case FREQ_REPORT_TOP_TASK:
- load = top_task_load(rq);
+ load = tt_load;
break;
case FREQ_REPORT_CPU_LOAD:
break;
@@ -496,6 +503,9 @@ u64 freq_policy_load(struct rq *rq)
break;
}
+done:
+ trace_sched_load_to_gov(rq, aggr_grp_load, tt_load, freq_aggr_thresh,
+ load, reporting_policy);
return load;
}
@@ -612,40 +622,6 @@ void update_cluster_load_subtractions(struct task_struct *p,
raw_spin_unlock(&cluster->load_lock);
}
-#ifdef CONFIG_SCHED_HMP
-static inline void
-init_new_task_load_hmp(struct task_struct *p, bool idle_task)
-{
- p->ravg.curr_burst = 0;
- /*
- * Initialize the avg_burst to twice the threshold, so that
- * a task would not be classified as short burst right away
- * after fork. It takes at least 6 sleep-wakeup cycles for
- * the avg_burst to go below the threshold.
- */
- p->ravg.avg_burst = 2 * (u64)sysctl_sched_short_burst;
- p->ravg.avg_sleep_time = 0;
-}
-
-static inline void
-update_task_burst(struct task_struct *p, struct rq *rq, int event, u64 runtime)
-{
- /*
- * update_task_demand() has checks for idle task and
- * exit task. The runtime may include the wait time,
- * so update the burst only for the cases where the
- * task is running.
- */
- if (event == PUT_PREV_TASK || (event == TASK_UPDATE &&
- rq->curr == p))
- p->ravg.curr_burst += runtime;
-}
-
-static void reset_task_stats_hmp(struct task_struct *p)
-{
- p->ravg.avg_burst = 2 * (u64)sysctl_sched_short_burst;
-}
-#else
static inline void
init_new_task_load_hmp(struct task_struct *p, bool idle_task)
{
@@ -659,7 +635,6 @@ update_task_burst(struct task_struct *p, struct rq *rq, int event, int runtime)
static void reset_task_stats_hmp(struct task_struct *p)
{
}
-#endif
static inline void inter_cluster_migration_fixup
(struct task_struct *p, int new_cpu, int task_cpu, bool new_task)
@@ -870,12 +845,8 @@ void fixup_busy_time(struct task_struct *p, int new_cpu)
migrate_top_tasks(p, src_rq, dest_rq);
- if (!same_freq_domain(new_cpu, task_cpu(p))) {
- cpufreq_update_util(dest_rq, SCHED_CPUFREQ_INTERCLUSTER_MIG |
- SCHED_CPUFREQ_WALT);
- cpufreq_update_util(src_rq, SCHED_CPUFREQ_INTERCLUSTER_MIG |
- SCHED_CPUFREQ_WALT);
- }
+ if (!same_freq_domain(new_cpu, task_cpu(p)))
+ irq_work_queue(&walt_migration_irq_work);
if (p == src_rq->ed_task) {
src_rq->ed_task = NULL;
@@ -1901,7 +1872,7 @@ static inline void run_walt_irq_work(u64 old_window_start, struct rq *rq)
result = atomic64_cmpxchg(&walt_irq_work_lastq_ws, old_window_start,
rq->window_start);
if (result == old_window_start)
- irq_work_queue(&rq->irq_work);
+ irq_work_queue(&walt_cpufreq_irq_work);
}
/* Reflect task activity on its demand and cpu's busy time statistics */
@@ -2896,6 +2867,11 @@ void sched_update_cpu_freq_min_max(const cpumask_t *cpus, u32 fmin, u32 fmax)
update_cpu_cluster_capacity(cpus);
}
+void note_task_waking(struct task_struct *p, u64 wallclock)
+{
+ p->last_wake_ts = wallclock;
+}
+
/*
* Task's cpu usage is accounted in:
* rq->curr/prev_runnable_sum, when its ->grp is NULL
@@ -3016,6 +2992,11 @@ void walt_irq_work(struct irq_work *irq_work)
struct rq *rq;
int cpu;
u64 wc;
+ int flag = SCHED_CPUFREQ_WALT;
+
+ /* Am I the window rollover work or the migration work? */
+ if (irq_work == &walt_migration_irq_work)
+ flag |= SCHED_CPUFREQ_INTERCLUSTER_MIG;
for_each_cpu(cpu, cpu_possible_mask)
raw_spin_lock(&cpu_rq(cpu)->lock);
@@ -3044,15 +3025,15 @@ void walt_irq_work(struct irq_work *irq_work)
for_each_sched_cluster(cluster)
for_each_cpu(cpu, &cluster->cpus)
- cpufreq_update_util(cpu_rq(cpu), SCHED_CPUFREQ_WALT);
+ cpufreq_update_util(cpu_rq(cpu), flag);
for_each_cpu(cpu, cpu_possible_mask)
raw_spin_unlock(&cpu_rq(cpu)->lock);
- core_ctl_check(this_rq()->window_start);
+ if (irq_work != &walt_migration_irq_work)
+ core_ctl_check(this_rq()->window_start);
}
-#ifndef CONFIG_SCHED_HMP
int walt_proc_update_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
loff_t *ppos)
@@ -3080,4 +3061,54 @@ int walt_proc_update_handler(struct ctl_table *table, int write,
return ret;
}
-#endif
+
+void walt_sched_init(struct rq *rq)
+{
+ int j;
+
+ cpumask_set_cpu(cpu_of(rq), &rq->freq_domain_cpumask);
+ init_irq_work(&walt_migration_irq_work, walt_irq_work);
+ init_irq_work(&walt_cpufreq_irq_work, walt_irq_work);
+ rq->hmp_stats.cumulative_runnable_avg = 0;
+ rq->window_start = 0;
+ rq->cum_window_start = 0;
+ rq->hmp_stats.nr_big_tasks = 0;
+ rq->hmp_flags = 0;
+ rq->cur_irqload = 0;
+ rq->avg_irqload = 0;
+ rq->irqload_ts = 0;
+ rq->static_cpu_pwr_cost = 0;
+ rq->cc.cycles = 1;
+ rq->cc.time = 1;
+ rq->cstate = 0;
+ rq->wakeup_latency = 0;
+ rq->wakeup_energy = 0;
+
+ /*
+ * All cpus part of same cluster by default. This avoids the
+ * need to check for rq->cluster being non-NULL in hot-paths
+ * like select_best_cpu()
+ */
+ rq->cluster = &init_cluster;
+ rq->curr_runnable_sum = rq->prev_runnable_sum = 0;
+ rq->nt_curr_runnable_sum = rq->nt_prev_runnable_sum = 0;
+ memset(&rq->grp_time, 0, sizeof(struct group_cpu_time));
+ rq->old_busy_time = 0;
+ rq->old_estimated_time = 0;
+ rq->old_busy_time_group = 0;
+ rq->hmp_stats.pred_demands_sum = 0;
+ rq->ed_task = NULL;
+ rq->curr_table = 0;
+ rq->prev_top = 0;
+ rq->curr_top = 0;
+ for (j = 0; j < NUM_TRACKED_WINDOWS; j++) {
+ memset(&rq->load_subs[j], 0,
+ sizeof(struct load_subtractions));
+ rq->top_tasks[j] = kcalloc(NUM_LOAD_INDICES,
+ sizeof(u8), GFP_NOWAIT);
+ /* No other choice */
+ BUG_ON(!rq->top_tasks[j]);
+ clear_top_tasks_bitmap(rq->top_tasks_bitmap[j]);
+ }
+ rq->cum_window_demand = 0;
+}
diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h
index 887933f..3f4739e 100644
--- a/kernel/sched/walt.h
+++ b/kernel/sched/walt.h
@@ -65,7 +65,6 @@ extern void update_task_ravg(struct task_struct *p, struct rq *rq, int event,
extern unsigned int nr_eligible_big_tasks(int cpu);
-#ifndef CONFIG_SCHED_HMP
static inline void
inc_nr_big_task(struct hmp_sched_stats *stats, struct task_struct *p)
{
@@ -87,7 +86,6 @@ dec_nr_big_task(struct hmp_sched_stats *stats, struct task_struct *p)
BUG_ON(stats->nr_big_tasks < 0);
}
-#endif
static inline void
adjust_nr_big_tasks(struct hmp_sched_stats *stats, int delta, bool inc)
@@ -291,8 +289,12 @@ void sort_clusters(void);
void walt_irq_work(struct irq_work *irq_work);
+void walt_sched_init(struct rq *rq);
+
#else /* CONFIG_SCHED_WALT */
+static inline void walt_sched_init(struct rq *rq) { }
+
static inline void update_task_ravg(struct task_struct *p, struct rq *rq,
int event, u64 wallclock, u64 irqtime) { }
static inline void inc_cumulative_runnable_avg(struct hmp_sched_stats *stats,
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index b076cba..1d894fc 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -128,9 +128,6 @@ static int __maybe_unused four = 4;
static unsigned long one_ul = 1;
static int one_hundred = 100;
static int one_thousand = 1000;
-#ifdef CONFIG_SCHED_HMP
-static int max_freq_reporting_policy = FREQ_REPORT_INVALID_POLICY - 1;
-#endif
#ifdef CONFIG_PRINTK
static int ten_thousand = 10000;
#endif
@@ -305,11 +302,7 @@ static struct ctl_table kern_table[] = {
.data = &sysctl_sched_group_upmigrate_pct,
.maxlen = sizeof(unsigned int),
.mode = 0644,
-#ifdef CONFIG_SCHED_HMP
- .proc_handler = sched_hmp_proc_update_handler,
-#else
.proc_handler = walt_proc_update_handler,
-#endif
.extra1 = &sysctl_sched_group_downmigrate_pct,
},
{
@@ -317,194 +310,11 @@ static struct ctl_table kern_table[] = {
.data = &sysctl_sched_group_downmigrate_pct,
.maxlen = sizeof(unsigned int),
.mode = 0644,
-#ifdef CONFIG_SCHED_HMP
- .proc_handler = sched_hmp_proc_update_handler,
-#else
.proc_handler = walt_proc_update_handler,
-#endif
.extra1 = &zero,
.extra2 = &sysctl_sched_group_upmigrate_pct,
},
#endif
-#ifdef CONFIG_SCHED_HMP
- {
- .procname = "sched_freq_reporting_policy",
- .data = &sysctl_sched_freq_reporting_policy,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
- .extra2 = &max_freq_reporting_policy,
- },
- {
- .procname = "sched_freq_inc_notify",
- .data = &sysctl_sched_freq_inc_notify,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
- },
- {
- .procname = "sched_freq_dec_notify",
- .data = &sysctl_sched_freq_dec_notify,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
- },
- {
- .procname = "sched_ravg_hist_size",
- .data = &sysctl_sched_ravg_hist_size,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = sched_window_update_handler,
- },
- {
- .procname = "sched_window_stats_policy",
- .data = &sysctl_sched_window_stats_policy,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = sched_window_update_handler,
- },
- {
- .procname = "sched_spill_load",
- .data = &sysctl_sched_spill_load_pct,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = sched_hmp_proc_update_handler,
- .extra1 = &zero,
- .extra2 = &one_hundred,
- },
- {
- .procname = "sched_spill_nr_run",
- .data = &sysctl_sched_spill_nr_run,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
- },
- {
- .procname = "sched_upmigrate",
- .data = &sysctl_sched_upmigrate_pct,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = sched_hmp_proc_update_handler,
- .extra1 = &zero,
- .extra2 = &one_hundred,
- },
- {
- .procname = "sched_downmigrate",
- .data = &sysctl_sched_downmigrate_pct,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = sched_hmp_proc_update_handler,
- .extra1 = &zero,
- .extra2 = &one_hundred,
- },
- {
- .procname = "sched_init_task_load",
- .data = &sysctl_sched_init_task_load_pct,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = sched_hmp_proc_update_handler,
- .extra1 = &zero,
- .extra2 = &one_hundred,
- },
- {
- .procname = "sched_select_prev_cpu_us",
- .data = &sysctl_sched_select_prev_cpu_us,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = sched_hmp_proc_update_handler,
- .extra1 = &zero,
- },
- {
- .procname = "sched_restrict_cluster_spill",
- .data = &sysctl_sched_restrict_cluster_spill,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
- .extra2 = &one,
- },
- {
- .procname = "sched_small_wakee_task_load",
- .data = &sysctl_sched_small_wakee_task_load_pct,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = sched_hmp_proc_update_handler,
- .extra1 = &zero,
- .extra2 = &one_hundred,
- },
- {
- .procname = "sched_big_waker_task_load",
- .data = &sysctl_sched_big_waker_task_load_pct,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = sched_hmp_proc_update_handler,
- .extra1 = &zero,
- .extra2 = &one_hundred,
- },
- {
- .procname = "sched_prefer_sync_wakee_to_waker",
- .data = &sysctl_sched_prefer_sync_wakee_to_waker,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
- .extra2 = &one,
- },
- {
- .procname = "sched_enable_thread_grouping",
- .data = &sysctl_sched_enable_thread_grouping,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "sched_pred_alert_freq",
- .data = &sysctl_sched_pred_alert_freq,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
- },
- {
- .procname = "sched_freq_aggregate",
- .data = &sysctl_sched_freq_aggregate,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = sched_window_update_handler,
- },
- {
- .procname = "sched_freq_aggregate_threshold",
- .data = &sysctl_sched_freq_aggregate_threshold_pct,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = sched_hmp_proc_update_handler,
- .extra1 = &zero,
- /*
- * Special handling for sched_freq_aggregate_threshold_pct
- * which can be greater than 100. Use 1000 as an upper bound
- * value which works for all practical use cases.
- */
- .extra2 = &one_thousand,
- },
- {
- .procname = "sched_short_burst_ns",
- .data = &sysctl_sched_short_burst,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "sched_short_sleep_ns",
- .data = &sysctl_sched_short_sleep,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
-#endif /* CONFIG_SCHED_HMP */
#ifdef CONFIG_SCHED_DEBUG
{
.procname = "sched_min_granularity_ns",
@@ -1965,6 +1775,22 @@ static struct ctl_table vm_table[] = {
.extra2 = (void *)&mmap_rnd_compat_bits_max,
},
#endif
+#ifdef CONFIG_SWAP
+ {
+ .procname = "swap_ratio",
+ .data = &sysctl_swap_ratio,
+ .maxlen = sizeof(sysctl_swap_ratio),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ },
+ {
+ .procname = "swap_ratio_enable",
+ .data = &sysctl_swap_ratio_enable,
+ .maxlen = sizeof(sysctl_swap_ratio_enable),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ },
+#endif
{ }
};
@@ -2463,9 +2289,12 @@ static int do_proc_douintvec_conv(bool *negp, unsigned long *lvalp,
if (write) {
if (*negp)
return -EINVAL;
+ if (*lvalp > UINT_MAX)
+ return -EINVAL;
*valp = *lvalp;
} else {
unsigned int val = *valp;
+ *negp = false;
*lvalp = (unsigned long)val;
}
return 0;
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 9055429..44cc350 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/irq_work.h>
#include <linux/posix-timers.h>
+#include <linux/timer.h>
#include <linux/context_tracking.h>
#include <linux/rq_stats.h>
@@ -933,6 +934,11 @@ static void __tick_nohz_idle_enter(struct tick_sched *ts)
now = tick_nohz_start_idle(ts);
+#ifdef CONFIG_SMP
+ if (check_pending_deferrable_timers(cpu))
+ raise_softirq_irqoff(TIMER_SOFTIRQ);
+#endif
+
if (can_stop_idle_tick(cpu, ts)) {
int was_stopped = ts->tick_stopped;
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index adede73..3a2dd86 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -207,6 +207,7 @@ struct timer_base {
static DEFINE_PER_CPU(struct timer_base, timer_bases[NR_BASES]);
struct timer_base timer_base_deferrable;
+static atomic_t deferrable_pending;
#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
unsigned int sysctl_timer_migration = 1;
@@ -1460,6 +1461,31 @@ static u64 cmp_next_hrtimer_event(u64 basem, u64 expires)
return DIV_ROUND_UP_ULL(nextevt, TICK_NSEC) * TICK_NSEC;
}
+
+#ifdef CONFIG_SMP
+/*
+ * check_pending_deferrable_timers - Check for unbound deferrable timer expiry
+ * @cpu - Current CPU
+ *
+ * The function checks whether any global deferrable pending timers
+ * are exipired or not. This function does not check cpu bounded
+ * diferrable pending timers expiry.
+ *
+ * The function returns true when a cpu unbounded deferrable timer is expired.
+ */
+bool check_pending_deferrable_timers(int cpu)
+{
+ if (cpu == tick_do_timer_cpu ||
+ tick_do_timer_cpu == TICK_DO_TIMER_NONE) {
+ if (time_after_eq(jiffies, timer_base_deferrable.clk)
+ && !atomic_cmpxchg(&deferrable_pending, 0, 1)) {
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
/**
* get_next_timer_interrupt - return the time (clock mono) of the next timer
* @basej: base time jiffies
@@ -1619,10 +1645,13 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h)
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
__run_timers(base);
- if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active) {
- __run_timers(&timer_base_deferrable);
+ if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active)
__run_timers(this_cpu_ptr(&timer_bases[BASE_DEF]));
- }
+
+ if ((atomic_cmpxchg(&deferrable_pending, 1, 0) &&
+ tick_do_timer_cpu == TICK_DO_TIMER_NONE) ||
+ tick_do_timer_cpu == smp_processor_id())
+ __run_timers(&timer_base_deferrable);
}
/*
diff --git a/kernel/trace/ipc_logging.c b/kernel/trace/ipc_logging.c
index 31e6a8e..ec9bde7 100644
--- a/kernel/trace/ipc_logging.c
+++ b/kernel/trace/ipc_logging.c
@@ -549,6 +549,7 @@ int ipc_log_extract(void *ctxt, char *buff, int size)
struct decode_context *dctxt);
struct ipc_log_context *ilctxt = (struct ipc_log_context *)ctxt;
unsigned long flags;
+ int ret;
if (size < MAX_MSG_DECODED_SIZE)
return -EINVAL;
@@ -558,6 +559,11 @@ int ipc_log_extract(void *ctxt, char *buff, int size)
dctxt.size = size;
read_lock_irqsave(&context_list_lock_lha1, flags);
spin_lock(&ilctxt->context_lock_lhb1);
+ if (ilctxt->destroyed) {
+ ret = -EIO;
+ goto done;
+ }
+
while (dctxt.size >= MAX_MSG_DECODED_SIZE &&
!is_nd_read_empty(ilctxt)) {
msg_read(ilctxt, &ectxt);
@@ -573,11 +579,17 @@ int ipc_log_extract(void *ctxt, char *buff, int size)
read_lock_irqsave(&context_list_lock_lha1, flags);
spin_lock(&ilctxt->context_lock_lhb1);
}
- if ((size - dctxt.size) == 0)
- reinit_completion(&ilctxt->read_avail);
+ ret = size - dctxt.size;
+ if (ret == 0) {
+ if (!ilctxt->destroyed)
+ reinit_completion(&ilctxt->read_avail);
+ else
+ ret = -EIO;
+ }
+done:
spin_unlock(&ilctxt->context_lock_lhb1);
read_unlock_irqrestore(&context_list_lock_lha1, flags);
- return size - dctxt.size;
+ return ret;
}
EXPORT_SYMBOL(ipc_log_extract);
@@ -835,6 +847,8 @@ void *ipc_log_context_create(int max_num_pages,
ctxt->nd_read_page = ctxt->first_page;
ctxt->write_avail = max_num_pages * LOG_PAGE_DATA_SIZE;
ctxt->header_size = sizeof(struct ipc_log_page_header);
+ kref_init(&ctxt->refcount);
+ ctxt->destroyed = false;
create_ctx_debugfs(ctxt, mod_name);
/* set magic last to signal context init is complete */
@@ -857,6 +871,21 @@ void *ipc_log_context_create(int max_num_pages,
}
EXPORT_SYMBOL(ipc_log_context_create);
+void ipc_log_context_free(struct kref *kref)
+{
+ struct ipc_log_context *ilctxt = container_of(kref,
+ struct ipc_log_context, refcount);
+ struct ipc_log_page *pg = NULL;
+
+ while (!list_empty(&ilctxt->page_list)) {
+ pg = get_first_page(ilctxt);
+ list_del(&pg->hdr.list);
+ kfree(pg);
+ }
+
+ kfree(ilctxt);
+}
+
/*
* Destroy debug log context
*
@@ -865,25 +894,24 @@ EXPORT_SYMBOL(ipc_log_context_create);
int ipc_log_context_destroy(void *ctxt)
{
struct ipc_log_context *ilctxt = (struct ipc_log_context *)ctxt;
- struct ipc_log_page *pg = NULL;
unsigned long flags;
if (!ilctxt)
return 0;
- while (!list_empty(&ilctxt->page_list)) {
- pg = get_first_page(ctxt);
- list_del(&pg->hdr.list);
- kfree(pg);
- }
+ debugfs_remove_recursive(ilctxt->dent);
+
+ spin_lock(&ilctxt->context_lock_lhb1);
+ ilctxt->destroyed = true;
+ complete_all(&ilctxt->read_avail);
+ spin_unlock(&ilctxt->context_lock_lhb1);
write_lock_irqsave(&context_list_lock_lha1, flags);
list_del(&ilctxt->list);
write_unlock_irqrestore(&context_list_lock_lha1, flags);
- debugfs_remove_recursive(ilctxt->dent);
+ ipc_log_context_put(ilctxt);
- kfree(ilctxt);
return 0;
}
EXPORT_SYMBOL(ipc_log_context_destroy);
diff --git a/kernel/trace/ipc_logging_debug.c b/kernel/trace/ipc_logging_debug.c
index a545387..d733724 100644
--- a/kernel/trace/ipc_logging_debug.c
+++ b/kernel/trace/ipc_logging_debug.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 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
@@ -74,23 +74,42 @@ static int debug_log(struct ipc_log_context *ilctxt,
static ssize_t debug_read_helper(struct file *file, char __user *buff,
size_t count, loff_t *ppos, int cont)
{
- struct ipc_log_context *ilctxt = file->private_data;
+ struct ipc_log_context *ilctxt;
+ struct dentry *d = file->f_path.dentry;
char *buffer;
int bsize;
+ int srcu_idx;
+ int r;
+
+ r = debugfs_use_file_start(d, &srcu_idx);
+ if (!r) {
+ ilctxt = file->private_data;
+ r = kref_get_unless_zero(&ilctxt->refcount) ? 0 : -EIO;
+ }
+ debugfs_use_file_finish(srcu_idx);
+ if (r)
+ return r;
buffer = kmalloc(count, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
+ if (!buffer) {
+ bsize = -ENOMEM;
+ goto done;
+ }
bsize = debug_log(ilctxt, buffer, count, cont);
+
if (bsize > 0) {
if (copy_to_user(buff, buffer, bsize)) {
+ bsize = -EFAULT;
kfree(buffer);
- return -EFAULT;
+ goto done;
}
*ppos += bsize;
}
kfree(buffer);
+
+done:
+ ipc_log_context_put(ilctxt);
return bsize;
}
@@ -127,7 +146,7 @@ static void debug_create(const char *name, mode_t mode,
struct ipc_log_context *ilctxt,
const struct file_operations *fops)
{
- debugfs_create_file(name, mode, dent, ilctxt, fops);
+ debugfs_create_file_unsafe(name, mode, dent, ilctxt, fops);
}
static void dfunc_string(struct encode_context *ectxt,
diff --git a/kernel/trace/ipc_logging_private.h b/kernel/trace/ipc_logging_private.h
index 594027a..47c41e9 100644
--- a/kernel/trace/ipc_logging_private.h
+++ b/kernel/trace/ipc_logging_private.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -119,6 +119,8 @@ struct ipc_log_context {
struct list_head dfunc_info_list;
spinlock_t context_lock_lhb1;
struct completion read_avail;
+ struct kref refcount;
+ bool destroyed;
};
struct dfunc_info {
@@ -147,6 +149,13 @@ enum {
((x) < TSV_TYPE_MSG_END))
#define MAX_MSG_DECODED_SIZE (MAX_MSG_SIZE*4)
+void ipc_log_context_free(struct kref *kref);
+
+static inline void ipc_log_context_put(struct ipc_log_context *ilctxt)
+{
+ kref_put(&ilctxt->refcount, ipc_log_context_free);
+}
+
#if (defined(CONFIG_DEBUG_FS))
void check_and_create_debugfs(void);
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 8d2b4d8..5ff45ca 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -667,30 +667,25 @@ static int create_trace_kprobe(int argc, char **argv)
pr_info("Probe point is not specified.\n");
return -EINVAL;
}
- if (isdigit(argv[1][0])) {
- if (is_return) {
- pr_info("Return probe point must be a symbol.\n");
- return -EINVAL;
- }
- /* an address specified */
- ret = kstrtoul(&argv[1][0], 0, (unsigned long *)&addr);
- if (ret) {
- pr_info("Failed to parse address.\n");
- return ret;
- }
- } else {
+
+ /* try to parse an address. if that fails, try to read the
+ * input as a symbol. */
+ if (kstrtoul(argv[1], 0, (unsigned long *)&addr)) {
/* a symbol specified */
symbol = argv[1];
/* TODO: support .init module functions */
ret = traceprobe_split_symbol_offset(symbol, &offset);
if (ret) {
- pr_info("Failed to parse symbol.\n");
+ pr_info("Failed to parse either an address or a symbol.\n");
return ret;
}
if (offset && is_return) {
pr_info("Return probe must be used without offset.\n");
return -EINVAL;
}
+ } else if (is_return) {
+ pr_info("Return probe point must be a symbol.\n");
+ return -EINVAL;
}
argc -= 2; argv += 2;
diff --git a/mm/Kconfig b/mm/Kconfig
index eb10c90..3363a70 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -730,3 +730,19 @@
always using ZONE_DMA memory.
If unsure, say "n".
+
+config PROCESS_RECLAIM
+ bool "Enable process reclaim"
+ depends on PROC_FS
+ default n
+ help
+ It allows to reclaim pages of the process by /proc/pid/reclaim.
+
+ (echo file > /proc/PID/reclaim) reclaims file-backed pages only.
+ (echo anon > /proc/PID/reclaim) reclaims anonymous pages only.
+ (echo all > /proc/PID/reclaim) reclaims all pages.
+
+ (echo addr size-byte > /proc/PID/reclaim) reclaims pages in
+ (addr, addr + size-bytes) of the process.
+
+ Any other vaule is ignored.
diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug
index b9019d4..78e68f9 100644
--- a/mm/Kconfig.debug
+++ b/mm/Kconfig.debug
@@ -65,6 +65,16 @@
If unsure, say N
+config PAGE_POISONING_ENABLE_DEFAULT
+ bool "Enable page poisoning by default?"
+ default n
+ depends on PAGE_POISONING
+ ---help---
+ Enable page poisoning of free pages by default? This value
+ can be overridden by page_poison=off|on. This can be used
+ to avoid passing the kernel parameter and let page poisoning
+ feature enabled by default.
+
config PAGE_POISONING_NO_SANITY
depends on PAGE_POISONING
bool "Only poison, don't sanity check"
diff --git a/mm/Makefile b/mm/Makefile
index a7e9b6a..7a9642f 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -37,7 +37,7 @@
mm_init.o mmu_context.o percpu.o slab_common.o \
compaction.o vmacache.o \
interval_tree.o list_lru.o workingset.o \
- debug.o $(mmu-y) showmem.o
+ debug.o $(mmu-y) showmem.o vmpressure.o
obj-y += init-mm.o
@@ -53,7 +53,7 @@
endif
obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o
-obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o
+obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o swap_ratio.o
obj-$(CONFIG_FRONTSWAP) += frontswap.o
obj-$(CONFIG_ZSWAP) += zswap.o
obj-$(CONFIG_HAS_DMA) += dmapool.o
@@ -76,7 +76,7 @@
obj-$(CONFIG_QUICKLIST) += quicklist.o
obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o khugepaged.o
obj-$(CONFIG_PAGE_COUNTER) += page_counter.o
-obj-$(CONFIG_MEMCG) += memcontrol.o vmpressure.o
+obj-$(CONFIG_MEMCG) += memcontrol.o
obj-$(CONFIG_MEMCG_SWAP) += swap_cgroup.o
obj-$(CONFIG_CGROUP_HUGETLB) += hugetlb_cgroup.o
obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o
@@ -100,3 +100,4 @@
obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
obj-$(CONFIG_DEBUG_PAGE_REF) += debug_page_ref.o
obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o
+obj-$(CONFIG_PROCESS_RECLAIM) += process_reclaim.o
diff --git a/mm/cma.c b/mm/cma.c
index 0306bab..3322b30 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -35,6 +35,7 @@
#include <linux/cma.h>
#include <linux/highmem.h>
#include <linux/io.h>
+#include <linux/delay.h>
#include <trace/events/cma.h>
#include "cma.h"
@@ -374,6 +375,7 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align)
unsigned long bitmap_maxno, bitmap_no, bitmap_count;
struct page *page = NULL;
int ret;
+ int retry_after_sleep = 0;
if (!cma || !cma->count)
return NULL;
@@ -400,8 +402,24 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align)
bitmap_maxno, start, bitmap_count, mask,
offset);
if (bitmap_no >= bitmap_maxno) {
- mutex_unlock(&cma->lock);
- break;
+ if (retry_after_sleep < 2) {
+ start = 0;
+ /*
+ * Page may be momentarily pinned by some other
+ * process which has been scheduled out, eg.
+ * in exit path, during unmap call, or process
+ * fork and so cannot be freed there. Sleep
+ * for 100ms and retry twice to see if it has
+ * been freed later.
+ */
+ mutex_unlock(&cma->lock);
+ msleep(100);
+ retry_after_sleep++;
+ continue;
+ } else {
+ mutex_unlock(&cma->lock);
+ break;
+ }
}
bitmap_set(cma->bitmap, bitmap_no, bitmap_count);
/*
diff --git a/mm/compaction.c b/mm/compaction.c
index 70e6bec..f002a7f 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -635,20 +635,52 @@ isolate_freepages_range(struct compact_control *cc,
}
/* Similar to reclaim, but different enough that they don't share logic */
-static bool too_many_isolated(struct zone *zone)
+static bool __too_many_isolated(struct zone *zone, int safe)
{
unsigned long active, inactive, isolated;
- inactive = node_page_state(zone->zone_pgdat, NR_INACTIVE_FILE) +
+ if (safe) {
+ inactive = node_page_state_snapshot(zone->zone_pgdat,
+ NR_INACTIVE_FILE) +
+ node_page_state_snapshot(zone->zone_pgdat,
+ NR_INACTIVE_ANON);
+ active = node_page_state_snapshot(zone->zone_pgdat,
+ NR_ACTIVE_FILE) +
+ node_page_state_snapshot(zone->zone_pgdat,
+ NR_ACTIVE_ANON);
+ isolated = node_page_state_snapshot(zone->zone_pgdat,
+ NR_ISOLATED_FILE) +
+ node_page_state_snapshot(zone->zone_pgdat,
+ NR_ISOLATED_ANON);
+ } else {
+ inactive = node_page_state(zone->zone_pgdat, NR_INACTIVE_FILE) +
node_page_state(zone->zone_pgdat, NR_INACTIVE_ANON);
- active = node_page_state(zone->zone_pgdat, NR_ACTIVE_FILE) +
+ active = node_page_state(zone->zone_pgdat, NR_ACTIVE_FILE) +
node_page_state(zone->zone_pgdat, NR_ACTIVE_ANON);
- isolated = node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE) +
+ isolated = node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE) +
node_page_state(zone->zone_pgdat, NR_ISOLATED_ANON);
+ }
return isolated > (inactive + active) / 2;
}
+/* Similar to reclaim, but different enough that they don't share logic */
+static bool too_many_isolated(struct compact_control *cc)
+{
+ /*
+ * __too_many_isolated(safe=0) is fast but inaccurate, because it
+ * doesn't account for the vm_stat_diff[] counters. So if it looks
+ * like too_many_isolated() is about to return true, fall back to the
+ * slower, more accurate zone_page_state_snapshot().
+ */
+ if (unlikely(__too_many_isolated(cc->zone, 0))) {
+ if (cc->mode != MIGRATE_ASYNC)
+ return __too_many_isolated(cc->zone, 1);
+ }
+
+ return false;
+}
+
/**
* isolate_migratepages_block() - isolate all migrate-able pages within
* a single pageblock
@@ -686,7 +718,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
* list by either parallel reclaimers or compaction. If there are,
* delay for some time until fewer pages are isolated
*/
- while (unlikely(too_many_isolated(zone))) {
+ while (unlikely(too_many_isolated(cc))) {
/* async migration should just abort */
if (cc->mode == MIGRATE_ASYNC)
return 0;
diff --git a/mm/filemap.c b/mm/filemap.c
index edfb90e..b4c09ec 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -251,10 +251,12 @@ void __delete_from_page_cache(struct page *page, void *shadow)
* invalidate any existing cleancache entries. We can't leave
* stale data around in the cleancache once our page is gone
*/
- if (PageUptodate(page) && PageMappedToDisk(page))
+ if (PageUptodate(page) && PageMappedToDisk(page)) {
+ count_vm_event(PGPGOUTCLEAN);
cleancache_put_page(page);
- else
+ } else {
cleancache_invalidate_page(mapping, page);
+ }
VM_BUG_ON_PAGE(PageTail(page), page);
VM_BUG_ON_PAGE(page_mapped(page), page);
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index 4df20e1..5cbd2de 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -366,6 +366,7 @@ void kasan_report(unsigned long addr, size_t size,
info.access_size = size;
info.is_write = is_write;
info.ip = ip;
+ info.first_bad_addr = NULL;
kasan_report_error(&info);
}
diff --git a/mm/ksm.c b/mm/ksm.c
index 5f1855b..927aa34 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1964,6 +1964,7 @@ int rmap_walk_ksm(struct page *page, struct rmap_walk_control *rwc)
stable_node = page_stable_node(page);
if (!stable_node)
return ret;
+
again:
hlist_for_each_entry(rmap_item, &stable_node->hlist, hlist) {
struct anon_vma *anon_vma = rmap_item->anon_vma;
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index fdc790a..3b38b73 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -5996,7 +5996,7 @@ bool mem_cgroup_swap_full(struct page *page)
VM_BUG_ON_PAGE(!PageLocked(page), page);
- if (vm_swap_full())
+ if (vm_swap_full(page_swap_info(page)))
return true;
if (!do_swap_account || !cgroup_subsys_on_dfl(memory_cgrp_subsys))
return false;
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index ce7d416..b335423 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -972,7 +972,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
if (kill)
collect_procs(hpage, &tokill, flags & MF_ACTION_REQUIRED);
- ret = try_to_unmap(hpage, ttu);
+ ret = try_to_unmap(hpage, ttu, NULL);
if (ret != SWAP_SUCCESS)
pr_err("Memory failure: %#lx: failed to unmap page (mapcount=%d)\n",
pfn, page_mapcount(hpage));
diff --git a/mm/migrate.c b/mm/migrate.c
index 435f674..f0b786d 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -1020,7 +1020,7 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
VM_BUG_ON_PAGE(PageAnon(page) && !PageKsm(page) && !anon_vma,
page);
try_to_unmap(page,
- TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
+ TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS, NULL);
page_was_mapped = 1;
}
@@ -1238,7 +1238,7 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
if (page_mapped(hpage)) {
try_to_unmap(hpage,
- TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
+ TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS, NULL);
page_was_mapped = 1;
}
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index ec9f11d..2efa9c9 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -368,7 +368,7 @@ static void select_bad_process(struct oom_control *oc)
* State information includes task's pid, uid, tgid, vm size, rss, nr_ptes,
* swapents, oom_score_adj value, and name.
*/
-static void dump_tasks(struct mem_cgroup *memcg, const nodemask_t *nodemask)
+void dump_tasks(struct mem_cgroup *memcg, const nodemask_t *nodemask)
{
struct task_struct *p;
struct task_struct *task;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 27ddaae..bdd2bea 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -233,10 +233,10 @@ char * const migratetype_names[MIGRATE_TYPES] = {
"Unmovable",
"Movable",
"Reclaimable",
- "HighAtomic",
#ifdef CONFIG_CMA
"CMA",
#endif
+ "HighAtomic",
#ifdef CONFIG_MEMORY_ISOLATION
"Isolate",
#endif
@@ -1706,10 +1706,10 @@ static inline int check_new_page(struct page *page)
return 1;
}
-static inline bool free_pages_prezeroed(bool poisoned)
+static inline bool free_pages_prezeroed(void)
{
return IS_ENABLED(CONFIG_PAGE_POISONING_ZERO) &&
- page_poisoning_enabled() && poisoned;
+ page_poisoning_enabled();
}
#ifdef CONFIG_DEBUG_VM
@@ -1763,17 +1763,10 @@ static void prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags
unsigned int alloc_flags)
{
int i;
- bool poisoned = true;
-
- for (i = 0; i < (1 << order); i++) {
- struct page *p = page + i;
- if (poisoned)
- poisoned &= page_is_poisoned(p);
- }
post_alloc_hook(page, order, gfp_flags);
- if (!free_pages_prezeroed(poisoned) && (gfp_flags & __GFP_ZERO))
+ if (!free_pages_prezeroed() && (gfp_flags & __GFP_ZERO))
for (i = 0; i < (1 << order); i++)
clear_highpage(page + i);
@@ -1839,6 +1832,11 @@ static int fallbacks[MIGRATE_TYPES][4] = {
#endif
};
+int *get_migratetype_fallbacks(int mtype)
+{
+ return fallbacks[mtype];
+}
+
#ifdef CONFIG_CMA
static struct page *__rmqueue_cma_fallback(struct zone *zone,
unsigned int order)
@@ -2209,17 +2207,30 @@ static struct page *__rmqueue(struct zone *zone, unsigned int order,
page = __rmqueue_smallest(zone, order, migratetype);
if (unlikely(!page)) {
- if (migratetype == MIGRATE_MOVABLE)
- page = __rmqueue_cma_fallback(zone, order);
-
- if (!page)
- page = __rmqueue_fallback(zone, order, migratetype);
+ page = __rmqueue_fallback(zone, order, migratetype);
}
trace_mm_page_alloc_zone_locked(page, order, migratetype);
return page;
}
+#ifdef CONFIG_CMA
+static struct page *__rmqueue_cma(struct zone *zone, unsigned int order)
+{
+ struct page *page = 0;
+ if (IS_ENABLED(CONFIG_CMA))
+ if (!zone->cma_alloc)
+ page = __rmqueue_cma_fallback(zone, order);
+ trace_mm_page_alloc_zone_locked(page, order, MIGRATE_CMA);
+ return page;
+}
+#else
+static inline struct page *__rmqueue_cma(struct zone *zone, unsigned int order)
+{
+ return NULL;
+}
+#endif
+
/*
* Obtain a specified number of elements from the buddy allocator, all under
* a single hold of the lock, for efficiency. Add them to the supplied list.
@@ -2233,7 +2244,17 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,
spin_lock(&zone->lock);
for (i = 0; i < count; ++i) {
- struct page *page = __rmqueue(zone, order, migratetype);
+ struct page *page;
+
+ /*
+ * If migrate type CMA is being requested only try to
+ * satisfy the request with CMA pages to try and increase
+ * CMA utlization.
+ */
+ if (is_migrate_cma(migratetype))
+ page = __rmqueue_cma(zone, order);
+ else
+ page = __rmqueue(zone, order, migratetype);
if (unlikely(page == NULL))
break;
@@ -2271,6 +2292,28 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,
return alloced;
}
+/*
+ * Return the pcp list that corresponds to the migrate type if that list isn't
+ * empty.
+ * If the list is empty return NULL.
+ */
+static struct list_head *get_populated_pcp_list(struct zone *zone,
+ unsigned int order, struct per_cpu_pages *pcp,
+ int migratetype, int cold)
+{
+ struct list_head *list = &pcp->lists[migratetype];
+
+ if (list_empty(list)) {
+ pcp->count += rmqueue_bulk(zone, order,
+ pcp->batch, list,
+ migratetype, cold);
+
+ if (list_empty(list))
+ list = NULL;
+ }
+ return list;
+}
+
#ifdef CONFIG_NUMA
/*
* Called from the vmstat counter updater to drain pagesets of this
@@ -2631,22 +2674,33 @@ struct page *buffered_rmqueue(struct zone *preferred_zone,
int migratetype)
{
unsigned long flags;
- struct page *page;
+ struct page *page = NULL;
bool cold = ((gfp_flags & __GFP_COLD) != 0);
if (likely(order == 0)) {
struct per_cpu_pages *pcp;
- struct list_head *list;
+ struct list_head *list = NULL;
local_irq_save(flags);
do {
pcp = &this_cpu_ptr(zone->pageset)->pcp;
- list = &pcp->lists[migratetype];
- if (list_empty(list)) {
- pcp->count += rmqueue_bulk(zone, 0,
- pcp->batch, list,
- migratetype, cold);
- if (unlikely(list_empty(list)))
+
+ /* First try to get CMA pages */
+ if (migratetype == MIGRATE_MOVABLE &&
+ gfp_flags & __GFP_CMA) {
+ list = get_populated_pcp_list(zone, 0, pcp,
+ get_cma_migrate_type(), cold);
+ }
+
+ if (list == NULL) {
+ /*
+ * Either CMA is not suitable or there are no
+ * free CMA pages.
+ */
+ list = get_populated_pcp_list(zone, 0, pcp,
+ migratetype, cold);
+ if (unlikely(list == NULL) ||
+ unlikely(list_empty(list)))
goto failed;
}
@@ -2674,9 +2728,14 @@ struct page *buffered_rmqueue(struct zone *preferred_zone,
if (page)
trace_mm_page_alloc_zone_locked(page, order, migratetype);
}
+ if (!page && migratetype == MIGRATE_MOVABLE &&
+ gfp_flags & __GFP_CMA)
+ page = __rmqueue_cma(zone, order);
+
if (!page)
page = __rmqueue(zone, order, migratetype);
} while (page && check_new_pages(page, order));
+
spin_unlock(&zone->lock);
if (!page)
goto failed;
@@ -2834,6 +2893,14 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,
return true;
for (mt = 0; mt < MIGRATE_PCPTYPES; mt++) {
+#ifdef CONFIG_CMA
+ /*
+ * Note that this check is needed only
+ * when MIGRATE_CMA < MIGRATE_PCPTYPES.
+ */
+ if (mt == MIGRATE_CMA)
+ continue;
+#endif
if (!list_empty(&area->free_list[mt]))
return true;
}
@@ -7311,6 +7378,7 @@ int alloc_contig_range(unsigned long start, unsigned long end,
if (ret)
return ret;
+ cc.zone->cma_alloc = 1;
/*
* In case of -EBUSY, we'd like to know which page causes problem.
* So, just fall through. We will check it in test_pages_isolated().
@@ -7386,6 +7454,7 @@ int alloc_contig_range(unsigned long start, unsigned long end,
done:
undo_isolate_page_range(pfn_max_align_down(start),
pfn_max_align_up(end), migratetype);
+ cc.zone->cma_alloc = 0;
return ret;
}
diff --git a/mm/page_ext.c b/mm/page_ext.c
index 121dcff..fc3e7ff 100644
--- a/mm/page_ext.c
+++ b/mm/page_ext.c
@@ -59,9 +59,6 @@
static struct page_ext_operations *page_ext_ops[] = {
&debug_guardpage_ops,
-#ifdef CONFIG_PAGE_POISONING
- &page_poisoning_ops,
-#endif
#ifdef CONFIG_PAGE_OWNER
&page_owner_ops,
#endif
diff --git a/mm/page_poison.c b/mm/page_poison.c
index 0abd75e..a2f6a4e 100644
--- a/mm/page_poison.c
+++ b/mm/page_poison.c
@@ -6,8 +6,8 @@
#include <linux/poison.h>
#include <linux/ratelimit.h>
-static bool __page_poisoning_enabled __read_mostly;
-static bool want_page_poisoning __read_mostly;
+static bool want_page_poisoning __read_mostly
+ = IS_ENABLED(CONFIG_PAGE_POISONING_ENABLE_DEFAULT);
static int early_page_poison_param(char *buf)
{
@@ -19,74 +19,21 @@ early_param("page_poison", early_page_poison_param);
bool page_poisoning_enabled(void)
{
- return __page_poisoning_enabled;
-}
-
-static bool need_page_poisoning(void)
-{
- return want_page_poisoning;
-}
-
-static void init_page_poisoning(void)
-{
/*
- * page poisoning is debug page alloc for some arches. If either
- * of those options are enabled, enable poisoning
+ * Assumes that debug_pagealloc_enabled is set before
+ * free_all_bootmem.
+ * Page poisoning is debug page alloc for some arches. If
+ * either of those options are enabled, enable poisoning.
*/
- if (!IS_ENABLED(CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC)) {
- if (!want_page_poisoning && !debug_pagealloc_enabled())
- return;
- } else {
- if (!want_page_poisoning)
- return;
- }
-
- __page_poisoning_enabled = true;
-}
-
-struct page_ext_operations page_poisoning_ops = {
- .need = need_page_poisoning,
- .init = init_page_poisoning,
-};
-
-static inline void set_page_poison(struct page *page)
-{
- struct page_ext *page_ext;
-
- page_ext = lookup_page_ext(page);
- if (unlikely(!page_ext))
- return;
-
- __set_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
-}
-
-static inline void clear_page_poison(struct page *page)
-{
- struct page_ext *page_ext;
-
- page_ext = lookup_page_ext(page);
- if (unlikely(!page_ext))
- return;
-
- __clear_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
-}
-
-bool page_is_poisoned(struct page *page)
-{
- struct page_ext *page_ext;
-
- page_ext = lookup_page_ext(page);
- if (unlikely(!page_ext))
- return false;
-
- return test_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
+ return (want_page_poisoning ||
+ (!IS_ENABLED(CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC) &&
+ debug_pagealloc_enabled()));
}
static void poison_page(struct page *page)
{
void *addr = kmap_atomic(page);
- set_page_poison(page);
memset(addr, PAGE_POISON, PAGE_SIZE);
kunmap_atomic(addr);
}
@@ -144,12 +91,13 @@ static void unpoison_page(struct page *page)
{
void *addr;
- if (!page_is_poisoned(page))
- return;
-
addr = kmap_atomic(page);
+ /*
+ * Page poisoning when enabled poisons each and every page
+ * that is freed to buddy. Thus no extra check is done to
+ * see if a page was posioned.
+ */
check_poison_mem(page, addr, PAGE_SIZE);
- clear_page_poison(page);
kunmap_atomic(addr);
}
diff --git a/mm/process_reclaim.c b/mm/process_reclaim.c
new file mode 100644
index 0000000..36516eb
--- /dev/null
+++ b/mm/process_reclaim.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2015-2016, 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/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/sort.h>
+#include <linux/oom.h>
+#include <linux/sched.h>
+#include <linux/rcupdate.h>
+#include <linux/notifier.h>
+#include <linux/vmpressure.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/process_reclaim.h>
+
+#define MAX_SWAP_TASKS SWAP_CLUSTER_MAX
+
+static void swap_fn(struct work_struct *work);
+DECLARE_WORK(swap_work, swap_fn);
+
+/* User knob to enable/disable process reclaim feature */
+static int enable_process_reclaim;
+module_param_named(enable_process_reclaim, enable_process_reclaim, int, 0644);
+
+/* The max number of pages tried to be reclaimed in a single run */
+int per_swap_size = SWAP_CLUSTER_MAX * 32;
+module_param_named(per_swap_size, per_swap_size, int, 0644);
+
+int reclaim_avg_efficiency;
+module_param_named(reclaim_avg_efficiency, reclaim_avg_efficiency, int, 0444);
+
+/* The vmpressure region where process reclaim operates */
+static unsigned long pressure_min = 50;
+static unsigned long pressure_max = 90;
+module_param_named(pressure_min, pressure_min, ulong, 0644);
+module_param_named(pressure_max, pressure_max, ulong, 0644);
+
+static short min_score_adj = 360;
+module_param_named(min_score_adj, min_score_adj, short, 0644);
+
+/*
+ * Scheduling process reclaim workqueue unecessarily
+ * when the reclaim efficiency is low does not make
+ * sense. We try to detect a drop in efficiency and
+ * disable reclaim for a time period. This period and the
+ * period for which we monitor a drop in efficiency is
+ * defined by swap_eff_win. swap_opt_eff is the optimal
+ * efficincy used as theshold for this.
+ */
+static int swap_eff_win = 2;
+module_param_named(swap_eff_win, swap_eff_win, int, 0644);
+
+static int swap_opt_eff = 50;
+module_param_named(swap_opt_eff, swap_opt_eff, int, 0644);
+
+static atomic_t skip_reclaim = ATOMIC_INIT(0);
+/* Not atomic since only a single instance of swap_fn run at a time */
+static int monitor_eff;
+
+struct selected_task {
+ struct task_struct *p;
+ int tasksize;
+ short oom_score_adj;
+};
+
+int selected_cmp(const void *a, const void *b)
+{
+ const struct selected_task *x = a;
+ const struct selected_task *y = b;
+ int ret;
+
+ ret = x->tasksize < y->tasksize ? -1 : 1;
+
+ return ret;
+}
+
+static int test_task_flag(struct task_struct *p, int flag)
+{
+ struct task_struct *t = p;
+
+ rcu_read_lock();
+ for_each_thread(p, t) {
+ task_lock(t);
+ if (test_tsk_thread_flag(t, flag)) {
+ task_unlock(t);
+ rcu_read_unlock();
+ return 1;
+ }
+ task_unlock(t);
+ }
+ rcu_read_unlock();
+
+ return 0;
+}
+
+static void swap_fn(struct work_struct *work)
+{
+ struct task_struct *tsk;
+ struct reclaim_param rp;
+
+ /* Pick the best MAX_SWAP_TASKS tasks in terms of anon size */
+ struct selected_task selected[MAX_SWAP_TASKS] = {{0, 0, 0},};
+ int si = 0;
+ int i;
+ int tasksize;
+ int total_sz = 0;
+ int total_scan = 0;
+ int total_reclaimed = 0;
+ int nr_to_reclaim;
+ int efficiency;
+
+ rcu_read_lock();
+ for_each_process(tsk) {
+ struct task_struct *p;
+ short oom_score_adj;
+
+ if (tsk->flags & PF_KTHREAD)
+ continue;
+
+ if (test_task_flag(tsk, TIF_MEMDIE))
+ continue;
+
+ p = find_lock_task_mm(tsk);
+ if (!p)
+ continue;
+
+ oom_score_adj = p->signal->oom_score_adj;
+ if (oom_score_adj < min_score_adj) {
+ task_unlock(p);
+ continue;
+ }
+
+ tasksize = get_mm_counter(p->mm, MM_ANONPAGES);
+ task_unlock(p);
+
+ if (tasksize <= 0)
+ continue;
+
+ if (si == MAX_SWAP_TASKS) {
+ sort(&selected[0], MAX_SWAP_TASKS,
+ sizeof(struct selected_task),
+ &selected_cmp, NULL);
+ if (tasksize < selected[0].tasksize)
+ continue;
+ selected[0].p = p;
+ selected[0].oom_score_adj = oom_score_adj;
+ selected[0].tasksize = tasksize;
+ } else {
+ selected[si].p = p;
+ selected[si].oom_score_adj = oom_score_adj;
+ selected[si].tasksize = tasksize;
+ si++;
+ }
+ }
+
+ for (i = 0; i < si; i++)
+ total_sz += selected[i].tasksize;
+
+ /* Skip reclaim if total size is too less */
+ if (total_sz < SWAP_CLUSTER_MAX) {
+ rcu_read_unlock();
+ return;
+ }
+
+ for (i = 0; i < si; i++)
+ get_task_struct(selected[i].p);
+
+ rcu_read_unlock();
+
+ while (si--) {
+ nr_to_reclaim =
+ (selected[si].tasksize * per_swap_size) / total_sz;
+ /* scan atleast a page */
+ if (!nr_to_reclaim)
+ nr_to_reclaim = 1;
+
+ rp = reclaim_task_anon(selected[si].p, nr_to_reclaim);
+
+ trace_process_reclaim(selected[si].tasksize,
+ selected[si].oom_score_adj, rp.nr_scanned,
+ rp.nr_reclaimed, per_swap_size, total_sz,
+ nr_to_reclaim);
+ total_scan += rp.nr_scanned;
+ total_reclaimed += rp.nr_reclaimed;
+ put_task_struct(selected[si].p);
+ }
+
+ if (total_scan) {
+ efficiency = (total_reclaimed * 100) / total_scan;
+
+ if (efficiency < swap_opt_eff) {
+ if (++monitor_eff == swap_eff_win) {
+ atomic_set(&skip_reclaim, swap_eff_win);
+ monitor_eff = 0;
+ }
+ } else {
+ monitor_eff = 0;
+ }
+
+ reclaim_avg_efficiency =
+ (efficiency + reclaim_avg_efficiency) / 2;
+ trace_process_reclaim_eff(efficiency, reclaim_avg_efficiency);
+ }
+}
+
+static int vmpressure_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ unsigned long pressure = action;
+
+ if (!enable_process_reclaim)
+ return 0;
+
+ if (!current_is_kswapd())
+ return 0;
+
+ if (atomic_dec_if_positive(&skip_reclaim) >= 0)
+ return 0;
+
+ if ((pressure >= pressure_min) && (pressure < pressure_max))
+ if (!work_pending(&swap_work))
+ queue_work(system_unbound_wq, &swap_work);
+ return 0;
+}
+
+static struct notifier_block vmpr_nb = {
+ .notifier_call = vmpressure_notifier,
+};
+
+static int __init process_reclaim_init(void)
+{
+ vmpressure_notifier_register(&vmpr_nb);
+ return 0;
+}
+
+static void __exit process_reclaim_exit(void)
+{
+ vmpressure_notifier_unregister(&vmpr_nb);
+}
+
+module_init(process_reclaim_init);
+module_exit(process_reclaim_exit);
diff --git a/mm/rmap.c b/mm/rmap.c
index cd37c1c..dfb19f0 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1616,9 +1616,12 @@ static int page_mapcount_is_zero(struct page *page)
* try_to_unmap - try to remove all page table mappings to a page
* @page: the page to get unmapped
* @flags: action and flags
+ * @vma : target vma for reclaim
*
* Tries to remove all the page table entries which are mapping this
* page, used in the pageout path. Caller must hold the page lock.
+ * If @vma is not NULL, this function try to remove @page from only @vma
+ * without peeking all mapped vma for @page.
* Return values are:
*
* SWAP_SUCCESS - we succeeded in removing all mappings
@@ -1626,7 +1629,8 @@ static int page_mapcount_is_zero(struct page *page)
* SWAP_FAIL - the page is unswappable
* SWAP_MLOCK - page is mlocked.
*/
-int try_to_unmap(struct page *page, enum ttu_flags flags)
+int try_to_unmap(struct page *page, enum ttu_flags flags,
+ struct vm_area_struct *vma)
{
int ret;
struct rmap_private rp = {
@@ -1639,6 +1643,7 @@ int try_to_unmap(struct page *page, enum ttu_flags flags)
.arg = &rp,
.done = page_mapcount_is_zero,
.anon_lock = page_lock_anon_vma_read,
+ .target_vma = vma,
};
/*
@@ -1698,6 +1703,7 @@ int try_to_munlock(struct page *page)
.arg = &rp,
.done = page_not_mapped,
.anon_lock = page_lock_anon_vma_read,
+ .target_vma = NULL,
};
@@ -1760,6 +1766,11 @@ static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc,
struct anon_vma_chain *avc;
int ret = SWAP_AGAIN;
+ if (rwc->target_vma) {
+ unsigned long address = vma_address(page, rwc->target_vma);
+ return rwc->rmap_one(page, rwc->target_vma, address, rwc->arg);
+ }
+
if (locked) {
anon_vma = page_anon_vma(page);
/* anon_vma disappear under us? */
@@ -1767,6 +1778,7 @@ static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc,
} else {
anon_vma = rmap_walk_anon_lock(page, rwc);
}
+
if (!anon_vma)
return ret;
@@ -1811,6 +1823,7 @@ static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc,
struct address_space *mapping = page_mapping(page);
pgoff_t pgoff;
struct vm_area_struct *vma;
+ unsigned long address;
int ret = SWAP_AGAIN;
/*
@@ -1827,6 +1840,13 @@ static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc,
pgoff = page_to_pgoff(page);
if (!locked)
i_mmap_lock_read(mapping);
+
+ if (rwc->target_vma) {
+ address = vma_address(page, rwc->target_vma);
+ ret = rwc->rmap_one(page, rwc->target_vma, address, rwc->arg);
+ goto done;
+ }
+
vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
unsigned long address = vma_address(page, vma);
diff --git a/mm/swap_ratio.c b/mm/swap_ratio.c
new file mode 100644
index 0000000..4ca5783
--- /dev/null
+++ b/mm/swap_ratio.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2015-2016, 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/mm_types.h>
+#include <linux/swapfile.h>
+#include <linux/swap.h>
+
+#define SWAP_RATIO_GROUP_START (SWAP_FLAG_PRIO_MASK - 9) /* 32758 */
+#define SWAP_RATIO_GROUP_END (SWAP_FLAG_PRIO_MASK) /* 32767 */
+#define SWAP_FAST_WRITES (SWAPFILE_CLUSTER * (SWAP_CLUSTER_MAX / 8))
+#define SWAP_SLOW_WRITES SWAPFILE_CLUSTER
+
+/*
+ * The fast/slow swap write ratio.
+ * 100 indicates that all writes should
+ * go to fast swap device.
+ */
+int sysctl_swap_ratio = 100;
+
+/* Enable the swap ratio feature */
+int sysctl_swap_ratio_enable;
+
+static bool is_same_group(struct swap_info_struct *a,
+ struct swap_info_struct *b)
+{
+ if (!sysctl_swap_ratio_enable)
+ return false;
+
+ if (!is_swap_ratio_group(a->prio))
+ return false;
+
+ if (a->prio == b->prio)
+ return true;
+
+ return false;
+}
+
+/* Caller must hold swap_avail_lock */
+static int calculate_write_pending(struct swap_info_struct *si,
+ struct swap_info_struct *n)
+{
+ int ratio = sysctl_swap_ratio;
+
+ if ((ratio < 0) || (ratio > 100))
+ return -EINVAL;
+
+ if (WARN_ON(!(si->flags & SWP_FAST)))
+ return -ENODEV;
+
+ if ((n->flags & SWP_FAST) || !is_same_group(si, n))
+ return -ENODEV;
+
+ si->max_writes = ratio ? SWAP_FAST_WRITES : 0;
+ n->max_writes = ratio ? (SWAP_FAST_WRITES * 100) /
+ ratio - SWAP_FAST_WRITES : SWAP_SLOW_WRITES;
+
+ si->write_pending = si->max_writes;
+ n->write_pending = n->max_writes;
+
+ return 0;
+}
+
+static int swap_ratio_slow(struct swap_info_struct **si)
+{
+ struct swap_info_struct *n = NULL;
+ int ret = 0;
+
+ spin_lock(&(*si)->lock);
+ spin_lock(&swap_avail_lock);
+ if (&(*si)->avail_list == plist_last(&swap_avail_head)) {
+ /* just to make skip work */
+ n = *si;
+ ret = -ENODEV;
+ goto skip;
+ }
+ n = plist_next_entry(&(*si)->avail_list,
+ struct swap_info_struct,
+ avail_list);
+ if (n == *si) {
+ /* No other swap device */
+ ret = -ENODEV;
+ goto skip;
+ }
+
+ spin_unlock(&swap_avail_lock);
+ spin_lock(&n->lock);
+ spin_lock(&swap_avail_lock);
+
+ if ((*si)->flags & SWP_FAST) {
+ if ((*si)->write_pending) {
+ (*si)->write_pending--;
+ goto exit;
+ } else {
+ if ((n->flags & SWP_FAST) || !is_same_group(*si, n)) {
+ /* Should never happen */
+ ret = -ENODEV;
+ } else if (n->write_pending) {
+ /*
+ * Requeue fast device, since there are pending
+ * writes for slow device.
+ */
+ plist_requeue(&(*si)->avail_list,
+ &swap_avail_head);
+ n->write_pending--;
+ spin_unlock(&(*si)->lock);
+ *si = n;
+ goto skip;
+ } else {
+ if (calculate_write_pending(*si, n) < 0) {
+ ret = -ENODEV;
+ goto exit;
+ }
+ /* Restart from fast device */
+ (*si)->write_pending--;
+ }
+ }
+ } else {
+ if (!(n->flags & SWP_FAST) || !is_same_group(*si, n)) {
+ /* Should never happen */
+ ret = -ENODEV;
+ } else if (n->write_pending) {
+ /*
+ * Pending writes for fast device.
+ * We reach here when slow device is swapped on first,
+ * before fast device.
+ */
+ /* requeue slow device to the end */
+ plist_requeue(&(*si)->avail_list, &swap_avail_head);
+ n->write_pending--;
+ spin_unlock(&(*si)->lock);
+ *si = n;
+ goto skip;
+ } else {
+ if ((*si)->write_pending) {
+ (*si)->write_pending--;
+ } else {
+ if (calculate_write_pending(n, *si) < 0) {
+ ret = -ENODEV;
+ goto exit;
+ }
+ n->write_pending--;
+ plist_requeue(&(*si)->avail_list,
+ &swap_avail_head);
+ spin_unlock(&(*si)->lock);
+ *si = n;
+ goto skip;
+ }
+ }
+ }
+exit:
+ spin_unlock(&(*si)->lock);
+skip:
+ spin_unlock(&swap_avail_lock);
+ /* n and si would have got interchanged */
+ spin_unlock(&n->lock);
+ return ret;
+}
+
+bool is_swap_ratio_group(int prio)
+{
+ return ((prio >= SWAP_RATIO_GROUP_START) &&
+ (prio <= SWAP_RATIO_GROUP_END)) ? true : false;
+}
+
+void setup_swap_ratio(struct swap_info_struct *p, int prio)
+{
+ /* Used only if sysctl_swap_ratio_enable is set */
+ if (is_swap_ratio_group(prio)) {
+ if (p->flags & SWP_FAST)
+ p->write_pending = SWAP_FAST_WRITES;
+ else
+ p->write_pending = SWAP_SLOW_WRITES;
+ p->max_writes = p->write_pending;
+ }
+}
+
+int swap_ratio(struct swap_info_struct **si)
+{
+ if (!sysctl_swap_ratio_enable)
+ return -ENODEV;
+
+ if (is_swap_ratio_group((*si)->prio))
+ return swap_ratio_slow(si);
+ else
+ return -ENODEV;
+}
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 35d7e0e..5ac5846 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -478,7 +478,7 @@ struct page *swapin_readahead(swp_entry_t entry, gfp_t gfp_mask,
unsigned long mask;
struct blk_plug plug;
- mask = swapin_nr_pages(offset) - 1;
+ mask = is_swap_fast(entry) ? 0 : swapin_nr_pages(offset) - 1;
if (!mask)
goto skip;
diff --git a/mm/swapfile.c b/mm/swapfile.c
index d76b2a1..9cf2595 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -81,8 +81,8 @@ PLIST_HEAD(swap_active_head);
* is held and the locking order requires swap_lock to be taken
* before any swap_info_struct->lock.
*/
-static PLIST_HEAD(swap_avail_head);
-static DEFINE_SPINLOCK(swap_avail_lock);
+PLIST_HEAD(swap_avail_head);
+DEFINE_SPINLOCK(swap_avail_lock);
struct swap_info_struct *swap_info[MAX_SWAPFILES];
@@ -97,6 +97,26 @@ static inline unsigned char swap_count(unsigned char ent)
return ent & ~SWAP_HAS_CACHE; /* may include SWAP_HAS_CONT flag */
}
+bool is_swap_fast(swp_entry_t entry)
+{
+ struct swap_info_struct *p;
+ unsigned long type;
+
+ if (non_swap_entry(entry))
+ return false;
+
+ type = swp_type(entry);
+ if (type >= nr_swapfiles)
+ return false;
+
+ p = swap_info[type];
+
+ if (p->flags & SWP_FAST)
+ return true;
+
+ return false;
+}
+
/* returns 1 if swap entry is freed */
static int
__try_to_reclaim_swap(struct swap_info_struct *si, unsigned long offset)
@@ -196,7 +216,6 @@ static void discard_swap_cluster(struct swap_info_struct *si,
}
}
-#define SWAPFILE_CLUSTER 256
#define LATENCY_LIMIT 256
static inline void cluster_set_flag(struct swap_cluster_info *info,
@@ -573,7 +592,7 @@ static unsigned long scan_swap_map(struct swap_info_struct *si,
scan_base = offset = si->lowest_bit;
/* reuse swap entry of cache-only swap if not busy. */
- if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
+ if (vm_swap_full(si) && si->swap_map[offset] == SWAP_HAS_CACHE) {
int swap_was_freed;
spin_unlock(&si->lock);
swap_was_freed = __try_to_reclaim_swap(si, offset);
@@ -613,7 +632,8 @@ static unsigned long scan_swap_map(struct swap_info_struct *si,
spin_lock(&si->lock);
goto checks;
}
- if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
+ if (vm_swap_full(si) &&
+ si->swap_map[offset] == SWAP_HAS_CACHE) {
spin_lock(&si->lock);
goto checks;
}
@@ -628,7 +648,8 @@ static unsigned long scan_swap_map(struct swap_info_struct *si,
spin_lock(&si->lock);
goto checks;
}
- if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
+ if (vm_swap_full(si) &&
+ si->swap_map[offset] == SWAP_HAS_CACHE) {
spin_lock(&si->lock);
goto checks;
}
@@ -649,18 +670,39 @@ swp_entry_t get_swap_page(void)
{
struct swap_info_struct *si, *next;
pgoff_t offset;
+ int swap_ratio_off = 0;
if (atomic_long_read(&nr_swap_pages) <= 0)
goto noswap;
atomic_long_dec(&nr_swap_pages);
+lock_and_start:
spin_lock(&swap_avail_lock);
start_over:
plist_for_each_entry_safe(si, next, &swap_avail_head, avail_list) {
+
+ if (sysctl_swap_ratio && !swap_ratio_off) {
+ int ret;
+
+ spin_unlock(&swap_avail_lock);
+ ret = swap_ratio(&si);
+ if (ret < 0) {
+ /*
+ * Error. Start again with swap
+ * ratio disabled.
+ */
+ swap_ratio_off = 1;
+ goto lock_and_start;
+ } else {
+ goto start;
+ }
+ }
+
/* requeue si to after same-priority siblings */
plist_requeue(&si->avail_list, &swap_avail_head);
spin_unlock(&swap_avail_lock);
+start:
spin_lock(&si->lock);
if (!si->highest_bit || !(si->flags & SWP_WRITEOK)) {
spin_lock(&swap_avail_lock);
@@ -2539,11 +2581,16 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
}
}
+ if (p->bdev && blk_queue_fast(bdev_get_queue(p->bdev)))
+ p->flags |= SWP_FAST;
+
mutex_lock(&swapon_mutex);
prio = -1;
- if (swap_flags & SWAP_FLAG_PREFER)
+ if (swap_flags & SWAP_FLAG_PREFER) {
prio =
(swap_flags & SWAP_FLAG_PRIO_MASK) >> SWAP_FLAG_PRIO_SHIFT;
+ setup_swap_ratio(p, prio);
+ }
enable_swap_info(p, prio, swap_map, cluster_info, frontswap_map);
pr_info("Adding %uk swap on %s. Priority:%d extents:%d across:%lluk %s%s%s%s%s\n",
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 195de42..ad182e6 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -301,6 +301,57 @@ static unsigned long cached_align;
static unsigned long vmap_area_pcpu_hole;
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+#define POSSIBLE_VMALLOC_START PAGE_OFFSET
+
+#define VMALLOC_BITMAP_SIZE ((VMALLOC_END - PAGE_OFFSET) >> \
+ PAGE_SHIFT)
+#define VMALLOC_TO_BIT(addr) ((addr - PAGE_OFFSET) >> PAGE_SHIFT)
+#define BIT_TO_VMALLOC(i) (PAGE_OFFSET + i * PAGE_SIZE)
+
+unsigned long total_vmalloc_size;
+unsigned long vmalloc_reserved;
+
+DECLARE_BITMAP(possible_areas, VMALLOC_BITMAP_SIZE);
+
+void mark_vmalloc_reserved_area(void *x, unsigned long size)
+{
+ unsigned long addr = (unsigned long)x;
+
+ bitmap_set(possible_areas, VMALLOC_TO_BIT(addr), size >> PAGE_SHIFT);
+ vmalloc_reserved += size;
+}
+
+int is_vmalloc_addr(const void *x)
+{
+ unsigned long addr = (unsigned long)x;
+
+ if (addr < POSSIBLE_VMALLOC_START || addr >= VMALLOC_END)
+ return 0;
+
+ if (test_bit(VMALLOC_TO_BIT(addr), possible_areas))
+ return 0;
+
+ return 1;
+}
+
+static void calc_total_vmalloc_size(void)
+{
+ total_vmalloc_size = VMALLOC_END - POSSIBLE_VMALLOC_START -
+ vmalloc_reserved;
+}
+#else
+int is_vmalloc_addr(const void *x)
+{
+ unsigned long addr = (unsigned long)x;
+
+ return addr >= VMALLOC_START && addr < VMALLOC_END;
+}
+
+static void calc_total_vmalloc_size(void) { }
+#endif
+EXPORT_SYMBOL(is_vmalloc_addr);
+
static struct vmap_area *__find_vmap_area(unsigned long addr)
{
struct rb_node *n = vmap_area_root.rb_node;
@@ -1178,6 +1229,33 @@ void *vm_map_ram(struct page **pages, unsigned int count, int node, pgprot_t pro
EXPORT_SYMBOL(vm_map_ram);
static struct vm_struct *vmlist __initdata;
+
+/**
+ * vm_area_check_early - check if vmap area is already mapped
+ * @vm: vm_struct to be checked
+ *
+ * This function is used to check if the vmap area has been
+ * mapped already. @vm->addr, @vm->size and @vm->flags should
+ * contain proper values.
+ *
+ */
+int __init vm_area_check_early(struct vm_struct *vm)
+{
+ struct vm_struct *tmp, **p;
+
+ BUG_ON(vmap_initialized);
+ for (p = &vmlist; (tmp = *p) != NULL; p = &tmp->next) {
+ if (tmp->addr >= vm->addr) {
+ if (tmp->addr < vm->addr + vm->size)
+ return 1;
+ } else {
+ if (tmp->addr + tmp->size > vm->addr)
+ return 1;
+ }
+ }
+ return 0;
+}
+
/**
* vm_area_add_early - add vmap area early during boot
* @vm: vm_struct to add
@@ -1258,7 +1336,7 @@ void __init vmalloc_init(void)
}
vmap_area_pcpu_hole = VMALLOC_END;
-
+ calc_total_vmalloc_size();
vmap_initialized = true;
}
@@ -1422,16 +1500,27 @@ struct vm_struct *__get_vm_area_caller(unsigned long size, unsigned long flags,
*/
struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
{
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+ return __get_vm_area_node(size, 1, flags, PAGE_OFFSET, VMALLOC_END,
+ NUMA_NO_NODE, GFP_KERNEL,
+ __builtin_return_address(0));
+#else
return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
NUMA_NO_NODE, GFP_KERNEL,
__builtin_return_address(0));
+#endif
}
struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
const void *caller)
{
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+ return __get_vm_area_node(size, 1, flags, PAGE_OFFSET, VMALLOC_END,
+ NUMA_NO_NODE, GFP_KERNEL, caller);
+#else
return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
NUMA_NO_NODE, GFP_KERNEL, caller);
+#endif
}
/**
@@ -2683,6 +2772,9 @@ static int s_show(struct seq_file *m, void *p)
if (is_vmalloc_addr(v->pages))
seq_puts(m, " vpages");
+ if (v->flags & VM_LOWMEM)
+ seq_puts(m, " lowmem");
+
show_numa_info(m, v);
seq_putc(m, '\n');
return 0;
diff --git a/mm/vmpressure.c b/mm/vmpressure.c
index 6063581..1306f32 100644
--- a/mm/vmpressure.c
+++ b/mm/vmpressure.c
@@ -22,6 +22,9 @@
#include <linux/slab.h>
#include <linux/swap.h>
#include <linux/printk.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+#include <linux/module.h>
#include <linux/vmpressure.h>
/*
@@ -38,7 +41,7 @@
* TODO: Make the window size depend on machine size, as we do for vmstat
* thresholds. Currently we set it to 512 pages (2MB for 4KB pages).
*/
-static const unsigned long vmpressure_win = SWAP_CLUSTER_MAX * 16;
+static unsigned long vmpressure_win = SWAP_CLUSTER_MAX * 16;
/*
* These thresholds are used when we account memory pressure through
@@ -49,6 +52,33 @@ static const unsigned long vmpressure_win = SWAP_CLUSTER_MAX * 16;
static const unsigned int vmpressure_level_med = 60;
static const unsigned int vmpressure_level_critical = 95;
+static unsigned long vmpressure_scale_max = 100;
+module_param_named(vmpressure_scale_max, vmpressure_scale_max,
+ ulong, 0644);
+
+/* vmpressure values >= this will be scaled based on allocstalls */
+static unsigned long allocstall_threshold = 70;
+module_param_named(allocstall_threshold, allocstall_threshold,
+ ulong, 0644);
+
+static struct vmpressure global_vmpressure;
+static BLOCKING_NOTIFIER_HEAD(vmpressure_notifier);
+
+int vmpressure_notifier_register(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&vmpressure_notifier, nb);
+}
+
+int vmpressure_notifier_unregister(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&vmpressure_notifier, nb);
+}
+
+static void vmpressure_notify(unsigned long pressure)
+{
+ blocking_notifier_call_chain(&vmpressure_notifier, pressure, NULL);
+}
+
/*
* When there are too little pages left to scan, vmpressure() may miss the
* critical pressure as number of pages will be less than "window size".
@@ -75,6 +105,7 @@ static struct vmpressure *work_to_vmpressure(struct work_struct *work)
return container_of(work, struct vmpressure, work);
}
+#ifdef CONFIG_MEMCG
static struct vmpressure *vmpressure_parent(struct vmpressure *vmpr)
{
struct cgroup_subsys_state *css = vmpressure_to_css(vmpr);
@@ -85,6 +116,12 @@ static struct vmpressure *vmpressure_parent(struct vmpressure *vmpr)
return NULL;
return memcg_to_vmpressure(memcg);
}
+#else
+static struct vmpressure *vmpressure_parent(struct vmpressure *vmpr)
+{
+ return NULL;
+}
+#endif
enum vmpressure_levels {
VMPRESSURE_LOW = 0,
@@ -108,7 +145,7 @@ static enum vmpressure_levels vmpressure_level(unsigned long pressure)
return VMPRESSURE_LOW;
}
-static enum vmpressure_levels vmpressure_calc_level(unsigned long scanned,
+static unsigned long vmpressure_calc_pressure(unsigned long scanned,
unsigned long reclaimed)
{
unsigned long scale = scanned + reclaimed;
@@ -135,7 +172,20 @@ static enum vmpressure_levels vmpressure_calc_level(unsigned long scanned,
pr_debug("%s: %3lu (s: %lu r: %lu)\n", __func__, pressure,
scanned, reclaimed);
- return vmpressure_level(pressure);
+ return pressure;
+}
+
+static unsigned long vmpressure_account_stall(unsigned long pressure,
+ unsigned long stall, unsigned long scanned)
+{
+ unsigned long scale;
+
+ if (pressure < allocstall_threshold)
+ return pressure;
+
+ scale = ((vmpressure_scale_max - pressure) * stall) / scanned;
+
+ return pressure + scale;
}
struct vmpressure_event {
@@ -169,6 +219,7 @@ static void vmpressure_work_fn(struct work_struct *work)
struct vmpressure *vmpr = work_to_vmpressure(work);
unsigned long scanned;
unsigned long reclaimed;
+ unsigned long pressure;
enum vmpressure_levels level;
spin_lock(&vmpr->sr_lock);
@@ -191,7 +242,8 @@ static void vmpressure_work_fn(struct work_struct *work)
vmpr->tree_reclaimed = 0;
spin_unlock(&vmpr->sr_lock);
- level = vmpressure_calc_level(scanned, reclaimed);
+ pressure = vmpressure_calc_pressure(scanned, reclaimed);
+ level = vmpressure_level(pressure);
do {
if (vmpressure_event(vmpr, level))
@@ -203,28 +255,8 @@ static void vmpressure_work_fn(struct work_struct *work)
} while ((vmpr = vmpressure_parent(vmpr)));
}
-/**
- * vmpressure() - Account memory pressure through scanned/reclaimed ratio
- * @gfp: reclaimer's gfp mask
- * @memcg: cgroup memory controller handle
- * @tree: legacy subtree mode
- * @scanned: number of pages scanned
- * @reclaimed: number of pages reclaimed
- *
- * This function should be called from the vmscan reclaim path to account
- * "instantaneous" memory pressure (scanned/reclaimed ratio). The raw
- * pressure index is then further refined and averaged over time.
- *
- * If @tree is set, vmpressure is in traditional userspace reporting
- * mode: @memcg is considered the pressure root and userspace is
- * notified of the entire subtree's reclaim efficiency.
- *
- * If @tree is not set, reclaim efficiency is recorded for @memcg, and
- * only in-kernel users are notified.
- *
- * This function does not return any value.
- */
-void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
+#ifdef CONFIG_MEMCG
+static void vmpressure_memcg(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
unsigned long scanned, unsigned long reclaimed)
{
struct vmpressure *vmpr = memcg_to_vmpressure(memcg);
@@ -265,6 +297,7 @@ void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
schedule_work(&vmpr->work);
} else {
enum vmpressure_levels level;
+ unsigned long pressure;
/* For now, no users for root-level efficiency */
if (!memcg || memcg == root_mem_cgroup)
@@ -280,7 +313,8 @@ void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
vmpr->scanned = vmpr->reclaimed = 0;
spin_unlock(&vmpr->sr_lock);
- level = vmpressure_calc_level(scanned, reclaimed);
+ pressure = vmpressure_calc_pressure(scanned, reclaimed);
+ level = vmpressure_level(pressure);
if (level > VMPRESSURE_LOW) {
/*
@@ -295,6 +329,106 @@ void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
}
}
}
+#else
+static void vmpressure_memcg(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
+ unsigned long scanned, unsigned long reclaimed) { }
+#endif
+
+static void calculate_vmpressure_win(void)
+{
+ long x;
+
+ x = global_node_page_state(NR_FILE_PAGES) -
+ global_node_page_state(NR_SHMEM) -
+ total_swapcache_pages() +
+ global_page_state(NR_FREE_PAGES);
+ if (x < 1)
+ x = 1;
+ /*
+ * For low (free + cached), vmpressure window should be
+ * small, and high for higher values of (free + cached).
+ * But it should not be linear as well. This ensures
+ * timely vmpressure notifications when system is under
+ * memory pressure, and optimal number of events when
+ * cached is high. The sqaure root function is empirically
+ * found to serve the purpose.
+ */
+ x = int_sqrt(x);
+ vmpressure_win = x;
+}
+
+static void vmpressure_global(gfp_t gfp, unsigned long scanned,
+ unsigned long reclaimed)
+{
+ struct vmpressure *vmpr = &global_vmpressure;
+ unsigned long pressure;
+ unsigned long stall;
+
+ if (!(gfp & (__GFP_HIGHMEM | __GFP_MOVABLE | __GFP_IO | __GFP_FS)))
+ return;
+
+ if (!scanned)
+ return;
+
+ spin_lock(&vmpr->sr_lock);
+ if (!vmpr->scanned)
+ calculate_vmpressure_win();
+
+ vmpr->scanned += scanned;
+ vmpr->reclaimed += reclaimed;
+
+ if (!current_is_kswapd())
+ vmpr->stall += scanned;
+
+ stall = vmpr->stall;
+ scanned = vmpr->scanned;
+ reclaimed = vmpr->reclaimed;
+ spin_unlock(&vmpr->sr_lock);
+
+ if (scanned < vmpressure_win)
+ return;
+
+ spin_lock(&vmpr->sr_lock);
+ vmpr->scanned = 0;
+ vmpr->reclaimed = 0;
+ vmpr->stall = 0;
+ spin_unlock(&vmpr->sr_lock);
+
+ pressure = vmpressure_calc_pressure(scanned, reclaimed);
+ pressure = vmpressure_account_stall(pressure, stall, scanned);
+ vmpressure_notify(pressure);
+}
+
+/**
+ * vmpressure() - Account memory pressure through scanned/reclaimed ratio
+ * @gfp: reclaimer's gfp mask
+ * @memcg: cgroup memory controller handle
+ * @tree: legacy subtree mode
+ * @scanned: number of pages scanned
+ * @reclaimed: number of pages reclaimed
+ *
+ * This function should be called from the vmscan reclaim path to account
+ * "instantaneous" memory pressure (scanned/reclaimed ratio). The raw
+ * pressure index is then further refined and averaged over time.
+ *
+ * If @tree is set, vmpressure is in traditional userspace reporting
+ * mode: @memcg is considered the pressure root and userspace is
+ * notified of the entire subtree's reclaim efficiency.
+ *
+ * If @tree is not set, reclaim efficiency is recorded for @memcg, and
+ * only in-kernel users are notified.
+ *
+ * This function does not return any value.
+ */
+void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
+ unsigned long scanned, unsigned long reclaimed)
+{
+ if (!memcg)
+ vmpressure_global(gfp, scanned, reclaimed);
+
+ if (IS_ENABLED(CONFIG_MEMCG))
+ vmpressure_memcg(gfp, memcg, tree, scanned, reclaimed);
+}
/**
* vmpressure_prio() - Account memory pressure through reclaimer priority level
@@ -427,3 +561,10 @@ void vmpressure_cleanup(struct vmpressure *vmpr)
*/
flush_work(&vmpr->work);
}
+
+static int vmpressure_global_init(void)
+{
+ vmpressure_init(&global_vmpressure);
+ return 0;
+}
+late_initcall(vmpressure_global_init);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index b4d398b..7b5848cf 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -108,6 +108,13 @@ struct scan_control {
/* Number of pages freed so far during a call to shrink_zones() */
unsigned long nr_reclaimed;
+
+ /*
+ * Reclaim pages from a vma. If the page is shared by other tasks
+ * it is zapped from a vma without reclaim so it ends up remaining
+ * on memory until last task zap it.
+ */
+ struct vm_area_struct *target_vma;
};
#ifdef ARCH_HAS_PREFETCH
@@ -963,7 +970,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
struct address_space *mapping;
struct page *page;
int may_enter_fs;
- enum page_references references = PAGEREF_RECLAIM_CLEAN;
+ enum page_references references = PAGEREF_RECLAIM;
bool dirty, writeback;
bool lazyfree = false;
int ret = SWAP_SUCCESS;
@@ -977,6 +984,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
goto keep;
VM_BUG_ON_PAGE(PageActive(page), page);
+ if (pgdat)
+ VM_BUG_ON_PAGE(page_pgdat(page) != pgdat, page);
sc->nr_scanned++;
@@ -1055,7 +1064,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
/* Case 1 above */
if (current_is_kswapd() &&
PageReclaim(page) &&
- test_bit(PGDAT_WRITEBACK, &pgdat->flags)) {
+ (pgdat && test_bit(PGDAT_WRITEBACK, &pgdat->flags))) {
nr_immediate++;
goto keep_locked;
@@ -1129,7 +1138,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
if (page_mapped(page) && mapping) {
switch (ret = try_to_unmap(page, lazyfree ?
(ttu_flags | TTU_BATCH_FLUSH | TTU_LZFREE) :
- (ttu_flags | TTU_BATCH_FLUSH))) {
+ (ttu_flags | TTU_BATCH_FLUSH),
+ sc->target_vma)) {
case SWAP_FAIL:
goto activate_locked;
case SWAP_AGAIN:
@@ -1151,7 +1161,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
*/
if (page_is_file_cache(page) &&
(!current_is_kswapd() ||
- !test_bit(PGDAT_DIRTY, &pgdat->flags))) {
+ (pgdat &&
+ !test_bit(PGDAT_DIRTY, &pgdat->flags)))) {
/*
* Immediately reclaim when written back.
* Similar in principal to deactivate_page()
@@ -1267,6 +1278,13 @@ static unsigned long shrink_page_list(struct list_head *page_list,
* appear not as the counts should be low
*/
list_add(&page->lru, &free_pages);
+ /*
+ * If pagelist are from multiple zones, we should decrease
+ * NR_ISOLATED_ANON + x on freed pages in here.
+ */
+ if (!pgdat)
+ dec_node_page_state(page, NR_ISOLATED_ANON +
+ page_is_file_cache(page));
continue;
cull_mlocked:
@@ -1312,6 +1330,8 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
.gfp_mask = GFP_KERNEL,
.priority = DEF_PRIORITY,
.may_unmap = 1,
+ /* Doesn't allow to write out dirty page */
+ .may_writepage = 0,
};
unsigned long ret, dummy1, dummy2, dummy3, dummy4, dummy5;
struct page *page, *next;
@@ -1333,6 +1353,42 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
return ret;
}
+#ifdef CONFIG_PROCESS_RECLAIM
+unsigned long reclaim_pages_from_list(struct list_head *page_list,
+ struct vm_area_struct *vma)
+{
+ struct scan_control sc = {
+ .gfp_mask = GFP_KERNEL,
+ .priority = DEF_PRIORITY,
+ .may_writepage = 1,
+ .may_unmap = 1,
+ .may_swap = 1,
+ .target_vma = vma,
+ };
+
+ unsigned long nr_reclaimed;
+ struct page *page;
+ unsigned long dummy1, dummy2, dummy3, dummy4, dummy5;
+
+ list_for_each_entry(page, page_list, lru)
+ ClearPageActive(page);
+
+ nr_reclaimed = shrink_page_list(page_list, NULL, &sc,
+ TTU_UNMAP|TTU_IGNORE_ACCESS,
+ &dummy1, &dummy2, &dummy3, &dummy4, &dummy5, true);
+
+ while (!list_empty(page_list)) {
+ page = lru_to_page(page_list);
+ list_del(&page->lru);
+ dec_node_page_state(page, NR_ISOLATED_ANON +
+ page_is_file_cache(page));
+ putback_lru_page(page);
+ }
+
+ return nr_reclaimed;
+}
+#endif
+
/*
* Attempt to remove the specified page from its LRU. Only take this page
* if it is of the appropriate PageActive status. Pages which are being
@@ -1585,30 +1641,31 @@ int isolate_lru_page(struct page *page)
return ret;
}
-/*
- * A direct reclaimer may isolate SWAP_CLUSTER_MAX pages from the LRU list and
- * then get resheduled. When there are massive number of tasks doing page
- * allocation, such sleeping direct reclaimers may keep piling up on each CPU,
- * the LRU list will go small and be scanned faster than necessary, leading to
- * unnecessary swapping, thrashing and OOM.
- */
-static int too_many_isolated(struct pglist_data *pgdat, int file,
- struct scan_control *sc)
+static int __too_many_isolated(struct pglist_data *pgdat, int file,
+ struct scan_control *sc, int safe)
{
unsigned long inactive, isolated;
- if (current_is_kswapd())
- return 0;
-
- if (!sane_reclaim(sc))
- return 0;
-
if (file) {
- inactive = node_page_state(pgdat, NR_INACTIVE_FILE);
- isolated = node_page_state(pgdat, NR_ISOLATED_FILE);
+ if (safe) {
+ inactive = node_page_state_snapshot(pgdat,
+ NR_INACTIVE_FILE);
+ isolated = node_page_state_snapshot(pgdat,
+ NR_ISOLATED_FILE);
+ } else {
+ inactive = node_page_state(pgdat, NR_INACTIVE_FILE);
+ isolated = node_page_state(pgdat, NR_ISOLATED_FILE);
+ }
} else {
- inactive = node_page_state(pgdat, NR_INACTIVE_ANON);
- isolated = node_page_state(pgdat, NR_ISOLATED_ANON);
+ if (safe) {
+ inactive = node_page_state_snapshot(pgdat,
+ NR_INACTIVE_ANON);
+ isolated = node_page_state_snapshot(pgdat,
+ NR_ISOLATED_ANON);
+ } else {
+ inactive = node_page_state(pgdat, NR_INACTIVE_ANON);
+ isolated = node_page_state(pgdat, NR_ISOLATED_ANON);
+ }
}
/*
@@ -1622,6 +1679,32 @@ static int too_many_isolated(struct pglist_data *pgdat, int file,
return isolated > inactive;
}
+/*
+ * A direct reclaimer may isolate SWAP_CLUSTER_MAX pages from the LRU list and
+ * then get resheduled. When there are massive number of tasks doing page
+ * allocation, such sleeping direct reclaimers may keep piling up on each CPU,
+ * the LRU list will go small and be scanned faster than necessary, leading to
+ * unnecessary swapping, thrashing and OOM.
+ */
+static int too_many_isolated(struct pglist_data *pgdat, int file,
+ struct scan_control *sc, int safe)
+{
+ if (current_is_kswapd())
+ return 0;
+
+ if (!sane_reclaim(sc))
+ return 0;
+
+ if (unlikely(__too_many_isolated(pgdat, file, sc, 0))) {
+ if (safe)
+ return __too_many_isolated(pgdat, file, sc, safe);
+ else
+ return 1;
+ }
+
+ return 0;
+}
+
static noinline_for_stack void
putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list)
{
@@ -1733,18 +1816,21 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
unsigned long nr_immediate = 0;
isolate_mode_t isolate_mode = 0;
int file = is_file_lru(lru);
+ int safe = 0;
struct pglist_data *pgdat = lruvec_pgdat(lruvec);
struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat;
if (!inactive_reclaimable_pages(lruvec, sc, lru))
return 0;
- while (unlikely(too_many_isolated(pgdat, file, sc))) {
+ while (unlikely(too_many_isolated(pgdat, file, sc, safe))) {
congestion_wait(BLK_RW_ASYNC, HZ/10);
/* We are about to die and free our memory. Return now. */
if (fatal_signal_pending(current))
return SWAP_CLUSTER_MAX;
+
+ safe = 1;
}
lru_add_drain();
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 25a1f39..42098b4 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -982,6 +982,7 @@ const char * const vmstat_text[] = {
/* enum vm_event_item counters */
"pgpgin",
"pgpgout",
+ "pgpgoutclean",
"pswpin",
"pswpout",
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index f45f619..227c249 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -687,7 +687,7 @@ void neigh_destroy(struct neighbour *neigh)
NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
if (!neigh->dead) {
- pr_warn("Destroying alive neighbour %p\n", neigh);
+ pr_warn("Destroying alive neighbour %pK\n", neigh);
dump_stack();
return;
}
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 08605a4..51ac77e 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -41,6 +41,10 @@ static int tcp_syn_retries_min = 1;
static int tcp_syn_retries_max = MAX_TCP_SYNCNT;
static int ip_ping_group_range_min[] = { 0, 0 };
static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
+static int tcp_delack_seg_min = TCP_DELACK_MIN;
+static int tcp_delack_seg_max = 60;
+static int tcp_use_userconfig_min;
+static int tcp_use_userconfig_max = 1;
/* Update system visible IP port range */
static void set_local_port_range(struct net *net, int range[2])
@@ -684,6 +688,25 @@ static struct ctl_table ipv4_table[] = {
.proc_handler = proc_dointvec_minmax,
.extra1 = &one
},
+ {
+ .procname = "tcp_delack_seg",
+ .data = &sysctl_tcp_delack_seg,
+ .maxlen = sizeof(sysctl_tcp_delack_seg),
+ .mode = 0644,
+ .proc_handler = tcp_proc_delayed_ack_control,
+ .extra1 = &tcp_delack_seg_min,
+ .extra2 = &tcp_delack_seg_max,
+ },
+ {
+ .procname = "tcp_use_userconfig",
+ .data = &sysctl_tcp_use_userconfig,
+ .maxlen = sizeof(sysctl_tcp_use_userconfig),
+ .mode = 0644,
+ .proc_handler = tcp_use_userconfig_sysctl_handler,
+ .extra1 = &tcp_use_userconfig_min,
+ .extra2 = &tcp_use_userconfig_max,
+ },
+
{ }
};
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 86fbf0f..c27382f 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -300,6 +300,12 @@ EXPORT_SYMBOL(sysctl_tcp_wmem);
atomic_long_t tcp_memory_allocated; /* Current allocated memory. */
EXPORT_SYMBOL(tcp_memory_allocated);
+int sysctl_tcp_delack_seg __read_mostly = TCP_DELACK_SEG;
+EXPORT_SYMBOL(sysctl_tcp_delack_seg);
+
+int sysctl_tcp_use_userconfig __read_mostly;
+EXPORT_SYMBOL(sysctl_tcp_use_userconfig);
+
/*
* Current number of TCP sockets.
*/
@@ -1438,8 +1444,11 @@ static void tcp_cleanup_rbuf(struct sock *sk, int copied)
/* Delayed ACKs frequently hit locked sockets during bulk
* receive. */
if (icsk->icsk_ack.blocked ||
- /* Once-per-two-segments ACK was not sent by tcp_input.c */
- tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss ||
+ /* Once-per-sysctl_tcp_delack_seg segments
+ * ACK was not sent by tcp_input.c
+ */
+ tp->rcv_nxt - tp->rcv_wup > (icsk->icsk_ack.rcv_mss) *
+ sysctl_tcp_delack_seg ||
/*
* If this read emptied read buffer, we send ACK, if
* connection is not bidirectional, user drained
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index a03f1e8..3d980d6 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5104,7 +5104,8 @@ static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible)
struct tcp_sock *tp = tcp_sk(sk);
/* More than one full frame received... */
- if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss &&
+ if (((tp->rcv_nxt - tp->rcv_wup) > (inet_csk(sk)->icsk_ack.rcv_mss) *
+ sysctl_tcp_delack_seg &&
/* ... and right edge of window advances far enough.
* (tcp_recvmsg() will send ACK otherwise). Or...
*/
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index b1e65b3..732060d 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -24,13 +24,45 @@
int sysctl_tcp_thin_linear_timeouts __read_mostly;
+static void set_tcp_default(void)
+{
+ sysctl_tcp_delack_seg = TCP_DELACK_SEG;
+}
+
+/*sysctl handler for tcp_ack realted master control */
+int tcp_proc_delayed_ack_control(struct ctl_table *table, int write,
+ void __user *buffer, size_t *length,
+ loff_t *ppos)
+{
+ int ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
+
+ /* The ret value will be 0 if the input validation is successful
+ * and the values are written to sysctl table. If not, the stack
+ * will continue to work with currently configured values
+ */
+ return ret;
+}
+
+/*sysctl handler for tcp_ack realted master control */
+int tcp_use_userconfig_sysctl_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *length,
+ loff_t *ppos)
+{
+ int ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
+
+ if (write && ret == 0) {
+ if (!sysctl_tcp_use_userconfig)
+ set_tcp_default();
+ }
+ return ret;
+}
+
/**
* tcp_write_err() - close socket and save error info
* @sk: The socket the error has appeared on.
*
* Returns: Nothing (void)
*/
-
static void tcp_write_err(struct sock *sk)
{
sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 545c79a..031273a 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3308,10 +3308,11 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *sdata_iter;
enum nl80211_iftype iftype = sdata->wdev.iftype;
- int num[NUM_NL80211_IFTYPES];
struct ieee80211_chanctx *ctx;
- int num_different_channels = 0;
int total = 1;
+ struct iface_combination_params params = {
+ .radar_detect = radar_detect,
+ };
lockdep_assert_held(&local->chanctx_mtx);
@@ -3322,9 +3323,6 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
!chandef->chan))
return -EINVAL;
- if (chandef)
- num_different_channels = 1;
-
if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
return -EINVAL;
@@ -3335,24 +3333,26 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
return 0;
}
- memset(num, 0, sizeof(num));
+ if (chandef)
+ params.num_different_channels = 1;
if (iftype != NL80211_IFTYPE_UNSPECIFIED)
- num[iftype] = 1;
+ params.iftype_num[iftype] = 1;
list_for_each_entry(ctx, &local->chanctx_list, list) {
if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
continue;
- radar_detect |= ieee80211_chanctx_radar_detect(local, ctx);
+ params.radar_detect |=
+ ieee80211_chanctx_radar_detect(local, ctx);
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
- num_different_channels++;
+ params.num_different_channels++;
continue;
}
if (chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
cfg80211_chandef_compatible(chandef,
&ctx->conf.def))
continue;
- num_different_channels++;
+ params.num_different_channels++;
}
list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
@@ -3365,16 +3365,14 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
continue;
- num[wdev_iter->iftype]++;
+ params.iftype_num[wdev_iter->iftype]++;
total++;
}
- if (total == 1 && !radar_detect)
+ if (total == 1 && !params.radar_detect)
return 0;
- return cfg80211_check_combinations(local->hw.wiphy,
- num_different_channels,
- radar_detect, num);
+ return cfg80211_check_combinations(local->hw.wiphy, ¶ms);
}
static void
@@ -3390,12 +3388,10 @@ ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
int ieee80211_max_num_channels(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
- int num[NUM_NL80211_IFTYPES] = {};
struct ieee80211_chanctx *ctx;
- int num_different_channels = 0;
- u8 radar_detect = 0;
u32 max_num_different_channels = 1;
int err;
+ struct iface_combination_params params = {0};
lockdep_assert_held(&local->chanctx_mtx);
@@ -3403,17 +3399,17 @@ int ieee80211_max_num_channels(struct ieee80211_local *local)
if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
continue;
- num_different_channels++;
+ params.num_different_channels++;
- radar_detect |= ieee80211_chanctx_radar_detect(local, ctx);
+ params.radar_detect |=
+ ieee80211_chanctx_radar_detect(local, ctx);
}
list_for_each_entry_rcu(sdata, &local->interfaces, list)
- num[sdata->wdev.iftype]++;
+ params.iftype_num[sdata->wdev.iftype]++;
- err = cfg80211_iter_combinations(local->hw.wiphy,
- num_different_channels, radar_detect,
- num, ieee80211_iter_max_chans,
+ err = cfg80211_iter_combinations(local->hw.wiphy, ¶ms,
+ ieee80211_iter_max_chans,
&max_num_different_channels);
if (err < 0)
return err;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 6bd1508..19b89b1 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1022,7 +1022,7 @@ static void gc_worker(struct work_struct *work)
static void conntrack_gc_work_init(struct conntrack_gc_work *gc_work)
{
- INIT_DELAYED_WORK(&gc_work->dwork, gc_worker);
+ INIT_DEFERRABLE_WORK(&gc_work->dwork, gc_worker);
gc_work->next_gc_run = HZ;
gc_work->exiting = false;
}
diff --git a/net/netfilter/xt_HARDIDLETIMER.c b/net/netfilter/xt_HARDIDLETIMER.c
index fc0b83f..c6f70da9 100644
--- a/net/netfilter/xt_HARDIDLETIMER.c
+++ b/net/netfilter/xt_HARDIDLETIMER.c
@@ -72,7 +72,7 @@ static void notify_netlink_uevent(const char *iface,
{
char iface_msg[NLMSG_MAX_SIZE];
char state_msg[NLMSG_MAX_SIZE];
- static const char * const envp[] = { iface_msg, state_msg, NULL };
+ char *envp[] = { iface_msg, state_msg, NULL };
int res;
res = snprintf(iface_msg, NLMSG_MAX_SIZE, "INTERFACE=%s",
diff --git a/net/rmnet_data/rmnet_data_config.c b/net/rmnet_data/rmnet_data_config.c
index 2a30d55..50d9b51 100644
--- a/net/rmnet_data/rmnet_data_config.c
+++ b/net/rmnet_data/rmnet_data_config.c
@@ -1173,6 +1173,7 @@ static void rmnet_force_unassociate_device(struct net_device *dev)
{
int i, j;
struct net_device *vndev;
+ struct rmnet_phys_ep_config *config;
struct rmnet_logical_ep_conf_s *cfg;
struct rmnet_free_vnd_work *vnd_work;
@@ -1228,6 +1229,16 @@ static void rmnet_force_unassociate_device(struct net_device *dev)
kfree(vnd_work);
}
+ config = _rmnet_get_phys_ep_config(dev);
+
+ if (config) {
+ cfg = &config->local_ep;
+
+ if (cfg && cfg->refcount)
+ rmnet_unset_logical_endpoint_config
+ (cfg->egress_dev, RMNET_LOCAL_LOGICAL_ENDPOINT);
+ }
+
/* Clear the mappings on the phys ep */
trace_rmnet_unregister_cb_clear_lepcs(dev);
rmnet_unset_logical_endpoint_config(dev, RMNET_LOCAL_LOGICAL_ENDPOINT);
diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c
index 46fdf5a..35be79e 100644
--- a/net/rmnet_data/rmnet_data_handlers.c
+++ b/net/rmnet_data/rmnet_data_handlers.c
@@ -552,12 +552,9 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
LOGD("headroom of %d bytes", required_headroom);
if (skb_headroom(skb) < required_headroom) {
- if (pskb_expand_head(skb, required_headroom, 0, GFP_KERNEL)) {
- LOGD("Failed to add headroom of %d bytes",
- required_headroom);
- kfree_skb(skb);
- return 1;
- }
+ LOGE("Not enough headroom for %d bytes", required_headroom);
+ kfree_skb(skb);
+ return 1;
}
if ((config->egress_data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV3) ||
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 5f5867f..80890c0 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -477,7 +477,7 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
u32 *mask);
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
- u32 beacon_int);
+ enum nl80211_iftype iftype, u32 beacon_int);
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 9ed6b0f..4ba0d590 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1060,6 +1060,10 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
c->radar_detect_regions)))
goto nla_put_failure;
+ if (c->beacon_int_min_gcd &&
+ nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
+ c->beacon_int_min_gcd))
+ goto nla_put_failure;
nla_nest_end(msg, nl_combi);
}
@@ -3790,7 +3794,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
params.dtim_period =
nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
- err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
+ err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
+ params.beacon_interval);
if (err)
return err;
@@ -8163,7 +8168,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
ibss.beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
- err = cfg80211_validate_beacon_int(rdev, ibss.beacon_interval);
+ err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
+ ibss.beacon_interval);
if (err)
return err;
@@ -9428,7 +9434,9 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
setup.beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
- err = cfg80211_validate_beacon_int(rdev, setup.beacon_interval);
+ err = cfg80211_validate_beacon_int(rdev,
+ NL80211_IFTYPE_MESH_POINT,
+ setup.beacon_interval);
if (err)
return err;
}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 7c8b406..877e9d3 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1560,30 +1560,50 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
- u32 beacon_int)
+ enum nl80211_iftype iftype, u32 beacon_int)
{
struct wireless_dev *wdev;
- int res = 0;
+ struct iface_combination_params params = {
+ .beacon_int_gcd = beacon_int, /* GCD(n) = n */
+ };
if (beacon_int < 10 || beacon_int > 10000)
return -EINVAL;
+ params.iftype_num[iftype] = 1;
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (!wdev->beacon_interval)
continue;
- if (wdev->beacon_interval != beacon_int) {
- res = -EINVAL;
- break;
+
+ params.iftype_num[wdev->iftype]++;
+ }
+
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
+ u32 bi_prev = wdev->beacon_interval;
+
+ if (!wdev->beacon_interval)
+ continue;
+
+ /* slight optimisation - skip identical BIs */
+ if (wdev->beacon_interval == beacon_int)
+ continue;
+
+ params.beacon_int_different = true;
+
+ /* Get the GCD */
+ while (bi_prev != 0) {
+ u32 tmp_bi = bi_prev;
+
+ bi_prev = params.beacon_int_gcd % bi_prev;
+ params.beacon_int_gcd = tmp_bi;
}
}
- return res;
+ return cfg80211_check_combinations(&rdev->wiphy, ¶ms);
}
int cfg80211_iter_combinations(struct wiphy *wiphy,
- const int num_different_channels,
- const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES],
+ struct iface_combination_params *params,
void (*iter)(const struct ieee80211_iface_combination *c,
void *data),
void *data)
@@ -1594,7 +1614,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
int num_interfaces = 0;
u32 used_iftypes = 0;
- if (radar_detect) {
+ if (params->radar_detect) {
rcu_read_lock();
regdom = rcu_dereference(cfg80211_regdomain);
if (regdom)
@@ -1603,8 +1623,8 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
}
for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
- num_interfaces += iftype_num[iftype];
- if (iftype_num[iftype] > 0 &&
+ num_interfaces += params->iftype_num[iftype];
+ if (params->iftype_num[iftype] > 0 &&
!(wiphy->software_iftypes & BIT(iftype)))
used_iftypes |= BIT(iftype);
}
@@ -1618,7 +1638,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if (num_interfaces > c->max_interfaces)
continue;
- if (num_different_channels > c->num_different_channels)
+ if (params->num_different_channels > c->num_different_channels)
continue;
limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
@@ -1633,16 +1653,17 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
all_iftypes |= limits[j].types;
if (!(limits[j].types & BIT(iftype)))
continue;
- if (limits[j].max < iftype_num[iftype])
+ if (limits[j].max < params->iftype_num[iftype])
goto cont;
- limits[j].max -= iftype_num[iftype];
+ limits[j].max -= params->iftype_num[iftype];
}
}
- if (radar_detect != (c->radar_detect_widths & radar_detect))
+ if (params->radar_detect !=
+ (c->radar_detect_widths & params->radar_detect))
goto cont;
- if (radar_detect && c->radar_detect_regions &&
+ if (params->radar_detect && c->radar_detect_regions &&
!(c->radar_detect_regions & BIT(region)))
goto cont;
@@ -1654,6 +1675,15 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;
+ if (params->beacon_int_gcd) {
+ if (c->beacon_int_min_gcd &&
+ params->beacon_int_gcd < c->beacon_int_min_gcd)
+ return -EINVAL;
+ if (!c->beacon_int_min_gcd &&
+ params->beacon_int_different)
+ goto cont;
+ }
+
/* This combination covered all interface types and
* supported the requested numbers, so we're good.
*/
@@ -1676,14 +1706,11 @@ cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
}
int cfg80211_check_combinations(struct wiphy *wiphy,
- const int num_different_channels,
- const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES])
+ struct iface_combination_params *params)
{
int err, num = 0;
- err = cfg80211_iter_combinations(wiphy, num_different_channels,
- radar_detect, iftype_num,
+ err = cfg80211_iter_combinations(wiphy, params,
cfg80211_iter_sum_ifcombs, &num);
if (err)
return err;
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index 56c458d..8d9330a 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -437,7 +437,7 @@ static struct skcipher_request *init_skcipher_req(const u8 *key,
static struct key *request_master_key(struct encrypted_key_payload *epayload,
const u8 **master_key, size_t *master_keylen)
{
- struct key *mkey = NULL;
+ struct key *mkey = ERR_PTR(-EINVAL);
if (!strncmp(epayload->master_desc, KEY_TRUSTED_PREFIX,
KEY_TRUSTED_PREFIX_LEN)) {
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index f800858..a472bf2 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -882,7 +882,6 @@
tristate
depends on WCD9XXX_CODEC_CORE
select SND_SOC_WCD9XXX
- select SND_SOC_WCD_MBHC
select SND_SOC_WCD_MBHC_LEGACY
select SND_SOC_WCD_CPE
@@ -900,7 +899,6 @@
config SND_SOC_WCD934X_MBHC
tristate
depends on SND_SOC_WCD934X
- select SND_SOC_WCD_MBHC
select SND_SOC_WCD_MBHC_ADC
config REGMAP_SWR
@@ -912,10 +910,6 @@
depends on REGMAP_SWR
select MSM_CDC_PINCTRL
-config SND_SOC_WSA881X_ANALOG
- tristate
- select REGMAP_I2C
-
config SND_SOC_WCD9XXX
tristate
default y if SND_SOC_WCD9335=y || SND_SOC_WCD934X=y
@@ -933,9 +927,11 @@
config SND_SOC_WCD_MBHC_LEGACY
tristate
+ select SND_SOC_WCD_MBHC
config SND_SOC_WCD_MBHC_ADC
tristate
+ select SND_SOC_WCD_MBHC
config SND_SOC_WCD_DSP_MGR
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index d5e4ab2..d8b5ae6 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -172,13 +172,13 @@
endif
snd-soc-wcd-cpe-objs := wcd_cpe_services.o wcd_cpe_core.o
snd-soc-wsa881x-objs := wsa881x.o wsa881x-tables.o wsa881x-regmap.o wsa881x-temp-sensor.o
+snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o
ifneq (,$(filter $(CONFIG_SND_SOC_WCD_MBHC_LEGACY),y m))
- snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o wcd-mbhc-legacy.o
-else ifneq (,$(filter $(CONFIG_SND_SOC_WCD_MBHC_ADC),y m))
- snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o wcd-mbhc-adc.o
+ snd-soc-wcd-mbhc-objs += wcd-mbhc-legacy.o
endif
-snd-soc-wsa881x-analog-objs := wsa881x-analog.o wsa881x-tables-analog.o
-snd-soc-wsa881x-analog-objs += wsa881x-regmap-analog.o wsa881x-irq.o
+ifneq (,$(filter $(CONFIG_SND_SOC_WCD_MBHC_ADC),y m))
+ snd-soc-wcd-mbhc-objs += wcd-mbhc-adc.o
+endif
snd-soc-wcd-spi-objs := wcd-spi.o
snd-soc-wl1273-objs := wl1273.o
snd-soc-wm-adsp-objs := wm_adsp.o
@@ -410,7 +410,6 @@
obj-$(CONFIG_SND_SOC_WCD_CPE) += snd-soc-wcd-cpe.o
obj-$(CONFIG_SND_SOC_WCD_MBHC) += snd-soc-wcd-mbhc.o
obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o
-obj-$(CONFIG_SND_SOC_WSA881X_ANALOG) += snd-soc-wsa881x-analog.o
obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
obj-$(CONFIG_SND_SOC_WCD_SPI) += snd-soc-wcd-spi.o
obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
index cfe42e0..34227a0 100644
--- a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
@@ -937,9 +937,8 @@ static int msm_sdw_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol,
static int msm_sdw_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct msm_sdw_priv *msm_sdw_p = snd_soc_codec_get_drvdata(codec);
@@ -951,9 +950,8 @@ static int msm_sdw_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
static int msm_sdw_vi_feed_mixer_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct msm_sdw_priv *msm_sdw_p = snd_soc_codec_get_drvdata(codec);
struct soc_multi_mixer_control *mixer =
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 9c365a7..7899a2c 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -1108,6 +1108,13 @@ static const struct dmi_system_id force_combo_jack_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Kabylake Client platform")
}
},
+ {
+ .ident = "Thinkpad Helix 2nd",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix 2nd")
+ }
+ },
{ }
};
diff --git a/sound/soc/codecs/sdm660_cdc/Kconfig b/sound/soc/codecs/sdm660_cdc/Kconfig
index 2f36c39..e618258 100644
--- a/sound/soc/codecs/sdm660_cdc/Kconfig
+++ b/sound/soc/codecs/sdm660_cdc/Kconfig
@@ -1,5 +1,4 @@
config SND_SOC_SDM660_CDC
tristate "MSM Internal PMIC based codec"
- select SND_SOC_WCD_MBHC
select SND_SOC_WCD_MBHC_LEGACY
diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
index 7892f61..f126d35 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -2055,6 +2055,9 @@ static const char * const rdac2_mux_text[] = {
"ZERO", "RX2", "RX1"
};
+static const struct snd_kcontrol_new adc1_switch =
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
static const struct soc_enum rdac2_mux_enum =
SOC_ENUM_SINGLE(MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL,
0, 3, rdac2_mux_text);
@@ -3105,7 +3108,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"ADC2 MUX", "INP2", "ADC2_INP2"},
{"ADC2 MUX", "INP3", "ADC2_INP3"},
- {"ADC1", NULL, "AMIC1"},
+ {"ADC1", NULL, "ADC1_INP1"},
+ {"ADC1_INP1", "Switch", "AMIC1"},
{"ADC2_INP2", NULL, "AMIC2"},
{"ADC2_INP3", NULL, "AMIC3"},
@@ -3446,6 +3450,8 @@ static const struct snd_soc_dapm_widget msm_anlg_cdc_dapm_widgets[] = {
SND_SOC_DAPM_SPK("Ext Spk", msm_anlg_cdc_codec_enable_spk_ext_pa),
+ SND_SOC_DAPM_SWITCH("ADC1_INP1", SND_SOC_NOPM, 0, 0,
+ &adc1_switch),
SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
0, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
index 68a1d8d..5e0a104 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
@@ -122,9 +122,7 @@ static void disable_digital_callback(void *flag)
static int msm_dig_cdc_put_dec_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *w = wlist->widgets[0];
+ struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int dec_mux, decimator;
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index 3b2426d..eb67de9 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -329,6 +329,7 @@ static int wcd_event_notify(struct notifier_block *self, unsigned long val,
/* Disable micbias, pullup & enable cs */
wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
mutex_unlock(&mbhc->hphl_pa_lock);
+ clear_bit(WCD_MBHC_ANC0_OFF_ACK, &mbhc->hph_anc_state);
break;
case WCD_EVENT_PRE_HPHR_PA_OFF:
mutex_lock(&mbhc->hphr_pa_lock);
@@ -346,6 +347,7 @@ static int wcd_event_notify(struct notifier_block *self, unsigned long val,
/* Disable micbias, pullup & enable cs */
wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
mutex_unlock(&mbhc->hphr_pa_lock);
+ clear_bit(WCD_MBHC_ANC1_OFF_ACK, &mbhc->hph_anc_state);
break;
case WCD_EVENT_PRE_HPHL_PA_ON:
set_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
@@ -439,6 +441,25 @@ static void wcd_mbhc_clr_and_turnon_hph_padac(struct wcd_mbhc *mbhc)
__func__);
usleep_range(wg_time * 1000, wg_time * 1000 + 50);
}
+
+ if (test_and_clear_bit(WCD_MBHC_ANC0_OFF_ACK,
+ &mbhc->hph_anc_state)) {
+ usleep_range(20000, 20100);
+ pr_debug("%s: HPHL ANC clear flag and enable ANC_EN\n",
+ __func__);
+ if (mbhc->mbhc_cb->update_anc_state)
+ mbhc->mbhc_cb->update_anc_state(mbhc->codec, true, 0);
+ }
+
+ if (test_and_clear_bit(WCD_MBHC_ANC1_OFF_ACK,
+ &mbhc->hph_anc_state)) {
+ usleep_range(20000, 20100);
+ pr_debug("%s: HPHR ANC clear flag and enable ANC_EN\n",
+ __func__);
+ if (mbhc->mbhc_cb->update_anc_state)
+ mbhc->mbhc_cb->update_anc_state(mbhc->codec, true, 1);
+ }
+
}
static bool wcd_mbhc_is_hph_pa_on(struct wcd_mbhc *mbhc)
@@ -471,6 +492,20 @@ static void wcd_mbhc_set_and_turnoff_hph_padac(struct wcd_mbhc *mbhc)
}
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPH_PA_EN, 0);
usleep_range(wg_time * 1000, wg_time * 1000 + 50);
+
+
+ if (mbhc->mbhc_cb->is_anc_on && mbhc->mbhc_cb->is_anc_on(mbhc)) {
+ usleep_range(20000, 20100);
+ pr_debug("%s ANC is on, setting ANC_OFF_ACK\n", __func__);
+ set_bit(WCD_MBHC_ANC0_OFF_ACK, &mbhc->hph_anc_state);
+ set_bit(WCD_MBHC_ANC1_OFF_ACK, &mbhc->hph_anc_state);
+ if (mbhc->mbhc_cb->update_anc_state) {
+ mbhc->mbhc_cb->update_anc_state(mbhc->codec, false, 0);
+ mbhc->mbhc_cb->update_anc_state(mbhc->codec, false, 1);
+ } else {
+ pr_debug("%s ANC is off\n", __func__);
+ }
+ }
}
int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
@@ -581,7 +616,8 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
jack_type == SND_JACK_LINEOUT) &&
(mbhc->hph_status && mbhc->hph_status != jack_type)) {
- if (mbhc->micbias_enable) {
+ if (mbhc->micbias_enable &&
+ mbhc->hph_status == SND_JACK_HEADSET) {
if (mbhc->mbhc_cb->mbhc_micbias_control)
mbhc->mbhc_cb->mbhc_micbias_control(
codec, MIC_BIAS_2,
@@ -1108,7 +1144,7 @@ static irqreturn_t wcd_mbhc_release_handler(int irq, void *data)
* For ADC MBHC, ADC_COMPLETE interrupt will be generated
* in this case. So skip the check here.
*/
- if (!WCD_MBHC_DETECTION &&
+ if (mbhc->mbhc_detection_logic == WCD_DETECTION_LEGACY &&
mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET);
goto exit;
@@ -1922,7 +1958,7 @@ int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_codec *codec,
init_waitqueue_head(&mbhc->wait_btn_press);
mutex_init(&mbhc->codec_resource_lock);
- switch (WCD_MBHC_DETECTION) {
+ switch (mbhc->mbhc_detection_logic) {
case WCD_DETECTION_LEGACY:
wcd_mbhc_legacy_init(mbhc);
break;
@@ -1931,7 +1967,7 @@ int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_codec *codec,
break;
default:
pr_err("%s: Unknown detection logic type %d\n",
- __func__, WCD_MBHC_DETECTION);
+ __func__, mbhc->mbhc_detection_logic);
break;
}
diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h
index 7ed06c3..c8714fc 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.h
+++ b/sound/soc/codecs/wcd-mbhc-v2.h
@@ -157,12 +157,6 @@ enum wcd_mbhc_detect_logic {
WCD_DETECTION_ADC,
};
-#ifdef CONFIG_SND_SOC_WCD_MBHC_ADC
-#define WCD_MBHC_DETECTION WCD_DETECTION_ADC
-#else
-#define WCD_MBHC_DETECTION WCD_DETECTION_LEGACY
-#endif
-
enum wcd_mbhc_cs_mb_en_flag {
WCD_MBHC_EN_CS = 0,
WCD_MBHC_EN_MB,
@@ -240,6 +234,11 @@ enum pa_dac_ack_flags {
WCD_MBHC_HPHR_PA_OFF_ACK,
};
+enum anc_ack_flags {
+ WCD_MBHC_ANC0_OFF_ACK = 0,
+ WCD_MBHC_ANC1_OFF_ACK,
+};
+
enum wcd_mbhc_btn_det_mem {
WCD_MBHC_BTN_DET_V_BTN_LOW,
WCD_MBHC_BTN_DET_V_BTN_HIGH
@@ -488,6 +487,9 @@ struct wcd_mbhc_cb {
void (*hph_pull_down_ctrl)(struct snd_soc_codec *, bool);
void (*mbhc_moisture_config)(struct wcd_mbhc *);
bool (*hph_register_recovery)(struct wcd_mbhc *);
+ void (*update_anc_state)(struct snd_soc_codec *codec,
+ bool enable, int anc_num);
+ bool (*is_anc_on)(struct wcd_mbhc *mbhc);
};
struct wcd_mbhc_fn {
@@ -538,6 +540,7 @@ struct wcd_mbhc {
/* track PA/DAC state to sync with userspace */
unsigned long hph_pa_dac_state;
+ unsigned long hph_anc_state;
unsigned long event_state;
unsigned long jiffies_atreport;
@@ -565,6 +568,9 @@ struct wcd_mbhc {
struct mutex hphl_pa_lock;
struct mutex hphr_pa_lock;
+ /* Holds mbhc detection method - ADC/Legacy */
+ unsigned int mbhc_detection_logic;
+
unsigned long intr_status;
bool is_hph_ocp_pending;
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index f8cd9e2..a6a5350 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -2014,6 +2014,32 @@ static void tasha_mbhc_moisture_config(struct wcd_mbhc *mbhc)
tasha_mbhc_hph_l_pull_up_control(codec, mbhc->moist_iref);
}
+static void tasha_update_anc_state(struct snd_soc_codec *codec, bool enable,
+ int anc_num)
+{
+ if (enable)
+ snd_soc_update_bits(codec, WCD9335_CDC_RX1_RX_PATH_CFG0 +
+ (20 * anc_num), 0x10, 0x10);
+ else
+ snd_soc_update_bits(codec, WCD9335_CDC_RX1_RX_PATH_CFG0 +
+ (20 * anc_num), 0x10, 0x00);
+}
+
+static bool tasha_is_anc_on(struct wcd_mbhc *mbhc)
+{
+ bool anc_on = false;
+ u16 ancl, ancr;
+
+ ancl =
+ (snd_soc_read(mbhc->codec, WCD9335_CDC_RX1_RX_PATH_CFG0)) & 0x10;
+ ancr =
+ (snd_soc_read(mbhc->codec, WCD9335_CDC_RX2_RX_PATH_CFG0)) & 0x10;
+
+ anc_on = !!(ancl | ancr);
+
+ return anc_on;
+}
+
static const struct wcd_mbhc_cb mbhc_cb = {
.request_irq = tasha_mbhc_request_irq,
.irq_control = tasha_mbhc_irq_control,
@@ -2036,6 +2062,8 @@ static const struct wcd_mbhc_cb mbhc_cb = {
.mbhc_gnd_det_ctrl = tasha_mbhc_gnd_det_ctrl,
.hph_pull_down_ctrl = tasha_mbhc_hph_pull_down_ctrl,
.mbhc_moisture_config = tasha_mbhc_moisture_config,
+ .update_anc_state = tasha_update_anc_state,
+ .is_anc_on = tasha_is_anc_on,
};
static int tasha_get_anc_slot(struct snd_kcontrol *kcontrol,
@@ -2233,9 +2261,8 @@ static const struct snd_kcontrol_new hph_type_detect_controls[] = {
static int tasha_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
@@ -2247,9 +2274,8 @@ static int tasha_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
static int tasha_vi_feed_mixer_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
struct wcd9xxx *core = tasha_p->wcd9xxx;
@@ -2300,9 +2326,8 @@ static int tasha_vi_feed_mixer_put(struct snd_kcontrol *kcontrol,
static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
@@ -2313,9 +2338,8 @@ static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
@@ -2408,9 +2432,8 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
@@ -2426,9 +2449,8 @@ static const char *const slim_rx_mux_text[] = {
static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
@@ -8477,9 +8499,8 @@ static const struct snd_kcontrol_new tasha_snd_controls[] = {
static int tasha_put_dec_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val;
@@ -8537,9 +8558,8 @@ static int tasha_put_dec_enum(struct snd_kcontrol *kcontrol,
static int tasha_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val;
@@ -8871,9 +8891,8 @@ static int tasha_codec_configure_cpe_input(struct snd_soc_dapm_widget *w,
static int tasha_codec_aif4_mixer_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
@@ -8890,9 +8909,8 @@ static int tasha_codec_aif4_mixer_switch_get(struct snd_kcontrol *kcontrol,
static int tasha_codec_aif4_mixer_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_dapm_update *update = NULL;
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
index a1a5e2d..ea19caa 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
@@ -829,6 +829,32 @@ static bool tavil_hph_register_recovery(struct wcd_mbhc *mbhc)
return wcd934x_mbhc->is_hph_recover;
}
+static void tavil_update_anc_state(struct snd_soc_codec *codec, bool enable,
+ int anc_num)
+{
+ if (enable)
+ snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CFG0 +
+ (20 * anc_num), 0x10, 0x10);
+ else
+ snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CFG0 +
+ (20 * anc_num), 0x10, 0x00);
+}
+
+static bool tavil_is_anc_on(struct wcd_mbhc *mbhc)
+{
+ bool anc_on = false;
+ u16 ancl, ancr;
+
+ ancl =
+ (snd_soc_read(mbhc->codec, WCD934X_CDC_RX1_RX_PATH_CFG0)) & 0x10;
+ ancr =
+ (snd_soc_read(mbhc->codec, WCD934X_CDC_RX2_RX_PATH_CFG0)) & 0x10;
+
+ anc_on = !!(ancl | ancr);
+
+ return anc_on;
+}
+
static const struct wcd_mbhc_cb mbhc_cb = {
.request_irq = tavil_mbhc_request_irq,
.irq_control = tavil_mbhc_irq_control,
@@ -852,6 +878,8 @@ static const struct wcd_mbhc_cb mbhc_cb = {
.hph_pull_down_ctrl = tavil_mbhc_hph_pull_down_ctrl,
.mbhc_moisture_config = tavil_mbhc_moisture_config,
.hph_register_recovery = tavil_hph_register_recovery,
+ .update_anc_state = tavil_update_anc_state,
+ .is_anc_on = tavil_is_anc_on,
};
static struct regulator *tavil_codec_find_ondemand_regulator(
@@ -998,19 +1026,26 @@ int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc,
struct snd_soc_codec *codec)
{
int ret;
+ struct wcd_mbhc *wcd_mbhc;
if (!mbhc || !codec)
return -EINVAL;
- wcd_mbhc_deinit(&mbhc->wcd_mbhc);
- ret = wcd_mbhc_init(&mbhc->wcd_mbhc, codec, &mbhc_cb, &intr_ids,
+ wcd_mbhc = &mbhc->wcd_mbhc;
+ if (wcd_mbhc == NULL) {
+ pr_err("%s: wcd_mbhc is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ wcd_mbhc_deinit(wcd_mbhc);
+ ret = wcd_mbhc_init(wcd_mbhc, codec, &mbhc_cb, &intr_ids,
wcd_mbhc_registers, TAVIL_ZDET_SUPPORTED);
if (ret) {
dev_err(codec->dev, "%s: mbhc initialization failed\n",
__func__);
goto done;
}
- if (!WCD_MBHC_DETECTION) {
+ if (wcd_mbhc->mbhc_detection_logic == WCD_DETECTION_LEGACY) {
snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_1, 0x04, 0x04);
snd_soc_update_bits(codec, WCD934X_MBHC_CTL_BCS, 0x01, 0x01);
}
@@ -1033,6 +1068,7 @@ int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, struct snd_soc_codec *codec,
{
struct regulator *supply;
struct wcd934x_mbhc *wcd934x_mbhc;
+ struct wcd_mbhc *wcd_mbhc;
int ret;
wcd934x_mbhc = devm_kzalloc(codec->dev, sizeof(struct wcd934x_mbhc),
@@ -1043,8 +1079,18 @@ int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, struct snd_soc_codec *codec,
wcd934x_mbhc->wcd9xxx = dev_get_drvdata(codec->dev->parent);
wcd934x_mbhc->fw_data = fw_data;
BLOCKING_INIT_NOTIFIER_HEAD(&wcd934x_mbhc->notifier);
+ wcd_mbhc = &wcd934x_mbhc->wcd_mbhc;
+ if (wcd_mbhc == NULL) {
+ pr_err("%s: wcd_mbhc is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
- ret = wcd_mbhc_init(&wcd934x_mbhc->wcd_mbhc, codec, &mbhc_cb,
+
+ /* Setting default mbhc detection logic to ADC for Tavil */
+ wcd_mbhc->mbhc_detection_logic = WCD_DETECTION_ADC;
+
+ ret = wcd_mbhc_init(wcd_mbhc, codec, &mbhc_cb,
&intr_ids, wcd_mbhc_registers,
TAVIL_ZDET_SUPPORTED);
if (ret) {
@@ -1070,7 +1116,7 @@ int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, struct snd_soc_codec *codec,
snd_soc_add_codec_controls(codec, hph_type_detect_controls,
ARRAY_SIZE(hph_type_detect_controls));
- if (!WCD_MBHC_DETECTION) {
+ if (wcd_mbhc->mbhc_detection_logic == WCD_DETECTION_LEGACY) {
snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_1, 0x04, 0x04);
snd_soc_update_bits(codec, WCD934X_MBHC_CTL_BCS, 0x01, 0x01);
}
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 3079cca..fe1ce45 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -1110,9 +1110,8 @@ static int tavil_put_clkmode(struct snd_kcontrol *kcontrol,
static int tavil_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
@@ -1124,9 +1123,8 @@ static int tavil_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
static int tavil_vi_feed_mixer_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
@@ -1176,9 +1174,8 @@ static int tavil_vi_feed_mixer_put(struct snd_kcontrol *kcontrol,
static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
@@ -1189,9 +1186,8 @@ static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
@@ -1271,9 +1267,8 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
@@ -1285,9 +1280,8 @@ static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
@@ -5929,9 +5923,8 @@ static const struct snd_kcontrol_new tavil_snd_controls[] = {
static int tavil_dec_enum_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val;
@@ -5989,9 +5982,8 @@ static int tavil_dec_enum_put(struct snd_kcontrol *kcontrol,
static int tavil_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val;
diff --git a/sound/soc/codecs/wsa881x-analog.c b/sound/soc/codecs/wsa881x-analog.c
deleted file mode 100644
index 4de9624..0000000
--- a/sound/soc/codecs/wsa881x-analog.c
+++ /dev/null
@@ -1,1446 +0,0 @@
-/*
- * Copyright (c) 2015-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/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
-#include <linux/device.h>
-#include <linux/printk.h>
-#include <linux/bitops.h>
-#include <linux/regulator/consumer.h>
-#include <linux/pm_runtime.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/tlv.h>
-#include <sound/q6afe-v2.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <linux/regmap.h>
-#include "wsa881x-analog.h"
-#include "wsa881x-temp-sensor.h"
-#include "../msm/msm-audio-pinctrl.h"
-
-#define SPK_GAIN_12DB 4
-#define WIDGET_NAME_MAX_SIZE 80
-
-/*
- * Private data Structure for wsa881x. All parameters related to
- * WSA881X codec needs to be defined here.
- */
-struct wsa881x_pdata {
- struct regmap *regmap[2];
- struct i2c_client *client[2];
- struct snd_soc_codec *codec;
-
- /* track wsa881x status during probe */
- int status;
- bool boost_enable;
- bool visense_enable;
- int spk_pa_gain;
- struct i2c_msg xfer_msg[2];
- struct mutex xfer_lock;
- bool regmap_flag;
- bool wsa_active;
- int index;
- int (*enable_mclk)(struct snd_soc_card *, bool);
- struct wsa881x_tz_priv tz_pdata;
- int bg_cnt;
- int clk_cnt;
- int enable_cnt;
- int version;
- struct mutex bg_lock;
- struct mutex res_lock;
- struct delayed_work ocp_ctl_work;
-};
-
-enum {
- WSA881X_STATUS_PROBING,
- WSA881X_STATUS_I2C,
-};
-
-#define WSA881X_OCP_CTL_TIMER_SEC 2
-#define WSA881X_OCP_CTL_TEMP_CELSIUS 25
-#define WSA881X_OCP_CTL_POLL_TIMER_SEC 60
-
-static int wsa881x_ocp_poll_timer_sec = WSA881X_OCP_CTL_POLL_TIMER_SEC;
-module_param(wsa881x_ocp_poll_timer_sec, int, 0664);
-MODULE_PARM_DESC(wsa881x_ocp_poll_timer_sec, "timer for ocp ctl polling");
-
-static int32_t wsa881x_resource_acquire(struct snd_soc_codec *codec,
- bool enable);
-
-const char *wsa_tz_names[] = {"wsa881x.0e", "wsa881x.0f"};
-
-struct wsa881x_pdata wsa_pdata[MAX_WSA881X_DEVICE];
-
-static bool pinctrl_init;
-
-static int wsa881x_populate_dt_pdata(struct device *dev);
-static int wsa881x_reset(struct wsa881x_pdata *pdata, bool enable);
-static int wsa881x_startup(struct wsa881x_pdata *pdata);
-static int wsa881x_shutdown(struct wsa881x_pdata *pdata);
-
-static int delay_array_msec[] = {10, 20, 30, 40, 50};
-
-static int wsa881x_i2c_addr = -1;
-static int wsa881x_probing_count;
-static int wsa881x_presence_count;
-
-static const char * const wsa881x_spk_pa_gain_text[] = {
-"POS_13P5_DB", "POS_12_DB", "POS_10P5_DB", "POS_9_DB", "POS_7P5_DB",
-"POS_6_DB", "POS_4P5_DB", "POS_3_DB", "POS_1P5_DB", "POS_0_DB"};
-
-static const struct soc_enum wsa881x_spk_pa_gain_enum[] = {
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa881x_spk_pa_gain_text),
- wsa881x_spk_pa_gain_text),
-};
-
-static int wsa881x_spk_pa_gain_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- ucontrol->value.integer.value[0] = wsa881x->spk_pa_gain;
-
- dev_dbg(codec->dev, "%s: spk_pa_gain = %ld\n", __func__,
- ucontrol->value.integer.value[0]);
-
- return 0;
-}
-
-static int wsa881x_spk_pa_gain_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- if (ucontrol->value.integer.value[0] < 0 ||
- ucontrol->value.integer.value[0] > 0xC) {
- dev_err(codec->dev, "%s: Unsupported gain val %ld\n",
- __func__, ucontrol->value.integer.value[0]);
- return -EINVAL;
- }
- wsa881x->spk_pa_gain = ucontrol->value.integer.value[0];
- dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
- __func__, ucontrol->value.integer.value[0]);
-
- return 0;
-}
-
-static int get_i2c_wsa881x_device_index(u16 reg)
-{
- u16 mask = 0x0f00;
- int value = 0;
-
- value = ((reg & mask) >> 8) & 0x000f;
-
- switch (value) {
- case 0:
- return 0;
- case 1:
- return 1;
- default:
- break;
- }
- return -EINVAL;
-}
-
-static int wsa881x_i2c_write_device(struct wsa881x_pdata *wsa881x,
- unsigned int reg, unsigned int val)
-{
- int i = 0, rc = 0;
- int wsa881x_index;
- struct i2c_msg *msg;
- int ret = 0;
- int bytes = 1;
- u8 reg_addr = 0;
- u8 data[bytes + 1];
-
- wsa881x_index = get_i2c_wsa881x_device_index(reg);
- if (wsa881x_index < 0) {
- pr_err("%s:invalid register to write\n", __func__);
- return -EINVAL;
- }
- if (wsa881x->regmap_flag) {
- rc = regmap_write(wsa881x->regmap[wsa881x_index], reg, val);
- for (i = 0; rc && i < ARRAY_SIZE(delay_array_msec); i++) {
- pr_err("Failed writing reg=%u - retry(%d)\n", reg, i);
- /* retry after delay of increasing order */
- msleep(delay_array_msec[i]);
- rc = regmap_write(wsa881x->regmap[wsa881x_index],
- reg, val);
- }
- if (rc)
- pr_err("Failed writing reg=%u rc=%d\n", reg, rc);
- else
- pr_err("write success register = %x val = %x\n",
- reg, val);
- } else {
- reg_addr = (u8)reg;
- msg = &wsa881x->xfer_msg[0];
- msg->addr = wsa881x->client[wsa881x_index]->addr;
- msg->len = bytes + 1;
- msg->flags = 0;
- data[0] = reg;
- data[1] = (u8)val;
- msg->buf = data;
- ret = i2c_transfer(wsa881x->client[wsa881x_index]->adapter,
- wsa881x->xfer_msg, 1);
- /* Try again if the write fails */
- if (ret != 1) {
- ret = i2c_transfer(
- wsa881x->client[wsa881x_index]->adapter,
- wsa881x->xfer_msg, 1);
- if (ret != 1) {
- pr_err("failed to write the device\n");
- return ret;
- }
- }
- pr_debug("write success reg = %x val = %x\n", reg, data[1]);
- }
- return rc;
-}
-
-static int wsa881x_i2c_read_device(struct wsa881x_pdata *wsa881x,
- unsigned int reg)
-{
- int wsa881x_index;
- int i = 0, rc = 0;
- unsigned int val;
- struct i2c_msg *msg;
- int ret = 0;
- u8 reg_addr = 0;
- u8 dest[5];
-
- wsa881x_index = get_i2c_wsa881x_device_index(reg);
- if (wsa881x_index < 0) {
- pr_err("%s:invalid register to read\n", __func__);
- return -EINVAL;
- }
- if (wsa881x->regmap_flag) {
- rc = regmap_read(wsa881x->regmap[wsa881x_index], reg, &val);
- for (i = 0; rc && i < ARRAY_SIZE(delay_array_msec); i++) {
- pr_err("Failed reading reg=%u - retry(%d)\n", reg, i);
- /* retry after delay of increasing order */
- msleep(delay_array_msec[i]);
- rc = regmap_read(wsa881x->regmap[wsa881x_index],
- reg, &val);
- }
- if (rc) {
- pr_err("Failed reading reg=%u rc=%d\n", reg, rc);
- return rc;
- }
- pr_debug("read success reg = %x val = %x\n",
- reg, val);
- } else {
- reg_addr = (u8)reg;
- msg = &wsa881x->xfer_msg[0];
- msg->addr = wsa881x->client[wsa881x_index]->addr;
- msg->len = 1;
- msg->flags = 0;
- msg->buf = ®_addr;
-
- msg = &wsa881x->xfer_msg[1];
- msg->addr = wsa881x->client[wsa881x_index]->addr;
- msg->len = 1;
- msg->flags = I2C_M_RD;
- msg->buf = dest;
- ret = i2c_transfer(wsa881x->client[wsa881x_index]->adapter,
- wsa881x->xfer_msg, 2);
-
- /* Try again if read fails first time */
- if (ret != 2) {
- ret = i2c_transfer(
- wsa881x->client[wsa881x_index]->adapter,
- wsa881x->xfer_msg, 2);
- if (ret != 2) {
- pr_err("failed to read wsa register:%d\n",
- reg);
- return ret;
- }
- }
- val = dest[0];
- }
- return val;
-}
-
-static unsigned int wsa881x_i2c_read(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- struct wsa881x_pdata *wsa881x;
- unsigned int val;
- int ret;
-
- if (codec == NULL) {
- pr_err("%s: invalid codec\n", __func__);
- return -EINVAL;
- }
- wsa881x = snd_soc_codec_get_drvdata(codec);
- if (!wsa881x->wsa_active) {
- ret = snd_soc_cache_read(codec, reg, &val);
- if (ret >= 0)
- return val;
- dev_err(codec->dev,
- "cache read failed for reg: 0x%x ret: %d\n",
- reg, ret);
- return ret;
- }
- return wsa881x_i2c_read_device(wsa881x, reg);
-}
-
-static int wsa881x_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int val)
-{
- struct wsa881x_pdata *wsa881x;
- int ret = 0;
-
- if (codec == NULL) {
- pr_err("%s: invalid codec\n", __func__);
- return -EINVAL;
- }
- wsa881x = snd_soc_codec_get_drvdata(codec);
- if (!wsa881x->wsa_active) {
- ret = snd_soc_cache_write(codec, reg, val);
- if (ret != 0)
- dev_err(codec->dev, "cache write to %x failed: %d\n",
- reg, ret);
- return ret;
- }
- return wsa881x_i2c_write_device(wsa881x, reg, val);
-}
-
-static int wsa881x_i2c_get_client_index(struct i2c_client *client,
- int *wsa881x_index)
-{
- int ret = 0;
-
- switch (client->addr) {
- case WSA881X_I2C_SPK0_SLAVE0_ADDR:
- case WSA881X_I2C_SPK0_SLAVE1_ADDR:
- *wsa881x_index = WSA881X_I2C_SPK0_SLAVE0;
- break;
- case WSA881X_I2C_SPK1_SLAVE0_ADDR:
- case WSA881X_I2C_SPK1_SLAVE1_ADDR:
- *wsa881x_index = WSA881X_I2C_SPK1_SLAVE0;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int wsa881x_boost_ctrl(struct snd_soc_codec *codec, bool enable)
-{
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- pr_debug("%s: enable:%d\n", __func__, enable);
- if (enable) {
- if (!WSA881X_IS_2_0(wsa881x->version)) {
- snd_soc_update_bits(codec, WSA881X_ANA_CTL,
- 0x01, 0x01);
- snd_soc_update_bits(codec, WSA881X_ANA_CTL,
- 0x04, 0x04);
- snd_soc_update_bits(codec, WSA881X_BOOST_PS_CTL,
- 0x40, 0x00);
- snd_soc_update_bits(codec, WSA881X_BOOST_PRESET_OUT1,
- 0xF0, 0xB0);
- snd_soc_update_bits(codec, WSA881X_BOOST_ZX_CTL,
- 0x20, 0x00);
- snd_soc_update_bits(codec, WSA881X_BOOST_EN_CTL,
- 0x80, 0x80);
- } else {
- snd_soc_update_bits(codec, WSA881X_BOOST_LOOP_STABILITY,
- 0x03, 0x03);
- snd_soc_update_bits(codec, WSA881X_BOOST_MISC2_CTL,
- 0xFF, 0x14);
- snd_soc_update_bits(codec, WSA881X_BOOST_START_CTL,
- 0x80, 0x80);
- snd_soc_update_bits(codec, WSA881X_BOOST_START_CTL,
- 0x03, 0x00);
- snd_soc_update_bits(codec,
- WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
- 0x0C, 0x04);
- snd_soc_update_bits(codec,
- WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
- 0x03, 0x00);
- snd_soc_update_bits(codec, WSA881X_BOOST_PRESET_OUT1,
- 0xF0, 0x70);
- snd_soc_update_bits(codec, WSA881X_ANA_CTL, 0x03, 0x01);
- snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN,
- 0x08, 0x08);
- snd_soc_update_bits(codec, WSA881X_ANA_CTL, 0x04, 0x04);
- snd_soc_update_bits(codec, WSA881X_BOOST_CURRENT_LIMIT,
- 0x0F, 0x08);
- snd_soc_update_bits(codec, WSA881X_BOOST_EN_CTL,
- 0x80, 0x80);
- }
- /* For WSA8810, start-up time is 1500us as per qcrg sequence */
- usleep_range(1500, 1510);
- } else {
- /* ENSURE: Class-D amp is shutdown. CLK is still on */
- snd_soc_update_bits(codec, WSA881X_BOOST_EN_CTL, 0x80, 0x00);
- /* boost settle time is 1500us as per qcrg sequence */
- usleep_range(1500, 1510);
- }
- return 0;
-}
-
-static int wsa881x_visense_txfe_ctrl(struct snd_soc_codec *codec, bool enable,
- u8 isense1_gain, u8 isense2_gain,
- u8 vsense_gain)
-{
- u8 value = 0;
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- pr_debug("%s: enable:%d\n", __func__, enable);
-
- if (enable) {
- if (WSA881X_IS_2_0(wsa881x->version)) {
- snd_soc_update_bits(codec, WSA881X_OTP_REG_28,
- 0x3F, 0x3A);
- snd_soc_update_bits(codec, WSA881X_BONGO_RESRV_REG1,
- 0xFF, 0xB2);
- snd_soc_update_bits(codec, WSA881X_BONGO_RESRV_REG2,
- 0xFF, 0x05);
- }
- snd_soc_update_bits(codec, WSA881X_SPKR_PROT_FE_VSENSE_VCM,
- 0x08, 0x00);
- if (WSA881X_IS_2_0(wsa881x->version)) {
- snd_soc_update_bits(codec, WSA881X_SPKR_PROT_ATEST2,
- 0x1C, 0x04);
- } else {
- snd_soc_update_bits(codec, WSA881X_SPKR_PROT_ATEST2,
- 0x08, 0x08);
- snd_soc_update_bits(codec, WSA881X_SPKR_PROT_ATEST2,
- 0x02, 0x02);
- }
- value = ((isense2_gain << 6) | (isense1_gain << 4) |
- (vsense_gain << 3));
- snd_soc_update_bits(codec, WSA881X_SPKR_PROT_FE_GAIN,
- 0xF8, value);
- snd_soc_update_bits(codec, WSA881X_SPKR_PROT_FE_GAIN,
- 0x01, 0x01);
- } else {
- if (WSA881X_IS_2_0(wsa881x->version))
- snd_soc_update_bits(codec,
- WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x10, 0x10);
- else
- snd_soc_update_bits(codec,
- WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x08, 0x08);
- /*
- * 200us sleep is needed after visense txfe disable as per
- * HW requirement.
- */
- usleep_range(200, 210);
-
- snd_soc_update_bits(codec, WSA881X_SPKR_PROT_FE_GAIN,
- 0x01, 0x00);
- }
- return 0;
-}
-
-static int wsa881x_visense_adc_ctrl(struct snd_soc_codec *codec, bool enable)
-{
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- pr_debug("%s: enable:%d\n", __func__, enable);
- if (enable) {
- if (!WSA881X_IS_2_0(wsa881x->version))
- snd_soc_update_bits(codec, WSA881X_ADC_SEL_IBIAS,
- 0x70, 0x40);
- snd_soc_update_bits(codec, WSA881X_ADC_EN_SEL_IBIAS,
- 0x07, 0x04);
- snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_V, 0x80, 0x80);
- snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_I, 0x80, 0x80);
- } else {
- /* Ensure: Speaker Protection has been stopped */
- snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_V, 0x80, 0x00);
- snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_I, 0x80, 0x00);
- }
-
- return 0;
-}
-
-static void wsa881x_bandgap_ctrl(struct snd_soc_codec *codec, bool enable)
-{
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- dev_dbg(codec->dev, "%s: enable:%d, bg_count:%d\n", __func__,
- enable, wsa881x->bg_cnt);
- mutex_lock(&wsa881x->bg_lock);
- if (enable) {
- ++wsa881x->bg_cnt;
- if (wsa881x->bg_cnt == 1) {
- snd_soc_update_bits(codec, WSA881X_TEMP_OP,
- 0x08, 0x08);
- /* 400usec sleep is needed as per HW requirement */
- usleep_range(400, 410);
- snd_soc_update_bits(codec, WSA881X_TEMP_OP, 0x04, 0x04);
- }
- } else {
- --wsa881x->bg_cnt;
- if (wsa881x->bg_cnt <= 0) {
- WARN_ON(wsa881x->bg_cnt < 0);
- wsa881x->bg_cnt = 0;
- snd_soc_update_bits(codec, WSA881X_TEMP_OP, 0x04, 0x00);
- snd_soc_update_bits(codec, WSA881X_TEMP_OP, 0x08, 0x00);
- }
- }
- mutex_unlock(&wsa881x->bg_lock);
-}
-
-static void wsa881x_clk_ctrl(struct snd_soc_codec *codec, bool enable)
-{
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- dev_dbg(codec->dev, "%s:ss enable:%d, clk_count:%d\n", __func__,
- enable, wsa881x->clk_cnt);
- mutex_lock(&wsa881x->res_lock);
- if (enable) {
- ++wsa881x->clk_cnt;
- if (wsa881x->clk_cnt == 1) {
- snd_soc_write(codec, WSA881X_CDC_RST_CTL, 0x02);
- snd_soc_write(codec, WSA881X_CDC_RST_CTL, 0x03);
- snd_soc_write(codec, WSA881X_CLOCK_CONFIG, 0x01);
- snd_soc_write(codec, WSA881X_CDC_DIG_CLK_CTL, 0x01);
- snd_soc_write(codec, WSA881X_CDC_ANA_CLK_CTL, 0x01);
- }
- } else {
- --wsa881x->clk_cnt;
- if (wsa881x->clk_cnt <= 0) {
- WARN_ON(wsa881x->clk_cnt < 0);
- wsa881x->clk_cnt = 0;
- snd_soc_write(codec, WSA881X_CDC_ANA_CLK_CTL, 0x00);
- snd_soc_write(codec, WSA881X_CDC_DIG_CLK_CTL, 0x00);
- if (WSA881X_IS_2_0(wsa881x->version))
- snd_soc_update_bits(codec,
- WSA881X_CDC_TOP_CLK_CTL, 0x01, 0x00);
- }
- }
- mutex_unlock(&wsa881x->res_lock);
-}
-
-static int wsa881x_rdac_ctrl(struct snd_soc_codec *codec, bool enable)
-{
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- pr_debug("%s: enable:%d\n", __func__, enable);
- if (enable) {
- snd_soc_update_bits(codec, WSA881X_ANA_CTL, 0x08, 0x00);
- snd_soc_update_bits(codec, WSA881X_SPKR_DRV_GAIN, 0x08, 0x08);
- snd_soc_update_bits(codec, WSA881X_SPKR_DAC_CTL, 0x20, 0x20);
- snd_soc_update_bits(codec, WSA881X_SPKR_DAC_CTL, 0x20, 0x00);
- snd_soc_update_bits(codec, WSA881X_SPKR_DAC_CTL, 0x40, 0x40);
- snd_soc_update_bits(codec, WSA881X_SPKR_DAC_CTL, 0x80, 0x80);
- if (WSA881X_IS_2_0(wsa881x->version)) {
- snd_soc_update_bits(codec, WSA881X_SPKR_BIAS_CAL,
- 0x01, 0x01);
- snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL,
- 0x30, 0x30);
- snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL,
- 0x0C, 0x00);
- }
- snd_soc_update_bits(codec, WSA881X_SPKR_DRV_GAIN, 0xF0, 0x40);
- snd_soc_update_bits(codec, WSA881X_SPKR_MISC_CTL1, 0x01, 0x01);
- } else {
- /* Ensure class-D amp is off */
- snd_soc_update_bits(codec, WSA881X_SPKR_DAC_CTL, 0x80, 0x00);
- }
- return 0;
-}
-
-static int wsa881x_spkr_pa_ctrl(struct snd_soc_codec *codec, bool enable)
-{
- int ret = 0;
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- pr_debug("%s: enable:%d\n", __func__, enable);
- if (enable) {
- /*
- * Ensure: Boost is enabled and stable, Analog input is up
- * and outputting silence
- */
- if (!WSA881X_IS_2_0(wsa881x->version)) {
- snd_soc_update_bits(codec, WSA881X_ADC_EN_DET_TEST_I,
- 0xFF, 0x01);
- snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_V,
- 0x02, 0x02);
- snd_soc_update_bits(codec, WSA881X_ADC_EN_DET_TEST_V,
- 0xFF, 0x10);
- snd_soc_update_bits(codec, WSA881X_SPKR_PWRSTG_DBG,
- 0xA0, 0xA0);
- snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN,
- 0x80, 0x80);
- usleep_range(700, 710);
- snd_soc_update_bits(codec, WSA881X_SPKR_PWRSTG_DBG,
- 0x00, 0x00);
- snd_soc_update_bits(codec, WSA881X_ADC_EN_DET_TEST_V,
- 0xFF, 0x00);
- snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_V,
- 0x02, 0x00);
- snd_soc_update_bits(codec, WSA881X_ADC_EN_DET_TEST_I,
- 0xFF, 0x00);
- } else
- snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN,
- 0x80, 0x80);
- /* add 1000us delay as per qcrg */
- usleep_range(1000, 1010);
- snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN, 0x01, 0x01);
- if (WSA881X_IS_2_0(wsa881x->version))
- snd_soc_update_bits(codec, WSA881X_SPKR_BIAS_CAL,
- 0x01, 0x00);
- usleep_range(1000, 1010);
- snd_soc_update_bits(codec, WSA881X_SPKR_DRV_GAIN, 0xF0,
- (wsa881x->spk_pa_gain << 4));
- if (wsa881x->visense_enable) {
- ret = msm_gpioset_activate(CLIENT_WSA_BONGO_1,
- "wsa_vi");
- if (ret) {
- pr_err("%s: gpio set cannot be activated %s\n",
- __func__, "wsa_vi");
- return ret;
- }
- wsa881x_visense_txfe_ctrl(codec, true,
- 0x00, 0x01, 0x00);
- wsa881x_visense_adc_ctrl(codec, true);
- }
- } else {
- /*
- * Ensure: Boost is still on, Stream from Analog input and
- * Speaker Protection has been stopped and input is at 0V
- */
- if (WSA881X_IS_2_0(wsa881x->version)) {
- snd_soc_update_bits(codec, WSA881X_SPKR_BIAS_CAL,
- 0x01, 0x01);
- usleep_range(1000, 1010);
- snd_soc_update_bits(codec, WSA881X_SPKR_BIAS_CAL,
- 0x01, 0x00);
- msleep(20);
- snd_soc_update_bits(codec, WSA881X_ANA_CTL,
- 0x03, 0x00);
- usleep_range(200, 210);
- }
- snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN, 0x80, 0x00);
- }
- return 0;
-}
-
-static int wsa881x_get_boost(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
-
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- ucontrol->value.integer.value[0] = wsa881x->boost_enable;
- return 0;
-}
-
-static int wsa881x_set_boost(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
- int value = ucontrol->value.integer.value[0];
-
- dev_dbg(codec->dev, "%s: Boost enable current %d, new %d\n",
- __func__, wsa881x->boost_enable, value);
- wsa881x->boost_enable = value;
- return 0;
-}
-
-static int wsa881x_get_visense(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
-
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- ucontrol->value.integer.value[0] = wsa881x->visense_enable;
- return 0;
-}
-
-static int wsa881x_set_visense(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
- int value = ucontrol->value.integer.value[0];
-
- dev_dbg(codec->dev, "%s: VIsense enable current %d, new %d\n",
- __func__, wsa881x->visense_enable, value);
- wsa881x->visense_enable = value;
- return 0;
-}
-
-static const struct snd_kcontrol_new wsa881x_snd_controls[] = {
- SOC_SINGLE_EXT("BOOST Switch", SND_SOC_NOPM, 0, 1, 0,
- wsa881x_get_boost, wsa881x_set_boost),
-
- SOC_SINGLE_EXT("VISENSE Switch", SND_SOC_NOPM, 0, 1, 0,
- wsa881x_get_visense, wsa881x_set_visense),
-
- SOC_ENUM_EXT("WSA_SPK PA Gain", wsa881x_spk_pa_gain_enum[0],
- wsa881x_spk_pa_gain_get, wsa881x_spk_pa_gain_put),
-};
-
-static const char * const rdac_text[] = {
- "ZERO", "Switch",
-};
-
-static const struct soc_enum rdac_enum =
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(rdac_text), rdac_text);
-
-static const struct snd_kcontrol_new rdac_mux[] = {
- SOC_DAPM_ENUM("RDAC", rdac_enum)
-};
-
-static int wsa881x_rdac_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = w->codec;
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
- int ret = 0;
-
- dev_dbg(codec->dev, "%s: %s %d boost %d visense %d\n",
- __func__, w->name, event,
- wsa881x->boost_enable, wsa881x->visense_enable);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- ret = wsa881x_startup(wsa881x);
- if (ret) {
- pr_err("%s: wsa startup failed ret: %d", __func__, ret);
- return ret;
- }
- wsa881x_clk_ctrl(codec, true);
- snd_soc_update_bits(codec, WSA881X_SPKR_DAC_CTL, 0x02, 0x02);
- if (!WSA881X_IS_2_0(wsa881x->version))
- snd_soc_update_bits(codec, WSA881X_BIAS_REF_CTRL,
- 0x0F, 0x08);
- wsa881x_bandgap_ctrl(codec, true);
- if (!WSA881X_IS_2_0(wsa881x->version))
- snd_soc_update_bits(codec, WSA881X_SPKR_BBM_CTL,
- 0x02, 0x02);
- snd_soc_update_bits(codec, WSA881X_SPKR_MISC_CTL1, 0xC0, 0x80);
- snd_soc_update_bits(codec, WSA881X_SPKR_MISC_CTL1, 0x06, 0x06);
- if (!WSA881X_IS_2_0(wsa881x->version)) {
- snd_soc_update_bits(codec, WSA881X_SPKR_MISC_CTL2,
- 0x04, 0x04);
- snd_soc_update_bits(codec, WSA881X_SPKR_BIAS_INT,
- 0x09, 0x09);
- }
- snd_soc_update_bits(codec, WSA881X_SPKR_PA_INT, 0xF0, 0x20);
- if (WSA881X_IS_2_0(wsa881x->version))
- snd_soc_update_bits(codec, WSA881X_SPKR_PA_INT,
- 0x0E, 0x0E);
- if (wsa881x->boost_enable)
- wsa881x_boost_ctrl(codec, true);
- break;
- case SND_SOC_DAPM_POST_PMU:
- wsa881x_rdac_ctrl(codec, true);
- break;
- case SND_SOC_DAPM_PRE_PMD:
- wsa881x_rdac_ctrl(codec, false);
- if (wsa881x->visense_enable) {
- wsa881x_visense_adc_ctrl(codec, false);
- wsa881x_visense_txfe_ctrl(codec, false,
- 0x00, 0x01, 0x00);
- ret = msm_gpioset_suspend(CLIENT_WSA_BONGO_1,
- "wsa_vi");
- if (ret) {
- pr_err("%s: gpio set cannot be suspended %s\n",
- __func__, "wsa_vi");
- return ret;
- }
- }
- break;
- case SND_SOC_DAPM_POST_PMD:
- if (wsa881x->boost_enable)
- wsa881x_boost_ctrl(codec, false);
- wsa881x_clk_ctrl(codec, false);
- wsa881x_bandgap_ctrl(codec, false);
- ret = wsa881x_shutdown(wsa881x);
- if (ret < 0) {
- pr_err("%s: wsa shutdown failed ret: %d",
- __func__, ret);
- return ret;
- }
- break;
- default:
- pr_err("%s: invalid event:%d\n", __func__, event);
- return -EINVAL;
- }
- return 0;
-}
-
-static void wsa881x_ocp_ctl_work(struct work_struct *work)
-{
- struct wsa881x_pdata *wsa881x;
- struct delayed_work *dwork;
- struct snd_soc_codec *codec;
- unsigned long temp_val;
-
- dwork = to_delayed_work(work);
- wsa881x = container_of(dwork, struct wsa881x_pdata, ocp_ctl_work);
-
- if (!wsa881x)
- return;
-
- codec = wsa881x->codec;
- wsa881x_get_temp(wsa881x->tz_pdata.tz_dev, &temp_val);
- dev_dbg(codec->dev, " temp = %ld\n", temp_val);
-
- if (temp_val <= WSA881X_OCP_CTL_TEMP_CELSIUS)
- snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0xC0, 0x00);
- else
- snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0xC0, 0xC0);
-
- schedule_delayed_work(&wsa881x->ocp_ctl_work,
- msecs_to_jiffies(wsa881x_ocp_poll_timer_sec * 1000));
-}
-
-static int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = w->codec;
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- pr_debug("%s: %s %d\n", __func__, w->name, event);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0xC0, 0x80);
- break;
- case SND_SOC_DAPM_POST_PMU:
- wsa881x_spkr_pa_ctrl(codec, true);
- schedule_delayed_work(&wsa881x->ocp_ctl_work,
- msecs_to_jiffies(WSA881X_OCP_CTL_TIMER_SEC * 1000));
- break;
- case SND_SOC_DAPM_PRE_PMD:
- wsa881x_spkr_pa_ctrl(codec, false);
- break;
- case SND_SOC_DAPM_POST_PMD:
- cancel_delayed_work_sync(&wsa881x->ocp_ctl_work);
- snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0xC0, 0xC0);
- break;
- default:
- pr_err("%s: invalid event:%d\n", __func__, event);
- return -EINVAL;
- }
- return 0;
-}
-
-
-static const struct snd_soc_dapm_widget wsa881x_dapm_widgets[] = {
- SND_SOC_DAPM_INPUT("WSA_IN"),
-
- SND_SOC_DAPM_DAC_E("RDAC Analog", NULL, SND_SOC_NOPM, 0, 0,
- wsa881x_rdac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MUX("WSA_RDAC", SND_SOC_NOPM, 0, 0,
- rdac_mux),
-
- SND_SOC_DAPM_PGA_S("WSA_SPKR PGA", 1, SND_SOC_NOPM, 0, 0,
- wsa881x_spkr_pa_event,
- SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_OUTPUT("WSA_SPKR"),
-};
-
-static const struct snd_soc_dapm_route wsa881x_audio_map[] = {
- {"WSA_RDAC", "Switch", "WSA_IN"},
- {"RDAC Analog", NULL, "WSA_RDAC"},
- {"WSA_SPKR PGA", NULL, "RDAC Analog"},
- {"WSA_SPKR", NULL, "WSA_SPKR PGA"},
-};
-
-
-static int wsa881x_startup(struct wsa881x_pdata *pdata)
-{
- int ret = 0;
- struct snd_soc_codec *codec = pdata->codec;
- struct snd_soc_card *card = codec->component.card;
-
- pr_debug("%s(): wsa startup, enable_cnt:%d\n", __func__,
- pdata->enable_cnt);
-
- if (pdata->enable_cnt++ > 0)
- return 0;
- ret = msm_gpioset_activate(CLIENT_WSA_BONGO_1, "wsa_clk");
- if (ret) {
- pr_err("%s: gpio set cannot be activated %s\n",
- __func__, "wsa_clk");
- return ret;
- }
- if (pdata->enable_mclk) {
- ret = pdata->enable_mclk(card, true);
- if (ret < 0) {
- dev_err_ratelimited(codec->dev,
- "%s: mclk enable failed %d\n",
- __func__, ret);
- return ret;
- }
- }
- ret = wsa881x_reset(pdata, true);
- return ret;
-}
-
-static int wsa881x_shutdown(struct wsa881x_pdata *pdata)
-{
- int ret = 0, reg;
- struct snd_soc_codec *codec = pdata->codec;
- struct snd_soc_card *card = codec->component.card;
-
- pr_debug("%s(): wsa shutdown, enable_cnt:%d\n", __func__,
- pdata->enable_cnt);
- if (--pdata->enable_cnt > 0)
- return 0;
- ret = wsa881x_reset(pdata, false);
- if (ret) {
- pr_err("%s: wsa reset failed suspend %d\n",
- __func__, ret);
- return ret;
- }
-
- if (pdata->enable_mclk) {
- ret = pdata->enable_mclk(card, false);
- if (ret < 0) {
- pr_err("%s: mclk disable failed %d\n",
- __func__, ret);
- return ret;
- }
- }
-
- ret = msm_gpioset_suspend(CLIENT_WSA_BONGO_1, "wsa_clk");
- if (ret) {
- pr_err("%s: gpio set cannot be suspended %s\n",
- __func__, "wsa_clk");
- return ret;
- }
- if (pdata->codec) {
- /* restore defaults to cache */
- for (reg = 0; reg < ARRAY_SIZE(wsa881x_ana_reg_defaults);
- reg++) {
- if (wsa881x_ana_reg_readable[reg])
- snd_soc_cache_write(pdata->codec,
- wsa881x_ana_reg_defaults[reg].reg,
- wsa881x_ana_reg_defaults[reg].def);
- }
- }
- return 0;
-}
-
-static int32_t wsa881x_resource_acquire(struct snd_soc_codec *codec,
- bool enable)
-{
- int ret = 0;
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- if (enable) {
- ret = wsa881x_startup(wsa881x);
- if (ret < 0) {
- dev_err_ratelimited(codec->dev,
- "%s: failed to startup\n", __func__);
- return ret;
- }
- }
- wsa881x_clk_ctrl(codec, enable);
- wsa881x_bandgap_ctrl(codec, enable);
- if (!enable) {
- ret = wsa881x_shutdown(wsa881x);
- if (ret < 0)
- dev_err_ratelimited(codec->dev,
- "%s: failed to shutdown\n", __func__);
- }
- return ret;
-}
-
-static int32_t wsa881x_temp_reg_read(struct snd_soc_codec *codec,
- struct wsa_temp_register *wsa_temp_reg)
-{
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
- int ret = 0;
-
- if (!wsa881x) {
- dev_err(codec->dev, "%s: wsa881x is NULL\n", __func__);
- return -EINVAL;
- }
- ret = wsa881x_resource_acquire(codec, true);
- if (ret) {
- dev_err_ratelimited(codec->dev,
- "%s: resource acquire fail\n", __func__);
- return ret;
- }
-
- if (WSA881X_IS_2_0(wsa881x->version)) {
- snd_soc_update_bits(codec, WSA881X_TADC_VALUE_CTL, 0x01, 0x00);
- wsa_temp_reg->dmeas_msb = snd_soc_read(codec, WSA881X_TEMP_MSB);
- wsa_temp_reg->dmeas_lsb = snd_soc_read(codec, WSA881X_TEMP_LSB);
- snd_soc_update_bits(codec, WSA881X_TADC_VALUE_CTL, 0x01, 0x01);
- } else {
- wsa_temp_reg->dmeas_msb = snd_soc_read(codec,
- WSA881X_TEMP_DOUT_MSB);
- wsa_temp_reg->dmeas_lsb = snd_soc_read(codec,
- WSA881X_TEMP_DOUT_LSB);
- }
- wsa_temp_reg->d1_msb = snd_soc_read(codec, WSA881X_OTP_REG_1);
- wsa_temp_reg->d1_lsb = snd_soc_read(codec, WSA881X_OTP_REG_2);
- wsa_temp_reg->d2_msb = snd_soc_read(codec, WSA881X_OTP_REG_3);
- wsa_temp_reg->d2_lsb = snd_soc_read(codec, WSA881X_OTP_REG_4);
-
- ret = wsa881x_resource_acquire(codec, false);
- if (ret)
- dev_err_ratelimited(codec->dev,
- "%s: resource release fail\n", __func__);
-
- return ret;
-}
-
-static int wsa881x_probe(struct snd_soc_codec *codec)
-{
- struct i2c_client *client;
- int ret = 0;
- int wsa881x_index = 0;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
- char *widget_name = NULL;
- struct snd_soc_card *card = codec->component.card;
- struct snd_soc_codec_conf *codec_conf = card->codec_conf;
-
- client = dev_get_drvdata(codec->dev);
- ret = wsa881x_i2c_get_client_index(client, &wsa881x_index);
- if (ret != 0) {
- dev_err(&client->dev, "%s: I2C get codec I2C\n"
- "client failed\n", __func__);
- return ret;
- }
- mutex_init(&wsa_pdata[wsa881x_index].bg_lock);
- mutex_init(&wsa_pdata[wsa881x_index].res_lock);
- snprintf(wsa_pdata[wsa881x_index].tz_pdata.name, 100, "%s",
- wsa_tz_names[wsa881x_index]);
- wsa_pdata[wsa881x_index].codec = codec;
- wsa_pdata[wsa881x_index].spk_pa_gain = SPK_GAIN_12DB;
- wsa_pdata[wsa881x_index].codec = codec;
- wsa_pdata[wsa881x_index].tz_pdata.codec = codec;
- wsa_pdata[wsa881x_index].tz_pdata.wsa_temp_reg_read =
- wsa881x_temp_reg_read;
- snd_soc_codec_set_drvdata(codec, &wsa_pdata[wsa881x_index]);
- wsa881x_init_thermal(&wsa_pdata[wsa881x_index].tz_pdata);
- INIT_DELAYED_WORK(&wsa_pdata[wsa881x_index].ocp_ctl_work,
- wsa881x_ocp_ctl_work);
-
- if (codec_conf->name_prefix) {
- widget_name = kcalloc(WIDGET_NAME_MAX_SIZE, sizeof(char),
- GFP_KERNEL);
- if (!widget_name)
- return -ENOMEM;
-
- snprintf(widget_name, WIDGET_NAME_MAX_SIZE,
- "%s WSA_SPKR", codec_conf->name_prefix);
- snd_soc_dapm_ignore_suspend(dapm, widget_name);
- snprintf(widget_name, WIDGET_NAME_MAX_SIZE,
- "%s WSA_IN", codec_conf->name_prefix);
- snd_soc_dapm_ignore_suspend(dapm, widget_name);
- kfree(widget_name);
- } else {
- snd_soc_dapm_ignore_suspend(dapm, "WSA_SPKR");
- snd_soc_dapm_ignore_suspend(dapm, "WSA_IN");
- }
-
- snd_soc_dapm_sync(dapm);
- return 0;
-}
-
-static int wsa881x_remove(struct snd_soc_codec *codec)
-{
- struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
-
- if (wsa881x->tz_pdata.tz_dev)
- wsa881x_deinit_thermal(wsa881x->tz_pdata.tz_dev);
-
- mutex_destroy(&wsa881x->bg_lock);
- mutex_destroy(&wsa881x->res_lock);
- return 0;
-}
-
-static struct snd_soc_codec_driver soc_codec_dev_wsa881x = {
- .probe = wsa881x_probe,
- .remove = wsa881x_remove,
-
- .read = wsa881x_i2c_read,
- .write = wsa881x_i2c_write,
-
- .reg_cache_size = WSA881X_CACHE_SIZE,
- .reg_cache_default = wsa881x_ana_reg_defaults,
- .reg_word_size = 1,
-
- .component_driver = {
- .controls = wsa881x_snd_controls,
- .num_controls = ARRAY_SIZE(wsa881x_snd_controls),
- .dapm_widgets = wsa881x_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(wsa881x_dapm_widgets),
- .dapm_routes = wsa881x_audio_map,
- .num_dapm_routes = ARRAY_SIZE(wsa881x_audio_map),
- },
-};
-
-static int wsa881x_reset(struct wsa881x_pdata *pdata, bool enable)
-{
- int ret = 0;
-
- /*
- * shutdown the GPIOs WSA_EN, WSA_MCLK, regulators
- * and restore defaults in soc cache when shutdown.
- * Enable regulators, GPIOs WSA_MCLK, WSA_EN when powerup.
- */
- if (enable) {
- if (pdata->wsa_active)
- return 0;
- ret = msm_gpioset_activate(CLIENT_WSA_BONGO_1, "wsa_reset");
- if (ret) {
- pr_err("%s: gpio set cannot be activated %s\n",
- __func__, "wsa_reset");
- return ret;
- }
- ret = msm_gpioset_suspend(CLIENT_WSA_BONGO_1, "wsa_reset");
- if (ret) {
- pr_err("%s: gpio set cannot be suspended(powerup) %s\n",
- __func__, "wsa_reset");
- return ret;
- }
- ret = msm_gpioset_activate(CLIENT_WSA_BONGO_1, "wsa_reset");
- if (ret) {
- pr_err("%s: gpio set cannot be activated %s\n",
- __func__, "wsa_reset");
- return ret;
- }
- pdata->wsa_active = true;
- } else {
- if (!pdata->wsa_active)
- return 0;
- ret = msm_gpioset_suspend(CLIENT_WSA_BONGO_1, "wsa_reset");
- if (ret) {
- pr_err("%s: gpio set cannot be suspended %s\n",
- __func__, "wsa_reset");
- return ret;
- }
- pdata->wsa_active = false;
- }
- return ret;
-}
-
-int wsa881x_get_client_index(void)
-{
- return wsa881x_i2c_addr;
-}
-EXPORT_SYMBOL(wsa881x_get_client_index);
-
-int wsa881x_get_probing_count(void)
-{
- return wsa881x_probing_count;
-}
-EXPORT_SYMBOL(wsa881x_get_probing_count);
-
-int wsa881x_get_presence_count(void)
-{
- return wsa881x_presence_count;
-}
-EXPORT_SYMBOL(wsa881x_get_presence_count);
-
-int wsa881x_set_mclk_callback(
- int (*enable_mclk_callback)(struct snd_soc_card *, bool))
-{
- int i;
-
- for (i = 0; i < MAX_WSA881X_DEVICE; i++) {
- if (wsa_pdata[i].status == WSA881X_STATUS_I2C)
- wsa_pdata[i].enable_mclk = enable_mclk_callback;
- }
- return 0;
-}
-EXPORT_SYMBOL(wsa881x_set_mclk_callback);
-
-static int check_wsa881x_presence(struct i2c_client *client)
-{
- int ret = 0;
- int wsa881x_index = 0;
-
- ret = wsa881x_i2c_get_client_index(client, &wsa881x_index);
- if (ret != 0) {
- dev_err(&client->dev, "%s: I2C get codec I2C\n"
- "client failed\n", __func__);
- return ret;
- }
- ret = wsa881x_i2c_read_device(&wsa_pdata[wsa881x_index],
- WSA881X_CDC_RST_CTL);
- if (ret < 0) {
- dev_err(&client->dev, "failed to read wsa881x with addr %x\n",
- client->addr);
- return ret;
- }
- ret = wsa881x_i2c_write_device(&wsa_pdata[wsa881x_index],
- WSA881X_CDC_RST_CTL, 0x01);
- if (ret < 0) {
- dev_err(&client->dev, "failed write addr %x reg:0x5 val:0x1\n",
- client->addr);
- return ret;
- }
- /* allow 20ms before trigger next write to verify WSA881x presence */
- msleep(20);
- ret = wsa881x_i2c_write_device(&wsa_pdata[wsa881x_index],
- WSA881X_CDC_RST_CTL, 0x00);
- if (ret < 0) {
- dev_err(&client->dev, "failed write addr %x reg:0x5 val:0x0\n",
- client->addr);
- return ret;
- }
- return ret;
-}
-
-static int wsa881x_populate_dt_pdata(struct device *dev)
-{
- int ret = 0;
-
- /* reading the gpio configurations from dtsi file */
- if (!pinctrl_init) {
- ret = msm_gpioset_initialize(CLIENT_WSA_BONGO_1, dev);
- if (ret < 0) {
- dev_err(dev,
- "%s: error reading dtsi files%d\n", __func__, ret);
- goto err;
- }
- pinctrl_init = true;
- }
-err:
- return ret;
-}
-
-static int wsa881x_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- int ret = 0;
- int wsa881x_index = 0;
- struct wsa881x_pdata *pdata = NULL;
-
- ret = wsa881x_i2c_get_client_index(client, &wsa881x_index);
- if (ret != 0) {
- dev_err(&client->dev, "%s: I2C get codec I2C\n"
- "client failed\n", __func__);
- return ret;
- }
-
- pdata = &wsa_pdata[wsa881x_index];
-
- if ((client->addr == WSA881X_I2C_SPK0_SLAVE1_ADDR ||
- client->addr == WSA881X_I2C_SPK1_SLAVE1_ADDR) &&
- (pdata->status == WSA881X_STATUS_PROBING))
- return ret;
-
- if (pdata->status == WSA881X_STATUS_I2C) {
- dev_dbg(&client->dev, "%s:probe for other slaves\n"
- "devices of codec I2C slave Addr = %x\n",
- __func__, client->addr);
-
- dev_dbg(&client->dev, "%s:wsa_idx = %d SLAVE = %d\n",
- __func__, wsa881x_index, WSA881X_ANALOG_SLAVE);
- pdata->regmap[WSA881X_ANALOG_SLAVE] =
- devm_regmap_init_i2c(
- client,
- &wsa881x_ana_regmap_config[WSA881X_ANALOG_SLAVE]);
- regcache_cache_bypass(pdata->regmap[WSA881X_ANALOG_SLAVE],
- true);
- if (IS_ERR(pdata->regmap[WSA881X_ANALOG_SLAVE])) {
- ret = PTR_ERR(pdata->regmap[WSA881X_ANALOG_SLAVE]);
- dev_err(&client->dev,
- "%s: regmap_init failed %d\n",
- __func__, ret);
- }
- client->dev.platform_data = pdata;
- i2c_set_clientdata(client, pdata);
- pdata->client[WSA881X_ANALOG_SLAVE] = client;
- if (pdata->version == WSA881X_2_0)
- wsa881x_update_regmap_2_0(
- pdata->regmap[WSA881X_ANALOG_SLAVE],
- WSA881X_ANALOG_SLAVE);
-
- return ret;
- } else if (pdata->status == WSA881X_STATUS_PROBING) {
- pdata->index = wsa881x_index;
- if (client->dev.of_node) {
- dev_dbg(&client->dev, "%s:Platform data\n"
- "from device tree\n", __func__);
- ret = wsa881x_populate_dt_pdata(&client->dev);
- if (ret < 0) {
- dev_err(&client->dev,
- "%s: Fail to obtain pdata from device tree\n",
- __func__);
- ret = -EINVAL;
- goto err;
- }
- client->dev.platform_data = pdata;
- } else {
- dev_dbg(&client->dev, "%s:Platform data from\n"
- "board file\n", __func__);
- pdata = client->dev.platform_data;
- }
- if (!pdata) {
- dev_dbg(&client->dev, "no platform data?\n");
- ret = -EINVAL;
- goto err;
- }
- i2c_set_clientdata(client, pdata);
- dev_set_drvdata(&client->dev, client);
-
- pdata->regmap[WSA881X_DIGITAL_SLAVE] =
- devm_regmap_init_i2c(
- client,
- &wsa881x_ana_regmap_config[WSA881X_DIGITAL_SLAVE]);
- regcache_cache_bypass(pdata->regmap[WSA881X_DIGITAL_SLAVE],
- true);
- if (IS_ERR(pdata->regmap[WSA881X_DIGITAL_SLAVE])) {
- ret = PTR_ERR(pdata->regmap[WSA881X_DIGITAL_SLAVE]);
- dev_err(&client->dev, "%s: regmap_init failed %d\n",
- __func__, ret);
- goto err;
- }
- /* bus reset sequence */
- ret = wsa881x_reset(pdata, true);
- if (ret < 0) {
- dev_err(&client->dev, "%s: WSA enable Failed %d\n",
- __func__, ret);
- goto err;
- }
- pdata->client[WSA881X_DIGITAL_SLAVE] = client;
- pdata->regmap_flag = true;
- ret = check_wsa881x_presence(client);
- if (ret < 0) {
- dev_err(&client->dev,
- "failed to ping wsa with addr:%x, ret = %d\n",
- client->addr, ret);
- wsa881x_probing_count++;
- goto err1;
- }
- pdata->version = wsa881x_i2c_read_device(pdata,
- WSA881X_CHIP_ID1);
- pr_debug("%s: wsa881x version: %d\n", __func__, pdata->version);
- if (pdata->version == WSA881X_2_0) {
- wsa881x_update_reg_defaults_2_0();
- wsa881x_update_regmap_2_0(
- pdata->regmap[WSA881X_DIGITAL_SLAVE],
- WSA881X_DIGITAL_SLAVE);
- }
- wsa881x_presence_count++;
- wsa881x_probing_count++;
- ret = snd_soc_register_codec(&client->dev,
- &soc_codec_dev_wsa881x,
- NULL, 0);
- if (ret < 0)
- goto err1;
- pdata->status = WSA881X_STATUS_I2C;
- }
-err1:
- wsa881x_reset(pdata, false);
-err:
- return 0;
-}
-
-static int wsa881x_i2c_remove(struct i2c_client *client)
-{
- struct wsa881x_pdata *wsa881x = i2c_get_clientdata(client);
-
- snd_soc_unregister_codec(&client->dev);
- i2c_set_clientdata(client, NULL);
- kfree(wsa881x);
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int wsa881x_i2c_suspend(struct device *dev)
-{
- pr_debug("%s: system suspend\n", __func__);
- return 0;
-}
-
-static int wsa881x_i2c_resume(struct device *dev)
-{
- pr_debug("%s: system resume\n", __func__);
- return 0;
-}
-
-static const struct dev_pm_ops wsa881x_i2c_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(wsa881x_i2c_suspend, wsa881x_i2c_resume)
-};
-#endif /* CONFIG_PM_SLEEP */
-
-static const struct i2c_device_id wsa881x_i2c_id[] = {
- {"wsa881x-i2c-dev", WSA881X_I2C_SPK0_SLAVE0_ADDR},
- {"wsa881x-i2c-dev", WSA881X_I2C_SPK0_SLAVE1_ADDR},
- {"wsa881x-i2c-dev", WSA881X_I2C_SPK1_SLAVE0_ADDR},
- {"wsa881x-i2c-dev", WSA881X_I2C_SPK1_SLAVE1_ADDR},
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, wsa881x_i2c_id);
-
-
-static const struct of_device_id msm_match_table[] = {
- {.compatible = "qcom,wsa881x-i2c-codec"},
- {}
-};
-MODULE_DEVICE_TABLE(of, msm_match_table);
-
-static struct i2c_driver wsa881x_codec_driver = {
- .driver = {
- .name = "wsa881x-i2c-codec",
- .owner = THIS_MODULE,
-#ifdef CONFIG_PM_SLEEP
- .pm = &wsa881x_i2c_pm_ops,
-#endif
- .of_match_table = msm_match_table,
- },
- .id_table = wsa881x_i2c_id,
- .probe = wsa881x_i2c_probe,
- .remove = wsa881x_i2c_remove,
-};
-
-static int __init wsa881x_codec_init(void)
-{
- int i = 0;
-
- for (i = 0; i < MAX_WSA881X_DEVICE; i++)
- wsa_pdata[i].status = WSA881X_STATUS_PROBING;
- return i2c_add_driver(&wsa881x_codec_driver);
-}
-module_init(wsa881x_codec_init);
-
-static void __exit wsa881x_codec_exit(void)
-{
- i2c_del_driver(&wsa881x_codec_driver);
-}
-
-module_exit(wsa881x_codec_exit);
-
-MODULE_DESCRIPTION("WSA881x Codec driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wsa881x-analog.h b/sound/soc/codecs/wsa881x-analog.h
deleted file mode 100644
index a2ef2a2..0000000
--- a/sound/soc/codecs/wsa881x-analog.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Copyright (c) 2015, 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 _WSA881X_H
-#define _WSA881X_H
-
-#include <linux/regmap.h>
-#include "wsa881x-registers-analog.h"
-#include <sound/soc.h>
-
-#define WSA881X_I2C_SPK0_SLAVE0_ADDR 0x0E
-#define WSA881X_I2C_SPK0_SLAVE1_ADDR 0x44
-#define WSA881X_I2C_SPK1_SLAVE0_ADDR 0x0F
-#define WSA881X_I2C_SPK1_SLAVE1_ADDR 0x45
-
-#define WSA881X_I2C_SPK0_SLAVE0 0
-#define WSA881X_I2C_SPK1_SLAVE0 1
-#define MAX_WSA881X_DEVICE 2
-#define WSA881X_DIGITAL_SLAVE 0
-#define WSA881X_ANALOG_SLAVE 1
-
-enum {
- WSA881X_1_X = 0,
- WSA881X_2_0,
-};
-
-#define WSA881X_IS_2_0(ver) \
- ((ver == WSA881X_2_0) ? 1 : 0)
-
-extern const u8 wsa881x_ana_reg_readable[WSA881X_CACHE_SIZE];
-extern struct reg_default wsa881x_ana_reg_defaults[WSA881X_CACHE_SIZE];
-extern struct regmap_config wsa881x_ana_regmap_config[2];
-int wsa881x_get_client_index(void);
-int wsa881x_get_probing_count(void);
-int wsa881x_get_presence_count(void);
-int wsa881x_set_mclk_callback(
- int (*enable_mclk_callback)(struct snd_soc_card *, bool));
-void wsa881x_update_reg_defaults_2_0(void);
-void wsa881x_update_regmap_2_0(struct regmap *regmap, int flag);
-
-#endif /* _WSA881X_H */
diff --git a/sound/soc/codecs/wsa881x-irq.c b/sound/soc/codecs/wsa881x-irq.c
deleted file mode 100644
index 9afbd92..0000000
--- a/sound/soc/codecs/wsa881x-irq.c
+++ /dev/null
@@ -1,610 +0,0 @@
-/* Copyright (c) 2015, 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/bitops.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/slab.h>
-#include <linux/ratelimit.h>
-#include <linux/pm_qos.h>
-#include <soc/qcom/pm.h>
-#include "wsa881x-irq.h"
-#include "wsa881x-registers-analog.h"
-
-#define BYTE_BIT_MASK(nr) (1UL << ((nr) % BITS_PER_BYTE))
-#define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE)
-
-
-#define WSA_MAX_NUM_IRQS 8
-
-#ifndef NO_IRQ
-#define NO_IRQ (-1)
-#endif
-
-static int virq_to_phyirq(
- struct wsa_resource *wsa_res, int virq);
-static int phyirq_to_virq(
- struct wsa_resource *wsa_res, int irq);
-static unsigned int wsa_irq_get_upstream_irq(
- struct wsa_resource *wsa_res);
-static void wsa_irq_put_upstream_irq(
- struct wsa_resource *wsa_res);
-static int wsa_map_irq(
- struct wsa_resource *wsa_res, int irq);
-
-static struct snd_soc_codec *ptr_codec;
-
-/**
- * wsa_set_codec() - to update codec pointer
- * @codec: codec pointer.
- *
- * To update the codec pointer, which is used to read/write
- * wsa register.
- *
- * Return: void.
- */
-void wsa_set_codec(struct snd_soc_codec *codec)
-{
- if (codec == NULL) {
- pr_err("%s: codec pointer is NULL\n", __func__);
- ptr_codec = NULL;
- return;
- }
- ptr_codec = codec;
- /* Initialize interrupt mask and level registers */
- snd_soc_write(codec, WSA881X_INTR_LEVEL, 0x8F);
- snd_soc_write(codec, WSA881X_INTR_MASK, 0x8F);
-}
-
-static void wsa_irq_lock(struct irq_data *data)
-{
- struct wsa_resource *wsa_res =
- irq_data_get_irq_chip_data(data);
-
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res pointer is NULL\n", __func__);
- return;
- }
- mutex_lock(&wsa_res->irq_lock);
-}
-
-static void wsa_irq_sync_unlock(struct irq_data *data)
-{
- struct wsa_resource *wsa_res =
- irq_data_get_irq_chip_data(data);
-
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res pointer is NULL\n", __func__);
- return;
- }
- if (wsa_res->codec == NULL) {
- pr_err("%s: codec pointer not registered\n", __func__);
- if (ptr_codec == NULL) {
- pr_err("%s: did not receive valid codec pointer\n",
- __func__);
- goto unlock;
- } else {
- wsa_res->codec = ptr_codec;
- }
- }
-
- /*
- * If there's been a change in the mask write it back
- * to the hardware.
- */
- if (wsa_res->irq_masks_cur !=
- wsa_res->irq_masks_cache) {
-
- wsa_res->irq_masks_cache =
- wsa_res->irq_masks_cur;
- snd_soc_write(wsa_res->codec,
- WSA881X_INTR_MASK,
- wsa_res->irq_masks_cur);
- }
-unlock:
- mutex_unlock(&wsa_res->irq_lock);
-}
-
-static void wsa_irq_enable(struct irq_data *data)
-{
- struct wsa_resource *wsa_res =
- irq_data_get_irq_chip_data(data);
- int wsa_irq;
-
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res pointer is NULL\n", __func__);
- return;
- }
- wsa_irq = virq_to_phyirq(wsa_res, data->irq);
- pr_debug("%s: wsa_irq = %d\n", __func__, wsa_irq);
- wsa_res->irq_masks_cur &=
- ~(BYTE_BIT_MASK(wsa_irq));
-}
-
-static void wsa_irq_disable(struct irq_data *data)
-{
- struct wsa_resource *wsa_res =
- irq_data_get_irq_chip_data(data);
- int wsa_irq;
-
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res pointer is NULL\n", __func__);
- return;
- }
- wsa_irq = virq_to_phyirq(wsa_res, data->irq);
- pr_debug("%s: wsa_irq = %d\n", __func__, wsa_irq);
- wsa_res->irq_masks_cur
- |= BYTE_BIT_MASK(wsa_irq);
-}
-
-static void wsa_irq_ack(struct irq_data *data)
-{
- int wsa_irq = 0;
- struct wsa_resource *wsa_res =
- irq_data_get_irq_chip_data(data);
-
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return;
- }
- wsa_irq = virq_to_phyirq(wsa_res, data->irq);
- pr_debug("%s: IRQ_ACK called for WCD9XXX IRQ: %d\n",
- __func__, wsa_irq);
-}
-
-static void wsa_irq_mask(struct irq_data *d)
-{
- /* do nothing but required as linux calls irq_mask without NULL check */
-}
-
-static struct irq_chip wsa_irq_chip = {
- .name = "wsa",
- .irq_bus_lock = wsa_irq_lock,
- .irq_bus_sync_unlock = wsa_irq_sync_unlock,
- .irq_disable = wsa_irq_disable,
- .irq_enable = wsa_irq_enable,
- .irq_mask = wsa_irq_mask,
- .irq_ack = wsa_irq_ack,
-};
-
-static irqreturn_t wsa_irq_thread(int irq, void *data)
-{
- struct wsa_resource *wsa_res = data;
- int i;
- u8 status;
-
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return IRQ_HANDLED;
- }
- if (wsa_res->codec == NULL) {
- pr_err("%s: codec pointer not registered\n", __func__);
- if (ptr_codec == NULL) {
- pr_err("%s: did not receive valid codec pointer\n",
- __func__);
- return IRQ_HANDLED;
- }
- wsa_res->codec = ptr_codec;
- }
- status = snd_soc_read(wsa_res->codec, WSA881X_INTR_STATUS);
- /* Apply masking */
- status &= ~wsa_res->irq_masks_cur;
-
- for (i = 0; i < wsa_res->num_irqs; i++) {
- if (status & BYTE_BIT_MASK(i)) {
- mutex_lock(&wsa_res->nested_irq_lock);
- handle_nested_irq(phyirq_to_virq(wsa_res, i));
- mutex_unlock(&wsa_res->nested_irq_lock);
- }
- }
-
- return IRQ_HANDLED;
-}
-
-/**
- * wsa_free_irq() - to free an interrupt
- * @irq: interrupt number.
- * @data: pointer to wsa resource.
- *
- * To free already requested interrupt.
- *
- * Return: void.
- */
-void wsa_free_irq(int irq, void *data)
-{
- struct wsa_resource *wsa_res = data;
-
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return;
- }
- free_irq(phyirq_to_virq(wsa_res, irq), data);
-}
-
-/**
- * wsa_enable_irq() - to enable an interrupt
- * @wsa_res: pointer to wsa resource.
- * @irq: interrupt number.
- *
- * This function is to enable an interrupt.
- *
- * Return: void.
- */
-void wsa_enable_irq(struct wsa_resource *wsa_res, int irq)
-{
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return;
- }
- enable_irq(phyirq_to_virq(wsa_res, irq));
-}
-
-/**
- * wsa_disable_irq() - to disable an interrupt
- * @wsa_res: pointer to wsa resource.
- * @irq: interrupt number.
- *
- * To disable an interrupt without waiting for executing
- * handler to complete.
- *
- * Return: void.
- */
-void wsa_disable_irq(struct wsa_resource *wsa_res, int irq)
-{
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return;
- }
- disable_irq_nosync(phyirq_to_virq(wsa_res, irq));
-}
-
-/**
- * wsa_disable_irq_sync() - to disable an interrupt
- * @wsa_res: pointer to wsa resource.
- * @irq: interrupt number.
- *
- * To disable an interrupt, wait for executing IRQ
- * handler to complete.
- *
- * Return: void.
- */
-void wsa_disable_irq_sync(
- struct wsa_resource *wsa_res, int irq)
-{
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return;
- }
- disable_irq(phyirq_to_virq(wsa_res, irq));
-}
-
-static int wsa_irq_setup_downstream_irq(struct wsa_resource *wsa_res)
-{
- int irq, virq, ret;
-
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return -EINVAL;
- }
- pr_debug("%s: enter\n", __func__);
-
- for (irq = 0; irq < wsa_res->num_irqs; irq++) {
- /* Map OF irq */
- virq = wsa_map_irq(wsa_res, irq);
- pr_debug("%s: irq %d -> %d\n", __func__, irq, virq);
- if (virq == NO_IRQ) {
- pr_err("%s, No interrupt specifier for irq %d\n",
- __func__, irq);
- return NO_IRQ;
- }
-
- ret = irq_set_chip_data(virq, wsa_res);
- if (ret) {
- pr_err("%s: Failed to configure irq %d (%d)\n",
- __func__, irq, ret);
- return ret;
- }
-
- if (wsa_res->irq_level_high[irq])
- irq_set_chip_and_handler(virq, &wsa_irq_chip,
- handle_level_irq);
- else
- irq_set_chip_and_handler(virq, &wsa_irq_chip,
- handle_edge_irq);
-
- irq_set_nested_thread(virq, 1);
- }
-
- pr_debug("%s: leave\n", __func__);
-
- return 0;
-}
-
-static int wsa_irq_init(struct wsa_resource *wsa_res)
-{
- int i, ret;
-
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return -EINVAL;
- }
- mutex_init(&wsa_res->irq_lock);
- mutex_init(&wsa_res->nested_irq_lock);
-
- wsa_res->irq = wsa_irq_get_upstream_irq(wsa_res);
- if (!wsa_res->irq) {
- pr_warn("%s: irq driver is not yet initialized\n", __func__);
- mutex_destroy(&wsa_res->irq_lock);
- mutex_destroy(&wsa_res->nested_irq_lock);
- return -EPROBE_DEFER;
- }
- pr_debug("%s: probed irq %d\n", __func__, wsa_res->irq);
-
- /* Setup downstream IRQs */
- ret = wsa_irq_setup_downstream_irq(wsa_res);
- if (ret) {
- pr_err("%s: Failed to setup downstream IRQ\n", __func__);
- goto fail_irq_init;
- }
-
- /* mask all the interrupts */
- for (i = 0; i < wsa_res->num_irqs; i++) {
- wsa_res->irq_masks_cur |= BYTE_BIT_MASK(i);
- wsa_res->irq_masks_cache |= BYTE_BIT_MASK(i);
- }
-
- ret = request_threaded_irq(wsa_res->irq, NULL, wsa_irq_thread,
- IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
- "wsa", wsa_res);
- if (ret != 0) {
- dev_err(wsa_res->dev, "Failed to request IRQ %d: %d\n",
- wsa_res->irq, ret);
- } else {
- ret = enable_irq_wake(wsa_res->irq);
- if (ret) {
- dev_err(wsa_res->dev,
- "Failed to set wake interrupt on IRQ %d: %d\n",
- wsa_res->irq, ret);
- free_irq(wsa_res->irq, wsa_res);
- }
- }
-
- if (ret)
- goto fail_irq_init;
-
- return ret;
-
-fail_irq_init:
- dev_err(wsa_res->dev,
- "%s: Failed to init wsa irq\n", __func__);
- wsa_irq_put_upstream_irq(wsa_res);
- mutex_destroy(&wsa_res->irq_lock);
- mutex_destroy(&wsa_res->nested_irq_lock);
- return ret;
-}
-
-/**
- * wsa_request_irq() - to request/register an interrupt
- * @wsa_res: pointer to wsa_resource.
- * @irq: interrupt number.
- * @handler: interrupt handler function pointer.
- * @name: interrupt name.
- * @data: device info.
- *
- * Convert physical irq to virtual irq and then
- * reguest for threaded handler.
- *
- * Return: Retuns success/failure.
- */
-int wsa_request_irq(struct wsa_resource *wsa_res,
- int irq, irq_handler_t handler,
- const char *name, void *data)
-{
- int virq;
-
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return -EINVAL;
- }
- virq = phyirq_to_virq(wsa_res, irq);
-
- /*
- * ARM needs us to explicitly flag the IRQ as valid
- * and will set them noprobe when we do so.
- */
-#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
- set_irq_flags(virq, IRQF_VALID);
-#else
- set_irq_noprobe(virq);
-#endif
-
- return request_threaded_irq(virq, NULL, handler, IRQF_TRIGGER_RISING,
- name, data);
-}
-
-/**
- * wsa_irq_exit() - to disable/clear interrupt/resources
- * @wsa_res: pointer to wsa_resource
- *
- * Disable and free the interrupts and then release resources.
- *
- * Return: void.
- */
-void wsa_irq_exit(struct wsa_resource *wsa_res)
-{
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return;
- }
- dev_dbg(wsa_res->dev, "%s: Cleaning up irq %d\n", __func__,
- wsa_res->irq);
-
- if (wsa_res->irq) {
- disable_irq_wake(wsa_res->irq);
- free_irq(wsa_res->irq, wsa_res);
- /* Release parent's of node */
- wsa_irq_put_upstream_irq(wsa_res);
- }
- mutex_destroy(&wsa_res->irq_lock);
- mutex_destroy(&wsa_res->nested_irq_lock);
-}
-
-static int phyirq_to_virq(struct wsa_resource *wsa_res, int offset)
-{
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return -EINVAL;
- }
- return irq_linear_revmap(wsa_res->domain, offset);
-}
-
-static int virq_to_phyirq(struct wsa_resource *wsa_res, int virq)
-{
- struct irq_data *irq_data = irq_get_irq_data(virq);
-
- if (unlikely(!irq_data)) {
- pr_err("%s: irq_data is NULL\n", __func__);
- return -EINVAL;
- }
- return irq_data->hwirq;
-}
-
-static unsigned int wsa_irq_get_upstream_irq(struct wsa_resource *wsa_res)
-{
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return -EINVAL;
- }
- return wsa_res->irq;
-}
-
-static void wsa_irq_put_upstream_irq(struct wsa_resource *wsa_res)
-{
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return;
- }
- /* Hold parent's of node */
- of_node_put(wsa_res->dev->of_node);
-}
-
-static int wsa_map_irq(struct wsa_resource *wsa_res, int irq)
-{
- if (wsa_res == NULL) {
- pr_err("%s: wsa_res is NULL\n", __func__);
- return -EINVAL;
- }
- return of_irq_to_resource(wsa_res->dev->of_node, irq, NULL);
-}
-
-static int wsa_irq_probe(struct platform_device *pdev)
-{
- int irq;
- struct wsa_resource *wsa_res = NULL;
- int ret = -EINVAL;
-
- irq = platform_get_irq_byname(pdev, "wsa-int");
- if (irq < 0) {
- dev_err(&pdev->dev, "%s: Couldn't find wsa-int node(%d)\n",
- __func__, irq);
- return -EINVAL;
- }
- pr_debug("%s: node %s\n", __func__, pdev->name);
- wsa_res = kzalloc(sizeof(*wsa_res), GFP_KERNEL);
- if (!wsa_res) {
- pr_err("%s: could not allocate memory\n", __func__);
- return -ENOMEM;
- }
- /*
- * wsa interrupt controller supports N to N irq mapping with
- * single cell binding with irq numbers(offsets) only.
- * Use irq_domain_simple_ops that has irq_domain_simple_map and
- * irq_domain_xlate_onetwocell.
- */
- wsa_res->dev = &pdev->dev;
- wsa_res->domain = irq_domain_add_linear(wsa_res->dev->of_node,
- WSA_MAX_NUM_IRQS, &irq_domain_simple_ops,
- wsa_res);
- if (!wsa_res->domain) {
- dev_err(&pdev->dev, "%s: domain is NULL\n", __func__);
- ret = -ENOMEM;
- goto err;
- }
- wsa_res->dev = &pdev->dev;
-
- dev_dbg(&pdev->dev, "%s: virq = %d\n", __func__, irq);
- wsa_res->irq = irq;
- wsa_res->num_irq_regs = 1;
- wsa_res->num_irqs = WSA_NUM_IRQS;
- ret = wsa_irq_init(wsa_res);
- if (ret < 0) {
- dev_err(&pdev->dev, "%s: failed to do irq init %d\n",
- __func__, ret);
- goto err;
- }
-
- return ret;
-err:
- kfree(wsa_res);
- return ret;
-}
-
-static int wsa_irq_remove(struct platform_device *pdev)
-{
- struct irq_domain *domain;
- struct wsa_resource *data;
-
- domain = irq_find_host(pdev->dev.of_node);
- if (unlikely(!domain)) {
- pr_err("%s: domain is NULL\n", __func__);
- return -EINVAL;
- }
- data = (struct wsa_resource *)domain->host_data;
- data->irq = 0;
-
- return 0;
-}
-
-static const struct of_device_id of_match[] = {
- { .compatible = "qcom,wsa-irq" },
- { }
-};
-
-static struct platform_driver wsa_irq_driver = {
- .probe = wsa_irq_probe,
- .remove = wsa_irq_remove,
- .driver = {
- .name = "wsa_intc",
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(of_match),
- },
-};
-
-static int wsa_irq_drv_init(void)
-{
- return platform_driver_register(&wsa_irq_driver);
-}
-subsys_initcall(wsa_irq_drv_init);
-
-static void wsa_irq_drv_exit(void)
-{
- platform_driver_unregister(&wsa_irq_driver);
-}
-module_exit(wsa_irq_drv_exit);
-
-MODULE_DESCRIPTION("WSA881x IRQ driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wsa881x-irq.h b/sound/soc/codecs/wsa881x-irq.h
deleted file mode 100644
index 270eb91..0000000
--- a/sound/soc/codecs/wsa881x-irq.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* Copyright (c) 2015, 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 __WSA881X_IRQ_H__
-#define __WSA881X_IRQ_H__
-
-#include <linux/irqdomain.h>
-#include <linux/interrupt.h>
-#include <sound/soc.h>
-
-/**
- * enum wsa_interrupts - wsa interrupt number
- * @WSA_INT_SAF2WAR: Temp irq interrupt, from safe state to warning state.
- * @WSA_INT_WAR2SAF: Temp irq interrupt, from warning state to safe state.
- * @WSA_INT_DISABLE: Disable Temp sensor interrupts.
- * @WSA_INT_OCP: OCP interrupt.
- * @WSA_INT_CLIP: CLIP detect interrupt.
- * @WSA_NUM_IRQS: MAX Interrupt number.
- *
- * WSA IRQ Interrupt numbers.
- */
-enum wsa_interrupts {
- WSA_INT_SAF2WAR = 0,
- WSA_INT_WAR2SAF,
- WSA_INT_DISABLE,
- WSA_INT_OCP,
- WSA_INT_CLIP,
- WSA_NUM_IRQS,
-};
-
-/**
- * struct wsa_resource - the basic wsa_resource structure
- * @irq_lock: lock used by irq_chip functions.
- * @nested_irq_lock: lock used while handling nested interrupts.
- * @irq: interrupt number.
- * @irq_masks_cur: current mask value to be written to mask registers.
- * @irq_masks_cache: cached mask value.
- * @num_irqs: number of supported interrupts.
- * @num_irq_regs: number of irq registers.
- * @parent: parent pointer.
- * @dev: device pointer.
- * @domain: irq domain pointer.
- * codec: codec pointer.
- *
- * Contains required members used in wsa irq driver.
- */
-
-struct wsa_resource {
- struct mutex irq_lock;
- struct mutex nested_irq_lock;
- unsigned int irq;
- u8 irq_masks_cur;
- u8 irq_masks_cache;
- bool irq_level_high[8];
- int num_irqs;
- int num_irq_regs;
- void *parent;
- struct device *dev;
- struct irq_domain *domain;
- struct snd_soc_codec *codec;
-};
-
-void wsa_set_codec(struct snd_soc_codec *codec);
-void wsa_free_irq(int irq, void *data);
-void wsa_enable_irq(struct wsa_resource *wsa_res, int irq);
-void wsa_disable_irq(struct wsa_resource *wsa_res, int irq);
-void wsa_disable_irq_sync(struct wsa_resource *wsa_res, int irq);
-int wsa_request_irq(struct wsa_resource *wsa_res,
- int irq, irq_handler_t handler,
- const char *name, void *data);
-
-void wsa_irq_exit(struct wsa_resource *wsa_res);
-
-#endif /* __WSA881X_IRQ_H__ */
diff --git a/sound/soc/codecs/wsa881x-registers-analog.h b/sound/soc/codecs/wsa881x-registers-analog.h
deleted file mode 100644
index a5ebf8e1..0000000
--- a/sound/soc/codecs/wsa881x-registers-analog.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/* Copyright (c) 2015, 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 WSA881X_REGISTERS_H
-#define WSA881X_REGISTERS_H
-
-#define WSA881X_DIGITAL_BASE 0x0000
-#define WSA881X_ANALOG_BASE 0x0100
-
-#define WSA881X_CHIP_ID0 (WSA881X_DIGITAL_BASE+0x0000)
-#define WSA881X_CHIP_ID1 (WSA881X_DIGITAL_BASE+0x0001)
-#define WSA881X_CHIP_ID2 (WSA881X_DIGITAL_BASE+0x0002)
-#define WSA881X_CHIP_ID3 (WSA881X_DIGITAL_BASE+0x0003)
-#define WSA881X_BUS_ID (WSA881X_DIGITAL_BASE+0x0004)
-#define WSA881X_CDC_RST_CTL (WSA881X_DIGITAL_BASE+0x0005)
-#define WSA881X_CDC_TOP_CLK_CTL (WSA881X_DIGITAL_BASE+0x0006)
-#define WSA881X_CDC_ANA_CLK_CTL (WSA881X_DIGITAL_BASE+0x0007)
-#define WSA881X_CDC_DIG_CLK_CTL (WSA881X_DIGITAL_BASE+0x0008)
-#define WSA881X_CLOCK_CONFIG (WSA881X_DIGITAL_BASE+0x0009)
-#define WSA881X_ANA_CTL (WSA881X_DIGITAL_BASE+0x000A)
-#define WSA881X_SWR_RESET_EN (WSA881X_DIGITAL_BASE+0x000B)
-#define WSA881X_RESET_CTL (WSA881X_DIGITAL_BASE+0x000C)
-#define WSA881X_TADC_VALUE_CTL (WSA881X_DIGITAL_BASE+0x000F)
-#define WSA881X_TEMP_DETECT_CTL (WSA881X_DIGITAL_BASE+0x0010)
-#define WSA881X_TEMP_MSB (WSA881X_DIGITAL_BASE+0x0011)
-#define WSA881X_TEMP_LSB (WSA881X_DIGITAL_BASE+0x0012)
-#define WSA881X_TEMP_CONFIG0 (WSA881X_DIGITAL_BASE+0x0013)
-#define WSA881X_TEMP_CONFIG1 (WSA881X_DIGITAL_BASE+0x0014)
-#define WSA881X_CDC_CLIP_CTL (WSA881X_DIGITAL_BASE+0x0015)
-#define WSA881X_SDM_PDM9_LSB (WSA881X_DIGITAL_BASE+0x0016)
-#define WSA881X_SDM_PDM9_MSB (WSA881X_DIGITAL_BASE+0x0017)
-#define WSA881X_CDC_RX_CTL (WSA881X_DIGITAL_BASE+0x0018)
-#define WSA881X_DEM_BYPASS_DATA0 (WSA881X_DIGITAL_BASE+0x0019)
-#define WSA881X_DEM_BYPASS_DATA1 (WSA881X_DIGITAL_BASE+0x001A)
-#define WSA881X_DEM_BYPASS_DATA2 (WSA881X_DIGITAL_BASE+0x001B)
-#define WSA881X_DEM_BYPASS_DATA3 (WSA881X_DIGITAL_BASE+0x001C)
-#define WSA881X_OTP_CTRL0 (WSA881X_DIGITAL_BASE+0x001D)
-#define WSA881X_OTP_CTRL1 (WSA881X_DIGITAL_BASE+0x001E)
-#define WSA881X_HDRIVE_CTL_GROUP1 (WSA881X_DIGITAL_BASE+0x001F)
-#define WSA881X_INTR_MODE (WSA881X_DIGITAL_BASE+0x0020)
-#define WSA881X_INTR_MASK (WSA881X_DIGITAL_BASE+0x0021)
-#define WSA881X_INTR_STATUS (WSA881X_DIGITAL_BASE+0x0022)
-#define WSA881X_INTR_CLEAR (WSA881X_DIGITAL_BASE+0x0023)
-#define WSA881X_INTR_LEVEL (WSA881X_DIGITAL_BASE+0x0024)
-#define WSA881X_INTR_SET (WSA881X_DIGITAL_BASE+0x0025)
-#define WSA881X_INTR_TEST (WSA881X_DIGITAL_BASE+0x0026)
-#define WSA881X_PDM_TEST_MODE (WSA881X_DIGITAL_BASE+0x0030)
-#define WSA881X_ATE_TEST_MODE (WSA881X_DIGITAL_BASE+0x0031)
-#define WSA881X_PIN_CTL_MODE (WSA881X_DIGITAL_BASE+0x0032)
-#define WSA881X_PIN_CTL_OE (WSA881X_DIGITAL_BASE+0x0033)
-#define WSA881X_PIN_WDATA_IOPAD (WSA881X_DIGITAL_BASE+0x0034)
-#define WSA881X_PIN_STATUS (WSA881X_DIGITAL_BASE+0x0035)
-#define WSA881X_DIG_DEBUG_MODE (WSA881X_DIGITAL_BASE+0x0037)
-#define WSA881X_DIG_DEBUG_SEL (WSA881X_DIGITAL_BASE+0x0038)
-#define WSA881X_DIG_DEBUG_EN (WSA881X_DIGITAL_BASE+0x0039)
-#define WSA881X_SWR_HM_TEST1 (WSA881X_DIGITAL_BASE+0x003B)
-#define WSA881X_SWR_HM_TEST2 (WSA881X_DIGITAL_BASE+0x003C)
-#define WSA881X_TEMP_DETECT_DBG_CTL (WSA881X_DIGITAL_BASE+0x003D)
-#define WSA881X_TEMP_DEBUG_MSB (WSA881X_DIGITAL_BASE+0x003E)
-#define WSA881X_TEMP_DEBUG_LSB (WSA881X_DIGITAL_BASE+0x003F)
-#define WSA881X_SAMPLE_EDGE_SEL (WSA881X_DIGITAL_BASE+0x0044)
-#define WSA881X_IOPAD_CTL (WSA881X_DIGITAL_BASE+0x0045)
-#define WSA881X_SPARE_0 (WSA881X_DIGITAL_BASE+0x0050)
-#define WSA881X_SPARE_1 (WSA881X_DIGITAL_BASE+0x0051)
-#define WSA881X_SPARE_2 (WSA881X_DIGITAL_BASE+0x0052)
-#define WSA881X_OTP_REG_0 (WSA881X_DIGITAL_BASE+0x0080)
-#define WSA881X_OTP_REG_1 (WSA881X_DIGITAL_BASE+0x0081)
-#define WSA881X_OTP_REG_2 (WSA881X_DIGITAL_BASE+0x0082)
-#define WSA881X_OTP_REG_3 (WSA881X_DIGITAL_BASE+0x0083)
-#define WSA881X_OTP_REG_4 (WSA881X_DIGITAL_BASE+0x0084)
-#define WSA881X_OTP_REG_5 (WSA881X_DIGITAL_BASE+0x0085)
-#define WSA881X_OTP_REG_6 (WSA881X_DIGITAL_BASE+0x0086)
-#define WSA881X_OTP_REG_7 (WSA881X_DIGITAL_BASE+0x0087)
-#define WSA881X_OTP_REG_8 (WSA881X_DIGITAL_BASE+0x0088)
-#define WSA881X_OTP_REG_9 (WSA881X_DIGITAL_BASE+0x0089)
-#define WSA881X_OTP_REG_10 (WSA881X_DIGITAL_BASE+0x008A)
-#define WSA881X_OTP_REG_11 (WSA881X_DIGITAL_BASE+0x008B)
-#define WSA881X_OTP_REG_12 (WSA881X_DIGITAL_BASE+0x008C)
-#define WSA881X_OTP_REG_13 (WSA881X_DIGITAL_BASE+0x008D)
-#define WSA881X_OTP_REG_14 (WSA881X_DIGITAL_BASE+0x008E)
-#define WSA881X_OTP_REG_15 (WSA881X_DIGITAL_BASE+0x008F)
-#define WSA881X_OTP_REG_16 (WSA881X_DIGITAL_BASE+0x0090)
-#define WSA881X_OTP_REG_17 (WSA881X_DIGITAL_BASE+0x0091)
-#define WSA881X_OTP_REG_18 (WSA881X_DIGITAL_BASE+0x0092)
-#define WSA881X_OTP_REG_19 (WSA881X_DIGITAL_BASE+0x0093)
-#define WSA881X_OTP_REG_20 (WSA881X_DIGITAL_BASE+0x0094)
-#define WSA881X_OTP_REG_21 (WSA881X_DIGITAL_BASE+0x0095)
-#define WSA881X_OTP_REG_22 (WSA881X_DIGITAL_BASE+0x0096)
-#define WSA881X_OTP_REG_23 (WSA881X_DIGITAL_BASE+0x0097)
-#define WSA881X_OTP_REG_24 (WSA881X_DIGITAL_BASE+0x0098)
-#define WSA881X_OTP_REG_25 (WSA881X_DIGITAL_BASE+0x0099)
-#define WSA881X_OTP_REG_26 (WSA881X_DIGITAL_BASE+0x009A)
-#define WSA881X_OTP_REG_27 (WSA881X_DIGITAL_BASE+0x009B)
-#define WSA881X_OTP_REG_28 (WSA881X_DIGITAL_BASE+0x009C)
-#define WSA881X_OTP_REG_29 (WSA881X_DIGITAL_BASE+0x009D)
-#define WSA881X_OTP_REG_30 (WSA881X_DIGITAL_BASE+0x009E)
-#define WSA881X_OTP_REG_31 (WSA881X_DIGITAL_BASE+0x009F)
-#define WSA881X_OTP_REG_32 (WSA881X_DIGITAL_BASE+0x00A0)
-#define WSA881X_OTP_REG_33 (WSA881X_DIGITAL_BASE+0x00A1)
-#define WSA881X_OTP_REG_34 (WSA881X_DIGITAL_BASE+0x00A2)
-#define WSA881X_OTP_REG_35 (WSA881X_DIGITAL_BASE+0x00A3)
-#define WSA881X_OTP_REG_36 (WSA881X_DIGITAL_BASE+0x00A4)
-#define WSA881X_OTP_REG_37 (WSA881X_DIGITAL_BASE+0x00A5)
-#define WSA881X_OTP_REG_38 (WSA881X_DIGITAL_BASE+0x00A6)
-#define WSA881X_OTP_REG_39 (WSA881X_DIGITAL_BASE+0x00A7)
-#define WSA881X_OTP_REG_40 (WSA881X_DIGITAL_BASE+0x00A8)
-#define WSA881X_OTP_REG_41 (WSA881X_DIGITAL_BASE+0x00A9)
-#define WSA881X_OTP_REG_42 (WSA881X_DIGITAL_BASE+0x00AA)
-#define WSA881X_OTP_REG_43 (WSA881X_DIGITAL_BASE+0x00AB)
-#define WSA881X_OTP_REG_44 (WSA881X_DIGITAL_BASE+0x00AC)
-#define WSA881X_OTP_REG_45 (WSA881X_DIGITAL_BASE+0x00AD)
-#define WSA881X_OTP_REG_46 (WSA881X_DIGITAL_BASE+0x00AE)
-#define WSA881X_OTP_REG_47 (WSA881X_DIGITAL_BASE+0x00AF)
-#define WSA881X_OTP_REG_48 (WSA881X_DIGITAL_BASE+0x00B0)
-#define WSA881X_OTP_REG_49 (WSA881X_DIGITAL_BASE+0x00B1)
-#define WSA881X_OTP_REG_50 (WSA881X_DIGITAL_BASE+0x00B2)
-#define WSA881X_OTP_REG_51 (WSA881X_DIGITAL_BASE+0x00B3)
-#define WSA881X_OTP_REG_52 (WSA881X_DIGITAL_BASE+0x00B4)
-#define WSA881X_OTP_REG_53 (WSA881X_DIGITAL_BASE+0x00B5)
-#define WSA881X_OTP_REG_54 (WSA881X_DIGITAL_BASE+0x00B6)
-#define WSA881X_OTP_REG_55 (WSA881X_DIGITAL_BASE+0x00B7)
-#define WSA881X_OTP_REG_56 (WSA881X_DIGITAL_BASE+0x00B8)
-#define WSA881X_OTP_REG_57 (WSA881X_DIGITAL_BASE+0x00B9)
-#define WSA881X_OTP_REG_58 (WSA881X_DIGITAL_BASE+0x00BA)
-#define WSA881X_OTP_REG_59 (WSA881X_DIGITAL_BASE+0x00BB)
-#define WSA881X_OTP_REG_60 (WSA881X_DIGITAL_BASE+0x00BC)
-#define WSA881X_OTP_REG_61 (WSA881X_DIGITAL_BASE+0x00BD)
-#define WSA881X_OTP_REG_62 (WSA881X_DIGITAL_BASE+0x00BE)
-#define WSA881X_OTP_REG_63 (WSA881X_DIGITAL_BASE+0x00BF)
-/* Analog Register address space */
-#define WSA881X_BIAS_REF_CTRL (WSA881X_ANALOG_BASE+0x0000)
-#define WSA881X_BIAS_TEST (WSA881X_ANALOG_BASE+0x0001)
-#define WSA881X_BIAS_BIAS (WSA881X_ANALOG_BASE+0x0002)
-#define WSA881X_TEMP_OP (WSA881X_ANALOG_BASE+0x0003)
-#define WSA881X_TEMP_IREF_CTRL (WSA881X_ANALOG_BASE+0x0004)
-#define WSA881X_TEMP_ISENS_CTRL (WSA881X_ANALOG_BASE+0x0005)
-#define WSA881X_TEMP_CLK_CTRL (WSA881X_ANALOG_BASE+0x0006)
-#define WSA881X_TEMP_TEST (WSA881X_ANALOG_BASE+0x0007)
-#define WSA881X_TEMP_BIAS (WSA881X_ANALOG_BASE+0x0008)
-#define WSA881X_TEMP_ADC_CTRL (WSA881X_ANALOG_BASE+0x0009)
-#define WSA881X_TEMP_DOUT_MSB (WSA881X_ANALOG_BASE+0x000A)
-#define WSA881X_TEMP_DOUT_LSB (WSA881X_ANALOG_BASE+0x000B)
-#define WSA881X_ADC_EN_MODU_V (WSA881X_ANALOG_BASE+0x0010)
-#define WSA881X_ADC_EN_MODU_I (WSA881X_ANALOG_BASE+0x0011)
-#define WSA881X_ADC_EN_DET_TEST_V (WSA881X_ANALOG_BASE+0x0012)
-#define WSA881X_ADC_EN_DET_TEST_I (WSA881X_ANALOG_BASE+0x0013)
-#define WSA881X_ADC_SEL_IBIAS (WSA881X_ANALOG_BASE+0x0014)
-#define WSA881X_ADC_EN_SEL_IBIAS (WSA881X_ANALOG_BASE+0x0015)
-#define WSA881X_SPKR_DRV_EN (WSA881X_ANALOG_BASE+0x001A)
-#define WSA881X_SPKR_DRV_GAIN (WSA881X_ANALOG_BASE+0x001B)
-#define WSA881X_SPKR_DAC_CTL (WSA881X_ANALOG_BASE+0x001C)
-#define WSA881X_SPKR_DRV_DBG (WSA881X_ANALOG_BASE+0x001D)
-#define WSA881X_SPKR_PWRSTG_DBG (WSA881X_ANALOG_BASE+0x001E)
-#define WSA881X_SPKR_OCP_CTL (WSA881X_ANALOG_BASE+0x001F)
-#define WSA881X_SPKR_CLIP_CTL (WSA881X_ANALOG_BASE+0x0020)
-#define WSA881X_SPKR_BBM_CTL (WSA881X_ANALOG_BASE+0x0021)
-#define WSA881X_SPKR_MISC_CTL1 (WSA881X_ANALOG_BASE+0x0022)
-#define WSA881X_SPKR_MISC_CTL2 (WSA881X_ANALOG_BASE+0x0023)
-#define WSA881X_SPKR_BIAS_INT (WSA881X_ANALOG_BASE+0x0024)
-#define WSA881X_SPKR_PA_INT (WSA881X_ANALOG_BASE+0x0025)
-#define WSA881X_SPKR_BIAS_CAL (WSA881X_ANALOG_BASE+0x0026)
-#define WSA881X_SPKR_BIAS_PSRR (WSA881X_ANALOG_BASE+0x0027)
-#define WSA881X_SPKR_STATUS1 (WSA881X_ANALOG_BASE+0x0028)
-#define WSA881X_SPKR_STATUS2 (WSA881X_ANALOG_BASE+0x0029)
-#define WSA881X_BOOST_EN_CTL (WSA881X_ANALOG_BASE+0x002A)
-#define WSA881X_BOOST_CURRENT_LIMIT (WSA881X_ANALOG_BASE+0x002B)
-#define WSA881X_BOOST_PS_CTL (WSA881X_ANALOG_BASE+0x002C)
-#define WSA881X_BOOST_PRESET_OUT1 (WSA881X_ANALOG_BASE+0x002D)
-#define WSA881X_BOOST_PRESET_OUT2 (WSA881X_ANALOG_BASE+0x002E)
-#define WSA881X_BOOST_FORCE_OUT (WSA881X_ANALOG_BASE+0x002F)
-#define WSA881X_BOOST_LDO_PROG (WSA881X_ANALOG_BASE+0x0030)
-#define WSA881X_BOOST_SLOPE_COMP_ISENSE_FB (WSA881X_ANALOG_BASE+0x0031)
-#define WSA881X_BOOST_RON_CTL (WSA881X_ANALOG_BASE+0x0032)
-#define WSA881X_BOOST_LOOP_STABILITY (WSA881X_ANALOG_BASE+0x0033)
-#define WSA881X_BOOST_ZX_CTL (WSA881X_ANALOG_BASE+0x0034)
-#define WSA881X_BOOST_START_CTL (WSA881X_ANALOG_BASE+0x0035)
-#define WSA881X_BOOST_MISC1_CTL (WSA881X_ANALOG_BASE+0x0036)
-#define WSA881X_BOOST_MISC2_CTL (WSA881X_ANALOG_BASE+0x0037)
-#define WSA881X_BOOST_MISC3_CTL (WSA881X_ANALOG_BASE+0x0038)
-#define WSA881X_BOOST_ATEST_CTL (WSA881X_ANALOG_BASE+0x0039)
-#define WSA881X_SPKR_PROT_FE_GAIN (WSA881X_ANALOG_BASE+0x003A)
-#define WSA881X_SPKR_PROT_FE_CM_LDO_SET (WSA881X_ANALOG_BASE+0x003B)
-#define WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1 (WSA881X_ANALOG_BASE+0x003C)
-#define WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2 (WSA881X_ANALOG_BASE+0x003D)
-#define WSA881X_SPKR_PROT_ATEST1 (WSA881X_ANALOG_BASE+0x003E)
-#define WSA881X_SPKR_PROT_ATEST2 (WSA881X_ANALOG_BASE+0x003F)
-#define WSA881X_SPKR_PROT_FE_VSENSE_VCM (WSA881X_ANALOG_BASE+0x0040)
-#define WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1 (WSA881X_ANALOG_BASE+0x0041)
-#define WSA881X_BONGO_RESRV_REG1 (WSA881X_ANALOG_BASE+0x0042)
-#define WSA881X_BONGO_RESRV_REG2 (WSA881X_ANALOG_BASE+0x0043)
-#define WSA881X_SPKR_PROT_SAR (WSA881X_ANALOG_BASE+0x0044)
-#define WSA881X_SPKR_STATUS3 (WSA881X_ANALOG_BASE+0x0045)
-
-#define WSA881X_NUM_REGISTERS (WSA881X_SPKR_STATUS3+1)
-#define WSA881X_MAX_REGISTER (WSA881X_NUM_REGISTERS-1)
-#define WSA881X_CACHE_SIZE WSA881X_NUM_REGISTERS
-#endif /* WSA881X_REGISTERS_H */
diff --git a/sound/soc/codecs/wsa881x-regmap-analog.c b/sound/soc/codecs/wsa881x-regmap-analog.c
deleted file mode 100644
index 2bc3c9e..0000000
--- a/sound/soc/codecs/wsa881x-regmap-analog.c
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- * Copyright (c) 2015, 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/regmap.h>
-#include <linux/device.h>
-#include "wsa881x-registers-analog.h"
-#include "wsa881x-analog.h"
-
-struct reg_default wsa881x_ana_reg_defaults[] = {
- {WSA881X_CHIP_ID0, 0x00},
- {WSA881X_CHIP_ID1, 0x00},
- {WSA881X_CHIP_ID2, 0x00},
- {WSA881X_CHIP_ID3, 0x02},
- {WSA881X_BUS_ID, 0x00},
- {WSA881X_CDC_RST_CTL, 0x00},
- {WSA881X_CDC_TOP_CLK_CTL, 0x03},
- {WSA881X_CDC_ANA_CLK_CTL, 0x00},
- {WSA881X_CDC_DIG_CLK_CTL, 0x00},
- {WSA881X_CLOCK_CONFIG, 0x00},
- {WSA881X_ANA_CTL, 0x08},
- {WSA881X_SWR_RESET_EN, 0x00},
- {WSA881X_TEMP_DETECT_CTL, 0x01},
- {WSA881X_TEMP_MSB, 0x00},
- {WSA881X_TEMP_LSB, 0x00},
- {WSA881X_TEMP_CONFIG0, 0x00},
- {WSA881X_TEMP_CONFIG1, 0x00},
- {WSA881X_CDC_CLIP_CTL, 0x03},
- {WSA881X_SDM_PDM9_LSB, 0x00},
- {WSA881X_SDM_PDM9_MSB, 0x00},
- {WSA881X_CDC_RX_CTL, 0x7E},
- {WSA881X_DEM_BYPASS_DATA0, 0x00},
- {WSA881X_DEM_BYPASS_DATA1, 0x00},
- {WSA881X_DEM_BYPASS_DATA2, 0x00},
- {WSA881X_DEM_BYPASS_DATA3, 0x00},
- {WSA881X_OTP_CTRL0, 0x00},
- {WSA881X_OTP_CTRL1, 0x00},
- {WSA881X_HDRIVE_CTL_GROUP1, 0x00},
- {WSA881X_INTR_MODE, 0x00},
- {WSA881X_INTR_MASK, 0x1F},
- {WSA881X_INTR_STATUS, 0x00},
- {WSA881X_INTR_CLEAR, 0x00},
- {WSA881X_INTR_LEVEL, 0x00},
- {WSA881X_INTR_SET, 0x00},
- {WSA881X_INTR_TEST, 0x00},
- {WSA881X_PDM_TEST_MODE, 0x00},
- {WSA881X_ATE_TEST_MODE, 0x00},
- {WSA881X_PIN_CTL_MODE, 0x00},
- {WSA881X_PIN_CTL_OE, 0x00},
- {WSA881X_PIN_WDATA_IOPAD, 0x00},
- {WSA881X_PIN_STATUS, 0x00},
- {WSA881X_DIG_DEBUG_MODE, 0x00},
- {WSA881X_DIG_DEBUG_SEL, 0x00},
- {WSA881X_DIG_DEBUG_EN, 0x00},
- {WSA881X_SWR_HM_TEST1, 0x08},
- {WSA881X_SWR_HM_TEST2, 0x00},
- {WSA881X_TEMP_DETECT_DBG_CTL, 0x00},
- {WSA881X_TEMP_DEBUG_MSB, 0x00},
- {WSA881X_TEMP_DEBUG_LSB, 0x00},
- {WSA881X_SAMPLE_EDGE_SEL, 0x0C},
- {WSA881X_SPARE_0, 0x00},
- {WSA881X_SPARE_1, 0x00},
- {WSA881X_SPARE_2, 0x00},
- {WSA881X_OTP_REG_0, 0x01},
- {WSA881X_OTP_REG_1, 0xFF},
- {WSA881X_OTP_REG_2, 0xC0},
- {WSA881X_OTP_REG_3, 0xFF},
- {WSA881X_OTP_REG_4, 0xC0},
- {WSA881X_OTP_REG_5, 0xFF},
- {WSA881X_OTP_REG_6, 0xFF},
- {WSA881X_OTP_REG_7, 0xFF},
- {WSA881X_OTP_REG_8, 0xFF},
- {WSA881X_OTP_REG_9, 0xFF},
- {WSA881X_OTP_REG_10, 0xFF},
- {WSA881X_OTP_REG_11, 0xFF},
- {WSA881X_OTP_REG_12, 0xFF},
- {WSA881X_OTP_REG_13, 0xFF},
- {WSA881X_OTP_REG_14, 0xFF},
- {WSA881X_OTP_REG_15, 0xFF},
- {WSA881X_OTP_REG_16, 0xFF},
- {WSA881X_OTP_REG_17, 0xFF},
- {WSA881X_OTP_REG_18, 0xFF},
- {WSA881X_OTP_REG_19, 0xFF},
- {WSA881X_OTP_REG_20, 0xFF},
- {WSA881X_OTP_REG_21, 0xFF},
- {WSA881X_OTP_REG_22, 0xFF},
- {WSA881X_OTP_REG_23, 0xFF},
- {WSA881X_OTP_REG_24, 0x03},
- {WSA881X_OTP_REG_25, 0x01},
- {WSA881X_OTP_REG_26, 0x03},
- {WSA881X_OTP_REG_27, 0x11},
- {WSA881X_OTP_REG_28, 0xFF},
- {WSA881X_OTP_REG_29, 0xFF},
- {WSA881X_OTP_REG_30, 0xFF},
- {WSA881X_OTP_REG_31, 0xFF},
- {WSA881X_OTP_REG_63, 0x40},
- /* WSA881x Analog registers */
- {WSA881X_BIAS_REF_CTRL, 0x6C},
- {WSA881X_BIAS_TEST, 0x16},
- {WSA881X_BIAS_BIAS, 0xF0},
- {WSA881X_TEMP_OP, 0x00},
- {WSA881X_TEMP_IREF_CTRL, 0x56},
- {WSA881X_TEMP_ISENS_CTRL, 0x47},
- {WSA881X_TEMP_CLK_CTRL, 0x87},
- {WSA881X_TEMP_TEST, 0x00},
- {WSA881X_TEMP_BIAS, 0x51},
- {WSA881X_TEMP_ADC_CTRL, 0x00},
- {WSA881X_TEMP_DOUT_MSB, 0x00},
- {WSA881X_TEMP_DOUT_LSB, 0x00},
- {WSA881X_ADC_EN_MODU_V, 0x00},
- {WSA881X_ADC_EN_MODU_I, 0x00},
- {WSA881X_ADC_EN_DET_TEST_V, 0x00},
- {WSA881X_ADC_EN_DET_TEST_I, 0x00},
- {WSA881X_ADC_SEL_IBIAS, 0x25},
- {WSA881X_ADC_EN_SEL_IBIAS, 0x10},
- {WSA881X_SPKR_DRV_EN, 0x74},
- {WSA881X_SPKR_DRV_GAIN, 0x01},
- {WSA881X_SPKR_DAC_CTL, 0x40},
- {WSA881X_SPKR_DRV_DBG, 0x15},
- {WSA881X_SPKR_PWRSTG_DBG, 0x00},
- {WSA881X_SPKR_OCP_CTL, 0xD4},
- {WSA881X_SPKR_CLIP_CTL, 0x90},
- {WSA881X_SPKR_BBM_CTL, 0x00},
- {WSA881X_SPKR_MISC_CTL1, 0x80},
- {WSA881X_SPKR_MISC_CTL2, 0x00},
- {WSA881X_SPKR_BIAS_INT, 0x56},
- {WSA881X_SPKR_PA_INT, 0x54},
- {WSA881X_SPKR_BIAS_CAL, 0xAC},
- {WSA881X_SPKR_BIAS_PSRR, 0x54},
- {WSA881X_SPKR_STATUS1, 0x00},
- {WSA881X_SPKR_STATUS2, 0x00},
- {WSA881X_BOOST_EN_CTL, 0x18},
- {WSA881X_BOOST_CURRENT_LIMIT, 0x7A},
- {WSA881X_BOOST_PS_CTL, 0xC0},
- {WSA881X_BOOST_PRESET_OUT1, 0x77},
- {WSA881X_BOOST_PRESET_OUT2, 0x70},
- {WSA881X_BOOST_FORCE_OUT, 0x0E},
- {WSA881X_BOOST_LDO_PROG, 0x16},
- {WSA881X_BOOST_SLOPE_COMP_ISENSE_FB, 0x71},
- {WSA881X_BOOST_RON_CTL, 0x0F},
- {WSA881X_BOOST_LOOP_STABILITY, 0xAD},
- {WSA881X_BOOST_ZX_CTL, 0x34},
- {WSA881X_BOOST_START_CTL, 0x23},
- {WSA881X_BOOST_MISC1_CTL, 0x80},
- {WSA881X_BOOST_MISC2_CTL, 0x00},
- {WSA881X_BOOST_MISC3_CTL, 0x00},
- {WSA881X_BOOST_ATEST_CTL, 0x00},
- {WSA881X_SPKR_PROT_FE_GAIN, 0x46},
- {WSA881X_SPKR_PROT_FE_CM_LDO_SET, 0x3B},
- {WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1, 0x8D},
- {WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2, 0x8D},
- {WSA881X_SPKR_PROT_ATEST1, 0x01},
- {WSA881X_SPKR_PROT_ATEST2, 0x00},
- {WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x8D},
- {WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1, 0x4D},
- {WSA881X_BONGO_RESRV_REG1, 0x00},
- {WSA881X_BONGO_RESRV_REG2, 0x00},
- {WSA881X_SPKR_PROT_SAR, 0x00},
- {WSA881X_SPKR_STATUS3, 0x00},
-};
-
-struct reg_default wsa881x_ana_reg_defaults_0[] = {
- {WSA881X_CHIP_ID0, 0x00},
- {WSA881X_CHIP_ID1, 0x00},
- {WSA881X_CHIP_ID2, 0x00},
- {WSA881X_CHIP_ID3, 0x02},
- {WSA881X_BUS_ID, 0x00},
- {WSA881X_CDC_RST_CTL, 0x00},
- {WSA881X_CDC_TOP_CLK_CTL, 0x03},
- {WSA881X_CDC_ANA_CLK_CTL, 0x00},
- {WSA881X_CDC_DIG_CLK_CTL, 0x00},
- {WSA881X_CLOCK_CONFIG, 0x00},
- {WSA881X_ANA_CTL, 0x08},
- {WSA881X_SWR_RESET_EN, 0x00},
- {WSA881X_TEMP_DETECT_CTL, 0x01},
- {WSA881X_TEMP_MSB, 0x00},
- {WSA881X_TEMP_LSB, 0x00},
- {WSA881X_TEMP_CONFIG0, 0x00},
- {WSA881X_TEMP_CONFIG1, 0x00},
- {WSA881X_CDC_CLIP_CTL, 0x03},
- {WSA881X_SDM_PDM9_LSB, 0x00},
- {WSA881X_SDM_PDM9_MSB, 0x00},
- {WSA881X_CDC_RX_CTL, 0x7E},
- {WSA881X_DEM_BYPASS_DATA0, 0x00},
- {WSA881X_DEM_BYPASS_DATA1, 0x00},
- {WSA881X_DEM_BYPASS_DATA2, 0x00},
- {WSA881X_DEM_BYPASS_DATA3, 0x00},
- {WSA881X_OTP_CTRL0, 0x00},
- {WSA881X_OTP_CTRL1, 0x00},
- {WSA881X_HDRIVE_CTL_GROUP1, 0x00},
- {WSA881X_INTR_MODE, 0x00},
- {WSA881X_INTR_MASK, 0x1F},
- {WSA881X_INTR_STATUS, 0x00},
- {WSA881X_INTR_CLEAR, 0x00},
- {WSA881X_INTR_LEVEL, 0x00},
- {WSA881X_INTR_SET, 0x00},
- {WSA881X_INTR_TEST, 0x00},
- {WSA881X_PDM_TEST_MODE, 0x00},
- {WSA881X_ATE_TEST_MODE, 0x00},
- {WSA881X_PIN_CTL_MODE, 0x00},
- {WSA881X_PIN_CTL_OE, 0x00},
- {WSA881X_PIN_WDATA_IOPAD, 0x00},
- {WSA881X_PIN_STATUS, 0x00},
- {WSA881X_DIG_DEBUG_MODE, 0x00},
- {WSA881X_DIG_DEBUG_SEL, 0x00},
- {WSA881X_DIG_DEBUG_EN, 0x00},
- {WSA881X_SWR_HM_TEST1, 0x08},
- {WSA881X_SWR_HM_TEST2, 0x00},
- {WSA881X_TEMP_DETECT_DBG_CTL, 0x00},
- {WSA881X_TEMP_DEBUG_MSB, 0x00},
- {WSA881X_TEMP_DEBUG_LSB, 0x00},
- {WSA881X_SAMPLE_EDGE_SEL, 0x0C},
- {WSA881X_SPARE_0, 0x00},
- {WSA881X_SPARE_1, 0x00},
- {WSA881X_SPARE_2, 0x00},
- {WSA881X_OTP_REG_0, 0x01},
- {WSA881X_OTP_REG_1, 0xFF},
- {WSA881X_OTP_REG_2, 0xC0},
- {WSA881X_OTP_REG_3, 0xFF},
- {WSA881X_OTP_REG_4, 0xC0},
- {WSA881X_OTP_REG_5, 0xFF},
- {WSA881X_OTP_REG_6, 0xFF},
- {WSA881X_OTP_REG_7, 0xFF},
- {WSA881X_OTP_REG_8, 0xFF},
- {WSA881X_OTP_REG_9, 0xFF},
- {WSA881X_OTP_REG_10, 0xFF},
- {WSA881X_OTP_REG_11, 0xFF},
- {WSA881X_OTP_REG_12, 0xFF},
- {WSA881X_OTP_REG_13, 0xFF},
- {WSA881X_OTP_REG_14, 0xFF},
- {WSA881X_OTP_REG_15, 0xFF},
- {WSA881X_OTP_REG_16, 0xFF},
- {WSA881X_OTP_REG_17, 0xFF},
- {WSA881X_OTP_REG_18, 0xFF},
- {WSA881X_OTP_REG_19, 0xFF},
- {WSA881X_OTP_REG_20, 0xFF},
- {WSA881X_OTP_REG_21, 0xFF},
- {WSA881X_OTP_REG_22, 0xFF},
- {WSA881X_OTP_REG_23, 0xFF},
- {WSA881X_OTP_REG_24, 0x03},
- {WSA881X_OTP_REG_25, 0x01},
- {WSA881X_OTP_REG_26, 0x03},
- {WSA881X_OTP_REG_27, 0x11},
- {WSA881X_OTP_REG_28, 0xFF},
- {WSA881X_OTP_REG_29, 0xFF},
- {WSA881X_OTP_REG_30, 0xFF},
- {WSA881X_OTP_REG_31, 0xFF},
- {WSA881X_OTP_REG_63, 0x40},
-};
-
-struct reg_default wsa881x_ana_reg_defaults_1[] = {
- {WSA881X_BIAS_REF_CTRL - WSA881X_ANALOG_BASE, 0x6C},
- {WSA881X_BIAS_TEST - WSA881X_ANALOG_BASE, 0x16},
- {WSA881X_BIAS_BIAS - WSA881X_ANALOG_BASE, 0xF0},
- {WSA881X_TEMP_OP - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_TEMP_IREF_CTRL - WSA881X_ANALOG_BASE, 0x56},
- {WSA881X_TEMP_ISENS_CTRL - WSA881X_ANALOG_BASE, 0x47},
- {WSA881X_TEMP_CLK_CTRL - WSA881X_ANALOG_BASE, 0x87},
- {WSA881X_TEMP_TEST - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_TEMP_BIAS - WSA881X_ANALOG_BASE, 0x51},
- {WSA881X_TEMP_ADC_CTRL - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_TEMP_DOUT_MSB - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_TEMP_DOUT_LSB - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_ADC_EN_MODU_V - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_ADC_EN_MODU_I - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_ADC_EN_DET_TEST_V - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_ADC_EN_DET_TEST_I - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_ADC_SEL_IBIAS - WSA881X_ANALOG_BASE, 0x25},
- {WSA881X_ADC_EN_SEL_IBIAS - WSA881X_ANALOG_BASE, 0x10},
- {WSA881X_SPKR_DRV_EN - WSA881X_ANALOG_BASE, 0x74},
- {WSA881X_SPKR_DRV_GAIN - WSA881X_ANALOG_BASE, 0x01},
- {WSA881X_SPKR_DAC_CTL - WSA881X_ANALOG_BASE, 0x40},
- {WSA881X_SPKR_DRV_DBG - WSA881X_ANALOG_BASE, 0x15},
- {WSA881X_SPKR_PWRSTG_DBG - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_SPKR_OCP_CTL - WSA881X_ANALOG_BASE, 0xD4},
- {WSA881X_SPKR_CLIP_CTL - WSA881X_ANALOG_BASE, 0x90},
- {WSA881X_SPKR_BBM_CTL - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_SPKR_MISC_CTL1 - WSA881X_ANALOG_BASE, 0x80},
- {WSA881X_SPKR_MISC_CTL2 - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_SPKR_BIAS_INT - WSA881X_ANALOG_BASE, 0x56},
- {WSA881X_SPKR_PA_INT - WSA881X_ANALOG_BASE, 0x54},
- {WSA881X_SPKR_BIAS_CAL - WSA881X_ANALOG_BASE, 0xAC},
- {WSA881X_SPKR_BIAS_PSRR - WSA881X_ANALOG_BASE, 0x54},
- {WSA881X_SPKR_STATUS1 - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_SPKR_STATUS2 - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_BOOST_EN_CTL - WSA881X_ANALOG_BASE, 0x18},
- {WSA881X_BOOST_CURRENT_LIMIT - WSA881X_ANALOG_BASE, 0x7A},
- {WSA881X_BOOST_PS_CTL - WSA881X_ANALOG_BASE, 0xC0},
- {WSA881X_BOOST_PRESET_OUT1 - WSA881X_ANALOG_BASE, 0x77},
- {WSA881X_BOOST_PRESET_OUT2 - WSA881X_ANALOG_BASE, 0x70},
- {WSA881X_BOOST_FORCE_OUT - WSA881X_ANALOG_BASE, 0x0E},
- {WSA881X_BOOST_LDO_PROG - WSA881X_ANALOG_BASE, 0x16},
- {WSA881X_BOOST_SLOPE_COMP_ISENSE_FB - WSA881X_ANALOG_BASE, 0x71},
- {WSA881X_BOOST_RON_CTL - WSA881X_ANALOG_BASE, 0x0F},
- {WSA881X_BOOST_LOOP_STABILITY - WSA881X_ANALOG_BASE, 0xAD},
- {WSA881X_BOOST_ZX_CTL - WSA881X_ANALOG_BASE, 0x34},
- {WSA881X_BOOST_START_CTL - WSA881X_ANALOG_BASE, 0x23},
- {WSA881X_BOOST_MISC1_CTL - WSA881X_ANALOG_BASE, 0x80},
- {WSA881X_BOOST_MISC2_CTL - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_BOOST_MISC3_CTL - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_BOOST_ATEST_CTL - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_SPKR_PROT_FE_GAIN - WSA881X_ANALOG_BASE, 0x46},
- {WSA881X_SPKR_PROT_FE_CM_LDO_SET - WSA881X_ANALOG_BASE, 0x3B},
- {WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1 - WSA881X_ANALOG_BASE, 0x8D},
- {WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2 - WSA881X_ANALOG_BASE, 0x8D},
- {WSA881X_SPKR_PROT_ATEST1 - WSA881X_ANALOG_BASE, 0x01},
- {WSA881X_SPKR_PROT_ATEST2 - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_SPKR_PROT_FE_VSENSE_VCM - WSA881X_ANALOG_BASE, 0x8D},
- {WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1 - WSA881X_ANALOG_BASE, 0x4D},
- {WSA881X_BONGO_RESRV_REG1 - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_BONGO_RESRV_REG2 - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_SPKR_PROT_SAR - WSA881X_ANALOG_BASE, 0x00},
- {WSA881X_SPKR_STATUS3 - WSA881X_ANALOG_BASE, 0x00},
-};
-
-struct reg_default wsa881x_rev_2_0_dig[] = {
- {WSA881X_RESET_CTL, 0x00},
- {WSA881X_TADC_VALUE_CTL, 0x01},
- {WSA881X_INTR_MASK, 0x1B},
- {WSA881X_IOPAD_CTL, 0x00},
- {WSA881X_OTP_REG_28, 0x3F},
- {WSA881X_OTP_REG_29, 0x3F},
- {WSA881X_OTP_REG_30, 0x01},
- {WSA881X_OTP_REG_31, 0x01},
-};
-
-struct reg_default wsa881x_rev_2_0_ana[] = {
- {WSA881X_TEMP_ADC_CTRL, 0x03},
- {WSA881X_ADC_SEL_IBIAS, 0x45},
- {WSA881X_SPKR_DRV_GAIN, 0xC1},
- {WSA881X_SPKR_DAC_CTL, 0x42},
- {WSA881X_SPKR_BBM_CTL, 0x02},
- {WSA881X_SPKR_MISC_CTL1, 0x40},
- {WSA881X_SPKR_MISC_CTL2, 0x07},
- {WSA881X_SPKR_BIAS_INT, 0x5F},
- {WSA881X_SPKR_BIAS_PSRR, 0x44},
- {WSA881X_BOOST_PS_CTL, 0xA0},
- {WSA881X_BOOST_PRESET_OUT1, 0xB7},
- {WSA881X_BOOST_LOOP_STABILITY, 0x8D},
- {WSA881X_SPKR_PROT_ATEST2, 0x02},
- {WSA881X_BONGO_RESRV_REG1, 0x5E},
- {WSA881X_BONGO_RESRV_REG2, 0x07},
-};
-
-struct reg_default wsa881x_rev_2_0_regmap_ana[] = {
- {WSA881X_TEMP_ADC_CTRL - WSA881X_ANALOG_BASE, 0x03},
- {WSA881X_ADC_SEL_IBIAS - WSA881X_ANALOG_BASE, 0x45},
- {WSA881X_SPKR_DRV_GAIN - WSA881X_ANALOG_BASE, 0xC1},
- {WSA881X_SPKR_DAC_CTL - WSA881X_ANALOG_BASE, 0x42},
- {WSA881X_SPKR_BBM_CTL - WSA881X_ANALOG_BASE, 0x02},
- {WSA881X_SPKR_MISC_CTL1 - WSA881X_ANALOG_BASE, 0x40},
- {WSA881X_SPKR_MISC_CTL2 - WSA881X_ANALOG_BASE, 0x07},
- {WSA881X_SPKR_BIAS_INT - WSA881X_ANALOG_BASE, 0x5F},
- {WSA881X_SPKR_BIAS_PSRR - WSA881X_ANALOG_BASE, 0x44},
- {WSA881X_BOOST_PS_CTL - WSA881X_ANALOG_BASE, 0xA0},
- {WSA881X_BOOST_PRESET_OUT1 - WSA881X_ANALOG_BASE, 0xB7},
- {WSA881X_BOOST_LOOP_STABILITY - WSA881X_ANALOG_BASE, 0x8D},
- {WSA881X_SPKR_PROT_ATEST2 - WSA881X_ANALOG_BASE, 0x02},
- {WSA881X_BONGO_RESRV_REG1 - WSA881X_ANALOG_BASE, 0x5E},
- {WSA881X_BONGO_RESRV_REG2 - WSA881X_ANALOG_BASE, 0x07},
-};
-
-/**
- * wsa881x_update_reg_defaults_2_0 - update default values of regs for v2.0
- *
- * WSA881x v2.0 has different default values for certain analog and digital
- * registers compared to v1.x. Therefore, update the values of these registers
- * with the values from tables defined above for v2.0.
- */
-void wsa881x_update_reg_defaults_2_0(void)
-{
- int i, j;
-
- for (i = 0; i < ARRAY_SIZE(wsa881x_rev_2_0_dig); i++) {
- for (j = 0; j < ARRAY_SIZE(wsa881x_ana_reg_defaults); j++)
- if (wsa881x_ana_reg_defaults[j].reg ==
- wsa881x_rev_2_0_dig[i].reg)
- wsa881x_ana_reg_defaults[j].def =
- wsa881x_rev_2_0_dig[i].def;
- }
- for (i = 0; i < ARRAY_SIZE(wsa881x_rev_2_0_ana); i++) {
- for (j = 0; j < ARRAY_SIZE(wsa881x_ana_reg_defaults); j++)
- if (wsa881x_ana_reg_defaults[j].reg ==
- wsa881x_rev_2_0_ana[i].reg)
- wsa881x_ana_reg_defaults[j].def =
- wsa881x_rev_2_0_ana[i].def;
- }
-}
-EXPORT_SYMBOL(wsa881x_update_reg_defaults_2_0);
-
-/**
- * wsa881x_update_regmap_2_0 - update regmap framework with new tables
- * @regmap: pointer to WSA881x regmap structure
- * @flag: indicates digital or analog WSA881x slave
- *
- * WSA881x v2.0 has some new registers for both analog and digital slaves.
- * Update the regmap framework with all the new registers.
- */
-void wsa881x_update_regmap_2_0(struct regmap *regmap, int flag)
-{
- u16 ret = 0;
-
- switch (flag) {
- case WSA881X_DIGITAL_SLAVE:
- ret = regmap_register_patch(regmap, wsa881x_rev_2_0_dig,
- ARRAY_SIZE(wsa881x_rev_2_0_dig));
- break;
- case WSA881X_ANALOG_SLAVE:
- ret = regmap_register_patch(regmap, wsa881x_rev_2_0_ana,
- ARRAY_SIZE(wsa881x_rev_2_0_ana));
- break;
- default:
- pr_debug("%s: unknown version", __func__);
- ret = -EINVAL;
- break;
- }
- if (ret)
- pr_err("%s: Failed to update regmap defaults ret= %d\n",
- __func__, ret);
-}
-EXPORT_SYMBOL(wsa881x_update_regmap_2_0);
-
-static bool wsa881x_readable_register(struct device *dev, unsigned int reg)
-{
- return wsa881x_ana_reg_readable[reg];
-}
-
-static bool wsa881x_volatile_register(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case WSA881X_CHIP_ID0:
- case WSA881X_CHIP_ID1:
- case WSA881X_CHIP_ID2:
- case WSA881X_CHIP_ID3:
- case WSA881X_BUS_ID:
- case WSA881X_TEMP_MSB:
- case WSA881X_TEMP_LSB:
- case WSA881X_SDM_PDM9_LSB:
- case WSA881X_SDM_PDM9_MSB:
- case WSA881X_OTP_REG_0:
- case WSA881X_OTP_REG_1:
- case WSA881X_OTP_REG_2:
- case WSA881X_OTP_REG_3:
- case WSA881X_OTP_REG_4:
- case WSA881X_OTP_REG_5:
- case WSA881X_OTP_REG_31:
- case WSA881X_TEMP_DOUT_MSB:
- case WSA881X_TEMP_DOUT_LSB:
- case WSA881X_TEMP_OP:
- case WSA881X_OTP_CTRL1:
- case WSA881X_INTR_STATUS:
- case WSA881X_ATE_TEST_MODE:
- case WSA881X_PIN_STATUS:
- case WSA881X_SWR_HM_TEST2:
- case WSA881X_SPKR_STATUS1:
- case WSA881X_SPKR_STATUS2:
- case WSA881X_SPKR_STATUS3:
- case WSA881X_SPKR_PROT_SAR:
- return true;
- default:
- return false;
- }
-}
-
-struct regmap_config wsa881x_ana_regmap_config[] = {
-{
- .reg_bits = 8,
- .val_bits = 8,
- .cache_type = REGCACHE_NONE,
- .reg_defaults = wsa881x_ana_reg_defaults_0,
- .num_reg_defaults = ARRAY_SIZE(wsa881x_ana_reg_defaults_0),
- .max_register = WSA881X_MAX_REGISTER,
- .volatile_reg = wsa881x_volatile_register,
- .readable_reg = wsa881x_readable_register,
- .reg_format_endian = REGMAP_ENDIAN_NATIVE,
- .val_format_endian = REGMAP_ENDIAN_NATIVE,
-},
-{
- .reg_bits = 8,
- .val_bits = 8,
- .cache_type = REGCACHE_NONE,
- .reg_defaults = wsa881x_ana_reg_defaults_1,
- .num_reg_defaults = ARRAY_SIZE(wsa881x_ana_reg_defaults_1),
- .max_register = WSA881X_MAX_REGISTER,
- .volatile_reg = wsa881x_volatile_register,
- .readable_reg = wsa881x_readable_register,
- .reg_format_endian = REGMAP_ENDIAN_NATIVE,
- .val_format_endian = REGMAP_ENDIAN_NATIVE,
-}
-};
diff --git a/sound/soc/codecs/wsa881x-tables-analog.c b/sound/soc/codecs/wsa881x-tables-analog.c
deleted file mode 100644
index 061ed6f..0000000
--- a/sound/soc/codecs/wsa881x-tables-analog.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (c) 2015, 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/regmap.h>
-#include <linux/device.h>
-#include "wsa881x-registers-analog.h"
-
-const u8 wsa881x_ana_reg_readable[WSA881X_CACHE_SIZE] = {
- [WSA881X_CHIP_ID0] = 1,
- [WSA881X_CHIP_ID1] = 1,
- [WSA881X_CHIP_ID2] = 1,
- [WSA881X_CHIP_ID3] = 1,
- [WSA881X_BUS_ID] = 1,
- [WSA881X_CDC_RST_CTL] = 1,
- [WSA881X_CDC_TOP_CLK_CTL] = 1,
- [WSA881X_CDC_ANA_CLK_CTL] = 1,
- [WSA881X_CDC_DIG_CLK_CTL] = 1,
- [WSA881X_CLOCK_CONFIG] = 1,
- [WSA881X_ANA_CTL] = 1,
- [WSA881X_SWR_RESET_EN] = 1,
- [WSA881X_RESET_CTL] = 1,
- [WSA881X_TADC_VALUE_CTL] = 1,
- [WSA881X_TEMP_DETECT_CTL] = 1,
- [WSA881X_TEMP_MSB] = 1,
- [WSA881X_TEMP_LSB] = 1,
- [WSA881X_TEMP_CONFIG0] = 1,
- [WSA881X_TEMP_CONFIG1] = 1,
- [WSA881X_CDC_CLIP_CTL] = 1,
- [WSA881X_SDM_PDM9_LSB] = 1,
- [WSA881X_SDM_PDM9_MSB] = 1,
- [WSA881X_CDC_RX_CTL] = 1,
- [WSA881X_DEM_BYPASS_DATA0] = 1,
- [WSA881X_DEM_BYPASS_DATA1] = 1,
- [WSA881X_DEM_BYPASS_DATA2] = 1,
- [WSA881X_DEM_BYPASS_DATA3] = 1,
- [WSA881X_OTP_CTRL0] = 1,
- [WSA881X_OTP_CTRL1] = 1,
- [WSA881X_HDRIVE_CTL_GROUP1] = 1,
- [WSA881X_INTR_MODE] = 1,
- [WSA881X_INTR_MASK] = 1,
- [WSA881X_INTR_STATUS] = 1,
- [WSA881X_INTR_CLEAR] = 1,
- [WSA881X_INTR_LEVEL] = 1,
- [WSA881X_INTR_SET] = 1,
- [WSA881X_INTR_TEST] = 1,
- [WSA881X_PDM_TEST_MODE] = 1,
- [WSA881X_ATE_TEST_MODE] = 1,
- [WSA881X_PIN_CTL_MODE] = 1,
- [WSA881X_PIN_CTL_OE] = 1,
- [WSA881X_PIN_WDATA_IOPAD] = 1,
- [WSA881X_PIN_STATUS] = 1,
- [WSA881X_DIG_DEBUG_MODE] = 1,
- [WSA881X_DIG_DEBUG_SEL] = 1,
- [WSA881X_DIG_DEBUG_EN] = 1,
- [WSA881X_SWR_HM_TEST1] = 1,
- [WSA881X_SWR_HM_TEST2] = 1,
- [WSA881X_TEMP_DETECT_DBG_CTL] = 1,
- [WSA881X_TEMP_DEBUG_MSB] = 1,
- [WSA881X_TEMP_DEBUG_LSB] = 1,
- [WSA881X_SAMPLE_EDGE_SEL] = 1,
- [WSA881X_IOPAD_CTL] = 1,
- [WSA881X_SPARE_0] = 1,
- [WSA881X_SPARE_1] = 1,
- [WSA881X_SPARE_2] = 1,
- [WSA881X_OTP_REG_0] = 1,
- [WSA881X_OTP_REG_1] = 1,
- [WSA881X_OTP_REG_2] = 1,
- [WSA881X_OTP_REG_3] = 1,
- [WSA881X_OTP_REG_4] = 1,
- [WSA881X_OTP_REG_5] = 1,
- [WSA881X_OTP_REG_6] = 1,
- [WSA881X_OTP_REG_7] = 1,
- [WSA881X_OTP_REG_8] = 1,
- [WSA881X_OTP_REG_9] = 1,
- [WSA881X_OTP_REG_10] = 1,
- [WSA881X_OTP_REG_11] = 1,
- [WSA881X_OTP_REG_12] = 1,
- [WSA881X_OTP_REG_13] = 1,
- [WSA881X_OTP_REG_14] = 1,
- [WSA881X_OTP_REG_15] = 1,
- [WSA881X_OTP_REG_16] = 1,
- [WSA881X_OTP_REG_17] = 1,
- [WSA881X_OTP_REG_18] = 1,
- [WSA881X_OTP_REG_19] = 1,
- [WSA881X_OTP_REG_20] = 1,
- [WSA881X_OTP_REG_21] = 1,
- [WSA881X_OTP_REG_22] = 1,
- [WSA881X_OTP_REG_23] = 1,
- [WSA881X_OTP_REG_24] = 1,
- [WSA881X_OTP_REG_25] = 1,
- [WSA881X_OTP_REG_26] = 1,
- [WSA881X_OTP_REG_27] = 1,
- [WSA881X_OTP_REG_28] = 1,
- [WSA881X_OTP_REG_29] = 1,
- [WSA881X_OTP_REG_30] = 1,
- [WSA881X_OTP_REG_31] = 1,
- [WSA881X_OTP_REG_63] = 1,
- /* Analog Registers */
- [WSA881X_BIAS_REF_CTRL] = 1,
- [WSA881X_BIAS_TEST] = 1,
- [WSA881X_BIAS_BIAS] = 1,
- [WSA881X_TEMP_OP] = 1,
- [WSA881X_TEMP_IREF_CTRL] = 1,
- [WSA881X_TEMP_ISENS_CTRL] = 1,
- [WSA881X_TEMP_CLK_CTRL] = 1,
- [WSA881X_TEMP_TEST] = 1,
- [WSA881X_TEMP_BIAS] = 1,
- [WSA881X_TEMP_ADC_CTRL] = 1,
- [WSA881X_TEMP_DOUT_MSB] = 1,
- [WSA881X_TEMP_DOUT_LSB] = 1,
- [WSA881X_ADC_EN_MODU_V] = 1,
- [WSA881X_ADC_EN_MODU_I] = 1,
- [WSA881X_ADC_EN_DET_TEST_V] = 1,
- [WSA881X_ADC_EN_DET_TEST_I] = 1,
- [WSA881X_ADC_SEL_IBIAS] = 1,
- [WSA881X_ADC_EN_SEL_IBIAS] = 1,
- [WSA881X_SPKR_DRV_EN] = 1,
- [WSA881X_SPKR_DRV_GAIN] = 1,
- [WSA881X_SPKR_DAC_CTL] = 1,
- [WSA881X_SPKR_DRV_DBG] = 1,
- [WSA881X_SPKR_PWRSTG_DBG] = 1,
- [WSA881X_SPKR_OCP_CTL] = 1,
- [WSA881X_SPKR_CLIP_CTL] = 1,
- [WSA881X_SPKR_BBM_CTL] = 1,
- [WSA881X_SPKR_MISC_CTL1] = 1,
- [WSA881X_SPKR_MISC_CTL2] = 1,
- [WSA881X_SPKR_BIAS_INT] = 1,
- [WSA881X_SPKR_PA_INT] = 1,
- [WSA881X_SPKR_BIAS_CAL] = 1,
- [WSA881X_SPKR_BIAS_PSRR] = 1,
- [WSA881X_SPKR_STATUS1] = 1,
- [WSA881X_SPKR_STATUS2] = 1,
- [WSA881X_BOOST_EN_CTL] = 1,
- [WSA881X_BOOST_CURRENT_LIMIT] = 1,
- [WSA881X_BOOST_PS_CTL] = 1,
- [WSA881X_BOOST_PRESET_OUT1] = 1,
- [WSA881X_BOOST_PRESET_OUT2] = 1,
- [WSA881X_BOOST_FORCE_OUT] = 1,
- [WSA881X_BOOST_LDO_PROG] = 1,
- [WSA881X_BOOST_SLOPE_COMP_ISENSE_FB] = 1,
- [WSA881X_BOOST_RON_CTL] = 1,
- [WSA881X_BOOST_LOOP_STABILITY] = 1,
- [WSA881X_BOOST_ZX_CTL] = 1,
- [WSA881X_BOOST_START_CTL] = 1,
- [WSA881X_BOOST_MISC1_CTL] = 1,
- [WSA881X_BOOST_MISC2_CTL] = 1,
- [WSA881X_BOOST_MISC3_CTL] = 1,
- [WSA881X_BOOST_ATEST_CTL] = 1,
- [WSA881X_SPKR_PROT_FE_GAIN] = 1,
- [WSA881X_SPKR_PROT_FE_CM_LDO_SET] = 1,
- [WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1] = 1,
- [WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2] = 1,
- [WSA881X_SPKR_PROT_ATEST1] = 1,
- [WSA881X_SPKR_PROT_ATEST2] = 1,
- [WSA881X_SPKR_PROT_FE_VSENSE_VCM] = 1,
- [WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1] = 1,
- [WSA881X_BONGO_RESRV_REG1] = 1,
- [WSA881X_BONGO_RESRV_REG2] = 1,
- [WSA881X_SPKR_PROT_SAR] = 1,
- [WSA881X_SPKR_STATUS3] = 1,
-};
diff --git a/sound/soc/msm/msm-audio-pinctrl.c b/sound/soc/msm/msm-audio-pinctrl.c
deleted file mode 100644
index f0fba84..0000000
--- a/sound/soc/msm/msm-audio-pinctrl.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/* Copyright (c) 2015-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/gpio.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
-#include "msm-audio-pinctrl.h"
-
-/*
- * pinctrl -- handle to query pinctrl apis
- * cdc lines -- stores pinctrl handles for pinctrl states
- * active_set -- maintain the overall pinctrl state
- */
-struct cdc_pinctrl_info {
- struct pinctrl *pinctrl;
- struct pinctrl_state **cdc_lines;
- int active_set;
-};
-
-/*
- * gpiosets -- stores all gpiosets mentioned in dtsi file
- * gpiosets_comb_names -- stores all possible gpioset combinations
- * gpioset_state -- maintains counter for each gpioset
- * gpiosets_max -- maintain the total supported gpiosets
- * gpiosets_comb_max -- maintain the total gpiosets combinations
- */
-struct cdc_gpioset_info {
- char **gpiosets;
- char **gpiosets_comb_names;
- uint8_t *gpioset_state;
- int gpiosets_max;
- int gpiosets_comb_max;
-};
-
-static struct cdc_pinctrl_info pinctrl_info[MAX_PINCTRL_CLIENT];
-static struct cdc_gpioset_info gpioset_info[MAX_PINCTRL_CLIENT];
-
-/* Finds the index for the gpio set in the dtsi file */
-int msm_get_gpioset_index(enum pinctrl_client client, char *keyword)
-{
- int i;
-
- for (i = 0; i < gpioset_info[client].gpiosets_max; i++) {
- if (!(strcmp(gpioset_info[client].gpiosets[i], keyword)))
- break;
- }
- /* Checking if the keyword is present in dtsi or not */
- if (i != gpioset_info[client].gpiosets_max)
- return i;
- else
- return -EINVAL;
-}
-
-/*
- * This function reads the following from dtsi file
- * 1. All gpio sets
- * 2. All combinations of gpio sets
- * 3. Pinctrl handles to gpio sets
- *
- * Returns error if there is
- * 1. Problem reading from dtsi file
- * 2. Memory allocation failure
- */
-int msm_gpioset_initialize(enum pinctrl_client client,
- struct device *dev)
-{
- struct pinctrl *pinctrl;
- const char *gpioset_names = "qcom,msm-gpios";
- const char *gpioset_combinations = "qcom,pinctrl-names";
- const char *gpioset_names_str = NULL;
- const char *gpioset_comb_str = NULL;
- int num_strings = 0;
- int ret = 0;
- int i = 0;
-
- pr_debug("%s\n", __func__);
- pinctrl = devm_pinctrl_get(dev);
- if (IS_ERR(pinctrl)) {
- pr_err("%s: Unable to get pinctrl handle\n",
- __func__);
- return -EINVAL;
- }
- pinctrl_info[client].pinctrl = pinctrl;
-
- /* Reading of gpio sets */
- num_strings = of_property_count_strings(dev->of_node,
- gpioset_names);
- if (num_strings < 0) {
- dev_err(dev,
- "%s: missing %s in dt node or length is incorrect\n",
- __func__, gpioset_names);
- goto err;
- }
- gpioset_info[client].gpiosets_max = num_strings;
- gpioset_info[client].gpiosets = devm_kzalloc(dev,
- gpioset_info[client].gpiosets_max *
- sizeof(char *), GFP_KERNEL);
- if (!gpioset_info[client].gpiosets) {
- dev_err(dev, "Can't allocate memory for gpio set names\n");
- ret = -ENOMEM;
- goto err;
- }
-
- for (i = 0; i < num_strings; i++) {
- ret = of_property_read_string_index(dev->of_node,
- gpioset_names, i, &gpioset_names_str);
-
- gpioset_info[client].gpiosets[i] = devm_kzalloc(dev,
- (strlen(gpioset_names_str) + 1), GFP_KERNEL);
-
- if (!gpioset_info[client].gpiosets[i]) {
- dev_err(dev, "%s: Can't allocate gpiosets[%d] data\n",
- __func__, i);
- ret = -ENOMEM;
- goto err;
- }
- strlcpy(gpioset_info[client].gpiosets[i],
- gpioset_names_str, strlen(gpioset_names_str)+1);
- gpioset_names_str = NULL;
- }
- num_strings = 0;
-
- /* Allocating memory for gpio set counter */
- gpioset_info[client].gpioset_state = devm_kzalloc(dev,
- gpioset_info[client].gpiosets_max *
- sizeof(uint8_t), GFP_KERNEL);
- if (!gpioset_info[client].gpioset_state) {
- dev_err(dev, "Can't allocate memory for gpio set counter\n");
- ret = -ENOMEM;
- goto err;
- }
-
- /* Reading of all combinations of gpio sets */
- num_strings = of_property_count_strings(dev->of_node,
- gpioset_combinations);
- if (num_strings < 0) {
- dev_err(dev,
- "%s: missing %s in dt node or length is incorrect\n",
- __func__, gpioset_combinations);
- goto err;
- }
- gpioset_info[client].gpiosets_comb_max = num_strings;
- gpioset_info[client].gpiosets_comb_names = devm_kzalloc(dev,
- num_strings * sizeof(char *), GFP_KERNEL);
- if (!gpioset_info[client].gpiosets_comb_names) {
- ret = -ENOMEM;
- goto err;
- }
-
- for (i = 0; i < gpioset_info[client].gpiosets_comb_max; i++) {
- ret = of_property_read_string_index(dev->of_node,
- gpioset_combinations, i, &gpioset_comb_str);
-
- gpioset_info[client].gpiosets_comb_names[i] = devm_kzalloc(dev,
- (strlen(gpioset_comb_str) + 1), GFP_KERNEL);
- if (!gpioset_info[client].gpiosets_comb_names[i]) {
- ret = -ENOMEM;
- goto err;
- }
-
- strlcpy(gpioset_info[client].gpiosets_comb_names[i],
- gpioset_comb_str,
- strlen(gpioset_comb_str)+1);
- pr_debug("%s: GPIO configuration %s\n",
- __func__,
- gpioset_info[client].gpiosets_comb_names[i]);
- gpioset_comb_str = NULL;
- }
-
- /* Allocating memory for handles to pinctrl states */
- pinctrl_info[client].cdc_lines = devm_kzalloc(dev,
- num_strings * sizeof(char *), GFP_KERNEL);
- if (!pinctrl_info[client].cdc_lines) {
- ret = -ENOMEM;
- goto err;
- }
-
- /* Get pinctrl handles for gpio sets in dtsi file */
- for (i = 0; i < num_strings; i++) {
- pinctrl_info[client].cdc_lines[i] = pinctrl_lookup_state(
- pinctrl,
- (const char *)gpioset_info[client].
- gpiosets_comb_names[i]);
- if (IS_ERR(pinctrl_info[client].cdc_lines[i]))
- pr_err("%s: Unable to get pinctrl handle for %s\n",
- __func__, gpioset_info[client].
- gpiosets_comb_names[i]);
- }
- goto success;
-
-err:
- /* Free up memory allocated for gpio set combinations */
- for (i = 0; i < gpioset_info[client].gpiosets_max; i++) {
- if (gpioset_info[client].gpiosets[i] != NULL) {
- devm_kfree(dev, gpioset_info[client].gpiosets[i]);
- gpioset_info[client].gpiosets[i] = NULL;
- }
- }
- if (gpioset_info[client].gpiosets != NULL) {
- devm_kfree(dev, gpioset_info[client].gpiosets);
- gpioset_info[client].gpiosets = NULL;
- }
-
- /* Free up memory allocated for gpio set combinations */
- for (i = 0; i < gpioset_info[client].gpiosets_comb_max; i++) {
- if (gpioset_info[client].gpiosets_comb_names[i] != NULL) {
- devm_kfree(dev,
- gpioset_info[client].gpiosets_comb_names[i]);
- gpioset_info[client].gpiosets_comb_names[i] = NULL;
- }
- }
- if (gpioset_info[client].gpiosets_comb_names != NULL) {
- devm_kfree(dev, gpioset_info[client].gpiosets_comb_names);
- gpioset_info[client].gpiosets_comb_names = NULL;
- }
-
- /* Free up memory allocated for handles to pinctrl states */
- if (pinctrl_info[client].cdc_lines != NULL) {
- devm_kfree(dev, pinctrl_info[client].cdc_lines);
- pinctrl_info[client].cdc_lines = NULL;
- }
-
- /* Free up memory allocated for counter of gpio sets */
- if (gpioset_info[client].gpioset_state != NULL) {
- devm_kfree(dev, gpioset_info[client].gpioset_state);
- gpioset_info[client].gpioset_state = NULL;
- }
-
-success:
- return ret;
-}
-
-int msm_gpioset_activate(enum pinctrl_client client, char *keyword)
-{
- int ret = 0;
- int gp_set = 0;
- int active_set = 0;
-
- gp_set = msm_get_gpioset_index(client, keyword);
- if (gp_set < 0) {
- pr_err("%s: gpio set name does not exist\n",
- __func__);
- return gp_set;
- }
-
- if (!gpioset_info[client].gpioset_state[gp_set]) {
- /*
- * If pinctrl pointer is not valid,
- * no need to proceed further
- */
- active_set = pinctrl_info[client].active_set;
- if (IS_ERR(pinctrl_info[client].cdc_lines[active_set]))
- return 0;
-
- pinctrl_info[client].active_set |= (1 << gp_set);
- active_set = pinctrl_info[client].active_set;
- pr_debug("%s: pinctrl.active_set: %d\n", __func__, active_set);
-
- /* Select the appropriate pinctrl state */
- ret = pinctrl_select_state(pinctrl_info[client].pinctrl,
- pinctrl_info[client].cdc_lines[active_set]);
- }
- gpioset_info[client].gpioset_state[gp_set]++;
-
- return ret;
-}
-
-int msm_gpioset_suspend(enum pinctrl_client client, char *keyword)
-{
- int ret = 0;
- int gp_set = 0;
- int active_set = 0;
-
- gp_set = msm_get_gpioset_index(client, keyword);
- if (gp_set < 0) {
- pr_err("%s: gpio set name does not exist\n",
- __func__);
- return gp_set;
- }
-
- if (gpioset_info[client].gpioset_state[gp_set] == 1) {
- pinctrl_info[client].active_set &= ~(1 << gp_set);
- /*
- * If pinctrl pointer is not valid,
- * no need to proceed further
- */
- active_set = pinctrl_info[client].active_set;
- if (IS_ERR(pinctrl_info[client].cdc_lines[active_set]))
- return -EINVAL;
-
- pr_debug("%s: pinctrl.active_set: %d\n", __func__,
- pinctrl_info[client].active_set);
- /* Select the appropriate pinctrl state */
- ret = pinctrl_select_state(pinctrl_info[client].pinctrl,
- pinctrl_info[client].cdc_lines[pinctrl_info[client].
- active_set]);
- }
- if (!(gpioset_info[client].gpioset_state[gp_set])) {
- pr_err("%s: Invalid call to de activate gpios: %d\n", __func__,
- gpioset_info[client].gpioset_state[gp_set]);
- return -EINVAL;
- }
-
- gpioset_info[client].gpioset_state[gp_set]--;
-
- return ret;
-}
diff --git a/sound/soc/msm/msm-audio-pinctrl.h b/sound/soc/msm/msm-audio-pinctrl.h
deleted file mode 100644
index ec7c6aa..0000000
--- a/sound/soc/msm/msm-audio-pinctrl.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Copyright (c) 2015-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 __MSM_AUDIO_PINCTRL_H
-#define __MSM_AUDIO_PINCTRL_H
-
-enum pinctrl_client {
- CLIENT_WCD,
- CLIENT_WSA_BONGO_1,
- CLIENT_WSA_BONGO_2,
- MAX_PINCTRL_CLIENT,
-};
-
-
-/* finds the index for the gpio set in the dtsi file */
-int msm_get_gpioset_index(enum pinctrl_client client, char *keyword);
-
-/*
- * this function reads the following from dtsi file
- * 1. all gpio sets
- * 2. all combinations of gpio sets
- * 3. pinctrl handles to gpio sets
- *
- * returns error if there is
- * 1. problem reading from dtsi file
- * 2. memory allocation failure
- */
-int msm_gpioset_initialize(enum pinctrl_client client, struct device *dev);
-
-int msm_gpioset_activate(enum pinctrl_client client, char *keyword);
-
-int msm_gpioset_suspend(enum pinctrl_client client, char *keyword);
-
-#endif /* __MSM_AUDIO_PINCTRL_H */
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index c319ccf..30a4d59 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -2496,8 +2496,21 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
.rate_min = 8000,
.rate_max = 384000,
},
+ .capture = {
+ .stream_name = "MultiMedia16 Capture",
+ .aif_name = "MM_UL16",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
.ops = &msm_fe_Multimedia_dai_ops,
- .compress_new = snd_soc_new_compress,
.name = "MultiMedia16",
.probe = fe_dai_probe,
},
diff --git a/sound/soc/msm/msm8996.c b/sound/soc/msm/msm8996.c
index 45c5479..0890037 100644
--- a/sound/soc/msm/msm8996.c
+++ b/sound/soc/msm/msm8996.c
@@ -2915,12 +2915,13 @@ static struct snd_soc_dai_link msm8996_common_dai_links[] = {
.id = MSM_FRONTEND_DAI_MULTIMEDIA15,
},
{
- .name = "MSM8996 Compress9",
- .stream_name = "Compress9",
+ .name = "MSM8996 ULL NOIRQ_2",
+ .stream_name = "MM_NOIRQ_2",
.cpu_dai_name = "MultiMedia16",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-pcm-dsp-noirq",
.dynamic = 1,
.dpcm_playback = 1,
+ .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index 222c65a..174db28 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -5312,12 +5312,13 @@ static struct snd_soc_dai_link msm_common_dai_links[] = {
.id = MSM_FRONTEND_DAI_MULTIMEDIA15,
},
{
- .name = MSM_DAILINK_NAME(Compress9),
- .stream_name = "Compress9",
+ .name = MSM_DAILINK_NAME(ULL_NOIRQ_2),
+ .stream_name = "MM_NOIRQ_2",
.cpu_dai_name = "MultiMedia16",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-pcm-dsp-noirq",
.dynamic = 1,
.dpcm_playback = 1,
+ .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
index 325d642..75a2bff 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
@@ -30,9 +30,12 @@
#include <sound/control.h>
#include <sound/q6audio-v2.h>
#include <sound/timer.h>
+#include <sound/hwdep.h>
+
#include <asm/dma.h>
#include <sound/tlv.h>
#include <sound/pcm_params.h>
+#include <sound/devdep_params.h>
#include "msm-pcm-q6-v2.h"
#include "msm-pcm-routing-v2.h"
@@ -421,6 +424,42 @@ static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return ret;
}
+
+static int msm_pcm_mmap_fd(struct snd_pcm_substream *substream,
+ struct snd_pcm_mmap_fd *mmap_fd)
+{
+ struct msm_audio *prtd;
+ struct audio_port_data *apd;
+ struct audio_buffer *ab;
+ int dir = -1;
+
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ return -EFAULT;
+ }
+
+ prtd = substream->runtime->private_data;
+ if (!prtd || !prtd->audio_client || !prtd->mmap_flag) {
+ pr_err("%s no audio client or not an mmap session\n", __func__);
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+
+ apd = prtd->audio_client->port;
+ ab = &(apd[dir].buf[0]);
+ mmap_fd->fd = ion_share_dma_buf_fd(ab->client, ab->handle);
+ if (mmap_fd->fd >= 0) {
+ mmap_fd->dir = dir;
+ mmap_fd->actual_size = ab->actual_size;
+ mmap_fd->size = ab->size;
+ }
+ return mmap_fd->fd < 0 ? -EFAULT : 0;
+}
+
static int msm_pcm_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
@@ -445,6 +484,15 @@ static int msm_pcm_ioctl(struct snd_pcm_substream *substream,
return snd_pcm_lib_ioctl(substream, cmd, arg);
}
+#ifdef CONFIG_COMPAT
+static int msm_pcm_compat_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ /* we only handle RESET which is common for both modes */
+ return msm_pcm_ioctl(substream, cmd, arg);
+}
+#endif
+
static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -994,6 +1042,101 @@ static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static int msm_pcm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ struct snd_pcm *pcm = hw->private_data;
+ struct snd_pcm_mmap_fd __user *_mmap_fd = NULL;
+ struct snd_pcm_mmap_fd mmap_fd;
+ struct snd_pcm_substream *substream = NULL;
+ int32_t dir = -1;
+
+ switch (cmd) {
+ case SNDRV_PCM_IOCTL_MMAP_DATA_FD:
+ _mmap_fd = (struct snd_pcm_mmap_fd __user *)arg;
+ if (get_user(dir, (int32_t __user *)&(_mmap_fd->dir))) {
+ pr_err("%s: error copying mmap_fd from user\n",
+ __func__);
+ ret = -EFAULT;
+ break;
+ }
+ if (dir != OUT && dir != IN) {
+ pr_err("%s invalid stream dir\n", __func__);
+ ret = -EINVAL;
+ break;
+ }
+ substream = pcm->streams[dir].substream;
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ ret = -ENODEV;
+ break;
+ }
+ pr_debug("%s : %s MMAP Data fd\n", __func__,
+ dir == 0 ? "P" : "C");
+ if (msm_pcm_mmap_fd(substream, &mmap_fd) < 0) {
+ pr_err("%s: error getting fd\n",
+ __func__);
+ ret = -EFAULT;
+ break;
+ }
+ if (put_user(mmap_fd.fd, &_mmap_fd->fd) ||
+ put_user(mmap_fd.size, &_mmap_fd->size) ||
+ put_user(mmap_fd.actual_size, &_mmap_fd->actual_size)) {
+ pr_err("%s: error copying fd\n", __func__);
+ return -EFAULT;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static int msm_pcm_hwdep_compat_ioctl(struct snd_hwdep *hw,
+ struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ /* we only support mmap fd. Handling is common in both modes */
+ return msm_pcm_hwdep_ioctl(hw, file, cmd, arg);
+}
+#else
+static int msm_pcm_hwdep_compat_ioctl(struct snd_hwdep *hw,
+ struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ return -EINVAL;
+}
+#endif
+
+static int msm_pcm_add_hwdep_dev(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_hwdep *hwdep;
+ int rc;
+ char id[] = "NOIRQ_NN";
+
+ snprintf(id, sizeof(id), "NOIRQ_%d", runtime->pcm->device);
+ pr_debug("%s: pcm dev %d\n", __func__, runtime->pcm->device);
+ rc = snd_hwdep_new(runtime->card->snd_card,
+ &id[0],
+ HWDEP_FE_BASE + runtime->pcm->device,
+ &hwdep);
+ if (!hwdep || rc < 0) {
+ pr_err("%s: hwdep intf failed to create %s - hwdep\n", __func__,
+ id);
+ return rc;
+ }
+
+ hwdep->iface = SNDRV_HWDEP_IFACE_AUDIO_BE; /* for lack of a FE iface */
+ hwdep->private_data = runtime->pcm; /* of type struct snd_pcm */
+ hwdep->ops.ioctl = msm_pcm_hwdep_ioctl;
+ hwdep->ops.ioctl_compat = msm_pcm_hwdep_compat_ioctl;
+ return 0;
+}
static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
@@ -1027,7 +1170,9 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
pr_err("%s: Could not add app type controls failed %d\n",
__func__, ret);
}
-
+ ret = msm_pcm_add_hwdep_dev(rtd);
+ if (ret)
+ pr_err("%s: Could not add hw dep node\n", __func__);
pcm->nonatomic = true;
exit:
return ret;
@@ -1040,6 +1185,9 @@ static const struct snd_pcm_ops msm_pcm_ops = {
.copy = msm_pcm_copy,
.hw_params = msm_pcm_hw_params,
.ioctl = msm_pcm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = msm_pcm_compat_ioctl,
+#endif
.trigger = msm_pcm_trigger,
.pointer = msm_pcm_pointer,
.mmap = msm_pcm_mmap,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index d67296f..ef50d92 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -1768,9 +1768,8 @@ static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol,
static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_dapm_update *update = NULL;
@@ -1810,9 +1809,8 @@ static int msm_routing_get_listen_mixer(struct snd_kcontrol *kcontrol,
static int msm_routing_put_listen_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_dapm_update *update = NULL;
@@ -1928,9 +1926,8 @@ static int msm_routing_get_voice_mixer(struct snd_kcontrol *kcontrol,
static int msm_routing_put_voice_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_dapm_update *update = NULL;
@@ -1972,9 +1969,8 @@ static int msm_routing_get_voice_stub_mixer(struct snd_kcontrol *kcontrol,
static int msm_routing_put_voice_stub_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_dapm_update *update = NULL;
@@ -2075,9 +2071,8 @@ static int msm_routing_get_switch_mixer(struct snd_kcontrol *kcontrol,
static int msm_routing_put_switch_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_dapm_update *update = NULL;
pr_debug("%s: FM Switch enable %ld\n", __func__,
@@ -2104,9 +2099,8 @@ static int msm_routing_get_hfp_switch_mixer(struct snd_kcontrol *kcontrol,
static int msm_routing_put_hfp_switch_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_dapm_update *update = NULL;
pr_debug("%s: HFP Switch enable %ld\n", __func__,
@@ -2133,9 +2127,8 @@ static int msm_routing_get_int0_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
static int msm_routing_put_int0_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_dapm_update *update = NULL;
pr_debug("%s: INT0 MI2S Switch enable %ld\n", __func__,
@@ -2162,9 +2155,8 @@ static int msm_routing_get_int4_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
static int msm_routing_put_int4_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_dapm_update *update = NULL;
pr_debug("%s: INT4 MI2S Switch enable %ld\n", __func__,
@@ -2191,9 +2183,8 @@ static int msm_routing_get_usb_switch_mixer(struct snd_kcontrol *kcontrol,
static int msm_routing_put_usb_switch_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_dapm_update *update = NULL;
pr_debug("%s: USB Switch enable %ld\n", __func__,
@@ -2220,9 +2211,8 @@ static int msm_routing_get_pri_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
static int msm_routing_put_pri_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_dapm_update *update = NULL;
pr_debug("%s: PRI MI2S Switch enable %ld\n", __func__,
@@ -2249,9 +2239,8 @@ static int msm_routing_get_sec_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
static int msm_routing_put_sec_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_dapm_update *update = NULL;
pr_debug("%s: SEC MI2S Switch enable %ld\n", __func__,
@@ -2280,9 +2269,8 @@ static int msm_routing_put_tert_mi2s_switch_mixer(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_dapm_update *update = NULL;
pr_debug("%s: TERT MI2S Switch enable %ld\n", __func__,
@@ -2311,9 +2299,8 @@ static int msm_routing_put_quat_mi2s_switch_mixer(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_dapm_update *update = NULL;
pr_debug("%s: QUAT MI2S Switch enable %ld\n", __func__,
@@ -2340,9 +2327,8 @@ static int msm_routing_get_fm_pcmrx_switch_mixer(struct snd_kcontrol *kcontrol,
static int msm_routing_put_fm_pcmrx_switch_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_dapm_update *update = NULL;
pr_debug("%s: FM Switch enable %ld\n", __func__,
@@ -3490,9 +3476,8 @@ static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int ec_ref_port_id;
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct snd_soc_dapm_update *update = NULL;
@@ -3655,6 +3640,11 @@ static const struct snd_kcontrol_new ext_ec_ref_mux_ul9 =
msm_route_ec_ref_rx_enum[0],
msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul16 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL16 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
static const struct snd_kcontrol_new ext_ec_ref_mux_ul17 =
SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL17 MUX Mux",
msm_route_ec_ref_rx_enum[0],
@@ -3684,9 +3674,8 @@ static int msm_routing_ext_ec_get(struct snd_kcontrol *kcontrol,
static int msm_routing_ext_ec_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget_list *wlist =
- dapm_kcontrol_get_wlist(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
int mux = ucontrol->value.enumerated.item[0];
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int ret = 1;
@@ -7103,6 +7092,114 @@ static const struct snd_kcontrol_new mmul8_mixer_controls[] = {
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul16_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_AUX_PCM_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new mmul9_mixer_controls[] = {
SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
@@ -11392,6 +11489,7 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL16", "MultiMedia16 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL17", "MultiMedia17 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL18", "MultiMedia18 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL19", "MultiMedia19 Capture", 0, 0, 0, 0),
@@ -12127,6 +12225,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia9 Mixer", SND_SOC_NOPM, 0, 0,
mmul9_mixer_controls, ARRAY_SIZE(mmul9_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia16 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul16_mixer_controls, ARRAY_SIZE(mmul16_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia17 Mixer", SND_SOC_NOPM, 0, 0,
mmul17_mixer_controls, ARRAY_SIZE(mmul17_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia18 Mixer", SND_SOC_NOPM, 0, 0,
@@ -12457,6 +12557,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
&ext_ec_ref_mux_ul8),
SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL9 MUX", SND_SOC_NOPM, 0, 0,
&ext_ec_ref_mux_ul9),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL16 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul16),
SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL17 MUX", SND_SOC_NOPM, 0, 0,
&ext_ec_ref_mux_ul17),
SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL18 MUX", SND_SOC_NOPM, 0, 0,
@@ -12708,6 +12810,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia8 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia16 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia5 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
{"MultiMedia5 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
{"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -13276,6 +13379,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia3 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia5 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia16 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
{"MultiMedia2 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
{"MultiMedia6 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
@@ -13294,12 +13398,15 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia3 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia5 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
+ {"MultiMedia16 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
+ {"MultiMedia16 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia1 Mixer", "TERT_AUXPCM_UL_TX", "TERT_AUX_PCM_TX"},
{"MultiMedia3 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"},
{"MultiMedia5 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"},
{"MultiMedia1 Mixer", "QUAT_AUXPCM_UL_TX", "QUAT_AUX_PCM_TX"},
{"MultiMedia3 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
{"MultiMedia5 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
+ {"MultiMedia16 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"},
{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia2 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"},
{"MultiMedia2 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
@@ -13314,9 +13421,11 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia6 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
{"MultiMedia3 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
{"MultiMedia5 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
+ {"MultiMedia16 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
{"MultiMedia6 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia3 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia5 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"MultiMedia16 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia6 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia6 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"MultiMedia6 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
@@ -13478,6 +13587,24 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia6 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
{"MultiMedia8 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
+ {"MultiMedia16 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"MultiMedia16 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"MultiMedia16 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"MultiMedia16 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"MultiMedia16 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"MultiMedia16 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"MultiMedia16 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"MultiMedia16 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+ {"MultiMedia16 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia16 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia16 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia16 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia16 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia16 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia16 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia16 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia16 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
+
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -13560,8 +13687,10 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia19 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia8 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia16 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia16 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia17 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia18 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia19 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
@@ -13577,6 +13706,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia19 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia8 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia16 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MM_UL1", NULL, "MultiMedia1 Mixer"},
{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MM_UL2", NULL, "MultiMedia2 Mixer"},
@@ -13586,6 +13716,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MM_UL6", NULL, "MultiMedia6 Mixer"},
{"MM_UL8", NULL, "MultiMedia8 Mixer"},
{"MM_UL9", NULL, "MultiMedia9 Mixer"},
+ {"MM_UL16", NULL, "MultiMedia16 Mixer"},
{"MM_UL17", NULL, "MultiMedia17 Mixer"},
{"MM_UL18", NULL, "MultiMedia18 Mixer"},
{"MM_UL19", NULL, "MultiMedia19 Mixer"},
@@ -13996,6 +14127,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MM_UL6", NULL, "AUDIO_REF_EC_UL6 MUX"},
{"MM_UL8", NULL, "AUDIO_REF_EC_UL8 MUX"},
{"MM_UL9", NULL, "AUDIO_REF_EC_UL9 MUX"},
+ {"MM_UL16", NULL, "AUDIO_REF_EC_UL16 MUX"},
{"MM_UL17", NULL, "AUDIO_REF_EC_UL17 MUX"},
{"MM_UL18", NULL, "AUDIO_REF_EC_UL18 MUX"},
{"MM_UL19", NULL, "AUDIO_REF_EC_UL19 MUX"},
diff --git a/sound/soc/msm/sdm660-ext-dai-links.c b/sound/soc/msm/sdm660-ext-dai-links.c
index 77d3875..6ff29c9 100644
--- a/sound/soc/msm/sdm660-ext-dai-links.c
+++ b/sound/soc/msm/sdm660-ext-dai-links.c
@@ -1270,10 +1270,10 @@ static struct snd_soc_dai_link msm_ext_common_fe_dai[] = {
.id = MSM_FRONTEND_DAI_MULTIMEDIA15,
},
{/* hw:x,33 */
- .name = MSM_DAILINK_NAME(Compress9),
- .stream_name = "Compress9",
+ .name = MSM_DAILINK_NAME(ULL_NOIRQ_2),
+ .stream_name = "MM_NOIRQ_2",
.cpu_dai_name = "MultiMedia16",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-pcm-dsp-noirq",
.dynamic = 1,
.dpcm_capture = 1,
.dpcm_playback = 1,
diff --git a/sound/soc/msm/sdm660-external.c b/sound/soc/msm/sdm660-external.c
index 84d1c2e..426c150 100644
--- a/sound/soc/msm/sdm660-external.c
+++ b/sound/soc/msm/sdm660-external.c
@@ -20,7 +20,6 @@
#include <sound/q6core.h>
#include <linux/qdsp6v2/audio_notifier.h>
#include "qdsp6v2/msm-pcm-routing-v2.h"
-#include "msm-audio-pinctrl.h"
#include "sdm660-common.h"
#include "sdm660-external.h"
#include "../codecs/wcd9335.h"
diff --git a/sound/soc/msm/sdm660-internal.c b/sound/soc/msm/sdm660-internal.c
index a57d6f6..4b9334b 100644
--- a/sound/soc/msm/sdm660-internal.c
+++ b/sound/soc/msm/sdm660-internal.c
@@ -2194,10 +2194,10 @@ static struct snd_soc_dai_link msm_int_dai[] = {
.id = MSM_FRONTEND_DAI_MULTIMEDIA15,
},
{/* hw:x,33 */
- .name = MSM_DAILINK_NAME(Compress9),
- .stream_name = "Compress9",
+ .name = MSM_DAILINK_NAME(ULL_NOIRQ_2),
+ .stream_name = "MM_NOIRQ_2",
.cpu_dai_name = "MultiMedia16",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-pcm-dsp-noirq",
.dynamic = 1,
.dpcm_capture = 1,
.dpcm_playback = 1,
diff --git a/sound/soc/msm/sdm845.c b/sound/soc/msm/sdm845.c
index 9248766..03a4938 100644
--- a/sound/soc/msm/sdm845.c
+++ b/sound/soc/msm/sdm845.c
@@ -495,6 +495,8 @@ static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_chs, mi2s_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_chs, mi2s_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(mi2s_rx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(mi2s_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_tx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(hifi_function, hifi_text);
static struct platform_device *spdev;
@@ -2252,7 +2254,7 @@ static int mi2s_get_sample_rate(int value)
return sample_rate;
}
-static int mi2s_get_format(int value)
+static int mi2s_auxpcm_get_format(int value)
{
int format;
@@ -2276,7 +2278,7 @@ static int mi2s_get_format(int value)
return format;
}
-static int mi2s_get_format_value(int format)
+static int mi2s_auxpcm_get_format_value(int format)
{
int value;
@@ -2441,7 +2443,7 @@ static int msm_mi2s_rx_format_get(struct snd_kcontrol *kcontrol,
return idx;
ucontrol->value.enumerated.item[0] =
- mi2s_get_format_value(mi2s_rx_cfg[idx].bit_format);
+ mi2s_auxpcm_get_format_value(mi2s_rx_cfg[idx].bit_format);
pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
idx, mi2s_rx_cfg[idx].bit_format,
@@ -2459,7 +2461,7 @@ static int msm_mi2s_rx_format_put(struct snd_kcontrol *kcontrol,
return idx;
mi2s_rx_cfg[idx].bit_format =
- mi2s_get_format(ucontrol->value.enumerated.item[0]);
+ mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]);
pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
idx, mi2s_rx_cfg[idx].bit_format,
@@ -2477,7 +2479,7 @@ static int msm_mi2s_tx_format_get(struct snd_kcontrol *kcontrol,
return idx;
ucontrol->value.enumerated.item[0] =
- mi2s_get_format_value(mi2s_tx_cfg[idx].bit_format);
+ mi2s_auxpcm_get_format_value(mi2s_tx_cfg[idx].bit_format);
pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
idx, mi2s_tx_cfg[idx].bit_format,
@@ -2495,7 +2497,7 @@ static int msm_mi2s_tx_format_put(struct snd_kcontrol *kcontrol,
return idx;
mi2s_tx_cfg[idx].bit_format =
- mi2s_get_format(ucontrol->value.enumerated.item[0]);
+ mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]);
pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
idx, mi2s_tx_cfg[idx].bit_format,
@@ -2504,6 +2506,78 @@ static int msm_mi2s_tx_format_put(struct snd_kcontrol *kcontrol,
return 0;
}
+static int msm_aux_pcm_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_auxpcm_get_format_value(aux_pcm_rx_cfg[idx].bit_format);
+
+ pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+ idx, aux_pcm_rx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_aux_pcm_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ aux_pcm_rx_cfg[idx].bit_format =
+ mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+ idx, aux_pcm_rx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_aux_pcm_tx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_auxpcm_get_format_value(aux_pcm_tx_cfg[idx].bit_format);
+
+ pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
+ idx, aux_pcm_tx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_aux_pcm_tx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ aux_pcm_tx_cfg[idx].bit_format =
+ mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
+ idx, aux_pcm_tx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
static int msm_hifi_ctrl(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
@@ -2765,6 +2839,22 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
msm_mi2s_rx_format_get, msm_mi2s_rx_format_put),
SOC_ENUM_EXT("QUAT_MI2S_TX Format", mi2s_tx_format,
msm_mi2s_tx_format_get, msm_mi2s_tx_format_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_RX Format", aux_pcm_rx_format,
+ msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_TX Format", aux_pcm_tx_format,
+ msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put),
+ SOC_ENUM_EXT("SEC_AUX_PCM_RX Format", aux_pcm_rx_format,
+ msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
+ SOC_ENUM_EXT("SEC_AUX_PCM_TX Format", aux_pcm_tx_format,
+ msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put),
+ SOC_ENUM_EXT("TERT_AUX_PCM_RX Format", aux_pcm_rx_format,
+ msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
+ SOC_ENUM_EXT("TERT_AUX_PCM_TX Format", aux_pcm_tx_format,
+ msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put),
+ SOC_ENUM_EXT("QUAT_AUX_PCM_RX Format", aux_pcm_rx_format,
+ msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
+ SOC_ENUM_EXT("QUAT_AUX_PCM_TX Format", aux_pcm_tx_format,
+ msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put),
SOC_ENUM_EXT("HiFi Function", hifi_function, msm_hifi_get,
msm_hifi_put),
};
@@ -3166,6 +3256,8 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
break;
case MSM_BACKEND_DAI_AUXPCM_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_rx_cfg[PRIM_AUX_PCM].bit_format);
rate->min = rate->max =
aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate;
channels->min = channels->max =
@@ -3173,6 +3265,8 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
break;
case MSM_BACKEND_DAI_AUXPCM_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_tx_cfg[PRIM_AUX_PCM].bit_format);
rate->min = rate->max =
aux_pcm_tx_cfg[PRIM_AUX_PCM].sample_rate;
channels->min = channels->max =
@@ -3180,6 +3274,8 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
break;
case MSM_BACKEND_DAI_SEC_AUXPCM_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_rx_cfg[SEC_AUX_PCM].bit_format);
rate->min = rate->max =
aux_pcm_rx_cfg[SEC_AUX_PCM].sample_rate;
channels->min = channels->max =
@@ -3187,6 +3283,8 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
break;
case MSM_BACKEND_DAI_SEC_AUXPCM_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_tx_cfg[SEC_AUX_PCM].bit_format);
rate->min = rate->max =
aux_pcm_tx_cfg[SEC_AUX_PCM].sample_rate;
channels->min = channels->max =
@@ -3194,6 +3292,8 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
break;
case MSM_BACKEND_DAI_TERT_AUXPCM_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_rx_cfg[TERT_AUX_PCM].bit_format);
rate->min = rate->max =
aux_pcm_rx_cfg[TERT_AUX_PCM].sample_rate;
channels->min = channels->max =
@@ -3201,6 +3301,8 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
break;
case MSM_BACKEND_DAI_TERT_AUXPCM_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_tx_cfg[TERT_AUX_PCM].bit_format);
rate->min = rate->max =
aux_pcm_tx_cfg[TERT_AUX_PCM].sample_rate;
channels->min = channels->max =
@@ -3208,6 +3310,8 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
break;
case MSM_BACKEND_DAI_QUAT_AUXPCM_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_rx_cfg[QUAT_AUX_PCM].bit_format);
rate->min = rate->max =
aux_pcm_rx_cfg[QUAT_AUX_PCM].sample_rate;
channels->min = channels->max =
@@ -3215,6 +3319,8 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
break;
case MSM_BACKEND_DAI_QUAT_AUXPCM_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_tx_cfg[QUAT_AUX_PCM].bit_format);
rate->min = rate->max =
aux_pcm_tx_cfg[QUAT_AUX_PCM].sample_rate;
channels->min = channels->max =
@@ -5219,12 +5325,13 @@ static struct snd_soc_dai_link msm_common_dai_links[] = {
.id = MSM_FRONTEND_DAI_MULTIMEDIA15,
},
{
- .name = MSM_DAILINK_NAME(Compress9),
- .stream_name = "Compress9",
+ .name = MSM_DAILINK_NAME(ULL_NOIRQ_2),
+ .stream_name = "MM_NOIRQ_2",
.cpu_dai_name = "MultiMedia16",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-pcm-dsp-noirq",
.dynamic = 1,
.dpcm_playback = 1,
+ .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 94ea909..d40bfef 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -423,14 +423,13 @@ static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
kfree(data);
}
-struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
+static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
const struct snd_kcontrol *kcontrol)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
return data->wlist;
}
-EXPORT_SYMBOL(dapm_kcontrol_get_wlist);
static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_widget *widget)
diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h
index e33fc1d..d94179f 100644
--- a/tools/include/linux/compiler.h
+++ b/tools/include/linux/compiler.h
@@ -126,4 +126,13 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
#define WRITE_ONCE(x, val) \
({ union { typeof(x) __val; char __c[1]; } __u = { .__val = (val) }; __write_once_size(&(x), __u.__c, sizeof(x)); __u.__val; })
+
+#ifndef __fallthrough
+# if defined(__GNUC__) && __GNUC__ >= 7
+# define __fallthrough __attribute__ ((fallthrough))
+# else
+# define __fallthrough
+# endif
+#endif
+
#endif /* _TOOLS_LINUX_COMPILER_H */
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
index 8efe904..9e5a02d 100644
--- a/tools/perf/bench/numa.c
+++ b/tools/perf/bench/numa.c
@@ -1573,13 +1573,13 @@ static int __bench_numa(const char *name)
"GB/sec,", "total-speed", "GB/sec total speed");
if (g->p.show_details >= 2) {
- char tname[32];
+ char tname[14 + 2 * 10 + 1];
struct thread_data *td;
for (p = 0; p < g->p.nr_proc; p++) {
for (t = 0; t < g->p.nr_threads; t++) {
- memset(tname, 0, 32);
+ memset(tname, 0, sizeof(tname));
td = g->threads + p*g->p.nr_threads + t;
- snprintf(tname, 32, "process%d:thread%d", p, t);
+ snprintf(tname, sizeof(tname), "process%d:thread%d", p, t);
print_res(tname, td->speed_gbs,
"GB/sec", "thread-speed", "GB/sec/thread speed");
print_res(tname, td->system_time_ns / NSEC_PER_SEC,
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index fe3af95..0b613e7 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -643,7 +643,7 @@ static void *display_thread(void *arg)
case -1:
if (errno == EINTR)
continue;
- /* Fall trhu */
+ __fallthrough;
default:
c = getc(stdin);
tcsetattr(0, TCSAFLUSH, &save);
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 20c2e64..aa9276b 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1779,15 +1779,14 @@ static int test_pmu_events(void)
}
while (!ret && (ent = readdir(dir))) {
-#define MAX_NAME 100
struct evlist_test e;
- char name[MAX_NAME];
+ char name[2 * NAME_MAX + 1 + 12 + 3];
/* Names containing . are special and cannot be used directly */
if (strchr(ent->d_name, '.'))
continue;
- snprintf(name, MAX_NAME, "cpu/event=%s/u", ent->d_name);
+ snprintf(name, sizeof(name), "cpu/event=%s/u", ent->d_name);
e.name = name;
e.check = test__checkevent_pmu_events;
@@ -1795,11 +1794,10 @@ static int test_pmu_events(void)
ret = test_event(&e);
if (ret)
break;
- snprintf(name, MAX_NAME, "%s:u,cpu/event=%s/u", ent->d_name, ent->d_name);
+ snprintf(name, sizeof(name), "%s:u,cpu/event=%s/u", ent->d_name, ent->d_name);
e.name = name;
e.check = test__checkevent_pmu_events_mix;
ret = test_event(&e);
-#undef MAX_NAME
}
closedir(dir);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 2f3eded..5337f49 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -3184,6 +3184,7 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
case PERF_EVENT_UPDATE__SCALE:
ev_scale = (struct event_update_event_scale *) ev->data;
evsel->scale = ev_scale->scale;
+ break;
case PERF_EVENT_UPDATE__CPUS:
ev_cpus = (struct event_update_event_cpus *) ev->data;
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
index 16c06d3..04387ab 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
@@ -22,6 +22,7 @@
#include <errno.h>
#include <stdint.h>
#include <inttypes.h>
+#include <linux/compiler.h>
#include "../cache.h"
#include "../util.h"
@@ -1744,6 +1745,7 @@ static int intel_pt_walk_psb(struct intel_pt_decoder *decoder)
switch (decoder->packet.type) {
case INTEL_PT_TIP_PGD:
decoder->continuous_period = false;
+ __fallthrough;
case INTEL_PT_TIP_PGE:
case INTEL_PT_TIP:
intel_pt_log("ERROR: Unexpected packet\n");
@@ -1797,6 +1799,8 @@ static int intel_pt_walk_psb(struct intel_pt_decoder *decoder)
decoder->pge = false;
decoder->continuous_period = false;
intel_pt_clear_tx_flags(decoder);
+ __fallthrough;
+
case INTEL_PT_TNT:
decoder->have_tma = false;
intel_pt_log("ERROR: Unexpected packet\n");
@@ -1837,6 +1841,7 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder)
switch (decoder->packet.type) {
case INTEL_PT_TIP_PGD:
decoder->continuous_period = false;
+ __fallthrough;
case INTEL_PT_TIP_PGE:
case INTEL_PT_TIP:
decoder->pge = decoder->packet.type != INTEL_PT_TIP_PGD;
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c
index 4f7b320..7528ae4 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c
@@ -17,6 +17,7 @@
#include <string.h>
#include <endian.h>
#include <byteswap.h>
+#include <linux/compiler.h>
#include "intel-pt-pkt-decoder.h"
@@ -498,6 +499,7 @@ int intel_pt_pkt_desc(const struct intel_pt_pkt *packet, char *buf,
case INTEL_PT_FUP:
if (!(packet->count))
return snprintf(buf, buf_len, "%s no ip", name);
+ __fallthrough;
case INTEL_PT_CYC:
case INTEL_PT_VMCS:
case INTEL_PT_MTC:
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1d9c02b..7ea13f4 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -618,6 +618,67 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
return ret ? : -ENOENT;
}
+/* Adjust symbol name and address */
+static int post_process_probe_trace_point(struct probe_trace_point *tp,
+ struct map *map, unsigned long offs)
+{
+ struct symbol *sym;
+ u64 addr = tp->address + tp->offset - offs;
+
+ sym = map__find_symbol(map, addr);
+ if (!sym)
+ return -ENOENT;
+
+ if (strcmp(sym->name, tp->symbol)) {
+ /* If we have no realname, use symbol for it */
+ if (!tp->realname)
+ tp->realname = tp->symbol;
+ else
+ free(tp->symbol);
+ tp->symbol = strdup(sym->name);
+ if (!tp->symbol)
+ return -ENOMEM;
+ }
+ tp->offset = addr - sym->start;
+ tp->address -= offs;
+
+ return 0;
+}
+
+/*
+ * Rename DWARF symbols to ELF symbols -- gcc sometimes optimizes functions
+ * and generate new symbols with suffixes such as .constprop.N or .isra.N
+ * etc. Since those symbols are not recorded in DWARF, we have to find
+ * correct generated symbols from offline ELF binary.
+ * For online kernel or uprobes we don't need this because those are
+ * rebased on _text, or already a section relative address.
+ */
+static int
+post_process_offline_probe_trace_events(struct probe_trace_event *tevs,
+ int ntevs, const char *pathname)
+{
+ struct map *map;
+ unsigned long stext = 0;
+ int i, ret = 0;
+
+ /* Prepare a map for offline binary */
+ map = dso__new_map(pathname);
+ if (!map || get_text_start_address(pathname, &stext) < 0) {
+ pr_warning("Failed to get ELF symbols for %s\n", pathname);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ntevs; i++) {
+ ret = post_process_probe_trace_point(&tevs[i].point,
+ map, stext);
+ if (ret < 0)
+ break;
+ }
+ map__put(map);
+
+ return ret;
+}
+
static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
int ntevs, const char *exec)
{
@@ -694,7 +755,8 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs,
/* Skip post process if the target is an offline kernel */
if (symbol_conf.ignore_vmlinux_buildid)
- return 0;
+ return post_process_offline_probe_trace_events(tevs, ntevs,
+ symbol_conf.vmlinux_name);
reloc_sym = kernel_get_ref_reloc_sym();
if (!reloc_sym) {
diff --git a/tools/perf/util/scripting-engines/Build b/tools/perf/util/scripting-engines/Build
index 6516e22..82d28c6 100644
--- a/tools/perf/util/scripting-engines/Build
+++ b/tools/perf/util/scripting-engines/Build
@@ -1,6 +1,6 @@
libperf-$(CONFIG_LIBPERL) += trace-event-perl.o
libperf-$(CONFIG_LIBPYTHON) += trace-event-python.o
-CFLAGS_trace-event-perl.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default
+CFLAGS_trace-event-perl.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-nested-externs -Wno-undef -Wno-switch-default
CFLAGS_trace-event-python.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c
index bcae659..efb5377 100644
--- a/tools/perf/util/strfilter.c
+++ b/tools/perf/util/strfilter.c
@@ -269,6 +269,7 @@ static int strfilter_node__sprint(struct strfilter_node *node, char *buf)
len = strfilter_node__sprint_pt(node->l, buf);
if (len < 0)
return len;
+ __fallthrough;
case '!':
if (buf) {
*(buf + len++) = *node->p;
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 7f7e072..f4e3444 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -21,6 +21,8 @@ s64 perf_atoll(const char *str)
case 'b': case 'B':
if (*p)
goto out_err;
+
+ __fallthrough;
case '\0':
return length;
default:
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 40585f5..ddec5c5 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -93,7 +93,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
{
DIR *proc;
int max_threads = 32, items, i;
- char path[256];
+ char path[NAME_MAX + 1 + 6];
struct dirent *dirent, **namelist = NULL;
struct thread_map *threads = thread_map__alloc(max_threads);