Merge "tty: serial: msm: Add suspend resume support"
diff --git a/.gitignore b/.gitignore
index d47ecbb..4105cfb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,7 @@
*.lzo
*.patch
*.gcno
+*.ll
modules.builtin
Module.symvers
*.dwo
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 3acc4f1..4a5a887 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -436,6 +436,8 @@
- info on the magic SysRq key.
target/
- directory with info on generating TCM v4 fabric .ko modules
+tee.txt
+ - info on the TEE subsystem and drivers
this_cpu_ops.txt
- List rationale behind and the way to use this_cpu operations.
thermal/
diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
index a809f60..db7aab1 100644
--- a/Documentation/ABI/testing/sysfs-fs-f2fs
+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
@@ -51,12 +51,33 @@
Controls the dirty page count condition for the in-place-update
policies.
+What: /sys/fs/f2fs/<disk>/min_hot_blocks
+Date: March 2017
+Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
+Description:
+ Controls the dirty page count condition for redefining hot data.
+
+What: /sys/fs/f2fs/<disk>/min_ssr_sections
+Date: October 2017
+Contact: "Chao Yu" <yuchao0@huawei.com>
+Description:
+ Controls the fee section threshold to trigger SSR allocation.
+
What: /sys/fs/f2fs/<disk>/max_small_discards
Date: November 2013
Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com>
Description:
Controls the issue rate of small discard commands.
+What: /sys/fs/f2fs/<disk>/discard_granularity
+Date: July 2017
+Contact: "Chao Yu" <yuchao0@huawei.com>
+Description:
+ Controls discard granularity of inner discard thread, inner thread
+ will not issue discards with size that is smaller than granularity.
+ The unit size is one block, now only support configuring in range
+ of [1, 512].
+
What: /sys/fs/f2fs/<disk>/max_victim_search
Date: January 2014
Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com>
@@ -93,6 +114,12 @@
Description:
Controls the idle timing.
+What: /sys/fs/f2fs/<disk>/iostat_enable
+Date: August 2017
+Contact: "Chao Yu" <yuchao0@huawei.com>
+Description:
+ Controls to enable/disable IO stat.
+
What: /sys/fs/f2fs/<disk>/ra_nid_pages
Date: October 2015
Contact: "Chao Yu" <chao2.yu@samsung.com>
@@ -112,3 +139,56 @@
Contact: "Shuoran Liu" <liushuoran@huawei.com>
Description:
Shows total written kbytes issued to disk.
+
+What: /sys/fs/f2fs/<disk>/feature
+Date: July 2017
+Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
+Description:
+ Shows all enabled features in current device.
+
+What: /sys/fs/f2fs/<disk>/inject_rate
+Date: May 2016
+Contact: "Sheng Yong" <shengyong1@huawei.com>
+Description:
+ Controls the injection rate.
+
+What: /sys/fs/f2fs/<disk>/inject_type
+Date: May 2016
+Contact: "Sheng Yong" <shengyong1@huawei.com>
+Description:
+ Controls the injection type.
+
+What: /sys/fs/f2fs/<disk>/reserved_blocks
+Date: June 2017
+Contact: "Chao Yu" <yuchao0@huawei.com>
+Description:
+ Controls target reserved blocks in system, the threshold
+ is soft, it could exceed current available user space.
+
+What: /sys/fs/f2fs/<disk>/current_reserved_blocks
+Date: October 2017
+Contact: "Yunlong Song" <yunlong.song@huawei.com>
+Contact: "Chao Yu" <yuchao0@huawei.com>
+Description:
+ Shows current reserved blocks in system, it may be temporarily
+ smaller than target_reserved_blocks, but will gradually
+ increase to target_reserved_blocks when more free blocks are
+ freed by user later.
+
+What: /sys/fs/f2fs/<disk>/gc_urgent
+Date: August 2017
+Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
+Description:
+ Do background GC agressively
+
+What: /sys/fs/f2fs/<disk>/gc_urgent_sleep_time
+Date: August 2017
+Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
+Description:
+ Controls sleep time of GC urgent mode
+
+What: /sys/fs/f2fs/<disk>/readdir_ra
+Date: November 2017
+Contact: "Sheng Yong" <shengyong1@huawei.com>
+Description:
+ Controls readahead inode block in readdir.
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index 3a96610..bda03f0 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -1,12 +1,222 @@
* CoreSight Components:
CoreSight components are compliant with the ARM CoreSight architecture
-specification and can be connected in various topologies to suit a particular
-SoCs tracing needs. These trace components can generally be classified as
-sinks, links and sources. Trace data produced by one or more sources flows
-through the intermediate links connecting the source to the currently selected
-sink. Each CoreSight component device should use these properties to describe
-its hardware characteristcs.
+specification and can be connected in various topologies to suite a particular
+SoCs tracing needs. These trace components can generally be classified as sinks,
+links and sources. Trace data produced by one or more sources flows through the
+intermediate links connecting the source to the currently selected sink. Each
+CoreSight component device should use these properties to describe its hardware
+characteristcs.
+
+Required properties:
+
+- compatible : name of the component used for driver matching, should be one of
+ the following:
+ "arm,coresight-tmc" for coresight tmc-etr or tmc-etf device,
+ "arm,coresight-tpiu" for coresight tpiu device,
+ "qcom,coresight-replicator" for coresight replicator device,
+ "arm,coresight-funnel" for coresight funnel devices,
+ "qcom,coresight-tpda" for coresight tpda device,
+ "qcom,coresight-tpdm" for coresight tpdm device,
+ "qcom,coresight-dbgui" for coresight dbgui device
+ "arm,coresight-stm" for coresight stm trace device,
+ "arm,coresight-etm" for coresight etm trace devices,
+ "arm,coresight-etmv4" for coresight etmv4 trace devices,
+ "qcom,coresight-csr" for coresight csr device,
+ "arm,coresight-cti" for coresight cti devices,
+ "qcom,coresight-hwevent" for coresight hardware event devices
+ "arm,coresight-fuse" for coresight fuse v1 device,
+ "arm,coresight-fuse-v2" for coresight fuse v2 device,
+ "arm,coresight-fuse-v3" for coresight fuse v3 device,
+ "qcom,coresight-remote-etm" for coresight remote processor etm trace device,
+ "qcom,coresight-qpdi" for coresight qpdi device
+- reg : physical base address and length of the register set(s) of the component.
+ Not required for the following compatible string:
+ - "qcom,coresight-remote-etm"
+- reg-names : names corresponding to each reg property value.
+ Not required for the following compatible string:
+ - "qcom,coresight-remote-etm"
+ The reg-names that need to be used with corresponding compatible string
+ for a coresight device are:
+ - for coresight tmc-etr or tmc-etf device:
+ compatible : should be "arm,coresight-tmc"
+ reg-names : should be:
+ "tmc-base" - physical base address of tmc configuration
+ registers
+ "bam-base" - physical base address of tmc-etr bam registers
+ - for coresight tpiu device:
+ compatible : should be "arm,coresight-tpiu"
+ reg-names : should be:
+ "tpiu-base" - physical base address of tpiu registers
+ - for coresight replicator device
+ compatible : should be "qcom,coresight-replicator"
+ reg-names : should be:
+ "replicator-base" - physical base address of replicator
+ registers
+ - for coresight funnel devices
+ compatible : should be "arm,coresight-funnel"
+ reg-names : should be:
+ "funnel-base" - physical base address of funnel registers
+ - for coresight tpda trace device
+ compatible : should be "qcom,coresight-tpda"
+ reg-names : should be:
+ "tpda-base" - physical base address of tpda registers
+ - for coresight tpdm trace device
+ compatible : should be "qcom,coresight-tpdm"
+ reg-names : should be:
+ "tpdm-base" - physical base address of tpdm registers
+ - for coresight dbgui device:
+ compatible : should be "qcom,coresight-dbgui"
+ reg-names : should be:
+ "dbgui-base" - physical base address of dbgui registers
+ - for coresight stm trace device
+ compatible : should be "arm,coresight-stm"
+ reg-names : should be:
+ "stm-base" - physical base address of stm configuration
+ registers
+ "stm-data-base" - physical base address of stm data registers
+ - for coresight etm trace devices
+ compatible : should be "arm,coresight-etm"
+ reg-names : should be:
+ "etm-base" - physical base address of etm registers
+ - for coresight etmv4 trace devices
+ compatible : should be "arm,coresight-etmv4"
+ reg-names : should be:
+ "etm-base" - physical base address of etmv4 registers
+ - for coresight csr device:
+ compatible : should be "qcom,coresight-csr"
+ reg-names : should be:
+ "csr-base" - physical base address of csr registers
+ - for coresight cti devices:
+ compatible : should be "arm,coresight-cti"
+ reg-names : should be:
+ "cti<num>-base" - physical base address of cti registers
+ - for coresight hardware event devices:
+ compatible : should be "qcom,coresight-hwevent"
+ reg-names : should be:
+ "<ss-mux>" - physical base address of hardware event mux
+ control registers where <ss-mux> is subsystem mux it
+ represents
+ - for coresight fuse device:
+ compatible : should be "arm,coresight-fuse"
+ reg-names : should be:
+ "fuse-base" - physical base address of fuse registers
+ "nidnt-fuse-base" - physical base address of nidnt fuse registers
+ "qpdi-fuse-base" - physical base address of qpdi fuse registers
+ - for coresight qpdi device:
+ compatible : should be "qcom,coresight-qpdi"
+ reg-names : should be:
+ "qpdi-base" - physical base address of qpdi registers
+- coresight-id : unique integer identifier for the component
+- coresight-name : unique descriptive name of the component
+- coresight-nr-inports : number of input ports on the component
+
+Optional properties:
+
+- coresight-outports : list of output port numbers of this component
+- coresight-child-list : list of phandles pointing to the children of this
+ component
+- coresight-child-ports : list of input port numbers of the children
+- coresight-default-sink : represents the default compile time CoreSight sink
+- coresight-ctis : list of ctis that this component interacts with
+- qcom,cti-save : boolean, indicating cti context needs to be saved and restored
+- qcom,cti-hwclk : boolean, indicating support of hardware clock to access cti
+ registers to be saved and restored
+- qcom,cti-gpio-trigin : cti trigger input driven by gpio
+- qcom,cti-gpio-trigout : cti trigger output sent to gpio
+- qcom,pc-save : program counter save implemented
+- qcom,blk-size : block size for tmc-etr to usb transfers
+- qcom,memory-size : size of coherent memory to be allocated for tmc-etr buffer
+- qcom,round-robin : indicates if per core etms are allowed round-robin access
+ by the funnel
+- qcom,write-64bit : only 64bit data writes supported by stm
+- qcom,data-barrier : barrier required for every stm data write to channel space
+- <supply-name>-supply: phandle to the regulator device tree node. The required
+ <supply-name> is "vdd" for SD card and "vdd-io" for SD
+ I/O supply. Used for tpiu component
+- qcom,<supply>-voltage-level : specifies voltage level for vdd supply. Should
+ be specified in pairs (min, max) with units
+ being uV. Here <supply> can be "vdd" for SD card
+ vdd supply or "vdd-io" for SD I/O vdd supply.
+- qcom,<supply>-current-level : specifies current load levels for vdd supply.
+ Should be specified in pairs (lpm, hpm) with
+ units being uA. Here <supply> can be "vdd" for
+ SD card vdd supply or "vdd-io" for SD I/O vdd
+ supply.
+- qcom,hwevent-clks : list of clocks required by hardware event driver
+- qcom,hwevent-regs : list of regulators required by hardware event driver
+- qcom,byte-cntr-absent : specifies if the byte counter feature is absent on
+ the device. Only relevant in case of tmc-etr device.
+- interrupts : <a b c> where a is 0 or 1 depending on if the interrupt is
+ spi/ppi, b is the interrupt number and c is the mask,
+- interrupt-names : a list of strings that map in order to the list of
+ interrupts specified in the 'interrupts' property.
+- qcom,sg-enable : indicates whether scatter gather feature is supported for TMC
+ ETR configuration.
+- qcom,force-reg-dump : boolean, indicate whether TMC register need to be dumped.
+ Used for TMC component
+- qcom,nidntsw : boolean, indicating NIDnT software debug or trace support
+ present. Used for tpiu component
+- qcom,nidnthw : boolean, indicating NIDnT hardware sensing support present.
+ Used for tpiu component
+ qcom,nidntsw and qcom,nidnthw are mutually exclusive properties, either of
+ these may specified for tpiu component
+- qcom,nidnt-swduart : boolean, indicating NIDnT swd uart support present. Used
+ for tpiu component
+- qcom,nidnt-swdtrc : boolean, indicating NIDnT swd trace support present. Used
+ for tpiu component
+- qcom,nidnt-jtag : boolean, indicating NIDnT jtag debug support present. Used
+ for tpiu component
+- qcom,nidnt-spmi : boolean, indicating NIDnT spmi debug support present. Used
+ for tpiu component
+- nidnt-gpio : specifies gpio for NIDnT hardware detection
+- nidnt-gpio-polarity : specifies gpio polarity for NIDnT hardware detection
+- pinctrl-names : names corresponding to the numbered pinctrl. The allowed
+ names are subset of the following: cti-trigin-pctrl,
+ cti-trigout-pctrl. Used for cti component
+- pinctrl-<n>: list of pinctrl phandles for the different pinctrl states. Refer
+ to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt".
+- qcom,funnel-save-restore : boolean, indicating funnel port needs to be disabled
+ for the ETM whose CPU is being powered down. The port
+ state is restored when CPU is powered up. Used for
+ funnel component.
+- qcom,tmc-flush-powerdown : boolean, indicating trace data needs to be flushed before
+ powering down CPU. Used for TMC component.
+- qcom,bc-elem-size : specifies the BC element size supported by each monitor
+ connected to the aggregator on each port. Should be specified
+ in pairs (port, bc element size).
+- qcom,tc-elem-size : specifies the TC element size supported by each monitor
+ connected to the aggregator on each port. Should be specified
+ in pairs (port, tc element size).
+- qcom,dsb-elem-size : specifies the DSB element size supported by each monitor
+ connected to the aggregator on each port. Should be specified
+ in pairs (port, dsb element size).
+- qcom,cmb-elem-size : specifies the CMB element size supported by each monitor
+ connected to the aggregator on each port. Should be specified
+ in pairs (port, cmb element size).
+- qcom,clk-enable: specifies whether additional clock bit needs to be set for
+ M4M TPDM.
+- qcom,tpda-atid : specifies the ATID for TPDA.
+- qcom,inst-id : QMI instance id for remote ETMs.
+- qcom,noovrflw-enable : boolean, indicating whether no overflow bit needs to be
+ set in ETM stall control register.
+- coresight-cti-cpu : cpu phandle for cpu cti, required when qcom,cti-save is true
+- coresight-etm-cpu : specifies phandle for the cpu associated with the ETM device
+- qcom,dbgui-addr-offset : indicates the offset of dbgui address registers
+- qcom,dbgui-data-offset : indicates the offset of dbgui data registers
+- qcom,dbgui-size : indicates the size of dbgui address and data registers
+- qcom,pmic-carddetect-gpio : indicates the hotplug capabilities of the qpdi driver
+- qcom,cpuss-debug-cgc: debug clock gating phandle for etm
+ reg : the clock gating register for each cluster
+ cluster : indicate the cluster number
+
+coresight-outports, coresight-child-list and coresight-child-ports lists will
+be of the same length and will have a one to one correspondence among the
+elements at the same list index.
+
+coresight-default-sink must be specified for one of the sink devices that is
+intended to be made the default sink. Other sink devices must not have this
+specified. Not specifying this property on any of the sinks is invalid.
* Required properties for all components *except* non-configurable replicators:
diff --git a/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt b/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt
new file mode 100644
index 0000000..d38834c
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt
@@ -0,0 +1,31 @@
+OP-TEE Device Tree Bindings
+
+OP-TEE is a piece of software using hardware features to provide a Trusted
+Execution Environment. The security can be provided with ARM TrustZone, but
+also by virtualization or a separate chip.
+
+We're using "linaro" as the first part of the compatible property for
+the reference implementation maintained by Linaro.
+
+* OP-TEE based on ARM TrustZone required properties:
+
+- compatible : should contain "linaro,optee-tz"
+
+- method : The method of calling the OP-TEE Trusted OS. Permitted
+ values are:
+
+ "smc" : SMC #0, with the register assignments specified
+ in drivers/tee/optee/optee_smc.h
+
+ "hvc" : HVC #0, with the register assignments specified
+ in drivers/tee/optee/optee_smc.h
+
+
+
+Example:
+ firmware {
+ optee {
+ compatible = "linaro,optee-tz";
+ method = "smc";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/acpuclock/clock-a7.txt b/Documentation/devicetree/bindings/arm/msm/acpuclock/clock-a7.txt
new file mode 100644
index 0000000..dc7966a
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/acpuclock/clock-a7.txt
@@ -0,0 +1,43 @@
+* Qualcomm Application CPU clock driver
+
+clock-a7 is the driver for the Root Clock Generator (rcg) hw which controls
+the cpu rate. RCGs support selecting one of several clock inputs, as well as
+a configurable divider. This hw is different than normal rcgs in that it may
+optionally have a register which encodes the maximum rate supported by hw.
+
+Required properties:
+- compatible: "qcom,clock-a53-8916", "qcom,clock-a7-9650",
+ "qcom,clock-a7-mdm9607", "qcom,clock-a7-sdx20"
+- reg: pairs of physical address and region size
+- reg-names: "rcg-base" is expected
+- clock-names: list of names of clock inputs
+- qcom,speedX-bin-vZ:
+ A table of CPU frequency (Hz) to regulator voltage (uV) mapping.
+ Format: <freq uV>
+ This represents the max frequency possible for each possible
+ power configuration for a CPU that's binned as speed bin X,
+ speed bin revision Z. Speed bin values can be between [0-7]
+ and the version can be between [0-3].
+
+- cpu-vdd-supply: regulator phandle for cpu power domain.
+
+Optional properties:
+- reg-names: "efuse", "efuse1"
+- qcom,safe-freq: Frequency in HZ
+ When switching rates from A to B, the mux div clock will
+ instead switch from A -> safe_freq -> B.
+- qcom,enable-opp: This will allow to register the cpu clock with OPP
+ framework.
+
+Example:
+ qcom,acpuclk@f9011050 {
+ compatible = "qcom,clock-a7-8226";
+ reg = <0xf9011050 0x8>;
+ reg-names = "rcg_base";
+ cpu-vdd-supply = <&apc_vreg_corner>;
+
+ clock-names = "clk-4", "clk-5";
+ qcom,speed0-bin-v0 =
+ <384000000 1150000>,
+ <600000000 1200000>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
new file mode 100644
index 0000000..ef40b72
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
@@ -0,0 +1,28 @@
+Qualcomm Technologies, Inc. BAM Data Multiplexer Driver
+
+Required properties:
+- compatible : should be "qcom,bam_dmux"
+- reg : the location and size of the BAM hardware
+- interrupts : the BAM hardware to apps processor interrupt line
+
+Optional properties:
+-qcom,satellite-mode: the hardware needs to be configured in satellite mode
+-qcom,rx-ring-size: the size of the receive ring buffer pool, default is 32
+-qcom,max-rx-mtu: the maximum receive MTU that can be negotiated, in bytes.
+ Default is 2048. Other possible values are 4096, 8192, and 16384.
+-qcom,no-cpu-affinity: boolean value indicating that workqueue CPU affinity
+ is not required.
+-qcom,fast-shutdown: boolean value to support fast shutdown time.
+
+Example:
+
+ qcom,bam_dmux@fc834000 {
+ compatible = "qcom,bam_dmux";
+ reg = <0xfc834000 0x7000>;
+ interrupts = <0 29 1>;
+ qcom,satellite-mode;
+ qcom,rx-ring-size = <64>;
+ qcom,max-rx-mtu = <8192>;
+ qcom,no-cpu-affinity;
+ qcom,fast-shutdown;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
index 4afbb24b..37718e1 100644
--- a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
+++ b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
@@ -1,6 +1,6 @@
-Qualcomm Technologies MSM Clock controller
+Qualcomm Technologies, Inc. MSM Clock controller
-Qualcomm Technologies MSM Clock controller devices contain PLLs, root clock
+Qualcomm Technologies, Inc. MSM Clock controller devices contain PLLs, root clock
generators and other clocking hardware blocks that provide stable, low power
clocking to hardware blocks on Qualcomm Technologies SOCs. The clock controller
device node lists the power supplies needed to be scaled using the vdd_*-supply
@@ -12,8 +12,10 @@
Required properties:
- compatible: Must be one of following,
"qcom,gcc-8953"
+ "qcom,gcc-8909"
"qcom,gcc-sdm632"
"qcom,cc-debug-8953"
+ "qcom,cc-debug-8909"
"qcom,cc-debug-sdm632"
"qcom,gcc-mdss-8953"
"qcom,gcc-mdss-sdm632"
@@ -28,6 +30,8 @@
"qcom,gcc-8920"
"qcom,gcc-spm-8952"
"qcom,gcc-spm-8937"
+ "qcom,rpmcc-8909"
+ "qcom,rpmcc-8909-pm660"
"qcom,cc-debug-8952"
"qcom,cc-debug-8953"
"qcom,cc-debug-8937"
@@ -36,12 +40,18 @@
"qcom,cc-debug-8920"
"qcom,gcc-mdss-8953"
"qcom,gcc-mdss-8952"
+ "qcom,gcc-mdss-8909"
"qcom,gcc-mdss-8937"
"qcom,gcc-mdss-8917"
"qcom,gcc-mdss-8940"
"qcom,gcc-mdss-8920"
"qcom,gcc-gfx-8953"
"qcom,gcc-gfx-sdm450"
+ "qcom,gcc-mdm9607"
+ "qcom,cc-debug-mdm9607"
+ "qcom,gcc-9650"
+ "qcom,cc-debug-9650"
+ "qcom,gcc-sdx20"
- reg: Pairs of physical base addresses and region sizes of
memory mapped registers.
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-cpu-8939.txt b/Documentation/devicetree/bindings/arm/msm/clock-cpu-8939.txt
index d9e1510..5d570d0 100644
--- a/Documentation/devicetree/bindings/arm/msm/clock-cpu-8939.txt
+++ b/Documentation/devicetree/bindings/arm/msm/clock-cpu-8939.txt
@@ -1,4 +1,4 @@
-Qualcomm Technology MSM8939 CPU clock tree
+Qualcomm Technologies, Inc. MSM8939 CPU clock tree
clock-cpu-8939 is a device that represents the MSM8939 or MSM8952 CPU
subsystem clock tree. It lists the various power supplies that need to be
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-cpu-sdm632.txt b/Documentation/devicetree/bindings/arm/msm/clock-cpu-sdm632.txt
new file mode 100644
index 0000000..2d89614
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/clock-cpu-sdm632.txt
@@ -0,0 +1,94 @@
+Qualcomm Technologies, Inc SDM632 CPU clock driver
+
+clock-cpu-sdm632 is a device that represents the SDM632 CPU subystem clock
+tree. It lists the various power supplies that need to be scaled when the
+clocks are scaled and also other HW specific parameters like fmax tables etc.
+
+The root clock generator could have the ramp controller in built.
+Ramp control will allow programming the sequence ID for pulse swallowing,
+enable sequence and for linking sequence IDs.
+
+Required properties:
+- compatible: Must be "qcom,clock-cpu-sdm632".
+
+- reg: Pairs of physical base addresses and region sizes of
+ memory mapped registers.
+- reg-names: Names of the bases for the above registers. Expected
+ bases are:
+ "apcs-c1-pll-base", "apcs-c0-pll-base",
+ "apcs-cci-pll-base", "apcs-c1-rcg-base",
+ "apcs-c0-rcg-base", "apcs-cci-rcg-base",
+ "efuse", "rcgwr-c0-base(optional)",
+ "rcgwr-c1-base(optional)".
+- clocks: The clocks sources used by the cluster/cci mux.
+- clock-names: Name of the clocks for the above clocks.
+- vdd-mx-supply: The regulator powering all the PLLs of clusters & cci.
+- vdd-c0-supply: The regulator powering the cluster 0.
+- vdd-c1-supply: The regulator powering the cluster 1.
+- vdd-cci-supply: The regulator powering the CCI cluster.
+
+- qcom,speedX-bin-vY-ZZZ:
+ A table of CPU frequency (Hz) to voltage (corner)
+ mapping that represents the max frequency possible
+ for each supported voltage level for a CPU. 'X' is
+ the speed bin into which the device falls into - a
+ bin will have unique frequency-voltage relationships.
+ 'Y' is the characterization version, implying that
+ characterization (deciding what speed bin a device
+ falls into) methods and/or encoding may change. The
+ values 'X' and 'Y' are read from efuse registers, and
+ the right table is picked from multiple possible tables.
+ 'ZZZ' can be cl for(c0 & c1) or cci depending on whether
+ the table for the clusters or cci.
+
+Example:
+ clock_cpu {
+ compatible = "qcom,cpu-clock-sdm632";
+ reg = <0xb114000 0x68>,
+ <0xb014000 0x68>,
+ <0xb016000 0x8>,
+ <0xb116000 0x8>,
+ <0xb1d0000 0x8>,
+ <0xb011050 0x8>,
+ <0xb111050 0x8>,
+ <0xb1d1050 0x8>,
+ <0x00a412c 0x8>;
+ reg-names = "rcgwr-c0-base", "rcgwr-c1-base",
+ "apcs-c1-pll-base", "apcs-c0-pll-base",
+ "apcs-cci-pll-base", "apcs-c1-rcg-base",
+ "apcs-c0-rcg-base", "apcs-cci-rcg-base",
+ "efuse";
+ qcom,num-clusters = <2>;
+ vdd-mx-supply = <&pm8953_s7_level_ao>;
+ vdd-c0-supply = <&apc_vreg_corner>;
+ vdd-c1-supply = <&apc_vreg_corner>;
+ vdd-cci-supply = <&apc_vreg_corner>;
+ clocks = <&clock_gcc clk_xo_a_clk_src>;
+ clock-names = "xo_a";
+ qcom,speed0-bin-v0-c0 =
+ < 0 0>,
+ < 614400000 1>,
+ < 883200000 2>,
+ < 1036200000 3>,
+ < 1363200000 4>,
+ < 1563000000 5>,
+ < 1670400000 6>,
+ < 1785600000 7>;
+ qcom,speed0-bin-v0-c1 =
+ < 0 0>,
+ < 633600000 1>,
+ < 902400000 2>,
+ < 1094400000 3>,
+ < 1401600000 4>,
+ < 1555200000 5>,
+ < 1785600000 6>;
+ qcom,speed0-bin-v0-cci =
+ < 0 0>,
+ < 307200000 1>,
+ < 403200000 2>,
+ < 499200000 3>,
+ < 691200000 4>,
+ < 768000000 5>,
+ < 787200000 6>;
+ #clock-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
new file mode 100644
index 0000000..56fa470
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
@@ -0,0 +1,49 @@
+* MSM Sleep status
+
+MSM Sleep status device is used to check the power collapsed status of a
+offlined core. The core that initiates the hotplug would wait on the
+sleep status device before CPU_DEAD notifications are sent out. Some hardware
+devices require that the offlined core is power collapsed before turning off
+the resources that are used by the offlined core.
+
+The required properties of core sleep status node are:
+- compatible: qcom,cpu-sleep-status
+
+The required properties of sleep status node are:
+- reg: physical address of the sleep status register for the cpus
+- qcom,cpu-sleep-status-mask - The bit mask within the status register that
+ indicates the Core's sleep state.
+
+Example:
+ qcom,cpu-sleep-status {
+ compatible = "qcom,cpu-sleep-status";
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ CPU0: cpu@0 {
+ device_type = "cpu";
+ compatible = "qcom,kryo";
+
+ qcom,sleep-status = <&cpu0_slp_sts>;
+ };
+
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ compatible = "qcom,kryo";
+
+ qcom,sleep-status = <&cpu1_slp_sts>;
+ };
+ };
+
+ cpu0_slp_sts: cpu-sleep-status@9981058 {
+ reg = <0x9981058 0x100>;
+ qcom,sleep-status-mask = <0xc00000>;
+ };
+
+ cpu1_slp_sts: cpu-sleep-status@9991058 {
+ reg = <0x9991058 0x100>;
+ qcom,sleep-status-mask = <0xc00000>;
+ }
diff --git a/Documentation/devicetree/bindings/arm/msm/glink_bgcom_xprt.txt b/Documentation/devicetree/bindings/arm/msm/glink_bgcom_xprt.txt
new file mode 100644
index 0000000..d034bb8
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/glink_bgcom_xprt.txt
@@ -0,0 +1,33 @@
+Qualcomm Technologies, Inc. G-link bgcom Transport
+
+Required properties:
+-compatible : should be "qcom,glink-bgcom-xprt".
+-label : the name of the subsystem this link connects to.
+
+Optional properties:
+-qcom,qos-config: Reference to the qos configuration elements.It depends on
+ ramp-time.
+-qcom,ramp-time: Worst case time in microseconds to transition to this power
+ state. Power states are numbered by array index position.
+
+Example:
+
+ qcom,glink-bgcom-xprt-bg {
+ compatible = "qcom,glink-bgcom-xprt";
+ label = "bg";
+ qcom,qos-config = <&glink_qos_bg>;
+ qcom,ramp-time = <0x10>,
+ <0x20>,
+ <0x30>,
+ <0x40>;
+ };
+
+ glink_qos_bg: qcom,glink-qos-config-bg {
+ compatible = "qcom,glink-qos-config";
+ qcom,flow-info = <0x80 0x0>,
+ <0x70 0x1>,
+ <0x60 0x2>,
+ <0x50 0x3>;
+ qcom,mtu-size = <0x800>;
+ qcom,tput-stats-cycle = <0xa>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/jtag-fuse.txt b/Documentation/devicetree/bindings/arm/msm/jtag-fuse.txt
new file mode 100644
index 0000000..9fc2031
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/jtag-fuse.txt
@@ -0,0 +1,22 @@
+* JTAG-FUSE
+
+The jtag-fuse entry specifies the memory mapped addresses for the fuse
+registers. The jtag-fuse driver uses these to provide api(s) that can be used
+by jtag save and restore driver(s) to query whether the Hardware they manage
+is functionally disabled or not and take corresponding steps.
+
+Required Properties:
+compatible: component name used for driver matching, should be one of the
+ following:
+ "qcom,jtag-fuse" for jtag fuse device
+ "qcom,jtag-fuse-v2" for jtag fuse v2 device
+ "qcom,jtag-fuse-v3" for jtag fuse v3 device
+reg: physical base address and length of the register set
+reg-names: should be "fuse-base"
+
+Example:
+ jtag_fuse: jtagfuse@fc4be024 {
+ compatible = "qcom,jtag-fuse";
+ reg = <0xfc4be024 0x8>;
+ reg-names = "fuse-base";
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt b/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt
new file mode 100644
index 0000000..0304035
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt
@@ -0,0 +1,55 @@
+* LPM Workarounds
+
+The required properties are:
+
+- compatible: "qcom,lpm-workarounds"
+
+The optional properties are:
+- reg: The physical address and the size of the l1_l2_gcc and l2_pwr_sts
+ regitsters of performance cluster.
+
+- reg-names: "l2_pwr_sts" - string to identify l2_pwr_sts physical address.
+ "l1_l2_gcc" - string to identify l1_l2_gcc physical address.
+
+- qcom,lpm-wa-cx-turbo-unvote: Indicates the workaround to unvote CX turbo
+ vote when system is coming out of rpm assisted power collaspe.
+ lpm-cx-supply is required if this is present.
+
+- lpm-cx-supply: will hold handle for CX regulator supply which is used
+ to unvote.
+
+- qcom,lpm-wa-skip-l2-spm: Due to a hardware bug on 8939 and 8909, secure
+ world needs to disable and enable L2 SPM to get the proper context
+ in secure watchdog bite cases. With this workaround there is a race
+ in programming L2 SPM between HLOS and secure world. This leads to
+ stability issues. To avoid this program L2 SPM only in secure world
+ based on the L2 mode flag passed. Set lpm-wa-skip-l2-spm node if this
+ is required.
+
+- qcom,lpm-wa-dynamic-clock-gating: Due to a hardware bug on 8952, L1/L2 dynamic
+ clock gating needs to be enabled by software for performance cluster
+ cores and L2. Set lpm-wa-dynamic-clock-gating node if this workaround is
+ required.
+
+- qcom,cpu-offline-mask: Dynamic clock gating should be enabled when cluster is
+ in L2 PC. Each bit of cpu-offline-mask lists the cpu no. to hotplug by KTM
+ driver.
+
+- qcom,non-boot-cpu-index: will hold index of non boot cluster cpu.
+
+- qcom,l1-l2-gcc-secure: indicates L1/L2 clock enabling register is secure.
+
+Example:
+
+qcom,lpm-workarounds {
+ compatible = "qcom,lpm-workarounds";
+ reg = <0x0B011018 0x4>,
+ <0x0B011088 0x4>;
+ reg-names = "l2-pwr-sts", "l1-l2-gcc";
+ lpm-cx-supply = <&pm8916_s2_corner>;
+ qcom,lpm-wa-cx-turbo-unvote;
+ qcom,lpm-wa-skip-l2-spm;
+ qcom,lpm-wa-dynamic-clock-gating;
+ qcom,cpu-offline-mask = "0xF";
+ qcom,non-boot-cpu-index = <4>;
+}
diff --git a/Documentation/devicetree/bindings/arm/msm/mpm.txt b/Documentation/devicetree/bindings/arm/msm/mpm.txt
new file mode 100644
index 0000000..c3535cb
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/mpm.txt
@@ -0,0 +1,77 @@
+* MSM Sleep Power Manager (mpm-v2)
+
+The MPM acts a sleep power manager to shutdown the clock source and put the
+device into a retention mode to save power. The MPM is also responsible for
+waking up and bringing up the resources from sleep. The MPM driver configures
+interrupts monitored by the MPM hardware before entering sleep through a
+RPM interface.
+
+The required nodes for the MPM driver are:
+
+- compatible: "qcom, mpm-v2"
+- reg: Specifies the base physical address(s) and the size of the MPM
+ registers. The MPM driver access two memory regions for confifure the
+ virtual MPM driver on the RPM. The first region is the memory space
+ shared with the virtual MPM driver. The second region is the address
+ to the register that triggers a interrupt to the RPM.
+- reg-names: "vmpm" - string to identify the shared memory space region
+ "ipc" - string to identify the register that triggers a interrupt
+- clocks: clock identifers used by clock driver while looking up mpm clocks.
+- clock-names: name of the clock used by mpm driver.
+- qcom,ipc-bit-offset: The bit to set in the ipc register that triggers a interrupt
+ to the RPM
+- qcom,gic-parent: phandle to the gic interrupt controller
+- qcom,gic-map: Provides a mapping of how a GIC interrupt is connect to a MPM. The
+ mapping is presented in tuples. Each tuple represents a MPM pin and
+ which GIC interrupt is routed to it. Since MPM monitors interrupts
+ only during system wide low power mode, system interrupts originating
+ from other processors can be ignored and assigned an MPM pin mapping
+ of 0xff.
+- qcom,gpio-parent: phandle to the GPIO interrupt controller
+- qcom,gpio-map: Provides a mapping of how a GPIO interrupt is connect to a MPM. The
+ mapping is presented in tuples. Each tuple represents a MPM pin and
+ which GIC interrupt is routed to it. Since MPM monitors interrupts
+ only during system wide low power mode, system interrupts originating
+ from other processors can be ignored and assigned an MPM pin mapping
+ of 0xff.
+
+Optional Properties:
+
+- qcom,num-mpm-irqs : Specifies the number of mpm interrupts supported on a
+ target. If the property isn't present, 64 interrupts are
+ considered for the target by default.
+
+Example:
+ qcom,mpm@fc4281d0 {
+ compatible = "qcom,mpm-v2";
+ reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K*/
+ <0xfa006000 0x1000>; /* MSM_APCS_GCC_BASE 4K*/
+ reg-names = "vmpm", "ipc"
+ interrupts = <0 171 1>;
+ clocks = <&clock_rpm clk_xo_lpm_clk>;
+ clock-names = "xo";
+
+ qcom,ipc-bit-offset = <0>;
+
+ qcom,gic-parent = <&intc>;
+ qcom,gic-map = <25 132>,
+ <27 111>,
+ <0xff 48>,
+ <0xff 51>,
+ <0xff 52>,
+ <0xff 53>,
+ <0xff 54>,
+ <0xff 55>;
+
+ qcom,gpio-parent = <&msmgpio>;
+ qcom,gpio-map = <1 46>,
+ <2 150>,
+ <4 103>,
+ <5 104>,
+ <6 105>,
+ <7 106>,
+ <8 107>,
+ <53 37>,
+ <54 24>,
+ <55 14>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index 1b8b7cf..561a181 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -119,11 +119,17 @@
- MSM8937
compatible = "qcom,msm8937"
+- SDM439
+ compatible = "qcom,sdm439"
+
+- SDM429
+ compatible = "qcom,sdm429"
+
- MDM9640
compatible = "qcom,mdm9640"
-- MDMCALIFORNIUM
- compatible = "qcom,mdmcalifornium"
+- MDM9650
+ compatible = "qcom,mdm9650"
- SDXPOORWILLS
compatible = "qcom,sdxpoorwills"
@@ -184,6 +190,9 @@
- IPC device:
compatible = "qcom,ipc"
+- TTP device:
+ compatible = "qcom,ttp"
+
Boards (SoC type + board variant):
compatible = "qcom,apq8016"
@@ -214,6 +223,7 @@
compatible = "qcom,apq8053-cdp"
compatible = "qcom,apq8053-mtp"
compatible = "qcom,apq8053-ipc"
+compatible = "qcom,apq8053-lite-dragonboard"
compatible = "qcom,mdm9630-cdp"
compatible = "qcom,mdm9630-mtp"
compatible = "qcom,mdm9630-sim"
@@ -321,6 +331,12 @@
compatible = "qcom,msm8937-qrd"
compatible = "qcom,msm8937-pmi8950-qrd-sku1"
compatible = "qcom,msm8937-pmi8937-qrd-sku2"
+compatible = "qcom,sdm429-cdp"
+compatible = "qcom,sdm429-mtp"
+compatible = "qcom,sdm429-qrd"
+compatible = "qcom,sdm439-cdp"
+compatible = "qcom,sdm439-mtp"
+compatible = "qcom,sdm439-qrd"
compatible = "qcom,msm8953-rumi"
compatible = "qcom,msm8953-sim"
compatible = "qcom,msm8953-cdp"
@@ -343,10 +359,8 @@
compatible = "qcom,mdm9607-rumi"
compatible = "qcom,mdm9607-cdp"
compatible = "qcom,mdm9607-mtp"
-compatible = "qcom,mdmcalifornium-rumi"
-compatible = "qcom,mdmcalifornium-sim"
-compatible = "qcom,mdmcalifornium-cdp"
-compatible = "qcom,mdmcalifornium-mtp"
+compatible = "qcom,mdm9650-mtp"
+compatible = "qcom,mdm9650-ttp"
compatible = "qcom,apq8009-cdp"
compatible = "qcom,apq8009-mtp"
compatible = "qcom,sdxpoorwills-rumi"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
new file mode 100644
index 0000000..de66152
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -0,0 +1,448 @@
+MSM thermal driver (MSM_THERMAL)
+
+MSM_THERMAL is a kernel platform driver which regulates thermal conditions
+on the device during kernel boot. The goal of MSM_THERMAL is to prevent the
+temperature of the system from exceeding a thermal limit at which it cannot
+operate. Examples are CPU junction thermal limit, or POP memory thermal limit.
+The MSM_THERMAL driver polls the TSENS sensor hardware during boot, and
+reduces the maximum CPU frequency allowed in steps, to limit power/thermal
+output when a threshold temperature is crossed. It restores the maximum CPU
+frequency allowed in the same stepwise fashion when the threshold temperature
+(with hysteresis gap) is cleared.
+
+The devicetree representation of the MSM_THERMAL block should be:
+
+Required properties
+
+- compatible: "qcom,msm-thermal"
+- qcom,sensor-id: The id of the TSENS sensor polled for temperature.
+ Typically the sensor closest to CPU0.
+- qcom,poll-ms: Sampling interval to read sensor, in ms.
+- qcom,limit-temp: Threshold temperature to start stepping CPU down, in degC.
+- qcom,temp-hysteresis: Degrees C below threshold temperature to step CPU up.
+- qcom,freq-step: Number of frequency steps to take on each CPU mitigation.
+
+Optional properties
+
+- reg: Physical address for uio mapping
+- qcom,core-limit-temp: Threshold temperature to start shutting down cores
+ in degC
+- qcom,core-temp-hysteresis: Degrees C below which the cores will be brought
+ online in sequence.
+- qcom,hotplug-temp: Threshold temperature to start shutting down cores
+ in degC. This will be used when polling based
+ core control is disabled. The difference between hotplug-temp
+ and core-limit-temp is that core-limit-temp is used during
+ early boot prior to thermal_sys being available for hotplug.
+- qcom,hotplug-temp-hysteresis: Degrees C below which thermal will not force the
+ cores to be offlined. Cores can be brought online if needed.
+- qcom,freq-mitigation-temp: Threshold temperature to mitigate
+ the CPU max frequency in degC. This will be
+ used when polling based frequency control is disabled.
+ The difference between freq-mitigation-temp
+ and limit-temp is that limit-temp is used during
+ early boot prior to thermal_sys being available for registering
+ temperature thresholds. Also, this emergency frequency
+ mitigation is a single step frequency mitigation to a predefined value
+ as opposed to the step by step frequency mitigation during boot-up.
+- qcom,freq-mitigation-temp-hysteresis: Degrees C below which thermal will not mitigate the
+ cpu max frequency.
+- qcom,freq-mitigation-value: The frequency value (in kHz) to which the thermal
+ should mitigate the CPU, when the freq-mitigation-temp
+ threshold is reached.
+- qcom,vdd-restriction-temp: When temperature is below this threshold, will
+ enable vdd restriction which will set higher voltage on
+ key voltage rails, in degC.
+- qcom,vdd-restriction-temp-hysteresis: When temperature is above this threshold
+ will disable vdd restriction on key rails, in degC.
+- qcom,pmic-sw-mode-temp: Threshold temperature to disable auto mode on the
+ rail, in degC. If this property exists,
+ qcom,pmic-sw-mode-temp-hysteresis and
+ qcom,pmic-sw-mode-regs need to exist, otherwise return error.
+- qcom,pmic-sw-mode-temp-hysteresis: Degree below threshold temperature to
+ enable auto mode on the rail, in degC. If this property exists,
+ qcom,pmic-sw-mode-temp and qcom,pmic-sw-mode-regs need to
+ exist, otherwise return error.
+- qcom,pmic-sw-mode-regs: Array of the regulator names that will want to
+ disable/enable automode based on the threshold. If this
+ property exists, qcom,pmic-sw-mode-temp and
+ qcom,pmic-sw-mode-temp-hysteresis need to exist, otherwise
+ return error. Also, if this property is defined, will have to
+ define <consumer_supply_name>-supply = <&phandle_of_regulator>
+- <consumer_supply_name>-supply = <&phandle_of_regulator>: consumer_supply_name
+ is the name that's defined in thermal driver.
+ phandle_of_regulator is defined by reuglator device tree.
+- qcom,online-hotplug-core: This property should be defined in targets where
+ KTM should online cores, which are hotplugged due to
+ thermal condition.
+- qcom,synchronous-cluster-id: This property specifies an array of synchronous cluster-ID's.
+ This property will be used by KTM to optimize the synchronous
+ cluster frequency update.
+- qcom,synchronous-cluster-map: This property specifies an array of cluster-ID,
+ number of cpus in that cluster and their corresponding cpu
+ phandles. This property should be defined in targets where
+ the kernel topology module is not present.
+ In the older kernel version, where the kernel topology module is
+ not available, KTM gets the mapping information from this property.
+- qcom,disable-vdd-mx: If this property is defined, the feature VDD MX
+ restriction will be disabled. All other properties
+ corresponding to this feature will be ignored.
+- qcom,disable-vdd-rstr: If this property is defined, the feature VDD
+ restriction will be disabled. All other properties
+ corresponding to this feature will be ignored.
+- qcom,disable-sensor-info: If this property is defined, the feature sensor
+ alias info will be disabled. All other properties
+ corresponding to this feature will be ignored.
+- qcom,disable-ocr: If this property is defined, the feature optimum current
+ request will be disabled. All other properties
+ corresponding to this feature will be ignored.
+- qcom,disable-psm: If this property is defined, the feature PMIC software
+ mode will be disabled. All other properties
+ corresponding to this feature will be ignored.
+- qcom,disable-gfx-phase-ctrl: If this property is defined, the feature graphics
+ phase control will be disabled. All other properties
+ corresponding to this feature will be ignored.
+- qcom,disable-cx-phase-ctrl: If this property is defined, the feature
+ cx phase control will be disabled. All other properties
+ corresponding to this feature will be ignored.
+- qcom,therm-ddr-lm-info: If this optional property is defined, it enables
+ DDR frequency restriction feature. It expects array of
+ sensor id to be monitored, high threshold and low threshold
+ for that sensor respectively.
+
+Optional child nodes
+- qcom,pmic-opt-curr-temp: Threshold temperature for requesting optimum current (request
+ dual phase) for rails with PMIC, in degC. If this property exists,
+ then the properties, qcom,pmic-opt-curr-temp-hysteresis and
+ qcom,pmic-opt-curr-regs should also be defined to enable this
+ feature.
+- qcom,pmic-opt-curr-temp-hysteresis: Degree below the threshold to disable the optimum
+ current request for a rail, in degC. If this property exists,
+ then the properties, qcom,pmic-opt-curr-temp and
+ qcom,pmic-opt-curr-regs should also be defined to enable
+ this feature.
+- qcom,pmic-opt-curr-regs: Name of the rails for which the optimum current should be
+ requested. If this property exists, then the properties,
+ qcom,pmic-opt-curr-temp and qcom,pmic-opt-curr-temp-hysteresis
+ should also be defined to enable this feature.
+- qcom,pmic-opt-curr-sensor-id: Sensor, which needs to be monitored for requesting OCR
+ when qcom,pmic-opt-curr-temp threshold is reached.
+ It is an optional property, if it is configured, msm_thermal will
+ monitor only this sensor, otherwise it will monitor all TSENS for
+ this feature. If this property exists, then the properties,
+ qcom,pmic-opt-curr-temp, qcom,pmic-opt-curr-temp-hysteresis and
+ qcom,pmic-opt-curr-regs should also be defined to enable this feature.
+- qcom,<vdd restriction child node name>: Define the name of the child node.
+ If this property exisits, qcom,vdd-rstr-reg, qcom,levels
+ need to exist. qcom,min-level is optional if qcom,freq-req
+ exists, otherwise it's required.
+- qcom,vdd-rstr-reg: Name of the rail
+- qcom,levels: Array of the level values. Unit is corner voltage for voltage request
+ or kHz for frequency request.
+- qcom,min-level: Request this level as minimum level when disabling voltage
+ restriction. Unit is corner voltage for voltage request.
+ This will not be required if qcom,freq-req exists.
+- qcom,freq-req: Flag to determine if we should restrict frequency on this rail
+ instead of voltage.
+- qcom,max-freq-level: Request this frequency as scaling maximum level when
+ enabling vdd restriction feature for a rail. This is
+ an optional property which is only applicable to the rail
+ with "qcom,freq-req" property set.
+- qcom,cx-phase-hot-crit-temp: Threshold temperature for sending the 'HOT_CRITICAL'
+ temperature band to RPM, in degC. This will aid RPM
+ in deciding the number of phases required for CX rail.
+ If this property exists, then the property,
+ qcom,cx-phase-hot-crit-temp-hyst should also be defined to
+ enable this feature.
+- qcom,cx-phase-hot-crit-temp-hyst: Degree below the threshold to send the 'WARM'
+ temperature band to RPM, in degC. This will aid RPM
+ in deciding the number of phases required for CX.
+ If this property exists, then the property,
+ qcom,cx-phase-hot-crit-temp should also be defined to enable
+ this feature.
+- qcom,cx-phase-resource-key: The key name to be used for sending the CX
+ temperature band message to RPM. This property should
+ be defined along with the other properties required for
+ CX phase selection feature.
+- qcom,gfx-phase-hot-crit-temp: Threshold temperature for sending the 'HOT_CRITICAL'
+ temperature band to RPM, in degC. This will aid RPM in
+ deciding the number of phases required for GFX rail.
+ If this property exists, then the properties,
+ qcom,gfx-phase-hot-crit-temp-hyst and qcom,gfx-sensor-id
+ should also be defined to enable this feature.
+- qcom,gfx-phase-hot-crit-temp-hyst: Degree below the threshold to clear the 'HOT_CRITICAL'
+ band and send the 'WARM' temperature band to RPM, in degC.
+ This will aid RPM in deciding the number of phases required
+ for GFX rail. If this property exists, then the properties,
+ qcom,gfx-phase-hot-crit-temp and qcom,gfx-sensor-id
+ should also be defined to enable this feature.
+- qcom,gfx-phase-warm-temp: Threshold temperature for sending the 'WARM' temperature
+ band to RPM, in degC. This will aid RPM in deciding the
+ number of phases required for GFX rail. If this property
+ exists, then the properties, qcom,gfx-sensor-id and
+ qcom,gfx-phase-warm-temp-hyst should also be defined to
+ enable this feature.
+- qcom,gfx-phase-warm-temp-hyst: Degree below the threshold to clear the 'WARM'
+ band and send the 'NORMAL' temperature band to RPM, in degC.
+ This will aid RPM in deciding the number of phases required
+ for GFX rail. If this property exists, then the property,
+ qcom,gfx-sensor-id and qcom,gfx-phase-warm-temp should also
+ be defined to enable this feature.
+-qcom,gfx-sensor-id: The ID of the TSENS sensor, which is closest to graphics
+ processor, monitoring the GPU temperature. If this property
+ exists, then the property, qcom,gfx-phase-hot-crit-temp and
+ qcom,gfx-phase-hot-crit-temp-hyst or/and qcom,gfx-phase-warm-temp
+ and qcom,gfx-phase-warm-temp-hyst should also be defined to
+ enable this feature.
+- qcom,gfx-phase-resource-key: The key name to be used for sending the GFX temperature
+ band message to RPM. This property should be defined along
+ with the other properties required for GFX phase selection
+ feature.
+- qcom,rpm-phase-resource-type: The RPM resource type name to be used for sending
+ temperature bands for CX and GFX phase selection. This
+ property should be defined along with the other properties
+ required for CX and GFX phase selection feature.
+- qcom,rpm-phase-resource-id: The RPM resource ID to be used for sending temperature
+ bands for CX and GFX phase selection. This property should
+ be defined along with the other properties required for CX
+ and GFX phase selection feature.
+- qcom,mx-restriction-temp: Threshold temperature below which the module votes for
+ higher data retention voltage of MX and CX supply. If and only if this
+ property exists, then the property qcom,mx-restriction-temp-hysteresis,
+ qcom,mx-retention-min should also be present. Also, if this
+ property is defined, will have to define vdd-mx-supply =
+ <&phandle_of_regulator>
+- qcom,mx-restriction-temp-hysteresis: Degree above the threshold to remove MX and CX vote.
+ If this property exists, then the property qcom,mx-restriction-temp,
+ qcom,mx-retention-min should also be present.Also, if this
+ property is defined, will have to define vdd-mx-supply =
+ <&phandle_of_regulator>
+- qcom,mx-retention-min: Minimum data retention voltage to be applied to MX rail if
+ the low threshold is crossed. If this property exists, then the
+ property qcom,mx-restriction-temp and
+ qcom,mx-restriction-temp-hysteresis should also be present.
+ Also, if this property is defined, will have to define
+ vdd-mx-supply = <&phandle_of_regulator>
+- qcom,cx-retention-min: Minimum data retention voltage to be applied to CX rail if the low
+ threshold is crossed. If this property exists, then the property
+ qcom,mx-restriction-temp and qcom,mx-restriction-temp-hysteresis
+ should also be present. Also, if this property is defined, will
+ have to define vdd-cx-supply = <&phandle_of_regulator>.
+- qcom,mx-restriction-sensor_id: sensor id, which needs to be monitored for requesting MX/CX
+ retention voltage. If this optional property is defined, msm_thermal
+ will monitor only this sensor, otherwise by default it will monitor
+ all TSENS for this feature. If this property exists, then the properties,
+ qcom,mx-restriction-temp, qcom,mx-restriction-temp-hysteresis and
+ qcom,mx-retention-min should also be defined to enable this feature.
+- qcom,therm-reset-temp: Degree above which the KTM will initiate a secure watchdog reset.
+ When this property is defined, KTM will monitor all the tsens from
+ boot time and will initiate a secure watchdog reset if any of the
+ tsens temperature reaches this threshold. This reset helps in
+ generating more informative crash dumps opposed to the crash dump
+ generated by the hardware reset.
+
+Example:
+
+ qcom,msm-thermal {
+ compatible = "qcom,msm-thermal";
+ reg = <0x70000 0x1000>;
+ qcom,sensor-id = <0>;
+ qcom,poll-ms = <250>;
+ qcom,limit-temp = <60>;
+ qcom,temp-hysteresis = <10>;
+ qcom,freq-step = <2>;
+ qcom,therm-reset-temp = <115>;
+ qcom,core-limit-temp = <90>;
+ qcom,core-temp-hysteresis = <10>;
+ qcom,hotplug-temp = <110>;
+ qcom,hotplug-temp-hysteresis = <20>;
+ qcom,freq-mitigation-temp = <110>;
+ qcom,freq-mitigation-temp-hysteresis = <20>;
+ qcom,freq-mitigation-value = <960000>;
+ qcom,rpm-phase-resource-type = "misc";
+ qcom,rpm-phase-resource-id = <0>;
+ qcom,cx-phase-resource-key = "tmpc";
+ qcom,cx-phase-hot-crit-temp = <75>;
+ qcom,cx-phase-hot-crit-temp-hyst = <15>;
+ qcom,gfx-phase-warm-temp = <60>;
+ qcom,gfx-phase-warm-temp-hyst = <10>;
+ qcom,gfx-phase-hot-crit-temp = <85>;
+ qcom,gfx-phase-hot-crit-temp-hyst = <15>;
+ qcom,gfx-sensor-id = <4>;
+ qcom,gfx-phase-resource-key = "tmpg";
+ qcom,pmic-sw-mode-temp = <90>;
+ qcom,pmic-sw-mode-temp-hysteresis = <80>;
+ qcom,pmic-sw-mode-regs = "vdd-dig";
+ qcom,vdd-restriction-temp = <5>;
+ qcom,vdd-restriction-temp-hysteresis = <10>;
+ vdd-dig-supply=<&pm8841_s2_floor_corner>
+ qcom,mx-restriction-temp = <5>;
+ qcom,mx-restriction-temp-hysteresis = <10>;
+ qcom,mx-retention-min = <710000>;
+ qcom,mx-restriction-sensor_id = <2>;
+ vdd-mx-supply = <&pma8084_s1>;
+ qcom,cx-retention-min = <RPM_SMD_REGULATOR_LEVEL_RETENTION_PLUS>;
+ vdd-cx-supply = <&pmd9635_s5_level>;
+ qcom,online-hotplug-core;
+ qcom,therm-ddr-lm-info = <1 90 75>;
+ qcom,synchronous-cluster-id = <0 1>; /* Indicates cluster 0 and 1 are synchronous */
+ qcom,synchronous-cluster-map = <0 2 &CPU0 &CPU1>,
+ <1 2 &CPU2 &CPU3>;
+ /* <cluster-ID, number of cores in cluster, cpu phandles>.
+ ** In the above case, the cluster with ID 0 & 1 has 2 cores
+ ** and their phandles are mentioned.
+ */
+
+ qcom,vdd-dig-rstr{
+ qcom,vdd-rstr-reg = "vdd-dig";
+ qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
+ qcom,min-level = <1>; /* No Request */
+ };
+
+ qcom,vdd-apps-rstr{
+ qcom,vdd-rstr-reg = "vdd-apps";
+ qcom,levels = <1881600 1958400 2265600>;
+ qcom,freq-req;
+ qcom,max-freq-level = <1958400>;
+ };
+ };
+
+
+
+The sensor information node is an optional node that holds information
+about thermal sensors on a target. The information includes sensor type,
+sensor name, sensor alias and sensor scaling factor. The parent node
+name is qcom,sensor-information. It has a list of optional child
+nodes, each representing a sensor. The child node is named as
+qcom,sensor-information-<id>. The id takes values sequentially
+from 0 to N-1 where N is the number of sensors. This id doesn't
+relate to zone id or sensor id.
+
+The devicetree representation of sensor information node should be:
+
+1.0 Required properties:
+
+- compatible: "qcom,sensor-information"
+
+1.1 Optional nodes:
+
+qcom,sensor-information-<id>
+
+The below properties belong to the child node qcom,sensor-information-<id>.
+Following are the required and optional properties of a child node.
+
+1.1.a Required properties:
+
+- qcom,sensor-type: Type of a sensor. A sensor can be of type tsens,
+ alarm or adc.
+ tsens: Sensors that are on MSM die.
+ alarm: Sensors that are on PMIC die.
+ adc: Sensors that are usually thermistors
+ placed out of the die.
+- qcom,sensor-name: Name of a sensor as defined by low level sensor driver.
+
+1.1.b Optional properties:
+
+- qcom,alias-name: Alias name for a sensor. The alias name corresponds
+ to a device such as gpu/pop-mem whose temperature
+ is relative to the sensor temperature defined in the
+ child node. This node can not be used for providing
+ alias name for cpu devices. Thermal driver assigns the
+ cpu device alias, based on the sensor defined in the
+ cpu mitigation profile.
+- qcom,scaling-factor: The unit that needs to be multiplied to the
+ sensor temperature to get temperature unit in
+ degree centigrade. If this property is not
+ present, a default scaling factor of 1 is assigned
+ to a sensor.
+
+Example:
+
+ qcom,sensor-information {
+ compatible = "qcom,sensor-information";
+ sensor_information0: qcom,sensor-information-0 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor0";
+ };
+
+ sensor_information1: qcom,sensor-information-1 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor1";
+ };
+
+ sensor_information2: qcom,sensor-information-2 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor2";
+ };
+
+ sensor_information3: qcom,sensor-information-3 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor3";
+ };
+
+ sensor_information4: qcom,sensor-information-4 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor4";
+ };
+
+ sensor_information5: qcom,sensor-information-5 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor5";
+ };
+
+ sensor_information6: qcom,sensor-information-6 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor6";
+ qcom,alias-name = "cpu7";
+ }
+
+ sensor_information7: qcom,sensor-information-7 {
+ qcom,sensor-type = "alarm";
+ qcom,sensor-name = "pm8994_tz";
+ qcom,scaling-factor = <1000>;
+ };
+
+ };
+
+===============================================================================
+Mitigation Profile:
+===============================================================================
+Thermal driver allows users to specify various mitigation profiles and
+associate a profile to a device. The device should have a phandle, to associate
+itself with a mitigation profile, using a "qcom,limits-info" property.
+This profile can specify whether to mitigate the device during various
+limiting conditions.
+
+Required Node:
+- qcom,limit_info-#: This is a mitigation profile node. A profile should
+ normally have a sensor(s) to monitor and a list
+ of properties enabling or disabling a mitigation.
+
+Required properties:
+
+- qcom,temperature-sensor: Array of phandle(s) to the temperature sensor(s) that
+ need(s) to be used for monitoring the device associated
+ with this mitigation profile. Right now the first
+ sensor will be used for KTM CPU monitoring. Alias
+ name of multiple sensors monitoring a same device will
+ be differentiated by appending an index like, "cpu0_0"
+ and "cpu0_1". A single sensor monitoring multiple
+ devices will have an alias name like "cpu0-cpu1-cpu2".
+
+Optional properties:
+
+- qcom,boot-frequency-mitigate: Enable thermal frequency mitigation
+ during boot.
+- qcom,emergency-frequency-mitigate: Enable emergency frequency mitigation.
+- qcom,hotplug-mitigation-enable: Enable hotplug mitigation. This enables
+ hotplug mitigation both during boot and emergency
+ condition.
+
+Example:
+ mitigation_profile7: qcom,limit_info-7 {
+ qcom,temperature-sensor =
+ <&sensor_information6 &sensor_information8>;
+ qcom,boot-frequency-mitigate;
+ qcom,emergency-frequency-mitigate;
+ qcom,hotplug-mitigation-enable;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/proxy-client.txt b/Documentation/devicetree/bindings/arm/msm/proxy-client.txt
new file mode 100644
index 0000000..29cfaf9
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/proxy-client.txt
@@ -0,0 +1,34 @@
+Bus Proxy Client Bindings
+
+Bus proxy client provides means to cast proxy bandwidth votes during bootup
+which is removed at the end of boot. This feature can be used in situations
+where a shared resource can be scaled between several possible perfomance
+levels and hardware requires that it be at a high level at the beginning of
+boot before the client has probed and voted for required bandwidth.
+
+Required properties:
+- compatible: Must be "qcom,bus-proxy-client".
+
+Optional properties:
+- qcom,msm-bus,name: String representing the client-name.
+- qcom,msm-bus,num-cases: Total number of usecases.
+- qcom,msm-bus,active-only: Boolean context flag for requests in active or
+ dual (active & sleep) contex.
+- qcom,msm-bus,num-paths: Total number of master-slave pairs.
+- qcom,msm-bus,vectors-KBps: Arrays of unsigned integers representing:
+ master-id, slave-id, arbitrated bandwidth
+ in KBps, instantaneous bandwidth in KBps.
+
+Example:
+
+ qcom,proxy-client {
+ compatible = "qcom,bus-proxy-client";
+ qcom,msm-bus,name = "proxy_client";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,vectors-KBps =
+ <22 512 0 0>, <23 512 0 0>,
+ <22 512 0 6400000>, <23 512 0 6400000>,
+ <22 512 0 6400000>, <23 512 0 6400000>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/qcom,debugcc.txt b/Documentation/devicetree/bindings/clock/qcom,debugcc.txt
new file mode 100644
index 0000000..a4452a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,debugcc.txt
@@ -0,0 +1,20 @@
+Qualcomm Technologies, Inc. Debug Clock Controller Binding
+----------------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+ "qcom,debugcc-sdm845"
+ "qcom,debugcc-sdxpoorwills"
+
+- clock-names: Shall contain "xo_clk_src"
+- clocks: phandle + clock reference to the CXO clock.
+- #clock-cells : Shall contain 1.
+
+Example:
+ clock_debug: qcom,cc-debug {
+ compatible = "qcom,sdxpoorwills";
+ qcom,gcc = <&clock_gcc>;
+ clock-names = "xo_clk_src";
+ clocks = <&clock_rpmh RPMH_CXO_CLK>;
+ #clock-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 7330db4..ba29471 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -20,7 +20,6 @@
"qcom,gcc-sdm845-v2"
"qcom,gcc-sdm845-v2.1"
"qcom,gcc-sdm670"
- "qcom,debugcc-sdm845"
"qcom,gcc-sdxpoorwills"
- reg : shall contain base register location and length
diff --git a/Documentation/devicetree/bindings/dma/snps-dma.txt b/Documentation/devicetree/bindings/dma/snps-dma.txt
index 0f55832..633481e 100644
--- a/Documentation/devicetree/bindings/dma/snps-dma.txt
+++ b/Documentation/devicetree/bindings/dma/snps-dma.txt
@@ -63,6 +63,6 @@
interrupts = <0 35 0x4>;
status = "disabled";
dmas = <&dmahost 12 0 1>,
- <&dmahost 13 0 1 0>;
+ <&dmahost 13 1 0>;
dma-names = "rx", "rx";
};
diff --git a/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt
index 35383adb..91a49af 100644
--- a/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt
+++ b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt
@@ -8,7 +8,7 @@
- compatible:
Usage: required
Value type: <string>
- Definition: Should contain "qcom,pm8941-misc";
+ Definition: Should contain "qcom,pm8941-misc" or "qcom,pmd-vbus-det";
- reg:
Usage: required
diff --git a/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt
index aece6ac..747e0b6 100644
--- a/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt
@@ -17,6 +17,10 @@
- qcom,gpu-pwrlevel: A single powerlevel
+- qcom,ca-target-pwrlevel:
+ This value indicates which qcom,gpu-pwrlevel
+ to jump on in case of context aware power level
+ jump.
Properties:
- reg: Index of the powerlevel (0 = highest perf)
- qcom,gpu-freq GPU frequency for the powerlevel (in Hz)
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 375e929..4fb47d6 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -29,7 +29,7 @@
Current values of clock-names are:
"src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk",
"alt_mem_iface_clk", "rbbmtimer_clk", "alwayson_clk",
- "iref_clk"
+ "iref_clk", "l3_vote"
"core_clk" and "iface_clk" are required and others are optional
- qcom,base-leakage-coefficient: Dynamic leakage coefficient.
@@ -78,7 +78,10 @@
GPU Power levels:
- qcom,gpu-pwrlevel-bins: Container for sets of GPU power levels (see
adreno-pwrlevels.txt)
-
+L3 Power levels:
+- qcom,l3-pwrlevels: Container for sets of L3 power levels, the
+ L3 frequency is adjusted according to the
+ performance hint received from userspace.
DCVS Core info
- qcom,dcvs-core-info Container for the DCVS core info (see
dcvs-core-info.txt)
@@ -167,6 +170,15 @@
Specify the size of snapshot in bytes. This will override
snapshot size defined in the driver code.
+- qcom,enable-ca-jump:
+ Boolean. Enables use of context aware DCVS
+- qcom,ca-busy-penalty:
+ This property represents the time in microseconds required to
+ initiate context aware power level jump.
+- qcom,ca-target-pwrlevel:
+ This value indicates which qcom,gpu-pwrlevel to jump on in case
+ of context aware power level jump.
+
- qcom,gpu-qdss-stm:
<baseAddr size>
baseAddr - base address of the gpu channels in the qdss stm memory region
@@ -323,6 +335,15 @@
coresight-child-list = <&funnel_in0>;
coresight-child-ports = <5>;
+ /* Enable context aware freq. scaling */
+ qcom,enable-ca-jump;
+
+ /* Context aware jump busy penalty in us */
+ qcom,ca-busy-penalty = <12000>;
+
+ /* Context aware jump target power level */
+ qcom,ca-target-pwrlevel = <1>;
+
qcom,soc-hw-revisions {
#address-cells = <1>;
#size-cells = <0>;
@@ -389,6 +410,7 @@
#size-cells = <0>;
qcom,speed-bin = <0>;
+ qcom,ca-target-pwrlevel = <1>;
qcom,gpu-pwrlevel@0 {
reg = <0>;
diff --git a/Documentation/devicetree/bindings/input/touchscreen/focaltech.txt b/Documentation/devicetree/bindings/input/touchscreen/focaltech.txt
new file mode 100644
index 0000000..fb40a31
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/focaltech.txt
@@ -0,0 +1,5 @@
+FocalTech touch controller
+
+Required properties:
+
+ - compatible : Should be "focaltech,5x06"
diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax.txt b/Documentation/devicetree/bindings/input/touchscreen/himax.txt
new file mode 100644
index 0000000..258ffec
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/himax.txt
@@ -0,0 +1,5 @@
+Himax touch controller
+
+Required properties:
+
+ - compatible : Should be "himax,hxcommon"
diff --git a/Documentation/devicetree/bindings/interrupt-controller/qti,mpm.txt b/Documentation/devicetree/bindings/interrupt-controller/qti,mpm.txt
index 12ced5f..833b108 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/qti,mpm.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/qti,mpm.txt
@@ -8,13 +8,16 @@
Platform interrupt controller MPM is next in hierarchy, followed by others.
+This defines 2 interrupt controllers to monitor the interrupts when the system is asleep:
+
+One for to monitor the wakeup capable gic interrupts called wakegic.
+
Properties:
- compatible:
Usage: required
Value type: <string>
- Definition: Should contain "qcom,mpm" for mpm pin data
- and the respective target compatible flag.
+ Definition: Should contain "qcom,mpm-gic" and the respective target compatible flag.
- interrupts:
Usage: required
@@ -48,18 +51,42 @@
Example:
-mpm: mpm@7781b8 {
- compatible = "qcom,mpm";
+wakegic: wake-gic@7781b8 {
+ compatible = "qcom,mpm-gic", "qcom,mpm-gic-msm8953", "qcom,mpm-gic-msm8937";
interrupts = <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>;
- reg = <0x7781b8 0x1000>,
- <0x17911008 0x4>; /* MSM_APCS_GCC_BASE 4K */
+ reg = <0x601d4 0x1000>,
+ <0xb011008 0x4>; /* MSM_APCS_GCC_BASE 4K */
reg-names = "vmpm", "ipc";
- qcom,num-mpm-irqs = <96>;
+ interrupt-controller;
+ interrupt-parent = <&intc>;
+ #interrupt-cells = <3>;
+};
- wakegic: wake-gic {
- compatible = "qcom,mpm-gic", "qcom,mpm-gic-msm8953";
- interrupt-controller;
- #interrupt-cells = <3>;
- interrupt-parent = <&intc>;
- };
+
+One for to monitor the wakeup capable gpio interrupts called wakegpio.
+
+properties:
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: Should contain "qcom,mpm-gpio" and the respective target compatible flag.
+
+- interrupt-parent:
+ Usage: required
+ Value type: <phandle>
+ Definition: Specifies the interrupt parent necessary for hierarchical domain to operate.
+
+- interrupt-controller:
+ Usage: required
+ Value type: <bool>
+ Definition: Identifies the node as an interrupt controller.
+
+Example:
+
+wakegpio: wake-gpio {
+ compatible = "qcom,mpm-gpio", "qcom,mpm-gpio-msm8953", "qcom,mpm-gpio-msm8937";
+ interrupt-controller;
+ interrupt-parent = <&tlmm>;
+ #interrupt-cells = <2>;
};
diff --git a/Documentation/devicetree/bindings/mcd/mcd.txt b/Documentation/devicetree/bindings/mcd/mcd.txt
new file mode 100644
index 0000000..4077ee2
--- /dev/null
+++ b/Documentation/devicetree/bindings/mcd/mcd.txt
@@ -0,0 +1,29 @@
+* MCD (MobiCore Driver)
+
+t-base is an operating system running in the secure world (TrustZone).
+The t-base implementation consists of several components in the
+secure world and the non-secure world (kernel and user space). The
+MobiCore driver communicates with the t-base operating system that
+exists in TrustZone.
+
+Required properties:
+ - compatible: Should be "qcom,mcd"
+ - qcom,ce-hw-instance: should contain crypto HW instance
+ - qcom,ce-device: Device number
+ - clocks: Array of <clock_controller_phandle clock_reference> listing
+ all the clocks that are accesed by this subsystem.
+ - qcom,ce-opp-freq: indicates the CE operating frequency in Hz, changes from target to target.
+
+Example:
+ mcd {
+ compatible = "qcom,mcd";
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ clocks = <&clock_gcc clk_crypto_clk_src>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ qcom,ce-opp-freq = <100000000>;
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt b/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt
index 4b16103..66eaae1 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt
@@ -108,6 +108,23 @@
Definition: List of strings corresponds clock-rates levels.
Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo.
+- control-camnoc-axi-clk
+ Usage: optional
+ Value type: <empty>
+ Definition: Bool property specifying whether to control camnoc axi
+ clock from cpas driver.
+
+- camnoc-bus-width
+ Usage: required if control-camnoc-axi-clk is enabled
+ Value type: <u32>
+ Definition: camnoc bus width.
+
+- camnoc-axi-clk-bw-margin-perc
+ Usage: optional
+ Value type: <u32>
+ Definition: Percentage value to be added to camnoc bw while calculating
+ camnoc axi clock frequency.
+
- qcom,msm-bus,name
- qcom,msm-bus,num-cases
- qcom,msm-bus,num-paths
@@ -147,6 +164,13 @@
Definition: Bool property specifying whether Clients are connected
through CAMNOC for AXI access.
+- nvmem-cells
+ Usage: optional
+ Definition: nvmem cell node
+
+- nvmem-cell-names
+ Usage: required
+ Definition: If nvmem node is present, cell name is required
===================================================================
Third Level Node - CAM AXI Port properties
===================================================================
@@ -204,6 +228,9 @@
src-clock-name = "slow_ahb_clk_src";
clock-rates = <0 0 0 0 80000000 0>;
clock-cntl-level = "turbo";
+ control-camnoc-axi-clk;
+ camnoc-bus-width = <32>;
+ camnoc-axi-clk-bw-margin-perc = <10>;
qcom,msm-bus,name = "cam_ahb";
qcom,msm-bus,num-cases = <4>;
qcom,msm-bus,num-paths = <1>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt b/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt
index cf551f6..c47cb34 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt
@@ -49,7 +49,7 @@
- compatible
Usage: required
Value type: <string>
- Definition: Should be "qcom,fd41".
+ Definition: Should be one of "qcom,fd41", "qcom,fd501".
- reg-names
Usage: optional
diff --git a/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt b/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt
index 49d33a3..3017468 100644
--- a/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt
+++ b/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt
@@ -19,6 +19,18 @@
- qcom,mhi-ep-msi: End point MSI number.
- qcom,mhi-version: MHI specification version supported by the device.
+Optional property:
+ - qcom,use-ipa-software-channel: If property is present use IPA hardware
+ accelerated path for MHI software channel data transfers
+ between host and device.
+ - qcom,mhi-config-iatu: If property is present map the control and data region
+ between host and device using iatu.
+ - qcom,mhi-interrupt: If property is present register for mhi interrupt.
+ - qcom,mhi-local-pa-base: The physical base address on the device used by the
+ MHI device driver to map the control and data region with the
+ MHI driver on the host. This property is required if iatu
+ property qcom,mhi-config-iatu is present.
+
Example:
mhi: qcom,msm-mhi-dev {
diff --git a/Documentation/devicetree/bindings/net/qcom-ssdk.txt b/Documentation/devicetree/bindings/net/qcom-ssdk.txt
new file mode 100644
index 0000000..b72215d
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/qcom-ssdk.txt
@@ -0,0 +1,35 @@
+
+* Qualcomm Technologies Inc. SSDK Driver.
+
+Add missing DT bindings documentation for 8337 ethernet switch.
+
+Required properties:
+- compatible: Should be "qcom,ess-switch-qca83xx"
+- qcom,switch-access-mode: Should be "mdio" or "local bus"
+- qcom,link-intr-gpio: Link interrupt number used by switch
+- qcom,switch-cpu-bmp: Switch cpu port bitmap
+- qcom,switch-lan-bmp: Switch lan port bitmap
+- qcom,switch-wan-bmp: Switch wan port bitmap
+- qcom,ar8327-initvals: Initial qca83xx configuration
+
+Optional:
+- qcom,link-polling-required: Boolean- Present if using polling for link check
+
+Example:
+
+ess-switch@0 {
+ compatible = "qcom,ess-switch-qca83xx";
+ qcom,switch-access-mode = "mdio";
+ qcom,ar8327-initvals = <
+ 0x0000c 0x7600000 /* PAD6_MODE */
+ 0x00008 0x0 /* PAD5_MODE */
+ 0x000e4 0xaa545 /* MAC_POWER_SEL */
+ 0x000e0 0xc74164de /* SGMII_CTRL */
+ 0x0007c 0x4e /* PORT0_STATUS */
+ 0x00094 0x4e /* PORT6_STATUS */
+ >;
+ qcom,link-intr-gpio = <2>;
+ qcom,switch-cpu-bmp = <0x40>; /* cpu port bitmap */
+ qcom,switch-lan-bmp = <0x3e>; /* lan port bitmap */
+ qcom,switch-wan-bmp = <0x0>; /* wan port bitmap */
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/msm.txt b/Documentation/devicetree/bindings/pinctrl/msm.txt
new file mode 100644
index 0000000..839bd05
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/msm.txt
@@ -0,0 +1,17 @@
+MSM Pinctrl Bindings
+
+Required properties:
+- compatible: "qcom,msm8996-pinctrl"
+ "qcom,mdm9640-pinctrl"
+ "qcom,msm8909-pinctrl"
+- reg: Should be the base address and length of the TLMM block.
+- interrupts: Should be the parent IRQ of the TLMM block.
+- interrupt-controller: Marks the device node as an interrupt controller.
+- #interrupt-cells: Should be two.
+- gpio-controller: Marks the device node as a GPIO controller.
+- #gpio-cells : Should be two.
+ The first cell is the gpio pin number and the
+ second cell is used for optional parameters.
+
+Optional properties:
+- qcom,tlmm-emmc-boot-select : Should be the bit-field position to set.
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9650-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9650-pinctrl.txt
new file mode 100644
index 0000000..b493285
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9650-pinctrl.txt
@@ -0,0 +1,139 @@
+QTI MDM9650 TLMM block
+
+This binding describes the Top Level Mode Multiplexer block found in the
+MDM9650 platform.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be "qcom,mdm9650-pinctrl"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: the base address and size of the TLMM register space.
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: should specify the TLMM summary IRQ.
+
+- interrupt-controller:
+ Usage: required
+ Value type: <none>
+ Definition: identifies this node as an interrupt controller
+
+- #interrupt-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 2. Specifying the pin number and flags, as defined
+ in <dt-bindings/interrupt-controller/irq.h>
+
+- gpio-controller:
+ Usage: required
+ Value type: <none>
+ Definition: identifies this node as a gpio controller
+
+- #gpio-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 2. Specifying the pin number and flags, as defined
+ in <dt-bindings/gpio/gpio.h>
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, drive strength, etc.
+
+
+PIN CONFIGURATION NODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+ Usage: required
+ Value type: <string-array>
+ Definition: List of gpio pins affected by the properties specified in
+ this subnode.
+
+- function:
+ Usage: required
+ Value type: <string>
+ Definition: Specify the alternative function to be configured for the
+ specified pins.
+
+- bias-disable:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configued as no pull.
+
+- bias-pull-down:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configued as pull down.
+
+- bias-pull-up:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configued as pull up.
+
+- output-high:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ high.
+
+- output-low:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ low.
+
+- drive-strength:
+ Usage: optional
+ Value type: <u32>
+ Definition: Selects the drive strength for the specified pins, in mA.
+
+Example:
+
+ tlmm_pinmux: pinctrl@1000000 {
+ compatible = "qcom,mdm9650-pinctrl";
+ reg = <0x1000000 0x300000>;
+ interrupts = <0 208 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ uart1_console_active: uart1_console_active {
+ mux {
+ pins = "gpio0", "gpio1";
+ function = "blsp_uart1";
+ };
+
+ config {
+ pins = "gpio0", "gpio1";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8917-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8917-pinctrl.txt
new file mode 100644
index 0000000..d2327a257
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8917-pinctrl.txt
@@ -0,0 +1,204 @@
+Qualcomm Technologies, Inc. MSM8917 TLMM block
+
+This binding describes the Top Level Mode Multiplexer block found in the
+MSM8917 platform.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be "qcom,msm8917-pinctrl"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: the base address and size of the TLMM register space.
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: should specify the TLMM summary IRQ.
+
+- interrupt-controller:
+ Usage: required
+ Value type: <none>
+ Definition: identifies this node as an interrupt controller
+
+- #interrupt-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 2. Specifying the pin number and flags, as defined
+ in <dt-bindings/interrupt-controller/irq.h>
+
+- gpio-controller:
+ Usage: required
+ Value type: <none>
+ Definition: identifies this node as a gpio controller
+
+- #gpio-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 2. Specifying the pin number and flags, as defined
+ in <dt-bindings/gpio/gpio.h>
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, drive strength, etc.
+
+
+PIN CONFIGURATION NODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+ Usage: required
+ Value type: <string-array>
+ Definition: List of gpio pins affected by the properties specified in
+ this subnode.
+ Valid pins are:
+ gpio0-gpio133,
+ sdc1_clk,
+ sdc1_cmd,
+ sdc1_data,
+ sdc1_rclk,
+ sdc2_clk,
+ sdc2_cmd,
+ sdc2_data,
+ qdsd_clk,
+ qdsd_cmd,
+ qdsd_data0,
+ qdsd_data1,
+ qdsd_data2,
+ qdsd_data3,
+
+- function:
+ Usage: required
+ Value type: <string>
+ Definition: Specify the alternative function to be configured for the
+ specified pins. Functions are only valid for gpio pins.
+ Valid values are:
+ qdss_tracedata_b, blsp_uart1, gpio, blsp_spi1, adsp_ext, blsp_i2c1, prng_rosc,
+ qdss_cti_trig_out_b0, blsp_spi2, blsp_uart2, blsp_uart3, pbs0, pbs1,
+ pwr_modem_enabled_b, blsp_i2c3, gcc_gp2_clk_b, ldo_update,
+ atest_combodac_to_gpio_native, ldo_en, blsp_i2c2, gcc_gp1_clk_b, pbs2,
+ atest_gpsadc_dtest0_native, blsp_spi3, gcc_gp3_clk_b, blsp_spi4, blsp_uart4,
+ sec_mi2s, pwr_nav_enabled_b, codec_mad, pwr_crypto_enabled_b, blsp_i2c4,
+ blsp_spi5, blsp_uart5, qdss_traceclk_a, atest_bbrx1, m_voc,
+ qdss_cti_trig_in_a0, qdss_cti_trig_in_b0, blsp_i2c6, qdss_traceclk_b,
+ atest_wlan0, atest_wlan1, atest_bbrx0, blsp_i2c5, qdss_tracectl_a,
+ atest_gpsadc_dtest1_native, qdss_tracedata_a, blsp_spi6, blsp_uart6,
+ qdss_tracectl_b, mdp_vsync, pri_mi2s_mclk_a, sec_mi2s_mclk_a, cam_mclk,
+ cci_i2c, pwr_modem_enabled_a, cci_timer0, cci_timer1, cam1_standby,
+ pwr_nav_enabled_a, cam1_rst, pwr_crypto_enabled_a, forced_usb,
+ qdss_cti_trig_out_b1, cam2_rst, webcam_standby, cci_async, webcam_rst,
+ ov_ldo, sd_write, accel_int, gcc_gp1_clk_a, alsp_int, gcc_gp2_clk_a,
+ mag_int, gcc_gp3_clk_a, blsp6_spi, fp_int, qdss_cti_trig_in_b1, uim_batt,
+ cam2_standby, uim1_data, uim1_clk, uim1_reset, uim1_present, uim2_data,
+ uim2_clk, uim2_reset, uim2_present, sensor_rst, mipi_dsi0, smb_int,
+ cam0_ldo, us_euro, atest_char3, dbg_out, bimc_dte0, ts_resout, ts_sample,
+ sec_mi2s_mclk_b, pri_mi2s, sdcard_det, atest_char1, ebi_cdc, audio_reset,
+ atest_char0, audio_ref, cdc_pdm0, pri_mi2s_mclk_b, lpass_slimbus,
+ lpass_slimbus0, lpass_slimbus1, codec_int1, codec_int2, wcss_bt,
+ atest_char2, ebi_ch0, wcss_wlan2, wcss_wlan1, wcss_wlan0, wcss_wlan,
+ wcss_fm, ext_lpass, cri_trng, cri_trng1, cri_trng0, blsp_spi7, blsp_uart7,
+ pri_mi2s_ws, blsp_i2c7, gcc_tlmm, dmic0_clk, dmic0_data, key_volp,
+ qdss_cti_trig_in_a1, us_emitter, wsa_irq, wsa_io, wsa_reset, blsp_spi8,
+ blsp_uart8, blsp_i2c8, gcc_plltest, nav_pps_in_a, pa_indicator, modem_tsync,
+ nav_tsync, nav_pps_in_b, nav_pps, gsm0_tx, atest_char, atest_tsens,
+ bimc_dte1, ssbi_wtr1, fp_gpio, coex_uart, key_snapshot, key_focus, nfc_pwr,
+ blsp8_spi, qdss_cti_trig_out_a0, qdss_cti_trig_out_a1
+
+- bias-disable:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configued as no pull.
+
+- bias-pull-down:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configued as pull down.
+
+- bias-pull-up:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configued as pull up.
+
+- output-high:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ high.
+ Not valid for sdc pins.
+
+- output-low:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ low.
+ Not valid for sdc pins.
+
+- drive-strength:
+ Usage: optional
+ Value type: <u32>
+ Definition: Selects the drive strength for the specified pins, in mA.
+ Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16
+
+Example:
+
+ tlmm: pinctrl@1000000 {
+ compatible = "qcom,msm8917-pinctrl";
+ reg = <0x1000000 0x300000>;
+ interrupts = <0 208 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ pmx-uartconsole {
+ uart_console_active: uart_console_active {
+ mux {
+ pins = "gpio4", "gpio5";
+ function = "blsp_uart2";
+ };
+
+ config {
+ pins = "gpio4", "gpio5";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ uart_console_sleep: uart_console_sleep {
+ mux {
+ pins = "gpio4", "gpio5";
+ function = "blsp_uart2";
+ };
+
+ config {
+ pins = "gpio4", "gpio5";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ };
+ };
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
index 75996a5..5034e9f 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -323,6 +323,20 @@
discharging. If not specified, a value of 0 will be set.
Allowed range is from 245 to 62256.
+- qcom,ki-coeff-low-dischg
+ Usage: optional
+ Value type: <u32>
+ Definition: Ki coefficient value for low discharge current during
+ discharging. Value has no unit. Allowed range is 0-62200
+ in micro units.
+
+- qcom,ki-coeff-hi-chg
+ Usage: optional
+ Value type: <u32>
+ Definition: Ki coefficient value for high charge current during
+ charging. Value has no unit. Allowed range is 0-62200
+ in micro units.
+
- qcom,fg-rconn-mohms
Usage: optional
Value type: <u32>
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
index 3481b80..f87f7db 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
@@ -144,6 +144,26 @@
Value type: <u32>
Definition: Resistance of the battery connectors in mOhms.
+- qcom,ignore-shutdown-soc-secs
+ Usage: optional
+ Value type: <u32>
+ Definition: Time in seconds beyond which shutdown SOC is ignored.
+ If not specified the default value is 360 secs.
+
+- qcom,hold-soc-while-full
+ Usage: optional
+ Value type: <empty>
+ Definition: A boolean property that when defined holds SOC at 100% when
+ the battery is full until recharge starts.
+
+- qcom,linearize-soc
+ Usage: optional
+ Value type: <empty>
+ Definition: A boolean property that when defined linearizes SOC when
+ the SOC drops after charge termination monotonically to
+ improve the user experience. This is applicable only if
+ "qcom,hold-soc-while-full" is specified.
+
==========================================================
Second Level Nodes - Peripherals managed by QGAUGE driver
==========================================================
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
index 8795aff..afa8009 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
@@ -35,6 +35,13 @@
addition battery properties will be faked such that the device
assumes normal operation.
+- qcom,use-extcon
+ Usage: optional
+ Value type: <empty>
+ Definition: Boolean flag which specify that SMB2 will act as main charger
+ to do extcon USB calls. If not defined, other charger driver can
+ act as main charger to do extcon USB calls.
+
- qcom,fcc-max-ua
Usage: optional
Value type: <u32>
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
index 65c3cb8..b7e6a31b 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
@@ -109,10 +109,18 @@
- qcom,auto-recharge-soc
Usage: optional
- Value type: <empty>
- Definition: Specifies if automatic recharge needs to be based off battery
- SOC. If this property is not specified, then auto recharge will
- be based off battery voltage.
+ Value type: <u32>
+ Definition: Specifies the SOC threshold at which the charger will
+ restart charging after termination. The value specified
+ ranges from 0 - 100. The feature is enabled if this
+ property is specified with a valid SOC value.
+
+- qcom,auto-recharge-vbat-mv
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the battery voltage threshold at which the charger
+ will restart charging after termination. The value specified
+ is in milli-volts.
- qcom,suspend-input-on-debug-batt
Usage: optional
@@ -164,6 +172,32 @@
to be get from these properties defined in battery profile:
qcom,step-chg-ranges, qcom,jeita-fcc-ranges, qcom,jeita-fv-ranges.
+- qcom,flash-derating-soc
+ Usage: optional
+ Value type: <u32>
+ Definition: SOC threshold in percentage below which hardware will start
+ derating flash. This is only applicable to certain PMICs like
+ PMI632 which has SCHGM_FLASH peripheral.
+
+- qcom,flash-disable-soc
+ Usage: optional
+ Value type: <u32>
+ Definition: SOC threshold in percentage below which hardware will disable
+ flash. This is only applicable to certain PMICs like PMI632
+ which has SCHGM_FLASH peripheral.
+
+- qcom,headroom-mode
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies flash hardware headroom management policy. The
+ possible values are:
+ <0>: Fixed mode, constant 5V at flash input.
+ <1>: Adaptive mode allows charger output voltage to be
+ dynamically controlled by the flash module based on the
+ required flash headroom.
+ This is only applicable to certain PMICs like PMI632 which
+ has SCHGM_FLASH peripheral.
+
=============================================
Second Level Nodes - SMB5 Charger Peripherals
=============================================
@@ -301,4 +335,25 @@
"temperature-change",
"switcher-power-ok";
};
+
+ qcom,schgm-flash@a600 {
+ reg = <0xa600 0x100>;
+ interrupts = <0x2 0xa6 0x0 IRQ_TYPE_NONE>,
+ <0x2 0xa6 0x1 IRQ_TYPE_NONE>,
+ <0x2 0xa6 0x2 IRQ_TYPE_NONE>,
+ <0x2 0xa6 0x3 IRQ_TYPE_NONE>,
+ <0x2 0xa6 0x4 IRQ_TYPE_NONE>,
+ <0x2 0xa6 0x5 IRQ_TYPE_NONE>,
+ <0x2 0xa6 0x6 IRQ_TYPE_NONE>,
+ <0x2 0xa6 0x7 IRQ_TYPE_NONE>;
+
+ interrupt-names = "flash-en",
+ "torch-req",
+ "flash-state-change",
+ "vout-up",
+ "vout-down",
+ "ilim1-s1",
+ "ilim2-s2",
+ "vreg-ok";
+ };
};
diff --git a/Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt b/Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt
new file mode 100644
index 0000000..2a5fc0f
--- /dev/null
+++ b/Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt
@@ -0,0 +1,24 @@
+Qualcomm Technologies, Inc. FastRPC MDSP CMA Heap
+
+The MSM MDSPRPC memory device allocates CMA memory, for sharing memory
+of FastRPC buffers to remote processor(MDSP).
+
+Required properties:
+-compatible: Must be "qcom,msm-mdsprpc-mem-region"
+-memory-region: A phandle that points to a memory heap where the
+heap memory is allocated
+
+Example:
+ qcom,mdsprpc-mem {
+ compatible = "qcom,msm-mdsprpc-mem-region";
+ memory-region = <&mdsp_mem>;
+ };
+
+Ion Heap:
+
+Ion heap allows for sharing of buffers between different processors
+and between user space and kernel space.
+(see Documentation/devicetree/bindings/arm/msm/msm_ion.txt).
+
+Required properties for Ion heap:
+- compatible : "qcom,msm-ion"
diff --git a/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt
index 05792b0..8fecf90 100644
--- a/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt
@@ -36,7 +36,8 @@
Usage: required
Value type: <string>
Definition: should be one of the following:
- "qcom,cpr4-msm8953-apss-regulator";
+ "qcom,cpr4-msm8953-apss-regulator",
+ "qcom,cpr4-sdm632-apss-regulator";
- interrupts
Usage: required
diff --git a/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt b/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt
new file mode 100644
index 0000000..149a01a
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt
@@ -0,0 +1,14 @@
+Qualcomm Technologies Inc. bg-daemon
+
+BG-Daemon : When Modem goes down, to re-establish the connections,
+BG-Daemon toggles the bg-reset gpio to reset BG.
+
+Required properties:
+- compatible : should be "qcom,bg-daemon"
+- qcom,bg-reset-gpio : gpio for the apps processor use to soft reset BG
+
+Example:
+ qcom,bg-daemon {
+ compatible = "qcom,bg-daemon";
+ qcom,bg-reset-gpio = <&pm660_gpios 5 0>;
+ };
diff --git a/Documentation/devicetree/bindings/soc/qcom/bg_rsb.txt b/Documentation/devicetree/bindings/soc/qcom/bg_rsb.txt
new file mode 100644
index 0000000..26a13cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/bg_rsb.txt
@@ -0,0 +1,19 @@
+Qualcomm technologies Inc bg-rsb
+
+BG-RSB : bg-rsb is used to communicate with BG over Glink to
+configure the RSB events. bg-rsb enable/disable LDO11 and LDO15
+before making any communication to BG regarding RSB.
+It also provides an input device, which is used to send the RSB/Button
+events to input framework.
+
+Required properties:
+- compatible : should be "qcom,bg-rsb"
+- vdd-ldo1-supply : pm660_l11 regulator
+- vdd-ldo2-supply : for pm660_l15 regulator
+
+Example:
+ qcom,bg-rsb {
+ compatible = "qcom,bg-rsb";
+ vdd-ldo1-supply = <&pm660_l11>;
+ vdd-ldo2-supply = <&pm660_l15>;
+ };
diff --git a/Documentation/devicetree/bindings/soc/qcom/bg_spi.txt b/Documentation/devicetree/bindings/soc/qcom/bg_spi.txt
new file mode 100644
index 0000000..e9a28a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/bg_spi.txt
@@ -0,0 +1,24 @@
+Qualcomm technologies Inc bg-spi
+
+BG-COM SPI : bg-spi is used for the communication with Blackghost
+chipset. It uses SPI protocol for communication.
+BG-COM: bgcome is a thin transport layer over glink which provides
+the read/write APIs to communicate with Blackghost chipset.
+
+Required properties:
+- compatible : should be "qcom,bg-spi"
+- spi-max-frequency : Maximum SPI clocking speed of device in Hz
+- qcom,irq-gpio : GPIO pin
+- reg : Register set
+
+Example:
+ spi@78b6000 { /* BLSP1 QUP2 */
+ status = "ok";
+ qcom,bg-spi {
+ compatible = "qcom,bg-spi";
+ reg = <0>;
+ spi-max-frequency = <19200000>;
+ interrupt-parent = <&msm_gpio>;
+ qcom,irq-gpio = <&msm_gpio 110 1>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index fa11e70..33dc684 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -1872,6 +1872,128 @@
asoc-wsa-codec-prefixes = "SpkrLeft";
};
+* MSM8909 BG ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,msm-bg-audio-codec"
+- qcom,model : The user-visible name of this sound card.
+- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets
+ mentioned in qcom,msm-gpios. Say we have 2^N combinations for N GPIOs,
+ this would list all the 2^N combinations.
+- pinctrl-names : The combinations of gpio sets from above that are supported in
+ the flavor. This can be sometimes same as qcom,pinctrl-names i.e with 2^N
+ combinations or will have less incase if some combination is not supported.
+- pinctrl-# : Pinctrl states as mentioned in pinctrl-names.
+- qcom,audio-routing : A list of the connections between audio components.
+ Each entry is a pair of strings, the first being the connection's sink,
+ the second being the connection's source.
+
+Optional properties:
+- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+- asoc-platform: This is phandle list containing the references to platform device
+ nodes that are used as part of the sound card dai-links.
+- asoc-platform-names: This property contains list of platform names. The order of
+ the platform names should match to that of the phandle order
+ given in "asoc-platform".
+- asoc-cpu: This is phandle list containing the references to cpu dai device nodes
+ that are used as part of the sound card dai-links.
+- asoc-cpu-names: This property contains list of cpu dai names. The order of the
+ cpu dai names should match to that of the phandle order given
+ in "asoc-cpu". The cpu names are in the form of "%s.%d" form,
+ where the id (%d) field represents the back-end AFE port id that
+ this CPU dai is associated with.
+- asoc-codec: This is phandle list containing the references to codec dai device
+ nodes that are used as part of the sound card dai-links.
+- asoc-codec-names: This property contains list of codec dai names. The order of the
+ codec dai names should match to that of the phandle order given
+ in "asoc-codec".
+- vdd-spkr-supply: BG codec supply's speaker regulator device tree node.
+
+Example:
+ sound {
+ status = "disabled";
+ compatible = "qcom,msm-bg-audio-codec";
+ qcom,model = "msm-bg-snd-card";
+ reg = <0x7702000 0x4>,
+ <0x7702004 0x4>,
+ <0x7702008 0x4>,
+ <0x770200c 0x4>;
+ reg-names = "csr_gp_io_mux_mic_ctl",
+ "csr_gp_io_mux_spkr_ctl",
+ "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+ "csr_gp_io_lpaif_sec_pcm_sec_mode_muxsel";
+ qcom,msm-snd-card-id = <0>;
+ qcom,msm-ext-pa = "primary";
+ qcom,tdm-audio-intf;
+ qcom,msm-afe-clk-ver = <1>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&lpa>,
+ <&voice_svc>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-pcm-lpa",
+ "msm-voice-svc";
+ asoc-cpu = <&dai_pri_auxpcm>,
+ <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>,
+ <&dai_mi2s3>, <&dai_mi2s5>, <&dai_mi2s6>,
+ <&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>,
+ <&int_fm_rx>, <&int_fm_tx>, <&afe_pcm_rx>,
+ <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>,
+ <&incall_music_rx>, <&incall_music_2_rx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_pri_tdm_rx_1>, <&dai_pri_tdm_tx_1>,
+ <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_tx_2>,
+ <&dai_pri_tdm_rx_3>, <&dai_pri_tdm_tx_3>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.5", "msm-dai-q6-mi2s.6",
+ "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+ "msm-dai-q6-dev.12290", "msm-dai-q6-dev.12292",
+ "msm-dai-q6-dev.12293", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770", "msm-dai-q6-tdm.36864",
+ "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36866",
+ "msm-dai-q6-tdm.36867", "msm-dai-q6-tdm.36868",
+ "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36870",
+ "msm-dai-q6-tdm.36871";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ };
+
+* BG Codec Driver.
+
+Required properties:
+- compatible : "qcom,bg-codec"
+- qcom,bg-glink : Glink component required for the BG codec communication.
+ - compatible :"qcom,bg-cdc-glink"
+- qcom,msm-glink-channels: Number of glink channels available to communicate
+ with the glink client
+- vdd-spkr-supply: BG codec supply's speaker regulator device tree node.
+
+Optional properties:
+- qcom,bg-speaker-connected: This flag will notify BG codec driver that speaker
+ is connected to target or not. Based on this flag BG
+ codec driver will send smart pa init params to BG.
+
+Example:
+
+ bg_cdc: bg_codec {
+ status = "disabled";
+ compatible = "qcom,bg-codec";
+ qcom,bg-glink {
+ compatible = "qcom,bg-cdc-glink";
+ qcom,msm-glink-channels = <4>;
+ };
+ };
+
* MDM9607 ASoC Machine driver
Required properties:
diff --git a/Documentation/devicetree/bindings/soundwire/swr-wcd-ctrl.txt b/Documentation/devicetree/bindings/soundwire/swr-wcd-ctrl.txt
index 757ca9a..8a67d6d 100644
--- a/Documentation/devicetree/bindings/soundwire/swr-wcd-ctrl.txt
+++ b/Documentation/devicetree/bindings/soundwire/swr-wcd-ctrl.txt
@@ -8,6 +8,7 @@
which the swr-devid is <0x0 0x032000> where 0x03 represents
device Unique_ID, 0x20 represents Part_Id1 and 0x00
represents part_Id2.
+- qcom,swr-num-dev : Maximum number of possible slave devices.
- #address-cells = <2>;
- #size-cells = <0>;
@@ -16,6 +17,7 @@
Example:
swr_master {
compatible = "qcom,swr-wcd";
+ qcom,swr-num-dev = <2>;
#address-cells = <2>;
#size-cells = <0>;
diff --git a/Documentation/devicetree/bindings/thermal/qcom-bcl-pmic5.txt b/Documentation/devicetree/bindings/thermal/qcom-bcl-pmic5.txt
new file mode 100644
index 0000000..ab21954
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/qcom-bcl-pmic5.txt
@@ -0,0 +1,43 @@
+===============================================================================
+BCL Peripheral driver for PMIC5:
+===============================================================================
+Qualcomm Technologies, Inc's PMIC has battery current limiting peripheral,
+which can monitor for high battery current and low battery voltage in the
+hardware. The BCL peripheral driver interacts with the PMIC peripheral using
+the SPMI driver interface. The hardware can take threshold for notifying for
+high battery current or low battery voltage events. This driver works only
+with PMIC version 5, where the same BCL peripheral can be found in multiple
+PMIC's that are used in a device, with limited functionalities. For example,
+one PMIC can have only vbat monitoring, while the other PMIC can have both
+vbat and ibat monitoring. This is a common driver, that can interact
+with the multiple BCL peripherals.
+
+Required Parameters:
+- compatible: must be
+ 'qcom,bcl-v5' for bcl peripheral in PMIC version 5.
+- reg: <a b> where 'a' is the starting register address of the PMIC
+ peripheral and 'b' is the size of the peripheral address space.
+- interrupts: <a b c d> Where,
+ 'a' is the SLAVE ID of the PMIC,
+ 'b' is the peripheral ID,
+ 'c' is the interrupt number in PMIC and
+ 'd' is the interrupt type.
+- interrupt-names: user defined names for the interrupts. These
+ interrupt names will be used by the drivers to identify the
+ interrupts, instead of specifying the ID's. bcl driver will
+ accept these standard interrupts.
+ "bcl-ibat-lvl0",
+ "bcl-ibat-lvl1",
+ "bcl-vbat-lvl0",
+ "bcl-vbat-lvl1",
+ "bcl-vbat-lvl2",
+
+Example:
+ bcl@4200 {
+ compatible = "qcom,bcl-v5";
+ reg = <0x4200 0x100>;
+ interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x42 0x1 IRQ_TYPE_NONE>;
+ interrupt-names = "bcl-ibat-lvl0",
+ "bcl-vbat-lvl0";
+ };
diff --git a/Documentation/devicetree/bindings/thermal/qcom-bcl-soc.txt b/Documentation/devicetree/bindings/thermal/qcom-bcl-soc.txt
new file mode 100644
index 0000000..00be6de
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/qcom-bcl-soc.txt
@@ -0,0 +1,13 @@
+===============================================================================
+PMIC state of charge driver:
+===============================================================================
+Battery state of charge driver can monitor for change in battery charge and
+notify thermal framework, when the value goes below a certain threshold.
+
+Required Parameters:
+- compatible: must be 'qcom,msm-bcl-soc' for battery state of charge driver.
+
+Example:
+ bcl-soc {
+ compatible = "qcom,msm-bcl-soc";
+ };
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index 5d3b232..83ecdc7 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -61,6 +61,8 @@
- usb-core-id: Differentiates between different controllers present on a device.
- snps,bus-suspend-enable: If present then controller supports low power mode
during bus suspend.
+ - snps,usb3-u1u2-disable: If present, disable U1U2 low power modes in Superspeed mode
+ - snps,usb2-l1-disable: If present, disable L1 low power modes in Highspeed mode
This is usually a subnode to DWC3 glue to which it is connected.
diff --git a/Documentation/devicetree/bindings/usb/msm-android-usb.txt b/Documentation/devicetree/bindings/usb/msm-android-usb.txt
new file mode 100644
index 0000000..4422a18
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/msm-android-usb.txt
@@ -0,0 +1,36 @@
+ANDROID USB:
+
+This describes the device tree node for the Android USB gadget device.
+This works in conjunction with a USB Device Controller (UDC) to provide
+a dynamically configurable composition of functions to be exposed when
+connected to a USB host.
+
+Required properties:
+- compatible: should be "qcom,android-usb"
+
+Optional properties :
+- reg : offset and length of memory region that is used by device to
+ update USB PID and serial numbers used by bootloader in DLOAD mode.
+- qcom,pm-qos-latency : This property must be a list of three integer values
+ (perf, normal, sleep) where each value respresents DMA latency in microsecs.
+ First value represents DMA latency to vote with pm_qos when back to back USB
+ transfers are happening and it requires USB thoughput to be maximum.
+ Second value represents value to vote when not many USB transfers are
+ happening and it is OK to have higher DMA latency to save power.
+ Third value represents DMA latency to vote when USB BUS is IDLE and absolutely
+ no transfers are happening. It should allow transition to lowest power state.
+- qcom,usb-core-id: Index to refer USB hardware core to bind android gadget driver
+ with UDC if multiple USB peripheral controllers are present. If unspecified,
+ core is set to zero by default.
+- qcom,supported-func: Represents list of supported function drivers. If this
+ property is present android USB driver dynamically creats the list of
+ supported function drivers and uses this list instead of statically defined default
+ supported function driver list.
+Example Android USB device node :
+ android_usb@fc42b0c8 {
+ compatible = "qcom,android-usb";
+ reg = <0xfc42b0c8 0xc8>;
+ qcom,pm-qos-latency = <2 1001 12701>;
+ qcom,supported-func = "rndis_gsi","ecm_gsi","rmnet_gsi";
+ qcom,usb-core-id = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt
index e94299f..b880890 100644
--- a/Documentation/devicetree/bindings/usb/msm-phy.txt
+++ b/Documentation/devicetree/bindings/usb/msm-phy.txt
@@ -24,6 +24,9 @@
- reset-names: reset signal name strings sorted in the same order as the resets
property.
+Optional properties:
+ - qcom,param-override-seq: parameter override sequence with value, reg offset pair.
+
Example:
hsphy@f9200000 {
compatible = "qcom,usb-hsphy-snps-femto";
@@ -32,6 +35,7 @@
vdda18-supply = <&pm8941_l6>;
vdda33-supply = <&pm8941_l24>;
qcom,vdd-voltage-level = <0 872000 872000>;
+ qcom,param-override-seq = <0x43 0x70>;
};
SSUSB-QMP PHY
@@ -186,6 +190,7 @@
state when attached in host mode and "suspend" state when detached.
- qcom,tune2-efuse-correction: The value to be adjusted from fused value for
improved rise/fall times.
+ - qcom,host-chirp-erratum: Indicates host chirp fix is required.
- nvmem-cells: specifies the handle to represent the SoC revision.
usually it is defined by qfprom device node.
- nvmem-cell-names: specifies the given nvmem cell name as defined in
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 01acb65..e1be5fd 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -158,6 +158,7 @@
lantiq Lantiq Semiconductor
lenovo Lenovo Group Ltd.
lg LG Corporation
+linaro Linaro Limited
linux Linux-specific binding
lltc Linear Technology Corporation
lsi LSI Corp. (LSI Logic)
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
index 6c0108e..2139ea2 100644
--- a/Documentation/filesystems/ext4.txt
+++ b/Documentation/filesystems/ext4.txt
@@ -233,7 +233,7 @@
data_err=abort Abort the journal if an error occurs in a file
data buffer in ordered mode.
-grpid Give objects the same group ID as their creator.
+grpid New objects have the group ID of their parent.
bsdgroups
nogrpid (*) New objects have the group ID of their creator.
diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt
index 753dd4f..e7fb61e 100644
--- a/Documentation/filesystems/f2fs.txt
+++ b/Documentation/filesystems/f2fs.txt
@@ -157,6 +157,20 @@
mode=%s Control block allocation mode which supports "adaptive"
and "lfs". In "lfs" mode, there should be no random
writes towards main area.
+io_bits=%u Set the bit size of write IO requests. It should be set
+ with "mode=lfs".
+usrquota Enable plain user disk quota accounting.
+grpquota Enable plain group disk quota accounting.
+prjquota Enable plain project quota accounting.
+usrjquota=<file> Appoint specified file and type during mount, so that quota
+grpjquota=<file> information can be properly updated during recovery flow,
+prjjquota=<file> <quota file>: must be in root directory;
+jqfmt=<quota type> <quota type>: [vfsold,vfsv0,vfsv1].
+offusrjquota Turn off user journelled quota.
+offgrpjquota Turn off group journelled quota.
+offprjjquota Turn off project journelled quota.
+quota Enable plain user disk quota accounting.
+noquota Disable all plain disk quota option.
================================================================================
DEBUGFS ENTRIES
@@ -202,6 +216,15 @@
gc_idle = 1 will select the Cost Benefit approach
& setting gc_idle = 2 will select the greedy approach.
+ gc_urgent This parameter controls triggering background GCs
+ urgently or not. Setting gc_urgent = 0 [default]
+ makes back to default behavior, while if it is set
+ to 1, background thread starts to do GC by given
+ gc_urgent_sleep_time interval.
+
+ gc_urgent_sleep_time This parameter controls sleep time for gc_urgent.
+ 500 ms is set by default. See above gc_urgent.
+
reclaim_segments This parameter controls the number of prefree
segments to be reclaimed. If the number of prefree
segments is larger than the number of segments
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 81c7f2b..efb38da 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -308,6 +308,7 @@
0xA3 80-8F Port ACL in development:
<mailto:tlewis@mindspring.com>
0xA3 90-9F linux/dtlk.h
+0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem
0xAA 00-3F linux/uapi/linux/userfaultfd.h
0xAB 00-1F linux/nbd.h
0xAC 00-1F linux/raw.h
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 9f5bfd6..0b8f21f 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1919,6 +1919,12 @@
kernel and module base offset ASLR (Address Space
Layout Randomization).
+ kasan_multi_shot
+ [KNL] Enforce KASAN (Kernel Address Sanitizer) to print
+ report on every invalid memory access. Without this
+ parameter KASAN will print report only for the first
+ invalid access.
+
keepinitrd [HW,ARM]
kernelcore= [KNL,X86,IA-64,PPC]
@@ -2821,8 +2827,6 @@
norandmaps Don't use address space randomization. Equivalent to
echo 0 > /proc/sys/kernel/randomize_va_space
- noreplace-paravirt [X86,IA-64,PV_OPS] Don't patch paravirt_ops
-
noreplace-smp [X86-32,SMP] Don't replace SMP instructions
with UP alternatives
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 7058d43..e52a472 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1502,6 +1502,11 @@
Functional default: enabled if accept_ra is enabled.
disabled if accept_ra is disabled.
+accept_ra_prefix_route - BOOLEAN
+ Set the prefix route for the autoconfigured interface address
+
+ Functional default: enabled
+
accept_redirects - BOOLEAN
Accept Redirects.
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index 3849814..0e03baf 100644
--- a/Documentation/security/keys.txt
+++ b/Documentation/security/keys.txt
@@ -1151,8 +1151,21 @@
usage. This is called key->payload.rcu_data0. The following accessors
wrap the RCU calls to this element:
- rcu_assign_keypointer(struct key *key, void *data);
- void *rcu_dereference_key(struct key *key);
+ (a) Set or change the first payload pointer:
+
+ rcu_assign_keypointer(struct key *key, void *data);
+
+ (b) Read the first payload pointer with the key semaphore held:
+
+ [const] void *dereference_key_locked([const] struct key *key);
+
+ Note that the return value will inherit its constness from the key
+ parameter. Static analysis will give an error if it things the lock
+ isn't held.
+
+ (c) Read the first payload pointer with the RCU read lock held:
+
+ const void *dereference_key_rcu(const struct key *key);
===================
diff --git a/Documentation/speculation.txt b/Documentation/speculation.txt
new file mode 100644
index 0000000..e9e6cba
--- /dev/null
+++ b/Documentation/speculation.txt
@@ -0,0 +1,90 @@
+This document explains potential effects of speculation, and how undesirable
+effects can be mitigated portably using common APIs.
+
+===========
+Speculation
+===========
+
+To improve performance and minimize average latencies, many contemporary CPUs
+employ speculative execution techniques such as branch prediction, performing
+work which may be discarded at a later stage.
+
+Typically speculative execution cannot be observed from architectural state,
+such as the contents of registers. However, in some cases it is possible to
+observe its impact on microarchitectural state, such as the presence or
+absence of data in caches. Such state may form side-channels which can be
+observed to extract secret information.
+
+For example, in the presence of branch prediction, it is possible for bounds
+checks to be ignored by code which is speculatively executed. Consider the
+following code:
+
+ int load_array(int *array, unsigned int index)
+ {
+ if (index >= MAX_ARRAY_ELEMS)
+ return 0;
+ else
+ return array[index];
+ }
+
+Which, on arm64, may be compiled to an assembly sequence such as:
+
+ CMP <index>, #MAX_ARRAY_ELEMS
+ B.LT less
+ MOV <returnval>, #0
+ RET
+ less:
+ LDR <returnval>, [<array>, <index>]
+ RET
+
+It is possible that a CPU mis-predicts the conditional branch, and
+speculatively loads array[index], even if index >= MAX_ARRAY_ELEMS. This
+value will subsequently be discarded, but the speculated load may affect
+microarchitectural state which can be subsequently measured.
+
+More complex sequences involving multiple dependent memory accesses may
+result in sensitive information being leaked. Consider the following
+code, building on the prior example:
+
+ int load_dependent_arrays(int *arr1, int *arr2, int index)
+ {
+ int val1, val2,
+
+ val1 = load_array(arr1, index);
+ val2 = load_array(arr2, val1);
+
+ return val2;
+ }
+
+Under speculation, the first call to load_array() may return the value
+of an out-of-bounds address, while the second call will influence
+microarchitectural state dependent on this value. This may provide an
+arbitrary read primitive.
+
+====================================
+Mitigating speculation side-channels
+====================================
+
+The kernel provides a generic API to ensure that bounds checks are
+respected even under speculation. Architectures which are affected by
+speculation-based side-channels are expected to implement these
+primitives.
+
+The array_index_nospec() helper in <linux/nospec.h> can be used to
+prevent information from being leaked via side-channels.
+
+A call to array_index_nospec(index, size) returns a sanitized index
+value that is bounded to [0, size) even under cpu speculation
+conditions.
+
+This can be used to protect the earlier load_array() example:
+
+ int load_array(int *array, unsigned int index)
+ {
+ if (index >= MAX_ARRAY_ELEMS)
+ return 0;
+ else {
+ index = array_index_nospec(index, MAX_ARRAY_ELEMS);
+ return array[index];
+ }
+ }
diff --git a/Documentation/tee.txt b/Documentation/tee.txt
new file mode 100644
index 0000000..56ea85f
--- /dev/null
+++ b/Documentation/tee.txt
@@ -0,0 +1,127 @@
+=============
+TEE subsystem
+=============
+
+This document describes the TEE subsystem in Linux.
+
+A TEE (Trusted Execution Environment) is a trusted OS running in some
+secure environment, for example, TrustZone on ARM CPUs, or a separate
+secure co-processor etc. A TEE driver handles the details needed to
+communicate with the TEE.
+
+This subsystem deals with:
+
+- Registration of TEE drivers
+
+- Managing shared memory between Linux and the TEE
+
+- Providing a generic API to the TEE
+
+The TEE interface
+=================
+
+include/uapi/linux/tee.h defines the generic interface to a TEE.
+
+User space (the client) connects to the driver by opening /dev/tee[0-9]* or
+/dev/teepriv[0-9]*.
+
+- TEE_IOC_SHM_ALLOC allocates shared memory and returns a file descriptor
+ which user space can mmap. When user space doesn't need the file
+ descriptor any more, it should be closed. When shared memory isn't needed
+ any longer it should be unmapped with munmap() to allow the reuse of
+ memory.
+
+- TEE_IOC_VERSION lets user space know which TEE this driver handles and
+ the its capabilities.
+
+- TEE_IOC_OPEN_SESSION opens a new session to a Trusted Application.
+
+- TEE_IOC_INVOKE invokes a function in a Trusted Application.
+
+- TEE_IOC_CANCEL may cancel an ongoing TEE_IOC_OPEN_SESSION or TEE_IOC_INVOKE.
+
+- TEE_IOC_CLOSE_SESSION closes a session to a Trusted Application.
+
+There are two classes of clients, normal clients and supplicants. The latter is
+a helper process for the TEE to access resources in Linux, for example file
+system access. A normal client opens /dev/tee[0-9]* and a supplicant opens
+/dev/teepriv[0-9].
+
+Much of the communication between clients and the TEE is opaque to the
+driver. The main job for the driver is to receive requests from the
+clients, forward them to the TEE and send back the results. In the case of
+supplicants the communication goes in the other direction, the TEE sends
+requests to the supplicant which then sends back the result.
+
+OP-TEE driver
+=============
+
+The OP-TEE driver handles OP-TEE [1] based TEEs. Currently it is only the ARM
+TrustZone based OP-TEE solution that is supported.
+
+Lowest level of communication with OP-TEE builds on ARM SMC Calling
+Convention (SMCCC) [2], which is the foundation for OP-TEE's SMC interface
+[3] used internally by the driver. Stacked on top of that is OP-TEE Message
+Protocol [4].
+
+OP-TEE SMC interface provides the basic functions required by SMCCC and some
+additional functions specific for OP-TEE. The most interesting functions are:
+
+- OPTEE_SMC_FUNCID_CALLS_UID (part of SMCCC) returns the version information
+ which is then returned by TEE_IOC_VERSION
+
+- OPTEE_SMC_CALL_GET_OS_UUID returns the particular OP-TEE implementation, used
+ to tell, for instance, a TrustZone OP-TEE apart from an OP-TEE running on a
+ separate secure co-processor.
+
+- OPTEE_SMC_CALL_WITH_ARG drives the OP-TEE message protocol
+
+- OPTEE_SMC_GET_SHM_CONFIG lets the driver and OP-TEE agree on which memory
+ range to used for shared memory between Linux and OP-TEE.
+
+The GlobalPlatform TEE Client API [5] is implemented on top of the generic
+TEE API.
+
+Picture of the relationship between the different components in the
+OP-TEE architecture::
+
+ User space Kernel Secure world
+ ~~~~~~~~~~ ~~~~~~ ~~~~~~~~~~~~
+ +--------+ +-------------+
+ | Client | | Trusted |
+ +--------+ | Application |
+ /\ +-------------+
+ || +----------+ /\
+ || |tee- | ||
+ || |supplicant| \/
+ || +----------+ +-------------+
+ \/ /\ | TEE Internal|
+ +-------+ || | API |
+ + TEE | || +--------+--------+ +-------------+
+ | Client| || | TEE | OP-TEE | | OP-TEE |
+ | API | \/ | subsys | driver | | Trusted OS |
+ +-------+----------------+----+-------+----+-----------+-------------+
+ | Generic TEE API | | OP-TEE MSG |
+ | IOCTL (TEE_IOC_*) | | SMCCC (OPTEE_SMC_CALL_*) |
+ +-----------------------------+ +------------------------------+
+
+RPC (Remote Procedure Call) are requests from secure world to kernel driver
+or tee-supplicant. An RPC is identified by a special range of SMCCC return
+values from OPTEE_SMC_CALL_WITH_ARG. RPC messages which are intended for the
+kernel are handled by the kernel driver. Other RPC messages will be forwarded to
+tee-supplicant without further involvement of the driver, except switching
+shared memory buffer representation.
+
+References
+==========
+
+[1] https://github.com/OP-TEE/optee_os
+
+[2] http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
+
+[3] drivers/tee/optee/optee_smc.h
+
+[4] drivers/tee/optee/optee_msg.h
+
+[5] http://www.globalplatform.org/specificationsdevice.asp look for
+ "TEE Client API Specification v1.0" and click download.
diff --git a/Kbuild b/Kbuild
index 3d0ae15..94c7527 100644
--- a/Kbuild
+++ b/Kbuild
@@ -7,31 +7,6 @@
# 4) Check for missing system calls
# 5) Generate constants.py (may need bounds.h)
-# Default sed regexp - multiline due to syntax constraints
-define sed-y
- "/^->/{s:->#\(.*\):/* \1 */:; \
- s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \
- s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
- s:->::; p;}"
-endef
-
-# Use filechk to avoid rebuilds when a header changes, but the resulting file
-# does not
-define filechk_offsets
- (set -e; \
- echo "#ifndef $2"; \
- echo "#define $2"; \
- echo "/*"; \
- echo " * DO NOT MODIFY."; \
- echo " *"; \
- echo " * This file was generated by Kbuild"; \
- echo " */"; \
- echo ""; \
- sed -ne $(sed-y); \
- echo ""; \
- echo "#endif" )
-endef
-
#####
# 1) Generate bounds.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 63cefa6..a419303 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9010,6 +9010,11 @@
F: drivers/oprofile/
F: include/linux/oprofile.h
+OP-TEE DRIVER
+M: Jens Wiklander <jens.wiklander@linaro.org>
+S: Maintained
+F: drivers/tee/optee/
+
ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
M: Mark Fasheh <mfasheh@versity.com>
M: Joel Becker <jlbec@evilplan.org>
@@ -10655,6 +10660,14 @@
F: include/linux/stm.h
F: include/uapi/linux/stm.h
+TEE SUBSYSTEM
+M: Jens Wiklander <jens.wiklander@linaro.org>
+S: Maintained
+F: include/linux/tee_drv.h
+F: include/uapi/linux/tee.h
+F: drivers/tee/
+F: Documentation/tee.txt
+
THUNDERBOLT DRIVER
M: Andreas Noever <andreas.noever@gmail.com>
S: Maintained
diff --git a/Makefile b/Makefile
index b075470..7c1b91b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 4
PATCHLEVEL = 9
-SUBLEVEL = 80
+SUBLEVEL = 84
EXTRAVERSION =
NAME = Roaring Lionus
@@ -87,10 +87,12 @@
ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4
ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
quiet=silent_
+ tools_silent=s
endif
else # make-3.8x
ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
quiet=silent_
+ tools_silent=-s
endif
endif
@@ -301,7 +303,7 @@
HOSTCC = gcc
HOSTCXX = g++
-HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89
+HOSTCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89
HOSTCXXFLAGS = -O2
ifeq ($(shell $(HOSTCC) -v 2>&1 | grep -c "clang version"), 1)
@@ -644,7 +646,8 @@
endif
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,)
+KBUILD_CFLAGS += $(call cc-option,-Oz,-Os)
+KBUILD_CFLAGS += $(call cc-disable-warning,maybe-uninitialized,)
else
ifdef CONFIG_PROFILE_ALL_BRANCHES
KBUILD_CFLAGS += -O2 $(call cc-disable-warning,maybe-uninitialized,)
@@ -704,11 +707,22 @@
KBUILD_CFLAGS += $(stackp-flag)
ifeq ($(cc-name),clang)
+ifneq ($(CROSS_COMPILE),)
+CLANG_TRIPLE ?= $(CROSS_COMPILE)
+CLANG_TARGET := --target=$(notdir $(CLANG_TRIPLE:%-=%))
+GCC_TOOLCHAIN := $(realpath $(dir $(shell which $(LD)))/..)
+endif
+ifneq ($(GCC_TOOLCHAIN),)
+CLANG_GCC_TC := --gcc-toolchain=$(GCC_TOOLCHAIN)
+endif
+KBUILD_CFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC)
+KBUILD_AFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC)
KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,)
-KBUILD_CPPFLAGS += $(call cc-option,-Wno-unknown-warning-option,)
KBUILD_CFLAGS += $(call cc-disable-warning, unused-variable)
KBUILD_CFLAGS += $(call cc-disable-warning, format-invalid-specifier)
KBUILD_CFLAGS += $(call cc-disable-warning, gnu)
+KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member)
+KBUILD_CFLAGS += $(call cc-disable-warning, duplicate-decl-specifier)
# Quiet clang warning: comparison of unsigned expression < 0 is always false
KBUILD_CFLAGS += $(call cc-disable-warning, tautological-compare)
# CLANG uses a _MergedGlobals as optimization, but this breaks modpost, as the
@@ -716,6 +730,8 @@
# See modpost pattern 2
KBUILD_CFLAGS += $(call cc-option, -mno-global-merge,)
KBUILD_CFLAGS += $(call cc-option, -fcatch-undefined-behavior)
+KBUILD_CFLAGS += $(call cc-option, -no-integrated-as)
+KBUILD_AFLAGS += $(call cc-option, -no-integrated-as)
else
# These warnings generated too much noise in a regular build.
@@ -1372,6 +1388,8 @@
@echo ' (default: $$(INSTALL_MOD_PATH)/lib/firmware)'
@echo ' dir/ - Build all files in dir and below'
@echo ' dir/file.[ois] - Build specified target only'
+ @echo ' dir/file.ll - Build the LLVM assembly file'
+ @echo ' (requires compiler support for LLVM assembly generation)'
@echo ' dir/file.lst - Build specified mixed source/assembly target only'
@echo ' (requires a recent binutils and recent build (System.map))'
@echo ' dir/file.ko - Build module including final link'
@@ -1556,6 +1574,7 @@
-o -name '*.symtypes' -o -name 'modules.order' \
-o -name modules.builtin -o -name '.tmp_*.o.*' \
-o -name '*.c.[012]*.*' \
+ -o -name '*.ll' \
-o -name '*.gcno' \) -type f -print | xargs rm -f
# Generate tags for editors
@@ -1620,11 +1639,11 @@
# Clear a bunch of variables before executing the submake
tools/: FORCE
$(Q)mkdir -p $(objtree)/tools
- $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/
+ $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/
tools/%: FORCE
$(Q)mkdir -p $(objtree)/tools
- $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/ $*
+ $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/ $*
# Single targets
# ---------------------------------------------------------------------------
@@ -1659,6 +1678,8 @@
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
%.symtypes: %.c prepare scripts FORCE
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.ll: %.c prepare scripts FORCE
+ $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
# Modules
/: prepare scripts FORCE
diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h
index 2b0ac42..412bb3c 100644
--- a/arch/alpha/kernel/pci_impl.h
+++ b/arch/alpha/kernel/pci_impl.h
@@ -143,7 +143,8 @@
};
#if defined(CONFIG_ALPHA_SRM) && \
- (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA))
+ (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA) || \
+ defined(CONFIG_ALPHA_AVANTI))
# define NEED_SRM_SAVE_RESTORE
#else
# undef NEED_SRM_SAVE_RESTORE
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index b483156..60c17b9 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -265,12 +265,13 @@
application calling fork. */
if (clone_flags & CLONE_SETTLS)
childti->pcb.unique = regs->r20;
+ else
+ regs->r20 = 0; /* OSF/1 has some strange fork() semantics. */
childti->pcb.usp = usp ?: rdusp();
*childregs = *regs;
childregs->r0 = 0;
childregs->r19 = 0;
childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */
- regs->r20 = 0;
stack = ((struct switch_stack *) regs) - 1;
*childstack = *stack;
childstack->r26 = (unsigned long) ret_from_fork;
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 74aceea..32ba92c 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -158,11 +158,16 @@
for(i=0; i < kstack_depth_to_print; i++) {
if (((long) stack & (THREAD_SIZE-1)) == 0)
break;
- if (i && ((i % 4) == 0))
- printk("\n ");
- printk("%016lx ", *stack++);
+ if ((i % 4) == 0) {
+ if (i)
+ pr_cont("\n");
+ printk(" ");
+ } else {
+ pr_cont(" ");
+ }
+ pr_cont("%016lx", *stack++);
}
- printk("\n");
+ pr_cont("\n");
dik_show_trace(sp);
}
diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
index a20a71d..c9c9a47 100644
--- a/arch/arm/boot/dts/am4372.dtsi
+++ b/arch/arm/boot/dts/am4372.dtsi
@@ -926,7 +926,8 @@
reg = <0x48038000 0x2000>,
<0x46000000 0x400000>;
reg-names = "mpu", "dat";
- interrupts = <80>, <81>;
+ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "tx", "rx";
status = "disabled";
dmas = <&edma 8 2>,
@@ -940,7 +941,8 @@
reg = <0x4803C000 0x2000>,
<0x46400000 0x400000>;
reg-names = "mpu", "dat";
- interrupts = <82>, <83>;
+ interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "tx", "rx";
status = "disabled";
dmas = <&edma 10 2>,
diff --git a/arch/arm/boot/dts/am437x-cm-t43.dts b/arch/arm/boot/dts/am437x-cm-t43.dts
index 9e92d48..3b9a94c 100644
--- a/arch/arm/boot/dts/am437x-cm-t43.dts
+++ b/arch/arm/boot/dts/am437x-cm-t43.dts
@@ -301,8 +301,8 @@
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&spi0_pins>;
- dmas = <&edma 16
- &edma 17>;
+ dmas = <&edma 16 0
+ &edma 17 0>;
dma-names = "tx0", "rx0";
flash: w25q64cvzpig@0 {
diff --git a/arch/arm/boot/dts/arm-realview-eb-mp.dtsi b/arch/arm/boot/dts/arm-realview-eb-mp.dtsi
index 7b8d90b..29b636f 100644
--- a/arch/arm/boot/dts/arm-realview-eb-mp.dtsi
+++ b/arch/arm/boot/dts/arm-realview-eb-mp.dtsi
@@ -150,11 +150,6 @@
interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>;
};
-&charlcd {
- interrupt-parent = <&intc>;
- interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
-};
-
&serial0 {
interrupt-parent = <&intc>;
interrupts = <0 4 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/exynos5410.dtsi b/arch/arm/boot/dts/exynos5410.dtsi
index 137f484..bb59fee 100644
--- a/arch/arm/boot/dts/exynos5410.dtsi
+++ b/arch/arm/boot/dts/exynos5410.dtsi
@@ -274,7 +274,6 @@
&rtc {
clocks = <&clock CLK_RTC>;
clock-names = "rtc";
- interrupt-parent = <&pmu_system_controller>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/logicpd-som-lv-37xx-devkit.dts b/arch/arm/boot/dts/logicpd-som-lv-37xx-devkit.dts
index 38faa90..2fa5eb4 100644
--- a/arch/arm/boot/dts/logicpd-som-lv-37xx-devkit.dts
+++ b/arch/arm/boot/dts/logicpd-som-lv-37xx-devkit.dts
@@ -72,7 +72,8 @@
};
&gpmc {
- ranges = <1 0 0x08000000 0x1000000>; /* CS1: 16MB for LAN9221 */
+ ranges = <0 0 0x30000000 0x1000000 /* CS0: 16MB for NAND */
+ 1 0 0x2c000000 0x1000000>; /* CS1: 16MB for LAN9221 */
ethernet@gpmc {
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/logicpd-som-lv.dtsi b/arch/arm/boot/dts/logicpd-som-lv.dtsi
index 26cce4d..4f2c5ec 100644
--- a/arch/arm/boot/dts/logicpd-som-lv.dtsi
+++ b/arch/arm/boot/dts/logicpd-som-lv.dtsi
@@ -37,7 +37,7 @@
};
&gpmc {
- ranges = <0 0 0x00000000 0x1000000>; /* CS0: 16MB for NAND */
+ ranges = <0 0 0x30000000 0x1000000>; /* CS0: 16MB for NAND */
nand@0,0 {
compatible = "ti,omap2-nand";
@@ -121,7 +121,7 @@
&mmc3 {
interrupts-extended = <&intc 94 &omap3_pmx_core2 0x46>;
- pinctrl-0 = <&mmc3_pins>;
+ pinctrl-0 = <&mmc3_pins &wl127x_gpio>;
pinctrl-names = "default";
vmmc-supply = <&wl12xx_vmmc>;
non-removable;
@@ -132,8 +132,8 @@
wlcore: wlcore@2 {
compatible = "ti,wl1273";
reg = <2>;
- interrupt-parent = <&gpio5>;
- interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; /* gpio 152 */
+ interrupt-parent = <&gpio1>;
+ interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; /* gpio 2 */
ref-clock-frequency = <26000000>;
};
};
@@ -157,8 +157,6 @@
OMAP3_CORE1_IOPAD(0x2166, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat5.sdmmc3_dat1 */
OMAP3_CORE1_IOPAD(0x2168, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat6.sdmmc3_dat2 */
OMAP3_CORE1_IOPAD(0x216a, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat6.sdmmc3_dat3 */
- OMAP3_CORE1_IOPAD(0x2184, PIN_INPUT_PULLUP | MUX_MODE4) /* mcbsp4_clkx.gpio_152 */
- OMAP3_CORE1_IOPAD(0x2a0c, PIN_OUTPUT | MUX_MODE4) /* sys_boot1.gpio_3 */
OMAP3_CORE1_IOPAD(0x21d0, PIN_INPUT_PULLUP | MUX_MODE3) /* mcspi1_cs1.sdmmc3_cmd */
OMAP3_CORE1_IOPAD(0x21d2, PIN_INPUT_PULLUP | MUX_MODE3) /* mcspi1_cs2.sdmmc_clk */
>;
@@ -228,6 +226,12 @@
OMAP3_WKUP_IOPAD(0x2a0e, PIN_OUTPUT | MUX_MODE4) /* sys_boot2.gpio_4 */
>;
};
+ wl127x_gpio: pinmux_wl127x_gpio_pin {
+ pinctrl-single,pins = <
+ OMAP3_WKUP_IOPAD(0x2a0c, PIN_INPUT | MUX_MODE4) /* sys_boot0.gpio_2 */
+ OMAP3_WKUP_IOPAD(0x2a0c, PIN_OUTPUT | MUX_MODE4) /* sys_boot1.gpio_3 */
+ >;
+ };
};
&omap3_pmx_core2 {
diff --git a/arch/arm/boot/dts/lpc3250-ea3250.dts b/arch/arm/boot/dts/lpc3250-ea3250.dts
index 52b3ed1..e2bc731 100644
--- a/arch/arm/boot/dts/lpc3250-ea3250.dts
+++ b/arch/arm/boot/dts/lpc3250-ea3250.dts
@@ -156,8 +156,8 @@
uda1380: uda1380@18 {
compatible = "nxp,uda1380";
reg = <0x18>;
- power-gpio = <&gpio 0x59 0>;
- reset-gpio = <&gpio 0x51 0>;
+ power-gpio = <&gpio 3 10 0>;
+ reset-gpio = <&gpio 3 2 0>;
dac-clk = "wspll";
};
diff --git a/arch/arm/boot/dts/lpc3250-phy3250.dts b/arch/arm/boot/dts/lpc3250-phy3250.dts
index fd95e2b..b7bd3a1 100644
--- a/arch/arm/boot/dts/lpc3250-phy3250.dts
+++ b/arch/arm/boot/dts/lpc3250-phy3250.dts
@@ -81,8 +81,8 @@
uda1380: uda1380@18 {
compatible = "nxp,uda1380";
reg = <0x18>;
- power-gpio = <&gpio 0x59 0>;
- reset-gpio = <&gpio 0x51 0>;
+ power-gpio = <&gpio 3 10 0>;
+ reset-gpio = <&gpio 3 2 0>;
dac-clk = "wspll";
};
diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 77c6b93..23fe049 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -197,12 +197,14 @@
compatible = "mediatek,mt2701-hifsys", "syscon";
reg = <0 0x1a000000 0 0x1000>;
#clock-cells = <1>;
+ #reset-cells = <1>;
};
ethsys: syscon@1b000000 {
compatible = "mediatek,mt2701-ethsys", "syscon";
reg = <0 0x1b000000 0 0x1000>;
#clock-cells = <1>;
+ #reset-cells = <1>;
};
bdpsys: syscon@1c000000 {
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 9c289dd..4d6584f 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -352,7 +352,7 @@
elm: elm@48078000 {
compatible = "ti,am3352-elm";
reg = <0x48078000 0x2000>;
- interrupts = <4>;
+ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "elm";
status = "disabled";
};
@@ -859,14 +859,12 @@
usbhsohci: ohci@4a064800 {
compatible = "ti,ohci-omap3";
reg = <0x4a064800 0x400>;
- interrupt-parent = <&gic>;
interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
};
usbhsehci: ehci@4a064c00 {
compatible = "ti,ehci-omap";
reg = <0x4a064c00 0x400>;
- interrupt-parent = <&gic>;
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
};
};
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index 8f6af4c..d9be3c3 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -2,9 +2,16 @@
dtb-$(CONFIG_ARCH_SDXPOORWILLS) += sdxpoorwills-rumi.dtb \
sdxpoorwills-cdp.dtb \
sdxpoorwills-mtp.dtb \
+ sdxpoorwills-cdp-256.dtb \
+ sdxpoorwills-mtp-256.dtb \
sdxpoorwills-pcie-ep-cdp.dtb \
sdxpoorwills-pcie-ep-mtp.dtb
+dtb-$(CONFIG_ARCH_MDM9650) += mdm9650-nand-mtp.dtb \
+ mdm9650-ttp.dtb \
+ mdm9650-v1.1-nand-mtp.dtb \
+ mdm9650-v1.1-nand-cv2x.dtb
+
targets += dtbs
targets += $(addprefix ../, $(dtb-y))
diff --git a/arch/arm/boot/dts/qcom/mdm9650-blsp.dtsi b/arch/arm/boot/dts/qcom/mdm9650-blsp.dtsi
new file mode 100644
index 0000000..47d276f
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-blsp.dtsi
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+/ {
+ aliases {
+ i2c1 = &i2c_1;
+ i2c2 = &i2c_2;
+ i2c3 = &i2c_3;
+ i2c4 = &i2c_4;
+ spi1 = &spi_1;
+ spi2 = &spi_2;
+ spi3 = &spi_3;
+ spi4 = &spi_4;
+ };
+};
+
+&soc {
+ dma_blsp1: qcom,sps-dma@7884000{ /* BLSP1 */
+ #dma-cells = <4>;
+ compatible = "qcom,sps-dma";
+ reg = <0x7884000 0x23000>;
+ interrupts = <0 238 0>;
+ qcom,summing-threshold = <0x10>;
+ };
+
+ i2c_1: i2c@78b5000 { /* BLSP1 QUP1 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b5000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 95 0>;
+ dmas = <&dma_blsp1 8 64 0x20000020 0x20>,
+ <&dma_blsp1 9 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ qcom,master-id = <86>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup1_i2c_apps_clk>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_1_active>;
+ pinctrl-1 = <&i2c_1_sleep>;
+ status = "disabled";
+ };
+
+ i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b6000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 96 0>;
+ dmas = <&dma_blsp1 10 64 0x20000020 0x20>,
+ <&dma_blsp1 11 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ qcom,master-id = <86>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup2_i2c_apps_clk>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_2_active>;
+ pinctrl-1 = <&i2c_2_sleep>;
+ status = "disabled";
+ };
+
+ i2c_3: i2c@78b7000 { /* BLSP1 QUP3 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b7000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 97 0>;
+ dmas = <&dma_blsp1 12 64 0x20000020 0x20>,
+ <&dma_blsp1 13 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ qcom,master-id = <86>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_3_active>;
+ pinctrl-1 = <&i2c_3_sleep>;
+ status = "disabled";
+
+ wcd9xxx_codec@d{
+ compatible = "qcom,tasha-i2c-pgd";
+ reg = <0x0d>;
+
+ interrupt-parent = <&wcd9xxx_intc>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29
+ 30>;
+
+ qcom,cdc-reset-gpio = <&tlmm_pinmux 90 0>;
+
+ clock-names = "wcd_clk";
+ clocks = <&clock_audio clk_audio_lpass_mclk>;
+
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+
+ cdc-vdd-buck-supply = <&codec_buck_vreg>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ cdc-buck-sido-supply = <&codec_buck_vreg>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <200000>;
+
+ cdc-vdd-tx-h-supply = <&pmd9650_l6>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&pmd9650_l6>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vddpx-1-supply = <&pmd9650_l6>;
+ qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+ qcom,cdc-vddpx-1-current = <10000>;
+
+ qcom,cdc-static-supplies = "cdc-vdd-buck",
+ "cdc-buck-sido",
+ "cdc-vdd-tx-h",
+ "cdc-vdd-rx-h",
+ "cdc-vddpx-1";
+
+ qcom,cdc-micbias1-mv = <1800>;
+ qcom,cdc-micbias2-mv = <1800>;
+ qcom,cdc-micbias3-mv = <1800>;
+ qcom,cdc-micbias4-mv = <1800>;
+ qcom,cdc-mclk-clk-rate = <12288000>;
+ qcom,cdc-dmic-sample-rate = <4800000>;
+
+ swr_master {
+ compatible = "qcom,swr-wcd";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ wsa881x_211: wsa881x@20170211 {
+ compatible = "qcom,wsa881x";
+ reg = <0x00 0x20170211>;
+ qcom,spkr-sd-n-gpio =
+ <&tlmm_pinmux 81 0>;
+ };
+
+ wsa881x_212: wsa881x@20170212 {
+ compatible = "qcom,wsa881x";
+ reg = <0x00 0x20170212>;
+ qcom,spkr-sd-n-gpio =
+ <&tlmm_pinmux 81 0>;
+ };
+
+ wsa881x_213: wsa881x@21170213 {
+ compatible = "qcom,wsa881x";
+ reg = <0x00 0x21170213>;
+ qcom,spkr-sd-n-gpio =
+ <&tlmm_pinmux 81 0>;
+ };
+
+ wsa881x_214: wsa881x@21170214 {
+ compatible = "qcom,wsa881x";
+ reg = <0x00 0x21170214>;
+ qcom,spkr-sd-n-gpio =
+ <&tlmm_pinmux 81 0>;
+ };
+ };
+ };
+ };
+
+ i2c_4: i2c@78b8000 { /* BLSP1 QUP4 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b8000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 98 0>;
+ dmas = <&dma_blsp1 14 64 0x20000020 0x20>,
+ <&dma_blsp1 15 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ qcom,master-id = <86>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup4_i2c_apps_clk>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_4_active>;
+ pinctrl-1 = <&i2c_4_sleep>;
+ status = "disabled";
+ };
+
+
+ spi_1: spi@78b5000 { /* BLSP1 QUP1 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0x078b5000 0x600>,
+ <0x7884000 0x23000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 95 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <8>;
+ qcom,bam-producer-pipe-index = <9>;
+ qcom,master-id = <86>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_1_active>;
+ pinctrl-1 = <&spi_1_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup1_spi_apps_clk>;
+ status = "disabled";
+ };
+
+ spi_2: spi@78b6000 { /* BLSP1 QUP2 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0x78b6000 0x600>,
+ <0x7884000 0x23000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 96 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <10>;
+ qcom,bam-producer-pipe-index = <11>;
+ qcom,master-id = <86>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_2_active>;
+ pinctrl-1 = <&spi_2_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup2_spi_apps_clk>;
+ status = "disabled";
+ };
+
+ spi_3: spi@78b7000 { /* BLSP1 QUP3 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0x078b7000 0x600>,
+ <0x7884000 0x23000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 97 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <12>;
+ qcom,bam-producer-pipe-index = <13>;
+ qcom,master-id = <86>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_3_active>;
+ pinctrl-1 = <&spi_3_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup3_spi_apps_clk>;
+ status = "disabled";
+ };
+
+ spi_4: spi@78b8000 { /* BLSP1 QUP4 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0x078b8000 0x600>,
+ <0x7884000 0x23000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 98 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <14>;
+ qcom,bam-producer-pipe-index = <15>;
+ qcom,master-id = <86>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_4_active>;
+ pinctrl-1 = <&spi_4_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup4_spi_apps_clk>;
+ status = "disabled";
+ };
+
+ blsp1_uart1_hs: uart@78af000 { /* BLSP1 UART1 */
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x78af000 0x200>,
+ <0x7884000 0x23000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+ #address-cells = <0>;
+ interrupt-parent = <&blsp1_uart1_hs>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 107 0
+ 1 &intc 0 238 0
+ 2 &tlmm_pinmux 1 0>;
+
+ qcom,inject-rx-on-wakeup;
+ qcom,rx-char-to-inject = <0xFD>;
+
+ qcom,bam-tx-ep-pipe-index = <0>;
+ qcom,bam-rx-ep-pipe-index = <1>;
+ qcom,master-id = <86>;
+ clock-names = "core_clk", "iface_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_uart1_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ pinctrl-names = "sleep", "default";
+ pinctrl-0 = <&blsp1_uart1_sleep>;
+ pinctrl-1 = <&blsp1_uart1_active>;
+
+ qcom,msm-bus,name = "buart1";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <86 512 0 0>,
+ <86 512 500 800>;
+ status = "disabled";
+ };
+
+ blsp1_uart2_hs: uart@78b0000 { /* BLSP1 UART2 */
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x78b0000 0x200>,
+ <0x7884000 0x23000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+ #address-cells = <0>;
+ interrupt-parent = <&blsp1_uart2_hs>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 108 0
+ 1 &intc 0 238 0
+ 2 &tlmm_pinmux 5 0>;
+
+ qcom,inject-rx-on-wakeup;
+ qcom,rx-char-to-inject = <0xFD>;
+
+ qcom,bam-tx-ep-pipe-index = <2>;
+ qcom,bam-rx-ep-pipe-index = <3>;
+ qcom,master-id = <86>;
+ clock-names = "core_clk", "iface_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ pinctrl-names = "sleep", "default";
+ pinctrl-0 = <&blsp1_uart2_sleep>;
+ pinctrl-1 = <&blsp1_uart2_active>;
+
+ qcom,msm-bus,name = "buart2";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <86 512 0 0>,
+ <86 512 500 800>;
+ status = "disabled";
+ };
+
+ blsp1_uart3_hs: uart@78b1000 { /* BLSP1 UART3 */
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x78b1000 0x200>,
+ <0x7884000 0x23000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+ #address-cells = <0>;
+ interrupt-parent = <&blsp1_uart3_hs>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 109 0
+ 1 &intc 0 238 0
+ 2 &tlmm_pinmux 9 0>;
+
+ qcom,inject-rx-on-wakeup;
+ qcom,rx-char-to-inject = <0xFD>;
+
+ qcom,bam-tx-ep-pipe-index = <4>;
+ qcom,bam-rx-ep-pipe-index = <5>;
+ qcom,master-id = <86>;
+ clock-names = "core_clk", "iface_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_uart3_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ pinctrl-names = "sleep", "default";
+ pinctrl-0 = <&blsp1_uart3_sleep>;
+ pinctrl-1 = <&blsp1_uart3_active>;
+
+ qcom,msm-bus,name = "buart3";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <86 512 0 0>,
+ <86 512 500 800>;
+ status = "disabled";
+ };
+
+ blsp1_uart4_hs: uart@78b2000 { /* BLSP1 UART4 */
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x78b2000 0x200>,
+ <0x7884000 0x23000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+ #address-cells = <0>;
+ interrupt-parent = <&blsp1_uart4_hs>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 110 0
+ 1 &intc 0 238 0
+ 2 &tlmm_pinmux 13 0>;
+
+ qcom,inject-rx-on-wakeup;
+ qcom,rx-char-to-inject = <0xFD>;
+
+ qcom,bam-tx-ep-pipe-index = <6>;
+ qcom,bam-rx-ep-pipe-index = <7>;
+ qcom,master-id = <86>;
+ clock-names = "core_clk", "iface_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_uart4_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ pinctrl-names = "sleep", "default";
+ pinctrl-0 = <&blsp1_uart4_sleep>;
+ pinctrl-1 = <&blsp1_uart4_active>;
+
+ qcom,msm-bus,name = "buart4";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <86 512 0 0>,
+ <86 512 500 800>;
+ status = "disabled";
+ };
+
+ blsp1_uart4b_hs: uart@78b2000 { /* BLSP1 UART4b */
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x78b2000 0x200>,
+ <0x7884000 0x23000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+ #address-cells = <0>;
+ interrupt-parent = <&blsp1_uart4_hs>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 110 0
+ 1 &intc 0 238 0
+ 2 &tlmm_pinmux 17 0>;
+
+ qcom,inject-rx-on-wakeup;
+ qcom,rx-char-to-inject = <0xFD>;
+
+ qcom,bam-tx-ep-pipe-index = <6>;
+ qcom,bam-rx-ep-pipe-index = <7>;
+ qcom,master-id = <86>;
+ clock-names = "core_clk", "iface_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_uart4_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ pinctrl-names = "sleep", "default";
+ pinctrl-0 = <&blsp1_uart4b_sleep>;
+ pinctrl-1 = <&blsp1_uart4b_active>;
+
+ qcom,msm-bus,name = "buart4b";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <86 512 0 0>,
+ <86 512 500 800>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-bus.dtsi b/arch/arm/boot/dts/qcom/mdm9650-bus.dtsi
new file mode 100644
index 0000000..ffa45ca
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-bus.dtsi
@@ -0,0 +1,776 @@
+/* Copyright (c) 2015, 2018, 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.
+ */
+
+/* Version = 2 */
+#include <dt-bindings/msm/msm-bus-ids.h>
+
+&soc {
+ ad_hoc_bus: ad-hoc-bus {
+ compatible = "qcom,msm-bus-device";
+ reg = <0x580000 0x14000>,
+ <0x400000 0x62000>,
+ <0x500000 0x11000>;
+ reg-names = "snoc-base", "bimc-base", "pcnoc-base";
+
+ /* Buses */
+
+ fab_bimc: fab-bimc {
+ cell-id = <MSM_BUS_FAB_BIMC>;
+ label = "fab-bimc";
+ qcom,fab-dev;
+ qcom,base-name = "bimc-base";
+ qcom,bus-type = <2>;
+ qcom,bypass-qos-prg;
+ qcom,util-fact = <153>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_gcc clk_bimc_msmbus_clk>,
+ <&clock_gcc clk_bimc_msmbus_a_clk>;
+ };
+
+ fab_pcnoc: fab-pcnoc {
+ cell-id = <MSM_BUS_FAB_PERIPH_NOC>;
+ label = "fab-pcnoc";
+ qcom,fab-dev;
+ qcom,base-name = "pcnoc-base";
+ qcom,bypass-qos-prg;
+ qcom,bus-type = <1>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_gcc clk_pcnoc_msmbus_clk>,
+ <&clock_gcc clk_pcnoc_msmbus_a_clk>;
+ };
+
+ fab_snoc: fab-snoc {
+ cell-id = <MSM_BUS_FAB_SYS_NOC>;
+ label = "fab-snoc";
+ qcom,fab-dev;
+ qcom,base-name = "snoc-base";
+ qcom,bypass-qos-prg;
+ qcom,bus-type = <1>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_gcc clk_snoc_msmbus_clk>,
+ <&clock_gcc clk_snoc_msmbus_a_clk>;
+
+ };
+
+ /* Masters */
+
+ mas_apps_proc: mas-apps-proc {
+ cell-id = <MSM_BUS_MASTER_AMPSS_M0>;
+ label = "mas-apps-proc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <0>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = < &slv_bimc_snoc_1_pcie &slv_ebi
+ &slv_bimc_snoc>;
+ qcom,prio-lvl = <0>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_APPSS_PROC>;
+ };
+
+ mas_snoc_bimc: mas-snoc-bimc {
+ cell-id = <MSM_BUS_SNOC_BIMC_MAS>;
+ label = "mas-snoc-bimc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <3>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_ebi>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC>;
+ };
+
+ mas_tcu_0: mas-tcu-0 {
+ cell-id = <MSM_BUS_MASTER_TCU_0>;
+ label = "mas-tcu-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <4>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = < &slv_bimc_snoc_1_pcie &slv_ebi
+ &slv_bimc_snoc>;
+ qcom,prio-lvl = <2>;
+ qcom,prio-rd = <2>;
+ qcom,prio-wr = <2>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_TCU_0>;
+ };
+
+ mas_audio: mas-audio {
+ cell-id = <MSM_BUS_MASTER_AUDIO>;
+ label = "mas-audio";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_m_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_AUDIO>;
+ qcom,blacklist = <&slv_pdm &slv_pmic_arb &slv_audio
+ &slv_usb3_phy_cfg &slv_tcsr &slv_snoc_cfg
+ &slv_blsp_1 &slv_qpic_cfg &slv_tcu
+ &slv_tlmm &slv_ipa_cfg &slv_prng
+ &slv_dcc_cfg &slv_crypto_0_cfg &slv_pcie_parf
+ &slv_message_ram &slv_sdcc_1
+ &slv_spmi_fetcher>;
+ };
+
+ mas_blsp_1: mas-blsp-1 {
+ cell-id = <MSM_BUS_MASTER_BLSP_1>;
+ label = "mas-blsp-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_m_1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_BLSP_1>;
+ };
+
+ mas_qpic: mas-qpic {
+ cell-id = <MSM_BUS_MASTER_QPIC>;
+ label = "mas-qpic";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_m_1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_QPIC>;
+ };
+
+ mas_crypto: mas-crypto {
+ cell-id = <MSM_BUS_MASTER_CRYPTO>;
+ label = "mas-crypto";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <0>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_1>;
+ qcom,prio1 = <0>;
+ qcom,prio0 = <0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_CRYPTO>;
+ qcom,blacklist = <&slv_pmic_arb &slv_audio &slv_tcsr
+ &slv_snoc_cfg &slv_tcu &slv_tlmm
+ &slv_ipa_cfg &slv_dcc_cfg &slv_crypto_0_cfg
+ &slv_pcie_parf &slv_message_ram
+ &slv_spmi_fetcher>;
+ };
+
+ mas_sdcc_1: mas-sdcc-1 {
+ cell-id = <MSM_BUS_MASTER_SDCC_1>;
+ label = "mas-sdcc-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_int_1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SDCC_1>;
+ };
+
+ mas_spmi_fetcher: mas-spmi-fetcher {
+ cell-id = <MSM_BUS_SPMI_FETCHER>;
+ label = "mas-spmi-fetcher";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_m_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SPMI_FETCHER>;
+ qcom,blacklist = <&slv_pdm &slv_audio &slv_usb3_phy_cfg
+ &slv_tcsr &slv_snoc_cfg &slv_blsp_1
+ &slv_qpic_cfg &slv_tcu &slv_tlmm
+ &slv_ipa_cfg &slv_prng &slv_dcc_cfg
+ &slv_crypto_0_cfg &slv_pcie_parf
+ &slv_message_ram &slv_sdcc_1 &slv_spmi_fetcher>;
+ };
+
+ mas_snoc_pcnoc: mas-snoc-pcnoc {
+ cell-id = <MSM_BUS_SNOC_PNOC_MAS>;
+ label = "mas-snoc-pcnoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <9>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_5>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_PCNOC>;
+ };
+
+ mas_qdss_bam: mas-qdss-bam {
+ cell-id = <MSM_BUS_MASTER_QDSS_BAM>;
+ label = "mas-qdss-bam";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <12>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_usb3 &slv_imem &slv_snoc_bimc
+ &slv_snoc_pcnoc>;
+ qcom,prio1 = <0>;
+ qcom,prio0 = <0>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_QDSS_BAM>;
+ };
+
+ mas_bimc_snoc: mas-bimc-snoc {
+ cell-id = <MSM_BUS_BIMC_SNOC_MAS>;
+ label = "mas-bimc-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = < &slv_usb3 &slv_cats_0
+ &slv_snoc_pcnoc &slv_imem &slv_qdss_stm
+ &slv_apss_ahb>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_BIMC_SNOC>;
+ };
+
+ mas_bimc_snoc_1_pcie: mas-bimc-snoc-1-pcie {
+ cell-id = <MSM_BUS_BIMC_SNOC_1_MAS>;
+ label = "mas-bimc-snoc-1-pcie";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_pcie_0>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_BIMC_SNOC_1>;
+ };
+
+ mas_ipa: mas-ipa {
+ cell-id = <MSM_BUS_MASTER_IPA>;
+ label = "mas-ipa";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_usb3 &slv_snoc_pcnoc
+ &slv_pcie_0 &slv_snoc_bimc &slv_imem
+ &slv_qdss_stm>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_IPA>;
+ };
+
+ mas_usb3: mas-usb3 {
+ cell-id = <MSM_BUS_MASTER_USB3>;
+ label = "mas-usb3";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <8>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_usb3 &slv_imem &slv_qdss_stm
+ &slv_snoc_bimc &slv_snoc_pcnoc>;
+ qcom,prio1 = <0>;
+ qcom,prio0 = <0>;
+ qcom,bus-dev = <&fab_snoc>;
+ //clock-names = "bus_qos_clocks";
+ //clocks = <&gcc_sys_noc_usb3_axi_clk>;
+ qcom,mas-rpm-id = <ICBID_MASTER_USB3>;
+ };
+
+ mas_pcnoc_snoc: mas-pcnoc-snoc {
+ cell-id = <MSM_BUS_PNOC_SNOC_MAS>;
+ label = "mas-pcnoc-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <5>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = < &slv_usb3 &slv_imem &slv_pcie_0
+ &slv_snoc_bimc &slv_apss_ahb
+ &slv_qdss_stm>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PNOC_SNOC>;
+ };
+
+ mas_qdss_etr: mas-qdss-etr {
+ cell-id = <MSM_BUS_MASTER_QDSS_ETR>;
+ label = "mas-qdss-etr";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <11>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_usb3 &slv_imem &slv_snoc_bimc
+ &slv_snoc_pcnoc>;
+ qcom,prio1 = <0>;
+ qcom,prio0 = <0>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_QDSS_ETR>;
+ };
+
+ mas_pcie_0: mas-pcie-0 {
+ cell-id = <MSM_BUS_MASTER_PCIE>;
+ label = "mas-pcie-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <7>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = < &slv_imem &slv_qdss_stm
+ &slv_apss_ahb
+ &slv_snoc_bimc &slv_snoc_pcnoc>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCIE_0>;
+ };
+
+ /* Internal nodes */
+
+ pcnoc_m_0: pcnoc-m-0 {
+ cell-id = <MSM_BUS_PNOC_M_0>;
+ label = "pcnoc-m-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <5>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&pcnoc_int_2>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_M_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_M_0>;
+ };
+
+ pcnoc_m_1: pcnoc-m-1 {
+ cell-id = <MSM_BUS_PNOC_M_1>;
+ label = "pcnoc-m-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <6>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_2>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_M_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_M_1>;
+ };
+
+ pcnoc_int_0: pcnoc-int-0 {
+ cell-id = <MSM_BUS_PNOC_INT_0>;
+ label = "pcnoc-int-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_s_1 &pcnoc_s_2 &pcnoc_s_0
+ &pcnoc_s_4 &pcnoc_s_7 &pcnoc_s_3>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_0>;
+ };
+
+ pcnoc_int_1: pcnoc-int-1 {
+ cell-id = <MSM_BUS_PNOC_INT_1>;
+ label = "pcnoc-int-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_pcnoc_snoc &pcnoc_int_5>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_1>;
+ };
+
+ pcnoc_int_2: pcnoc-int-2 {
+ cell-id = <MSM_BUS_PNOC_INT_2>;
+ label = "pcnoc-int-2";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_int_5 &pcnoc_int_4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_2>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_2>;
+ };
+
+ pcnoc_int_4: pcnoc-int-4 {
+ cell-id = <MSM_BUS_PNOC_INT_4>;
+ label = "pcnoc-int-4";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_pcnoc_snoc>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_4>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_4>;
+ };
+
+ pcnoc_int_5: pcnoc-int-5 {
+ cell-id = <MSM_BUS_PNOC_INT_5>;
+ label = "pcnoc-int-5";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = < &pcnoc_int_6 &pcnoc_int_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_5>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_5>;
+ };
+
+ pcnoc_int_6: pcnoc-int-6 {
+ cell-id = <MSM_BUS_PNOC_INT_6>;
+ label = "pcnoc-int-6";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_s_8 &slv_tcu>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_6>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_6>;
+ };
+
+ pcnoc_s_0: pcnoc-s-0 {
+ cell-id = <MSM_BUS_PNOC_SLV_0>;
+ label = "pcnoc-s-0";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = < &slv_tlmm&slv_tcsr>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_0>;
+ };
+
+ pcnoc_s_1: pcnoc-s-1 {
+ cell-id = <MSM_BUS_PNOC_SLV_1>;
+ label = "pcnoc-s-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_crypto_0_cfg &slv_prng &slv_pdm
+ &slv_message_ram>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_1>;
+ };
+
+ pcnoc_s_2: pcnoc-s-2 {
+ cell-id = <MSM_BUS_PNOC_SLV_2>;
+ label = "pcnoc-s-2";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_pmic_arb>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_2>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_2>;
+ };
+
+ pcnoc_s_3: pcnoc-s-3 {
+ cell-id = <MSM_BUS_PNOC_SLV_3>;
+ label = "pcnoc-s-3";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_snoc_cfg>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_3>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_3>;
+ };
+
+ pcnoc_s_4: pcnoc-s-4 {
+ cell-id = <MSM_BUS_PNOC_SLV_4>;
+ label = "pcnoc-s-4";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_pcie_parf &slv_usb3_phy_cfg
+ &slv_audio &slv_spmi_fetcher>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_4>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_4>;
+ };
+
+ pcnoc_s_7: pcnoc-s-7 {
+ cell-id = <MSM_BUS_PNOC_SLV_7>;
+ label = "pcnoc-s-7";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_ipa_cfg>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_7>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_7>;
+ };
+
+ pcnoc_s_8: pcnoc-s-8 {
+ cell-id = <MSM_BUS_PNOC_SLV_8>;
+ label = "pcnoc-s-8";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = < &slv_dcc_cfg &slv_qpic_cfg
+ &slv_blsp_1 &slv_sdcc_1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_8>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_8>;
+ };
+
+ /* Slaves */
+
+ slv_ebi:slv-ebi {
+ cell-id = <MSM_BUS_SLAVE_EBI_CH0>;
+ label = "slv-ebi";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_EBI1>;
+ };
+
+ slv_bimc_snoc:slv-bimc-snoc {
+ cell-id = <MSM_BUS_BIMC_SNOC_SLV>;
+ label = "slv-bimc-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,connections = <&mas_bimc_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_BIMC_SNOC>;
+ };
+
+ slv_bimc_snoc_1_pcie:slv-bimc-snoc-1-pcie {
+ cell-id = <MSM_BUS_BIMC_SNOC_1_SLV>;
+ label = "slv-bimc-snoc-1-pcie";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,connections = <&mas_bimc_snoc_1_pcie>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_BIMC_SNOC_1>;
+ };
+
+ slv_tcsr:slv-tcsr {
+ cell-id = <MSM_BUS_SLAVE_TCSR>;
+ label = "slv-tcsr";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_TCSR>;
+ };
+
+ slv_tlmm:slv-tlmm {
+ cell-id = <MSM_BUS_SLAVE_TLMM>;
+ label = "slv-tlmm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_TLMM>;
+ };
+
+ slv_crypto_0_cfg:slv-crypto-0-cfg {
+ cell-id = <MSM_BUS_SLAVE_CRYPTO_0_CFG>;
+ label = "slv-crypto-0-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CRYPTO_0_CFG>;
+ };
+
+ slv_message_ram:slv-message-ram {
+ cell-id = <MSM_BUS_SLAVE_MESSAGE_RAM>;
+ label = "slv-message-ram";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_MESSAGE_RAM>;
+ };
+
+ slv_pdm:slv-pdm {
+ cell-id = <MSM_BUS_SLAVE_PDM>;
+ label = "slv-pdm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PDM>;
+ };
+
+ slv_prng:slv-prng {
+ cell-id = <MSM_BUS_SLAVE_PRNG>;
+ label = "slv-prng";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PRNG>;
+ };
+
+ slv_pmic_arb:slv-pmic-arb {
+ cell-id = <MSM_BUS_SLAVE_PMIC_ARB>;
+ label = "slv-pmic-arb";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PMIC_ARB>;
+ };
+
+ slv_snoc_cfg:slv-snoc-cfg {
+ cell-id = <MSM_BUS_SLAVE_SNOC_CFG>;
+ label = "slv-snoc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_CFG>;
+ };
+
+ slv_sdcc_1:slv-sdcc-1 {
+ cell-id = <MSM_BUS_SLAVE_SDCC_1>;
+ label = "slv-sdcc-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SDCC_1>;
+ };
+
+ slv_blsp_1:slv-blsp-1 {
+ cell-id = <MSM_BUS_SLAVE_BLSP_1>;
+ label = "slv-blsp-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_BLSP_1>;
+ };
+
+ slv_dcc_cfg:slv-dcc-cfg {
+ cell-id = <MSM_BUS_SLAVE_DCC_CFG>;
+ label = "slv-dcc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_DCC_CFG>;
+ };
+
+ slv_audio:slv-audio {
+ cell-id = <MSM_BUS_SLAVE_AUDIO>;
+ label = "slv-audio";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_AUDIO>;
+ };
+
+ slv_spmi_fetcher:slv-spmi-fetcher {
+ cell-id = <MSM_BUS_SLAVE_SPMI_FETCHER>;
+ label = "slv-spmi-fetcher";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SPMI_FETCHER>;
+ };
+
+ slv_tcu:slv-tcu {
+ cell-id = <MSM_BUS_SLAVE_TCU>;
+ label = "slv-tcu";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_TCU>;
+ };
+
+ slv_pcnoc_snoc:slv-pcnoc-snoc {
+ cell-id = <MSM_BUS_PNOC_SNOC_SLV>;
+ label = "slv-pcnoc-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,connections = <&mas_pcnoc_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_SNOC>;
+ };
+
+ slv_pcie_parf:slv-pcie-parf {
+ cell-id = <MSM_BUS_SLAVE_PCIE_PARF>;
+ label = "slv-pcie-parf";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCIE_PARF>;
+ };
+
+ slv_usb3_phy_cfg:slv-usb3-phy-cfg {
+ cell-id = <MSM_BUS_SLAVE_USB3_PHY_CFG>;
+ label = "slv-usb3-phy-cfg";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_USB3_PHY_CFG>;
+ };
+
+ slv_qpic_cfg:slv-qpic-cfg {
+ cell-id = <MSM_BUS_SLAVE_QPIC>;
+ label = "slv-qpic-cfg";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_QPIC>;
+ };
+
+ slv_ipa_cfg:slv-ipa-cfg {
+ cell-id = <MSM_BUS_SLAVE_IPA_CFG>;
+ label = "slv-ipa-cfg";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_IPA_CFG>;
+ };
+
+ slv_apss_ahb:slv-apss-ahb {
+ cell-id = <MSM_BUS_SLAVE_APPSS>;
+ label = "slv-apss-ahb";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_APPSS>;
+ };
+
+ slv_snoc_bimc:slv-snoc-bimc {
+ cell-id = <MSM_BUS_SNOC_BIMC_SLV>;
+ label = "slv-snoc-bimc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,connections = <&mas_snoc_bimc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC>;
+ };
+
+ slv_imem:slv-imem {
+ cell-id = <MSM_BUS_SLAVE_OCIMEM>;
+ label = "slv-imem";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_IMEM>;
+ };
+
+ slv_snoc_pcnoc:slv-snoc-pcnoc {
+ cell-id = <MSM_BUS_SNOC_PNOC_SLV>;
+ label = "slv-snoc-pcnoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,connections = <&mas_snoc_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_PCNOC>;
+ };
+
+ slv_qdss_stm:slv-qdss-stm {
+ cell-id = <MSM_BUS_SLAVE_QDSS_STM>;
+ label = "slv-qdss-stm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_QDSS_STM>;
+ };
+
+ slv_pcie_0:slv-pcie-0 {
+ cell-id = <MSM_BUS_SLAVE_PCIE_0>;
+ label = "slv-pcie-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCIE_0>;
+ };
+
+ slv_usb3:slv-usb3 {
+ cell-id = <MSM_BUS_SLAVE_USB3>;
+ label = "slv-usb3";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_USB3>;
+ };
+
+ slv_cats_0:slv-cats-0 {
+ cell-id = <MSM_BUS_SLAVE_CATS_128>;
+ label = "slv-cats-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CATS_0>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi b/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi
new file mode 100644
index 0000000..28aa863
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi
@@ -0,0 +1,624 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "mdm9650-v1.1.dtsi"
+#include "mdm9650-pinctrl.dtsi"
+
+/ {
+ aliases {
+ serial0 = &blsp1_uart3;
+ serial1 = &blsp1_uart1;
+ };
+};
+
+&soc {
+ sound {
+ status = "disabled";
+ };
+
+ usb_detect {
+ compatible = "qcom,gpio-usbdetect";
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x0 0x0d 0x0>; /* PMD9655 VBUS DETECT */
+ interrupt-names = "vbus_det_irq";
+ };
+
+ bt_qca6174 {
+ qca,bt-vdd-core-supply = <&wlan_ext_vreg>;
+ /delete-property/ qca,bt-vdd-xtal-supply;
+ };
+
+ /* 4V regulator for peripherals */
+ periph_vreg: regulator-periph-lm53635 {
+ status = "disabled";
+ compatible = "regulator-fixed";
+ regulator-name = "periph_vreg";
+ startup-delay-us = <4000>;
+ gpio = <&tlmm_pinmux 9 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&periph_vreg_gpio>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
+ /* 1.8V/3.3V external regulator for wlan */
+ wlan_ext_vreg: regulator-wlan-tlv62065 {
+ compatible = "regulator-fixed";
+ regulator-name = "wlan_ext_vreg";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ startup-delay-us = <500>;
+ gpio = <&tlmm_pinmux 97 0>;
+ enable-active-high;
+ };
+
+ /* 1.8V/3.3V regulator for audio codec */
+ codec_vreg: regulator-codec-tlv7103318 {
+ compatible = "regulator-fixed";
+ regulator-name = "codec_vreg";
+ startup-delay-us = <100>;
+ gpio = <&tlmm_pinmux 38 0>;
+ enable-active-high;
+ };
+
+ /* 3.0V regulator for BTLE chip */
+ btle_vreg: regulator-btle-lp5907 {
+ compatible = "regulator-fixed";
+ regulator-name = "btle_vreg";
+ startup-delay-us = <150>;
+ gpio = <&tlmm_pinmux 34 0>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
+ /* 1.8V regulator for A2B transceiver */
+ a2b_vreg: regulator-a2b-lp3996 {
+ compatible = "regulator-fixed";
+ regulator-name = "a2b_vreg";
+ startup-delay-us = <300>;
+ gpio = <&tlmm_pinmux 96 0>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
+ /* 1.8V/3.3V regulator for gyro/accel */
+ gyro_vreg: regulator-gyro-tlv7103318 {
+ compatible = "regulator-fixed";
+ regulator-name = "gyro_vreg";
+ startup-delay-us = <100>;
+ gpio = <&tlmm_pinmux 99 0>;
+ enable-active-high;
+ regulator-always-on;
+ };
+};
+
+&tlmm_pinmux {
+ /* Set these up as hogs */
+ pinctrl-names = "default";
+ pinctrl-0 = <&ant_switch_gpio1>, <&ant_switch_gpio2>,
+ <&ant_switch_gpio3>, <ð_can_supply_gpio>,
+ <&oabr_enable_gpio>;
+
+ periph_vreg_gpio: periph_vreg_gpio {
+ mux {
+ pins = "gpio9";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio9";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ /* This gpio controls ETH supply on v1 and CAN supply on v2 */
+ eth_can_supply_gpio: eth_can_supply_gpio {
+ mux {
+ pins = "gpio69";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio69";
+ drive-strength = <2>;
+ output-high;
+ bias-pull-up;
+ };
+ };
+
+ oabr_enable_gpio: oabr_enable_gpio {
+ mux {
+ pins = "gpio29";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio29";
+ drive-strength = <2>;
+ output-high;
+ bias-pull-up;
+ };
+ };
+
+ pmx_sec_mi2s_aux {
+ sec_ws_sleep: sec_ws_sleep {
+ mux {
+ pins = "gpio20";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ sec_sck_sleep: sec_sck_sleep {
+ mux {
+ pins = "gpio23";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio23";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ sec_dout_sleep: sec_dout_sleep {
+ mux {
+ pins = "gpio22";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ sec_ws_active_master: sec_ws_active_master {
+ mux {
+ pins = "gpio20";
+ function = "sec_mi2s_ws_b";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+
+ sec_sck_active_master: sec_sck_active_master {
+ mux {
+ pins = "gpio23";
+ function = "sec_mi2s_sck_b";
+ };
+
+ config {
+ pins = "gpio23";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+
+ sec_ws_active_slave: sec_ws_active_slave {
+ mux {
+ pins = "gpio20";
+ function = "sec_mi2s_ws_b";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ };
+ };
+
+ sec_sck_active_slave: sec_sck_active_slave {
+ mux {
+ pins = "gpio23";
+ function = "sec_mi2s_sck_b";
+ };
+
+ config {
+ pins = "gpio23";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ };
+ };
+
+ sec_dout_active: sec_dout_active {
+ mux {
+ pins = "gpio22";
+ function = "sec_mi2s_data1_b";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+ };
+
+ pmx_sec_mi2s_aux_din {
+ sec_din_sleep: sec_din_sleep {
+ mux {
+ pins = "gpio21";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ sec_din_active: sec_din_active {
+ mux {
+ pins = "gpio21";
+ function = "sec_mi2s_data0_b";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ /* Pins for the antenna switch matrix */
+ pmx_antenna_switch_matrix {
+ ant_switch_gpio1: ant_switch_gpio1 {
+ mux {
+ pins = "gpio31";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio31";
+ drive-strength = <2>;
+ output-low;
+ bias-disable;
+ };
+ };
+
+ ant_switch_gpio2: ant_switch_gpio2 {
+ mux {
+ pins = "gpio32";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio32";
+ drive-strength = <2>;
+ output-high;
+ bias-pull-up;
+ };
+ };
+
+ ant_switch_gpio3: ant_switch_gpio3 {
+ mux {
+ pins = "gpio33";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio33";
+ drive-strength = <2>;
+ output-high;
+ bias-pull-up;
+ };
+ };
+ };
+
+ bmi160_int1_default: bmi160_int1_default {
+ mux {
+ pins = "gpio81";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio81";
+ drive-strength = <16>; /* 16 mA */
+ bias-pull-down; /* pull down */
+ };
+ };
+
+ bmi160_int2_default: bmi160_int2_default {
+ mux {
+ pins = "gpio94";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio94";
+ drive-strength = <16>; /* 16 mA */
+ bias-pull-down; /* pull down */
+ };
+ };
+
+ i2c_1b {
+ i2c_1b_active: i2c_1b_active {
+ mux {
+ pins = "gpio84", "gpio85";
+ function = "blsp_i2c1";
+ };
+
+ config {
+ pins = "gpio84", "gpio85";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_1b_sleep: i2c_1b_sleep {
+ mux {
+ pins = "gpio84", "gpio85";
+ function = "blsp_i2c1";
+ };
+
+ config {
+ pins = "gpio84", "gpio85";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ can_reset {
+ can_rst_on: rst_on {
+ mux {
+ pins = "gpio89";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio89";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-up;
+ };
+ };
+
+ can_rst_off: rst_off {
+ mux {
+ pins = "gpio89";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio89";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-up;
+ output-high;
+ };
+ };
+ };
+};
+
+&cnss_pcie {
+ vdd-wlan-io-supply = <&wlan_ext_vreg>;
+ /delete-property/ vdd-wlan-xtal-supply;
+ /delete-property/ vdd-wlan-xtal-aon-supply;
+};
+
+/* BLE serial (no HCI) */
+&blsp1_uart1 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_console_active>;
+};
+
+/* Console conflicts with periph_vreg (GPIO_9) */
+&blsp1_uart3 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_console_active>;
+};
+
+/* BT classic */
+&blsp1_uart2_hs {
+ status = "ok";
+};
+
+&i2c_1 {
+ status = "ok";
+ pinctrl-0 = <&i2c_1b_active>;
+ pinctrl-1 = <&i2c_1b_sleep>;
+};
+
+&i2c_3 {
+ status = "ok";
+
+ wcd9xxx_codec@d {
+ status = "disabled";
+ };
+
+ tlv320aic3x_codec: tlv320aic3x@18 {
+ compatible = "ti,tlv320aic3x";
+ reg = <0x18>;
+ gpio-reset = <&tlmm_pinmux 90 0>;
+ AVDD-supply = <&codec_vreg>;
+ IOVDD-supply = <&pmd9650_l6>;
+ };
+
+ lsm330-gyro@6a {
+ compatible = "st,lsm330-gyro";
+ reg = <0x6a>;
+ };
+
+ lsm330-accel@1d {
+ compatible = "st,lsm330-accel";
+ reg = <0x1d>;
+ };
+};
+
+&spi_4 {
+ status = "ok";
+ /delete-property/ qcom,use-bam;
+};
+
+&usb3 {
+ qcom,charging-disabled;
+};
+
+/* Needed by blsp1_uart1 (BLE) */
+&pmd9650_l13 {
+ regulator-always-on;
+};
+
+&pmd9650_gpios {
+ gpio@c000 { /* GPIO 1 - PCIESW_EN */
+ status = "ok";
+ qcom,mode = <1>; /* Digital output*/
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,invert = <1>; /* Output high */
+ qcom,vin-sel = <1>; /* 1.8 V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,out-strength = <1>; /* High drive strength */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c100 { /* GPIO 2 - VADC */
+ /* GPIO should be left off, and in the high
+ * impedance state when the pin is used with the VADC
+ */
+ status = "ok";
+ qcom,master-en = <0>; /* DISABLE GPIO */
+ };
+
+ gpio@c200 { /* GPIO 3 - CAN_ETH_EN, CAN on v1 and ETH on v2 */
+ status = "ok";
+ qcom,mode = <1>; /* Digital output*/
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,invert = <1>; /* Output high */
+ qcom,vin-sel = <1>; /* 1.8 V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,out-strength = <1>; /* High drive strength */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c400 { /* GPIO 5 - USB_ID */
+ status = "ok";
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <1>; /* Pull up 1.5 uA */
+ qcom,vin-sel = <1>; /* 1.8 V */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c500 { /* GPIO 6 - Rome 3.3V control */
+ status = "ok";
+ qcom,mode = <1>; /* Digital output*/
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,invert = <1>; /* Output high */
+ qcom,vin-sel = <0>; /* VPH_PWR */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,out-strength = <1>; /* High drive strength */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c700 { /* GPIO 8 - BT_EN */
+ status = "ok";
+ qcom,mode = <1>; /* Digital output*/
+ qcom,pull = <4>; /* Pulldown 10uA */
+ qcom,vin-sel = <0>; /* VPH_PWR */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,invert = <0>; /* Invert */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+};
+
+&pmd9650_vadc {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4c {
+ label = "xo_therm_buf";
+ reg = <0x4c>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@53 {
+ label = "ambient_therm";
+ reg = <0x53>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4d {
+ label = "mdm_case_therm";
+ reg = <0x4d>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4e {
+ label = "pa_therm1";
+ reg = <0x4e>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4f {
+ label = "pa_therm2";
+ reg = <0x4f>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-coresight.dtsi b/arch/arm/boot/dts/qcom/mdm9650-coresight.dtsi
new file mode 100644
index 0000000..81ef261
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-coresight.dtsi
@@ -0,0 +1,467 @@
+/* Copyright (c) 2015-2018, 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.
+ */
+
+&soc {
+ tmc_etr: tmc@828000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0x828000 0x1000>,
+ <0x884000 0x15000>;
+ reg-names = "tmc-base", "bam-base";
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
+
+ qcom,memory-size = <0x100000>;
+ qcom,sg-enable;
+
+ coresight-id = <1>;
+ coresight-name = "coresight-tmc-etr";
+ coresight-nr-inports = <1>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ replicator: replicator@3026000 {
+ compatible = "qcom,coresight-replicator";
+ reg = <0x826000 0x1000>;
+ reg-names = "replicator-base";
+
+ coresight-id = <2>;
+ coresight-name = "coresight-replicator";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0>;
+ coresight-child-list = <&tmc_etr>;
+ coresight-child-ports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ tmc_etf: tmc@827000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0x827000 0x1000>;
+ reg-names = "tmc-base";
+
+ coresight-id = <3>;
+ coresight-name = "coresight-tmc-etf";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0>;
+ coresight-child-list = <&replicator>;
+ coresight-child-ports = <0>;
+ coresight-default-sink;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ funnel_merge: funnel@825000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0x825000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <4>;
+ coresight-name = "coresight-funnel-merg";
+ coresight-nr-inports = <2>;
+ coresight-outports = <0>;
+ coresight-child-list = <&tmc_etf>;
+ coresight-child-ports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ funnel_in0: funnel@821000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0x821000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <5>;
+ coresight-name = "coresight-funnel-in0";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_merge>;
+ coresight-child-ports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ funnel_in1: funnel@822000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0x822000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <6>;
+ coresight-name = "coresight-funnel-in1";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_merge>;
+ coresight-child-ports = <1>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ modem_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+
+ coresight-id = <7>;
+ coresight-name = "coresight-modem-etm0";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <6>;
+
+ qcom,inst-id = <2>;
+ };
+
+ rpm_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+
+ coresight-id = <8>;
+ coresight-name = "coresight-rpm-etm0";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in0>;
+ coresight-child-ports = <0>;
+
+ qcom,inst-id = <4>;
+ };
+
+ etm0: etm@842000 {
+ compatible = "arm,coresight-etm";
+ reg = <0x842000 0x1000>;
+ reg-names = "etm-base";
+
+ coresight-id = <9>;
+ coresight-name = "coresight-etm0";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <7>;
+ coresight-etm-cpu = <&CPU0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ csr: csr@801000 {
+ compatible = "qcom,coresight-csr";
+ reg = <0x801000 0x1000>;
+ reg-names = "csr-base";
+
+ coresight-id = <11>;
+ coresight-name = "coresight-csr";
+ coresight-nr-inports = <0>;
+
+ qcom,blk-size = <1>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ stm: stm@802000 {
+ compatible = "arm,coresight-stm";
+ reg = <0x802000 0x1000>,
+ <0x9280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
+
+ coresight-id = <12>;
+ coresight-name = "coresight-stm";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in0>;
+ coresight-child-ports = <7>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ dbgui: dbgui@86d000 {
+ compatible = "qcom,coresight-dbgui";
+ reg = <0x86d000 0x1000>;
+ reg-names = "dbgui-base";
+
+ coresight-id = <13>;
+ coresight-name = "coresight-dbgui";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <4>;
+
+ qcom,dbgui-addr-offset = <0x30>;
+ qcom,dbgui-data-offset = <0xb0>;
+ qcom,dbgui-size = <0x20>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ tpda: tpda@803000 {
+ compatible = "qcom,coresight-tpda";
+ reg = <0x803000 0x1000>;
+ reg-names = "tpda-base";
+
+ coresight-id = <14>;
+ coresight-name = "coresight-tpda";
+ coresight-nr-inports = <32>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in0>;
+ coresight-child-ports = <6>;
+
+ qcom,tpda-atid = <65>;
+ qcom,cmb-elem-size = <0 8>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ tpda_modem: tpda@3003000 {
+ compatible = "qcom,coresight-tpda";
+ reg = <0x83b000 0x1000>;
+ reg-names = "tpda-base";
+
+ coresight-id = <15>;
+ coresight-name = "coresight-tpda-modem";
+ coresight-nr-inports = <32>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <5>;
+
+ qcom,tpda-atid = <66>;
+ qcom,dsb-elem-size = <0 32>;
+ qcom,cmb-elem-size = <0 8>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ tpdm_dcc: tpdm@864000 {
+ compatible = "qcom,coresight-tpdm";
+ reg = <0x864000 0x1000>;
+ reg-names = "tpdm-base";
+
+ coresight-id = <16>;
+ coresight-name = "coresight-tpdm-dcc";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&tpda>;
+ coresight-child-ports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ tpdm_modem: tpdm@83a000 {
+ compatible = "qcom,coresight-tpdm";
+ reg = <0x83a000 0x1000>;
+ reg-names = "tpdm-base";
+
+ coresight-id = <17>;
+ coresight-name = "coresight-tpdm-modem";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&tpda_modem>;
+ coresight-child-ports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti0: cti@810000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x810000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <18>;
+ coresight-name = "coresight-cti0";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti1: cti@811000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x811000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <19>;
+ coresight-name = "coresight-cti1";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti2: cti@812000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x812000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <20>;
+ coresight-name = "coresight-cti2";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+
+ qcom,cti-gpio-trigout = <4>;
+ pinctrl-names = "cti-trigout-pctrl";
+ pinctrl-0 = <&trigout_a>;
+ };
+
+ cti3: cti@813000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x813000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <21>;
+ coresight-name = "coresight-cti3";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti4: cti@814000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x814000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <22>;
+ coresight-name = "coresight-cti4";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti5: cti@815000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x815000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <23>;
+ coresight-name = "coresight-cti5";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti6: cti@816000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x816000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <24>;
+ coresight-name = "coresight-cti6";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_modem_cpu0: cti@8390000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x839000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <25>;
+ coresight-name = "coresight-cti-modem-cpu0";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_pmu_cpu0: cti@841000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x841000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <26>;
+ coresight-name = "coresight-cti-pmu-cpu0";
+ coresight-nr-inports = <0>;
+ coresight-cti-cpu = <&CPU0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_cpu0: cti@843000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x843000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <27>;
+ coresight-name = "coresight-cti-cpu0";
+ coresight-nr-inports = <0>;
+ coresight-cti-cpu = <&CPU0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ hwevent: hwevent@86c000 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0x0086c000 0x148>,
+ <0x08af8860 0x4>,
+ <0x0200c000 0x4>,
+ <0x0200c008 0x20>,
+ <0x08b05014 0x4>,
+ <0x0408200c 0x4>,
+ <0X0086cfb0 0x4>,
+ <0X00801fb0 0x4>;
+ reg-names = "qdss-wrapper",
+ "usb30",
+ "spmi-test",
+ "spmi-events",
+ "usb30-bam",
+ "mss",
+ "qdss-wrapper-expd-lockaccess",
+ "qdss-apb-csr-lockaccess";
+
+ coresight-id = <28>;
+ coresight-name = "coresight-hwevent";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-cv2x.dtsi b/arch/arm/boot/dts/qcom/mdm9650-cv2x.dtsi
new file mode 100644
index 0000000..c2627e1
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-cv2x.dtsi
@@ -0,0 +1,299 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "mdm9650-v1.1.dtsi"
+#include "mdm9650-pinctrl.dtsi"
+
+/ {
+ aliases {
+ serial0 = &blsp1_uart3;
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ status {
+ gpios = <&tlmm_pinmux 14 0>;
+ default-state = "on";
+ };
+ };
+};
+
+&soc {
+ sound {
+ status = "disabled";
+ };
+
+ usb_detect {
+ compatible = "qcom,gpio-usbdetect";
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x0 0x0d 0x0>; /* PMD9655 VBUS DETECT */
+ interrupt-names = "vbus_det_irq";
+ };
+
+ can_vreg: regulator-can-tps65051 {
+ compatible = "regulator-fixed";
+ regulator-name = "can_vreg";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ startup-delay-us = <920>;
+ gpio = <&tlmm_pinmux 69 0>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
+ pps {
+ use-system-time-ts;
+ };
+};
+
+&cnss_pcie {
+ status = "disabled";
+};
+
+&blsp1_uart3 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_console_active>;
+};
+
+&i2c_3 {
+ status = "ok";
+
+ wcd9xxx_codec@d {
+ status = "disabled";
+ };
+};
+
+&spi_1 {
+ status = "ok";
+ /delete-property/ qcom,use-bam;
+};
+
+&spi_2 {
+ status = "ok";
+};
+
+&qnand_1 {
+ status = "ok";
+};
+
+&usb3 {
+ qcom,charging-disabled;
+};
+
+&pcie_ep {
+ status = "ok";
+ perst-gpio = <&tlmm_pinmux 60 0>;
+ wake-gpio = <&tlmm_pinmux 61 0>;
+ clkreq-gpio = <&tlmm_pinmux 64 0>;
+ mdm2apstatus-gpio = <&tlmm_pinmux 20 0>;
+ /delete-property/ qcom,pcie-perst-enum;
+};
+
+&pcie0 {
+ status = "disabled";
+};
+
+&cnss_pcie {
+ status = "disabled";
+};
+
+&mhi_device {
+ status = "ok";
+};
+
+/* pinctrl redefinitions */
+&bmi160_int1_default {
+ mux {
+ pins = "gpio81";
+ };
+ config {
+ pins = "gpio81";
+ };
+};
+
+&bmi160_int2_default {
+ mux {
+ pins = "gpio94";
+ };
+ config {
+ pins = "gpio94";
+ };
+};
+
+&can_rst_on {
+ mux {
+ pins = "gpio89";
+ };
+ config {
+ pins = "gpio89";
+ };
+};
+
+&can_rst_off {
+ mux {
+ pins = "gpio89";
+ };
+ config {
+ pins = "gpio89";
+ };
+};
+
+&pcie_ep_perst_default {
+ mux {
+ pins = "gpio60";
+ };
+ config {
+ pins = "gpio60";
+ };
+};
+
+&pcie0_mdm2apstatus_default {
+ mux {
+ pins = "gpio20";
+ };
+ config {
+ pins = "gpio20";
+ bias-disable;
+ /delete-property/ bias-pull-down;
+ };
+};
+
+/* Needed by spi_1 */
+&pmd9650_l13 {
+ regulator-always-on;
+};
+
+&pmd9650_gpios {
+ gpio@c000 { /* GPIO 1 - MDM2AP_VDD_MIN */
+ status = "ok";
+ qcom,mode = <1>; /* Digital output*/
+ qcom,pull = <4>; /* Pulldown 10uA */
+ qcom,vin-sel = <0>; /* VPH_PWR */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,invert = <0>; /* Invert */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c100 { /* GPIO 2 - VADC */
+ /* GPIO should be left off, and in the high
+ * impedance state when the pin is used with the VADC
+ */
+ status = "ok";
+ qcom,master-en = <0>; /* DISABLE GPIO */
+ };
+
+ gpio@c200 { /* GPIO 3 - MDM2AP_VDD_WAKEUP */
+ status = "ok";
+ qcom,mode = <1>; /* Digital output*/
+ qcom,pull = <4>; /* Pulldown 10uA */
+ qcom,vin-sel = <0>; /* VPH_PWR */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,invert = <0>; /* Invert */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c400 { /* GPIO 5 - USB_ID */
+ status = "ok";
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <1>; /* Pull up 1.5 uA */
+ qcom,vin-sel = <1>; /* 1.8 V */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c800 { /* GPIO 9 - CAN_EN - not used */
+ /* Set as input since CAN_EN is being set
+ * from MDM GPIO, same line goes to this pin
+ */
+ status = "ok";
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <5>; /* No pull */
+ qcom,vin-sel = <1>; /* 1.8 V */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+};
+
+&pmd9650_vadc {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4c {
+ label = "xo_therm_buf";
+ reg = <0x4c>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@53 {
+ label = "ambient_therm";
+ reg = <0x53>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4d {
+ label = "mdm_case_therm";
+ reg = <0x4d>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4e {
+ label = "pa_therm1";
+ reg = <0x4e>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4f {
+ label = "pa_therm2";
+ reg = <0x4f>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-display.dtsi b/arch/arm/boot/dts/qcom/mdm9650-display.dtsi
new file mode 100644
index 0000000..367c290e
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-display.dtsi
@@ -0,0 +1,36 @@
+/* Copyright (c) 2015-2018, 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.
+ */
+
+/ {
+ mdss_qpic: qcom,msm_qpic@7980000 {
+ compatible = "qcom,mdss_qpic";
+ reg = <0x7980000 0x24000>;
+ reg-names = "qpic_base";
+ interrupts = <0 251 0>;
+
+ qcom,msm-bus,name = "mdss_qpic";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+
+ qcom,msm-bus,vectors-KBps =
+ <91 512 0 0>,
+ /* Voting for max b/w on PNOC bus for now */
+ <91 512 400000 800000>;
+
+ vdd-supply = <&pmd9650_l6>;
+ avdd-supply = <&pmd9650_l12>;
+
+ clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_gcc clk_qpic_clk>,
+ <&clock_gcc clk_qpic_a_clk>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-ion.dtsi b/arch/arm/boot/dts/qcom/mdm9650-ion.dtsi
new file mode 100644
index 0000000..aab5f06
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-ion.dtsi
@@ -0,0 +1,36 @@
+/* Copyright (c) 2014-2015, 2018, 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.
+ */
+
+&soc {
+ qcom,ion {
+ compatible = "qcom,msm-ion";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ion-heap@25 {
+ reg = <25>;
+ qcom,ion-heap-type = "SYSTEM";
+ };
+
+ qcom,ion-heap@28 { /* AUDIO HEAP */
+ reg = <28>;
+ memory-region = <&audio_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
+
+ qcom,ion-heap@27 { /* QSEECOM HEAP */
+ reg = <27>;
+ memory-region = <&qseecom_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-mtp.dtsi b/arch/arm/boot/dts/qcom/mdm9650-mtp.dtsi
new file mode 100644
index 0000000..da89cca
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-mtp.dtsi
@@ -0,0 +1,195 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "mdm9650.dtsi"
+#include "mdm9650-pinctrl.dtsi"
+#include "mdm9650-display.dtsi"
+#include "qpic-panel-ili-hvga.dtsi"
+
+&blsp1_uart3 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_console_active>;
+};
+
+&blsp1_uart2_hs {
+ status = "ok";
+};
+
+&i2c_3 {
+ status = "ok";
+ smb1351_otg_supply: smb1351-charger@55 {
+ compatible = "qcom,smb1351-charger";
+ reg = <0x55>;
+ interrupt-parent = <&tlmm_pinmux>;
+ interrupts = <83 IRQ_TYPE_LEVEL_LOW>;
+ qcom,float-voltage-mv = <4200>;
+ qcom,charging-timeout = <1536>;
+ qcom,recharge-thresh-mv = <200>;
+ qcom,iterm-ma = <100>;
+ regulator-name = "smb1351_otg_supply";
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_stat_active>;
+ qcom,id-line-not-connected;
+ qcom,switch-freq = <2>;
+ };
+};
+
+&pmd9650_gpios {
+ gpio@c100 { /* GPIO 2 - VADC */
+ /* GPIO should be left off, and in the high
+ * impedance state when the pin is used with the VADC
+ */
+ status = "ok";
+ qcom,master-en = <0>; /* DISABLE GPIO */
+ };
+
+ gpio@c200 { /* GPIO 3 - LED */
+ status = "ok";
+ qcom,master-en = <0>; /* Disable GPIO */
+ };
+
+ gpio@c400 { /* GPIO 5 - USB_ID */
+ status = "ok";
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <1>; /* Pull up 1.5 uA */
+ qcom,vin-sel = <1>; /* 1.8 V */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c500 { /* GPIO 6 - Rome 3.3V control */
+ status = "ok";
+ qcom,mode = <1>; /* Digital output*/
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,invert = <1>; /* Output high */
+ qcom,vin-sel = <0>; /* VPH_PWR */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,out-strength = <1>; /* High drive strength */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c700 { /* GPIO 8 - BT_EN */
+ status = "ok";
+ qcom,mode = <1>; /* Digital output*/
+ qcom,pull = <4>; /* Pulldown 10uA */
+ qcom,vin-sel = <0>; /* VPH_PWR */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,invert = <0>; /* Invert */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+};
+
+&pmd9650_misc {
+ qcom,pwm-sel = <2>; /* PWM2 */
+ qcom,enable-gp-driver; /* Enable GP */
+};
+
+&pmd9650_pwm_1 {
+ status = "ok";
+};
+
+&pmd9650_pwm_2 {
+ status = "ok";
+};
+
+&qnand_1 {
+ status = "ok";
+};
+
+&usb3 {
+ vbus_dwc3-supply = <&smb1351_otg_supply>;
+ cpe-gpio = <&tlmm_pinmux 87 0>;
+};
+
+&pmd9650_vadc {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4c {
+ label = "xo_therm_buf";
+ reg = <0x4c>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@53 {
+ label = "ambient_therm";
+ reg = <0x53>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4d {
+ label = "mdm_case_therm";
+ reg = <0x4d>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4e {
+ label = "pa_therm1";
+ reg = <0x4e>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4f {
+ label = "pa_therm2";
+ reg = <0x4f>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+};
+
+/* Display */
+&mdss_qpic {
+ pinctrl-names= "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_cs_active &mdss_te_active &mdss_rs_active
+ &mdss_ad_active &mdss_bl_active>;
+ pinctrl-1 = <&mdss_cs_sleep &mdss_te_sleep
+ &mdss_rs_sleep &mdss_ad_sleep &mdss_bl_sleep>;
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-nand-mtp.dts b/arch/arm/boot/dts/qcom/mdm9650-nand-mtp.dts
new file mode 100644
index 0000000..e107001
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-nand-mtp.dts
@@ -0,0 +1,40 @@
+/* Copyright (c) 2015-2018, 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 "mdm9650-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MDM 9650 MTP (NAND)";
+ compatible = "qcom,mdm9650-mtp", "qcom,mdm9650",
+ "qcom,mtp";
+ qcom,board-id = <8 0>, <8 0x100>;
+};
+
+&sdhc_1 {
+ vdd-supply = <&sdc_vreg>;
+
+ vdd-io-supply = <&pmd9650_l7>;
+ qcom,vdd-io-voltage-level = <1800000 2848000>;
+ qcom,vdd-io-current-level = <200 10000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>;
+
+ qcom,bus-width = <4>;
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+ 200000000>;
+
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-pinctrl.dtsi b/arch/arm/boot/dts/qcom/mdm9650-pinctrl.dtsi
new file mode 100644
index 0000000..f3c1491
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-pinctrl.dtsi
@@ -0,0 +1,1333 @@
+/* Copyright (c) 2015-2018, 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.
+ */
+
+&soc {
+ tlmm_pinmux: pinctrl@1000000 {
+ compatible = "qcom,mdm9650-pinctrl";
+ reg = <0x1000000 0x300000>;
+ interrupts = <0 208 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ uart1_console_active: uart1_console_active {
+ mux {
+ pins = "gpio0", "gpio1";
+ function = "blsp_uart1";
+ };
+ config {
+ pins = "gpio0", "gpio1";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ trigout_a: trigout_a {
+ mux {
+ pins = "gpio92";
+ function = "qdss_cti";
+ };
+ config {
+ pins = "gpio92";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ uart2_console_active: uart2_console_active {
+ mux {
+ pins = "gpio4", "gpio5";
+ function = "blsp_uart2";
+ };
+ config {
+ pins = "gpio4", "gpio5";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ uart3_console_active: uart3_console_active {
+ mux {
+ pins = "gpio8", "gpio9";
+ function = "blsp_uart3";
+ };
+ config {
+ pins = "gpio8", "gpio9";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ uart3_console_sleep: uart3_console_sleep {
+ mux {
+ pins = "gpio8", "gpio9";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio8", "gpio9";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ /* I2C CONFIGURATION */
+ i2c_1 {
+ i2c_1_active: i2c_1_active {
+ mux {
+ pins = "gpio2", "gpio3";
+ function = "blsp_i2c1";
+ };
+
+ config {
+ pins = "gpio2", "gpio3";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_1_sleep: i2c_1_sleep {
+ mux {
+ pins = "gpio2", "gpio3";
+ function = "blsp_i2c1";
+ };
+
+ config {
+ pins = "gpio2", "gpio3";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ i2c_2 {
+ i2c_2_active: i2c_2_active {
+ mux {
+ pins = "gpio6", "gpio7";
+ function = "blsp_i2c2";
+ };
+
+ config {
+ pins = "gpio6", "gpio7";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_2_sleep: i2c_2_sleep {
+ mux {
+ pins = "gpio6", "gpio7";
+ function = "blsp_i2c2";
+ };
+
+ config {
+ pins = "gpio6", "gpio7";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ i2c_3 {
+ i2c_3_active: i2c_3_active {
+ mux {
+ pins = "gpio10", "gpio11";
+ function = "blsp_i2c3";
+ };
+
+ config {
+ pins = "gpio10", "gpio11";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_3_sleep: i2c_3_sleep {
+ mux {
+ pins = "gpio10", "gpio11";
+ function = "blsp_i2c3";
+ };
+
+ config {
+ pins = "gpio10", "gpio11";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ i2c_4 {
+ i2c_4_active: i2c_4_active {
+ mux {
+ pins = "gpio14", "gpio15";
+ function = "blsp_i2c4";
+ };
+
+ config {
+ pins = "gpio14", "gpio15";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_4_sleep: i2c_4_sleep {
+ mux {
+ pins = "gpio14", "gpio15";
+ function = "blsp_i2c4";
+ };
+
+ config {
+ pins = "gpio14", "gpio15";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ bmi160_int1_default: bmi160_int1_default {
+ mux {
+ pins = "gpio0";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio0";
+ drive-strength = <12>;
+ bias-pull-down;
+ };
+ };
+
+ bmi160_int2_default: bmi160_int2_default {
+ mux {
+ pins = "gpio1";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio1";
+ drive-strength = <12>;
+ bias-pull-down;
+ };
+ };
+
+ cnss_pins {
+ cnss_wlan_en_active: cnss_wlan_en_active {
+ mux {
+ pins = "gpio95";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio95";
+ drive-strength = <16>;
+ output-high;
+ bias-pull-up;
+ };
+ };
+ cnss_wlan_en_sleep: cnss_wlan_en_sleep {
+ mux {
+ pins = "gpio95";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio95";
+ drive-strength = <2>;
+ output-low;
+ bias-pull-down;
+ };
+ };
+
+ cnss_sdio_active: cnss_sdio_active {
+ mux {
+ pins = "gpio37";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio37";
+ drive-strength = <16>;
+ output-high;
+ bias-pull-up;
+ };
+ };
+
+ cnss_sdio_sleep: cnss_sdio_sleep {
+ mux {
+ pins = "gpio37";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio37";
+ drive-strength = <2>;
+ output-low;
+ bias-pull-down;
+ };
+ };
+ };
+
+ /* SPI CONFIGURATION */
+ spi_1 {
+ spi_1_active: spi_1_active {
+ mux {
+ pins = "gpio0", "gpio1", "gpio2",
+ "gpio3";
+ function = "blsp_spi1";
+ };
+
+ config {
+ pins = "gpio0", "gpio1", "gpio2",
+ "gpio3";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_1_sleep: spi_1_sleep {
+ mux {
+ pins = "gpio0", "gpio1", "gpio2",
+ "gpio3";
+ function = "blsp_spi1";
+ };
+
+ config {
+ pins = "gpio0", "gpio1", "gpio2",
+ "gpio3";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ spi_2 {
+ spi_2_active: spi_2_active {
+ mux {
+ pins = "gpio4", "gpio5", "gpio6",
+ "gpio7";
+ function = "blsp_spi2";
+ };
+
+ config {
+ pins = "gpio4", "gpio5", "gpio6",
+ "gpio7";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_2_sleep: spi_2_sleep {
+ mux {
+ pins = "gpio4", "gpio5", "gpio6",
+ "gpio7";
+ function = "blsp_spi2";
+ };
+
+ config {
+ pins = "gpio4", "gpio5", "gpio6",
+ "gpio7";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ spi_3 {
+ spi_3_active: spi_3_active {
+ mux {
+ pins = "gpio8", "gpio9", "gpio10",
+ "gpio11";
+ function = "blsp_spi3";
+ };
+
+ config {
+ pins = "gpio8", "gpio9", "gpio10",
+ "gpio11";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_3_sleep: spi_3_sleep {
+ mux {
+ pins = "gpio8", "gpio9", "gpio10",
+ "gpio11";
+ function = "blsp_spi3";
+ };
+
+ config {
+ pins = "gpio8", "gpio9", "gpio10",
+ "gpio11";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ spi_4 {
+ spi_4_active: spi_4_active {
+ mux {
+ pins = "gpio16", "gpio17", "gpio18",
+ "gpio19";
+ function = "blsp_spi4";
+ };
+
+ config {
+ pins = "gpio16", "gpio17", "gpio18",
+ "gpio19";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_4_sleep: spi_4_sleep {
+ mux {
+ pins = "gpio16", "gpio17", "gpio18",
+ "gpio19";
+ function = "blsp_spi4";
+ };
+
+ config {
+ pins = "gpio16", "gpio17", "gpio18",
+ "gpio19";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SMB CONFIGURATION */
+ pmx_smb_stat {
+ smb_stat_active: smb_stat_active {
+ mux {
+ pins = "gpio83";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio83";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ pcie0 {
+ pcie0_clkreq_default: pcie0_clkreq_default {
+ mux {
+ pins = "gpio64";
+ function = "pcie_clkreq";
+ };
+ config {
+ pins = "gpio64";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ pcie0_perst_default: pcie0_perst_default {
+ mux {
+ pins = "gpio60";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio60";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ pcie0_wake_default: pcie0_wake_default {
+ mux {
+ pins = "gpio61";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio61";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ pcie0_mdm2apstatus_default: pcie0_mdm2apstatus_default {
+ mux {
+ pins = "gpio16";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio16";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ pcie_ep_perst_default: pcie_ep_perst_default {
+ mux {
+ pins = "gpio65";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio65";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ pcie_ep_wake_default: pcie_ep_wake_default {
+ mux {
+ pins = "gpio61";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio61";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+ };
+
+ /* UART HS CONFIGURATION */
+ blsp1_uart1_active: blsp1_uart1_active {
+ mux {
+ pins = "gpio0", "gpio1", "gpio2", "gpio3";
+ function = "blsp_uart1";
+ };
+
+ config {
+ pins = "gpio0", "gpio1", "gpio2", "gpio3";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart1_sleep: blsp1_uart1_sleep {
+ mux {
+ pins = "gpio0", "gpio1", "gpio2", "gpio3";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio0", "gpio1", "gpio2", "gpio3";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart2_active: blsp1_uart2_active {
+ mux {
+ pins = "gpio4", "gpio5", "gpio6", "gpio7";
+ function = "blsp_uart2";
+ };
+
+ config {
+ pins = "gpio4", "gpio5", "gpio6", "gpio7";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart2_sleep: blsp1_uart2_sleep {
+ mux {
+ pins = "gpio4", "gpio5", "gpio6", "gpio7";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio4", "gpio5", "gpio6", "gpio7";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart3_active: blsp1_uart3_active {
+ mux {
+ pins = "gpio8", "gpio9", "gpio10", "gpio11";
+ function = "blsp_uart3";
+ };
+
+ config {
+ pins = "gpio8", "gpio9", "gpio10", "gpio11";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart3_sleep: blsp1_uart3_sleep {
+ mux {
+ pins = "gpio8", "gpio9", "gpio10", "gpio11";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio8", "gpio9", "gpio10", "gpio11";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart4_active: blsp1_uart4_active {
+ mux {
+ pins = "gpio12", "gpio13", "gpio14", "gpio15";
+ function = "blsp_uart4";
+ };
+
+ config {
+ pins = "gpio12", "gpio13", "gpio14", "gpio15";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart4_sleep: blsp1_uart4_sleep {
+ mux {
+ pins = "gpio12", "gpio13", "gpio14", "gpio15";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio12", "gpio13", "gpio14", "gpio15";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart4b_active: blsp1_uart4b_active {
+ mux {
+ pins = "gpio16", "gpio17", "gpio18", "gpio19";
+ function = "blsp_uart4";
+ };
+
+ config {
+ pins = "gpio16", "gpio17", "gpio18", "gpio19";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart4b_sleep: blsp1_uart4b_sleep {
+ mux {
+ pins = "gpio16", "gpio17", "gpio18", "gpio19";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio16", "gpio17", "gpio18", "gpio19";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ mdss_cs_active: mdss_cs_active {
+ mux {
+ pins = "gpio21";
+ function = "ebi2_lcd";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <10>; /* 10 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_cs_sleep: mdss_cs_sleep {
+ mux {
+ pins = "gpio21";
+ function = "ebi2_lcd";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_te_active: mdss_te_active {
+ mux {
+ pins = "gpio22";
+ function = "ebi2_lcd";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <10>; /* 10 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_te_sleep: mdss_te_sleep {
+ mux {
+ pins = "gpio22";
+ function = "ebi2_lcd";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_rs_active: mdss_rs_active {
+ mux {
+ pins = "gpio23";
+ function = "ebi2_lcd";
+ };
+
+ config {
+ pins = "gpio23";
+ drive-strength = <10>; /* 10 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_rs_sleep: mdss_rs_sleep {
+ mux {
+ pins = "gpio23";
+ function = "ebi2_lcd";
+ };
+
+ config {
+ pins = "gpio23";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_ad_active: mdss_ad_active {
+ mux {
+ pins = "gpio20";
+ function = "ebi2_a";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <10>; /* 10 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_ad_sleep: mdss_ad_sleep {
+ mux {
+ pins = "gpio20";
+ function = "ebi2_a";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_bl_active: mdss_bl_active {
+ mux {
+ pins = "gpio68";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio68";
+ drive-strength = <10>; /* 10 mA */
+ bias-disable; /* NO pull */
+ output-high;
+ };
+ };
+
+ mdss_bl_sleep: mdss_bl_sleep {
+ mux {
+ pins = "gpio68";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio68";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO pull */
+ output-low;
+ };
+ };
+
+ i2s_mclk {
+ i2s_mclk_sleep: i2s_mclk_sleep {
+ mux {
+ pins = "gpio71";
+ function = "i2s_mclk";
+ };
+
+ config {
+ pins = "gpio71";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+
+ i2s_mclk_active: i2s_mclk_active {
+ mux {
+ pins = "gpio71";
+ function = "i2s_mclk";
+ };
+
+ config {
+ pins = "gpio71";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+
+ };
+
+ pmx_pri_mi2s_aux {
+ pri_ws_sleep: pri_ws_sleep {
+ mux {
+ pins = "gpio12";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio12";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ pri_sck_sleep: pri_sck_sleep {
+ mux {
+ pins = "gpio15";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio15";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ pri_dout_sleep: pri_dout_sleep {
+ mux {
+ pins = "gpio14";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio14";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ pri_ws_active_master: pri_ws_active_master {
+ mux {
+ pins = "gpio12";
+ function = "pri_mi2s_ws_a";
+ };
+
+ config {
+ pins = "gpio12";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+
+ pri_sck_active_master: pri_sck_active_master {
+ mux {
+ pins = "gpio15";
+ function = "pri_mi2s_sck_a";
+ };
+
+ config {
+ pins = "gpio15";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+
+ pri_ws_active_slave: pri_ws_active_slave {
+ mux {
+ pins = "gpio12";
+ function = "pri_mi2s_ws_a";
+ };
+
+ config {
+ pins = "gpio12";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ };
+ };
+
+ pri_sck_active_slave: pri_sck_active_slave {
+ mux {
+ pins = "gpio15";
+ function = "pri_mi2s_sck_a";
+ };
+
+ config {
+ pins = "gpio15";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ };
+ };
+
+ pri_dout_active: pri_dout_active {
+ mux {
+ pins = "gpio14";
+ function = "pri_mi2s_data1_a";
+ };
+
+ config {
+ pins = "gpio14";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+ };
+
+ pmx_pri_mi2s_aux_din {
+ pri_din_sleep: pri_din_sleep {
+ mux {
+ pins = "gpio13";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio13";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ pri_din_active: pri_din_active {
+ mux {
+ pins = "gpio13";
+ function = "pri_mi2s_data0_a";
+ };
+
+ config {
+ pins = "gpio13";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ pmx_sec_mi2s_aux {
+ sec_ws_sleep: sec_ws_sleep {
+ mux {
+ pins = "gpio16";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio16";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ sec_sck_sleep: sec_sck_sleep {
+ mux {
+ pins = "gpio19";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio19";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ sec_dout_sleep: sec_dout_sleep {
+ mux {
+ pins = "gpio18";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio18";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ sec_ws_active_master: sec_ws_active_master {
+ mux {
+ pins = "gpio16";
+ function = "sec_mi2s_ws_a";
+ };
+
+ config {
+ pins = "gpio16";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+
+ sec_sck_active_master: sec_sck_active_master {
+ mux {
+ pins = "gpio19";
+ function = "sec_mi2s_sck_a";
+ };
+
+ config {
+ pins = "gpio19";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+
+ sec_ws_active_slave: sec_ws_active_slave {
+ mux {
+ pins = "gpio16";
+ function = "sec_mi2s_ws_a";
+ };
+
+ config {
+ pins = "gpio16";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ };
+ };
+
+ sec_sck_active_slave: sec_sck_active_slave {
+ mux {
+ pins = "gpio19";
+ function = "sec_mi2s_sck_a";
+ };
+
+ config {
+ pins = "gpio19";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ };
+ };
+
+ sec_dout_active: sec_dout_active {
+ mux {
+ pins = "gpio18";
+ function = "sec_mi2s_data1_a";
+ };
+
+ config {
+ pins = "gpio18";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+ };
+
+ pmx_sec_mi2s_aux_din {
+ sec_din_sleep: sec_din_sleep {
+ mux {
+ pins = "gpio17";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio17";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ sec_din_active: sec_din_active {
+ mux {
+ pins = "gpio17";
+ function = "sec_mi2s_data0_a";
+ };
+
+ config {
+ pins = "gpio17";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ pmx_sec_mi2s_b_aux {
+ sec_ws_b_sleep: sec_ws_b_sleep {
+ mux {
+ pins = "gpio20";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ sec_sck_b_sleep: sec_sck_b_sleep {
+ mux {
+ pins = "gpio23";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio23";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ sec_dout_b_sleep: sec_dout_b_sleep {
+ mux {
+ pins = "gpio22";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ sec_ws_b_active_master: sec_ws_b_active_master {
+ mux {
+ pins = "gpio20";
+ function = "sec_mi2s_ws_b";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+
+ sec_sck_b_active_master: sec_sck_b_active_master {
+ mux {
+ pins = "gpio23";
+ function = "sec_mi2s_sck_b";
+ };
+
+ config {
+ pins = "gpio23";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+
+ sec_ws_b_active_slave: sec_ws_b_active_slave {
+ mux {
+ pins = "gpio20";
+ function = "sec_mi2s_ws_b";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ };
+ };
+
+ sec_sck_b_active_slave: sec_sck_b_active_slave {
+ mux {
+ pins = "gpio23";
+ function = "sec_mi2s_sck_b";
+ };
+
+ config {
+ pins = "gpio23";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ };
+ };
+
+ sec_dout_b_active: sec_dout_b_active {
+ mux {
+ pins = "gpio22";
+ function = "sec_mi2s_data1_b";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+ };
+
+ pmx_sec_mi2s_b_aux_din {
+ sec_din_b_sleep: sec_din_b_sleep {
+ mux {
+ pins = "gpio21";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ sec_din_b_active: sec_din_b_active {
+ mux {
+ pins = "gpio21";
+ function = "sec_mi2s_data0_b";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ sdc1_clk_on: sdc1_clk_on {
+ config {
+ pins = "sdc1_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <16>; /* 16 MA */
+ };
+ };
+
+ sdc1_clk_off: sdc1_clk_off {
+ config {
+ pins = "sdc1_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ sdc1_cmd_on: sdc1_cmd_on {
+ config {
+ pins = "sdc1_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc1_cmd_off: sdc1_cmd_off {
+ config {
+ pins = "sdc1_cmd";
+ num-grp-pins = <1>;
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ sdc1_data_on: sdc1_data_on {
+ config {
+ pins = "sdc1_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc1_data_off: sdc1_data_off {
+ config {
+ pins = "sdc1_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ sdc1_wlan_gpio {
+ sdc1_wlan_gpio_active: sdc1_wlan_gpio_active {
+ mux {
+ pins = "gpio80";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio80";
+ output-high;
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+ };
+
+ sdc1_wlan_gpio_sleep: sdc1_wlan_gpio_sleep {
+ mux {
+ pins = "gpio80";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio80";
+ drive-strength = <2>;
+ bias-pull-down;
+ output-low;
+ };
+ };
+ };
+
+ pinctrl_pps: ppsgrp{
+ mux {
+ pins = "gpio39";
+ function = "nav_dr";
+ };
+
+ config {
+ pins = "gpio39";
+ bias-pull-down;
+ };
+ };
+
+ can_reset {
+ can_rst_on: rst_on {
+ mux {
+ pins = "gpio68";
+ function = "gpio";
+ };
+
+
+ config {
+ pins = "gpio68";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-up;
+ };
+ };
+
+ can_rst_off: rst_off {
+ mux {
+ pins = "gpio68";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio68";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-up;
+ output-high;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-pm.dtsi b/arch/arm/boot/dts/qcom/mdm9650-pm.dtsi
new file mode 100644
index 0000000..f3b2626
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-pm.dtsi
@@ -0,0 +1,145 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/msm/pm.h>
+
+&soc {
+ qcom,spm@b009000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xb009000 0x1000>;
+ qcom,name = "core0";
+ qcom,cpu = <&CPU0>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x101>;
+ qcom,saw2-spm-dly= <0x401004>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,cpu-vctl-mask = <&CPU0>;
+ qcom,mode0 {
+ qcom,label = "qcom,saw2-spm-cmd-wfi";
+ qcom,sequence = [04 03 04 0f];
+ qcom,spm_en;
+ };
+ qcom,mode1 {
+ qcom,label = "qcom,saw2-spm-cmd-pc";
+ qcom,sequence = [1f 34 44 14 24 54 03
+ 54 44 14 24 3e 0f];
+ qcom,spm_en;
+ qcom,pc_mode;
+ qcom,slp_cmd_mode;
+ };
+ };
+
+ qcom,lpm-levels {
+ compatible = "qcom,lpm-levels";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,pm-cluster@0{
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ label = "system";
+ qcom,default-level = <0>;
+
+ qcom,pm-cluster-level@0 {
+ reg = <0>;
+ label = "l2-active";
+ qcom,latency-us = <100>;
+ qcom,ss-power = <8000>;
+ qcom,energy-overhead = <60100000>;
+ qcom,time-overhead = <3000>;
+ };
+
+ qcom,pm-cluster-level@1 {
+ reg = <1>;
+ label = "l2-flush-no-rpm";
+ qcom,latency-us = <2000>;
+ qcom,ss-power = <5000>;
+ qcom,energy-overhead = <60100000>;
+ qcom,time-overhead = <3000>;
+ qcom,min-child-idx = <0>;
+ };
+
+ qcom,pm-cluster-level@2 {
+ reg = <2>;
+ label = "l2-pc";
+ qcom,latency-us = <30000>;
+ qcom,ss-power = <4999>;
+ qcom,energy-overhead = <60350000>;
+ qcom,time-overhead = <7300>;
+ qcom,min-child-idx = <2>;
+ qcom,notify-rpm;
+ qcom,reset-level = <LPM_RESET_LVL_PC>;
+ };
+
+ qcom,pm-cpu {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,pm-cpu-level@0 {
+ reg = <0>;
+ qcom,spm-cpu-mode = "wfi";
+ qcom,latency-us = <100>;
+ qcom,ss-power = <8000>;
+ qcom,energy-overhead = <100000>;
+ qcom,time-overhead = <1>;
+ };
+
+ qcom,pm-cpu-level@1 {
+ reg = <1>;
+ qcom,spm-cpu-mode = "standalone_pc";
+ qcom,latency-us = <2000>;
+ qcom,ss-power = <5000>;
+ qcom,energy-overhead = <60100000>;
+ qcom,time-overhead = <3000>;
+ qcom,reset-level = <LPM_RESET_LVL_PC>;
+ };
+
+ qcom,pm-cpu-level@2 {
+ reg = <2>;
+ qcom,spm-cpu-mode = "pc";
+ qcom,latency-us = <30000>;
+ qcom,ss-power = <4999>;
+ qcom,energy-overhead = <60350000>;
+ qcom,time-overhead = <7300>;
+ qcom,reset-level = <LPM_RESET_LVL_PC>;
+ };
+ };
+ };
+ };
+
+ qcom,pm@8600664 {
+ compatible = "qcom,pm";
+ reg = <0x8600664 0x40>;
+ clocks = <&clock_cpu clk_a7ssmux>;
+ clock-names = "cpu0_clk";
+ qcom,use-sync-timer;
+ qcom,synced-clocks;
+ };
+
+ qcom,rpm-stats@2a1ba0 {
+ compatible = "qcom,rpm-stats";
+ reg = <0x2a1ba0 0x1000>;
+ reg-names = "phys_addr_base";
+ qcom,sleep-stats-version = <2>;
+ };
+
+ qcom,rpm-master-stats@60150 {
+ compatible = "qcom,rpm-master-stats";
+ reg = <0x60150 0x2030>;
+ qcom,masters = "APSS", "MPSS";
+ qcom,master-stats-version = <2>;
+ qcom,master-offset = <2560>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-regulator.dtsi b/arch/arm/boot/dts/qcom/mdm9650-regulator.dtsi
new file mode 100644
index 0000000..d4a6cd7
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-regulator.dtsi
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
+
+&rpm_bus {
+ /* PMD9650 S1 = VDD_MSS supply */
+ rpm-regulator-smpa1 {
+ status = "okay";
+ pmd9650_s1: regulator-s1 {
+ regulator-name = "pmd9650_s1";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <800000>;
+ qcom,init-voltage = <800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa2 {
+ status = "okay";
+ pmd9650_s2: regulator-s2 {
+ regulator-name = "pmd9650_s2";
+ regulator-min-microvolt = <1256000>;
+ regulator-max-microvolt = <1256000>;
+ qcom,init-voltage = <1256000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa3 {
+ status = "okay";
+ pmd9650_s3: regulator-s3 {
+ regulator-name = "pmd9650_s3";
+ regulator-min-microvolt = <1024000>;
+ regulator-max-microvolt = <1024000>;
+ qcom,init-voltage = <1024000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa4 {
+ status = "okay";
+ pmd9650_s4: regulator-s4 {
+ regulator-name = "pmd9650_s4";
+ regulator-min-microvolt = <1856000>;
+ regulator-max-microvolt = <1856000>;
+ qcom,init-voltage = <1856000>;
+ status = "okay";
+ };
+ };
+
+ /* PMD9650 S5 = VDD_CX supply */
+ rpm-regulator-smpa5 {
+ status = "okay";
+ pmd9650_s5_level: regulator-s5-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pmd9650_s5_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR>;
+ qcom,use-voltage-level;
+ };
+
+ pmd9650_s5_level_ao: regulator-s5-level-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pmd9650_s5_level_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR>;
+ qcom,use-voltage-level;
+ };
+
+ pmd9650_s5_floor_level: regulator-s5-floor-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pmd9650_s5_floor_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR>;
+ qcom,use-voltage-floor-level;
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ status = "okay";
+ pmd9650_l1: regulator-l1 {
+ regulator-name = "pmd9650_l1";
+ regulator-min-microvolt = <1224000>;
+ regulator-max-microvolt = <1224000>;
+ qcom,init-voltage = <1224000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ status = "okay";
+ pmd9650_l2: regulator-l2 {
+ regulator-name = "pmd9650_l2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1200000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ status = "okay";
+ pmd9650_l3: regulator-l3 {
+ regulator-name = "pmd9650_l3";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ qcom,init-voltage = <1000000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa4 {
+ status = "okay";
+ pmd9650_l4: regulator-l4 {
+ regulator-name = "pmd9650_l4";
+ regulator-min-microvolt = <928000>;
+ regulator-max-microvolt = <928000>;
+ qcom,init-voltage = <928000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ status = "okay";
+ pmd9650_l5: regulator-l5 {
+ regulator-name = "pmd9650_l5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ status = "okay";
+ pmd9650_l6: regulator-l6 {
+ regulator-name = "pmd9650_l6";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ status = "okay";
+ pmd9650_l7: regulator-l7 {
+ regulator-name = "pmd9650_l7";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2848000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ status = "okay";
+ pmd9650_l8: regulator-l8 {
+ regulator-name = "pmd9650_l8";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ qcom,init-voltage = <1000000>;
+ status = "okay";
+ };
+ };
+
+ /* PMD9650 L9 = VDD_MX supply */
+ rpm-regulator-ldoa9 {
+ status = "okay";
+ pmd9650_l9_level: regulator-l9-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pmd9650_l9_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR>;
+ qcom,use-voltage-level;
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ status = "okay";
+ pmd9650_l10: regulator-l10 {
+ regulator-name = "pmd9650_l10";
+ regulator-min-microvolt = <3088000>;
+ regulator-max-microvolt = <3088000>;
+ qcom,init-voltage = <3088000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ status = "okay";
+ pmd9650_l11: regulator-l11 {
+ regulator-name = "pmd9650_l11";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2848000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ status = "okay";
+ pmd9650_l12: regulator-l12 {
+ regulator-name = "pmd9650_l12";
+ regulator-min-microvolt = <2704000>;
+ regulator-max-microvolt = <2704000>;
+ qcom,init-voltage = <2704000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ status = "okay";
+ pmd9650_l13: regulator-l13 {
+ regulator-name = "pmd9650_l13";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2848000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+};
+
+&soc {
+ codec_buck_vreg: codec_buck_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "codec_1.8v";
+ regulator-always-on;
+ };
+
+ /* Rome 3.3V supply */
+ rome_vreg: rome_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "rome_vreg";
+ startup-delay-us = <4000>;
+ enable-active-high;
+ gpio = <&pmd9650_gpios 6 0>;
+ };
+
+ /* SD card 2.95 V supply */
+ sdc_vreg: sdc_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "sdc_vreg";
+ startup-delay-us = <4000>;
+ enable-active-high;
+ gpio = <&tlmm_pinmux 50 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-smp2p.dtsi b/arch/arm/boot/dts/qcom/mdm9650-smp2p.dtsi
new file mode 100644
index 0000000..5fb7440
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-smp2p.dtsi
@@ -0,0 +1,129 @@
+/* Copyright (c) 2015-2016, 2018, 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.
+ */
+
+&soc {
+ qcom,smp2p-modem {
+ compatible = "qcom,smp2p";
+ reg = <0xb011008 0x4>;
+ qcom,remote-pid = <1>;
+ qcom,irq-bitmask = <0x4000>;
+ interrupts = <0 27 1>;
+ };
+
+ smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <15>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_15_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+ gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <15>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_15_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+ gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+ gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+ gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+ };
+
+ /* ssr - inbound entry from mss. */
+ smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to mss. */
+ smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ipa - outbound entry to mss */
+ smp2pgpio_ipa_1_out: qcom,smp2pgpio-ipa-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "ipa";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ipa - inbound entry from mss */
+ smp2pgpio_ipa_1_in: qcom,smp2pgpio-ipa-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "ipa";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-ttp.dts b/arch/arm/boot/dts/qcom/mdm9650-ttp.dts
new file mode 100644
index 0000000..4a5d0d4
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-ttp.dts
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2017-2018, 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 "mdm9650-v1.1-mtp.dtsi"
+/ {
+ model = "Qualcomm Technologies, Inc. MDM 9650 TTP";
+ compatible = "qcom,mdm9650-ttp", "qcom,mdm9650", "qcom,ttp";
+ qcom,board-id = <0x1e 0>;
+};
+
+&pmd9650_l13 {
+ regulator-always-on;
+};
+
+&i2c_3 {
+ status = "ok";
+ smb1351_otg_supply: smb1351-charger@55{
+ status = "disabled";
+ };
+};
+
+&soc {
+ tlmm_pinmux: pinctrl@1000000 {
+ i2c_1 {
+ i2c_1_active {
+ config {
+ pins = "gpio2", "gpio3";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+ };
+ usb_detect {
+ compatible = "qcom,gpio-usbdetect";
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x0 0x0d 0x0>; /* PMD9655 VBUS DETECT */
+ interrupt-names = "vbus_det_irq";
+ };
+};
+
+&usb3 {
+ cpe-gpio = <&tlmm_pinmux 87 0>;
+};
+
+&blsp1_uart4b_hs {
+ status = "ok";
+};
+
+&blsp1_uart2_hs {
+ status = "disabled";
+};
+
+&snd_tasha {
+ pinctrl-names =
+ "all_off",
+ "pri_mi2s_aux_master_active",
+ "pri_mi2s_aux_slave_active",
+ "invalid_state_1",
+ "sec_mi2s_aux_master_active",
+ "pri_master_active_sec_master_active",
+ "pri_slave_active_sec_master_active",
+ "invalid_state_2",
+ "sec_mi2s_aux_slave_active",
+ "pri_master_active_sec_slave_active",
+ "pri_slave_active_sec_slave_active";
+ pinctrl-0 = <&pri_ws_sleep &pri_sck_sleep
+ &pri_dout_sleep &pri_din_sleep
+ &sec_ws_b_sleep &sec_sck_b_sleep
+ &sec_dout_b_sleep &sec_din_b_sleep>;
+ pinctrl-1 = <&pri_ws_active_master &pri_sck_active_master
+ &pri_dout_active &pri_din_active
+ &sec_ws_b_sleep &sec_sck_b_sleep
+ &sec_dout_b_sleep &sec_din_b_sleep>;
+ pinctrl-2 = <&pri_ws_active_slave &pri_sck_active_slave
+ &pri_dout_active &pri_din_active
+ &sec_ws_b_sleep &sec_sck_b_sleep
+ &sec_dout_b_sleep &sec_din_b_sleep>;
+ pinctrl-3 = <&pri_ws_sleep &pri_sck_sleep
+ &pri_dout_sleep &pri_din_sleep
+ &sec_ws_b_sleep &sec_sck_b_sleep
+ &sec_dout_b_sleep &sec_din_b_sleep>;
+ pinctrl-4 = <&pri_ws_sleep &pri_sck_sleep
+ &pri_dout_sleep &pri_din_sleep
+ &sec_ws_b_active_master &sec_sck_b_active_master
+ &sec_dout_b_active &sec_din_b_active>;
+ pinctrl-5 = <&pri_ws_active_master &pri_sck_active_master
+ &pri_dout_active &pri_din_active
+ &sec_ws_b_active_master &sec_sck_b_active_master
+ &sec_dout_b_active &sec_din_b_active>;
+ pinctrl-6 = <&pri_ws_active_slave &pri_sck_active_slave
+ &pri_dout_active &pri_din_active
+ &sec_ws_b_active_master &sec_sck_b_active_master
+ &sec_dout_b_active &sec_din_b_active>;
+ pinctrl-7 = <&pri_ws_sleep &pri_sck_sleep
+ &pri_dout_sleep &pri_din_sleep
+ &sec_ws_b_sleep &sec_sck_b_sleep
+ &sec_dout_b_sleep &sec_din_b_sleep>;
+ pinctrl-8 = <&pri_ws_sleep &pri_sck_sleep
+ &pri_dout_sleep &pri_din_sleep
+ &sec_ws_b_active_slave &sec_sck_b_active_slave
+ &sec_dout_b_active &sec_din_b_active>;
+ pinctrl-9 = <&pri_ws_active_master &pri_sck_active_master
+ &pri_dout_active &pri_din_active
+ &sec_ws_b_active_slave &sec_sck_b_active_slave
+ &sec_dout_b_active &sec_din_b_active>;
+ pinctrl-10 = <&pri_ws_active_slave &pri_sck_active_slave
+ &pri_dout_active &pri_din_active
+ &sec_ws_b_active_slave &sec_sck_b_active_slave
+ &sec_dout_b_active &sec_din_b_active>;
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-usb.dtsi b/arch/arm/boot/dts/qcom/mdm9650-usb.dtsi
new file mode 100644
index 0000000..2b005b4
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-usb.dtsi
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&soc {
+ usb3: ssusb@8a00000 {
+ compatible = "qcom,dwc-usb3-msm";
+ reg = <0x08a00000 0xf8c00>,
+ <0x0007e000 0x400>;
+ reg-names = "core_base", "ahb2phy_base";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ interrupt-parent = <&usb3>;
+ interrupts = <0 1 2 3>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0x0 0xffffffff>;
+ interrupt-map = <0x0 0 &intc 0 202 0
+ 0x0 1 &intc 0 203 0
+ 0x0 2 &intc 0 180 0
+ 0x0 3 &spmi_bus 0x0 0x0 0xc4 0x0>;
+ interrupt-names = "hs_phy_irq", "ss_phy_irq", "pwr_event_irq",
+ "pmic_id_irq";
+ USB3_GDSC-supply = <&gdsc_usb30>;
+ vdda33-supply = <&pmd9650_l10>;
+ vdda18-supply = <&pmd9650_l5>;
+ qcom,usb-dbm = <&dbm_1p5>;
+
+ qcom,msm-bus,name = "usb3";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ <61 512 0 0>, <61 676 0 0>,
+ <61 512 0 680000>, <61 676 0 2400>,
+ <61 512 0 680000>, <61 676 0 2400>;
+ qcom,lpm-to-suspend-delay-ms = <2000>;
+
+ clocks = <&clock_gcc clk_gcc_usb30_master_clk>,
+ <&clock_gcc clk_gcc_sys_noc_usb3_axi_clk>,
+ <&clock_gcc clk_gcc_usb30_mock_utmi_clk>,
+ <&clock_gcc clk_gcc_usb30_sleep_clk>,
+ <&clock_gcc clk_cxo_dwc3_clk>,
+ <&clock_gcc clk_gcc_usb_phy_cfg_ahb_clk>;
+
+ clock-names = "core_clk", "iface_clk", "utmi_clk", "sleep_clk",
+ "xo", "cfg_ahb_clk";
+
+ qcom,core-clk-rate = <120000000>;
+ qcom,dwc-usb3-msm-tx-fifo-size = <21288>;
+ dwc3@8a00000 {
+ compatible = "snps,dwc3";
+ reg = <0x08a00000 0xcd00>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 131 0>;
+ usb-phy = <&qusb_phy>, <&ssphy>;
+ tx-fifo-resize;
+ snps,nominal-elastic-buffer;
+ snps,is-utmi-l1-suspend;
+ snps,hird-threshold = /bits/ 8 <0x0>;
+ snps,bus-suspend-enable;
+ snps,usb3-u1u2-disable;
+ snps,num-gsi-evt-buffs = <0x3>;
+ xhci-imod-value = <4000>;
+ };
+
+ qcom,usbbam@0x8B04000 {
+ compatible = "qcom,usb-bam-msm";
+ reg = <0x8b04000 0x1b000>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 132 0>;
+
+ qcom,bam-type = <0>;
+ qcom,usb-bam-fifo-baseaddr = <0x08604000>;
+ qcom,usb-bam-num-pipes = <1>;
+ qcom,ignore-core-reset-ack;
+ qcom,disable-clk-gating;
+ qcom,usb-bam-override-threshold = <0x4001>;
+ qcom,usb-bam-max-mbps-highspeed = <400>;
+ qcom,usb-bam-max-mbps-superspeed = <3600>;
+ qcom,reset-bam-on-connect;
+
+ qcom,pipe0 {
+ label = "ssusb-qdss-in-0";
+ qcom,usb-bam-mem-type = <2>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <0>;
+ qcom,peer-bam-physical-address = <0x00884000>;
+ qcom,src-bam-pipe-index = <0>;
+ qcom,dst-bam-pipe-index = <2>;
+ qcom,data-fifo-offset = <0x0>;
+ qcom,data-fifo-size = <0xc00>;
+ qcom,descriptor-fifo-offset = <0xc00>;
+ qcom,descriptor-fifo-size = <0x400>;
+ };
+ };
+ };
+
+ qusb_phy: qusb@79000 {
+ compatible = "qcom,qusb2phy";
+ reg = <0x00079000 0x180>,
+ <0x01841030 0x4>,
+ <0x01956044 0x4>;
+ reg-names = "qusb_phy_base",
+ "ref_clk_addr",
+ "tcsr_phy_clk_scheme_sel";
+ vdd-supply = <&pmd9650_l4>;
+ vdda18-supply = <&pmd9650_l5>;
+ vdda33-supply = <&pmd9650_l10>;
+ qcom,vdd-voltage-level = <0 928000 928000>;
+ qcom,qusb-phy-init-seq = <0xf8 0x80
+ 0xb3 0x84
+ 0x83 0x88
+ 0xc0 0x8c
+ 0x30 0x08
+ 0x79 0x0c
+ 0x21 0x10
+ 0x14 0x9c
+ 0x9f 0x1c
+ 0x00 0x18>;
+ phy_type = "utmi";
+ qcom,secure-level-shifter-update;
+ USB3_GDSC-supply = <&gdsc_usb30>;
+
+ clocks = <&clock_gcc clk_ln_bb_clk>,
+ <&clock_gcc clk_gcc_qusb_ref_clk>,
+ <&clock_gcc clk_gcc_usb_phy_cfg_ahb_clk>,
+ <&clock_gcc clk_gcc_qusb2a_phy_reset>,
+ <&clock_gcc clk_gcc_sys_noc_usb3_axi_clk>;
+
+ clock-names = "ref_clk_src", "ref_clk", "cfg_ahb_clk",
+ "phy_reset", "iface_clk";
+ };
+
+ ssphy: ssphy@78000 {
+ compatible = "qcom,usb-ssphy-qmp";
+ reg = <0x00078000 0x9f8>,
+ <0x01947244 0x4>,
+ <0x01956044 0x4>;
+ reg-names = "qmp_phy_base",
+ "vls_clamp_reg",
+ "tcsr_phy_clk_scheme_sel";
+ qcom,qmp-phy-init-seq = <0xac 0x14 0x1a 0x00
+ 0x34 0x08 0x08 0x00
+ 0x174 0x30 0x30 0x00
+ 0x70 0x0f 0x0f 0x00
+ 0x19c 0x01 0x01 0x00
+ 0x178 0x00 0x00 0x00
+ 0x194 0x06 0x06 0x3e8
+ 0x48 0x0f 0x0f 0x00
+ 0x3c 0x02 0x02 0x00
+ 0xd0 0x82 0x82 0x00
+ 0xdc 0x55 0x55 0x00
+ 0xe0 0x55 0x55 0x00
+ 0xe4 0x03 0x03 0x00
+ 0x78 0x0b 0x0b 0x00
+ 0x84 0x16 0x16 0x00
+ 0x90 0x28 0x28 0x00
+ 0x108 0x80 0x80 0x00
+ 0x4c 0x15 0x15 0x00
+ 0x50 0x34 0x34 0x00
+ 0x54 0x00 0x00 0x00
+ 0x18c 0x00 0x00 0x00
+ 0xcc 0x00 0x00 0x00
+ 0x128 0x00 0x00 0x00
+ 0x0c 0x0a 0x0a 0x00
+ 0x10 0x01 0x01 0x00
+ 0x1c 0x31 0x31 0x00
+ 0x20 0x01 0x01 0x00
+ 0x14 0x00 0x00 0x00
+ 0x18 0x00 0x00 0x00
+ 0x24 0xde 0xde 0x00
+ 0x28 0x07 0x07 0x00
+ 0x41c 0x06 0x06 0x00
+ 0x4d8 0x02 0x02 0x00
+ 0x4dc 0x4c 0x4c 0x00
+ 0x4e0 0xb8 0xb8 0x00
+ 0x508 0x77 0x77 0x00
+ 0x50c 0x80 0x80 0x00
+ 0x514 0x03 0x03 0x00
+ 0x51c 0x16 0x16 0x00
+ 0x510 0x0c 0x0c 0x00
+ 0x268 0x45 0x45 0x00
+ 0x2ac 0x12 0x12 0x00
+ 0x294 0x06 0x06 0x00
+ 0x824 0x15 0x15 0x00
+ 0x828 0x0e 0x0e 0x00
+ 0x8c8 0x83 0x83 0x00
+ 0x8c4 0x02 0x02 0x00
+ 0x8cc 0x09 0x09 0x00
+ 0x8d0 0xa2 0xa2 0x00
+ 0x8d4 0x85 0x85 0x00
+ 0x880 0xd1 0xd1 0x00
+ 0x884 0x1f 0x1f 0x00
+ 0x888 0x47 0x47 0x00
+ 0x864 0x1b 0x1b 0x00
+ 0x8b8 0x75 0x75 0x00
+ 0x8bc 0x13 0x13 0x00
+ 0x8b0 0x86 0x86 0x00
+ 0x8a0 0x04 0x04 0x00
+ 0x88c 0x44 0x44 0x00
+ 0x870 0xe7 0xe7 0x00
+ 0x874 0x03 0x03 0x00
+ 0x878 0x40 0x40 0x00
+ 0x87c 0x00 0x00 0x00
+ 0x9d8 0x88 0x88 0x00
+ 0xffffffff 0xffffffff 0x00 0x00>;
+ qcom,qmp-phy-reg-offset = <0x988 0x98c 0x990 0x994
+ 0x974 0x8d8 0x8dc 0x804 0x800
+ 0x808>;
+ vdd-supply = <&pmd9650_l4>;
+ core-supply = <&pmd9650_l5>;
+ qcom,vdd-voltage-level = <0 928000 928000>;
+ qcom,vbus-valid-override;
+
+ clocks = <&clock_gcc clk_gcc_usb3_aux_clk>,
+ <&clock_gcc clk_gcc_usb3_pipe_clk>,
+ <&clock_gcc clk_gcc_usb_phy_cfg_ahb_clk>,
+ <&clock_gcc clk_gcc_usb3_phy_reset>,
+ <&clock_gcc clk_gcc_usb3phy_phy_reset>,
+ <&clock_gcc clk_ln_bb_clk>,
+ <&clock_gcc clk_gcc_usb_ss_ref_clk>;
+
+ clock-names = "aux_clk", "pipe_clk", "cfg_ahb_clk",
+ "phy_reset", "phy_phy_reset",
+ "ref_clk_src", "ref_clk";
+ };
+
+ dbm_1p5: dbm@0x8af8000 {
+ compatible = "qcom,usb-dbm-1p5";
+ reg = <0x08af8000 0x300>;
+ qcom,reset-ep-after-lpm-resume;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-v1.1-mtp.dtsi b/arch/arm/boot/dts/qcom/mdm9650-v1.1-mtp.dtsi
new file mode 100644
index 0000000..508abbf
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-v1.1-mtp.dtsi
@@ -0,0 +1,183 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "mdm9650-v1.1.dtsi"
+#include "mdm9650-pinctrl.dtsi"
+
+&blsp1_uart3 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_console_active>;
+};
+
+&blsp1_uart2_hs {
+ status = "ok";
+};
+
+&i2c_3 {
+ status = "ok";
+ smb1351_otg_supply: smb1351-charger@55 {
+ compatible = "qcom,smb1351-charger";
+ reg = <0x55>;
+ interrupt-parent = <&tlmm_pinmux>;
+ interrupts = <83 IRQ_TYPE_LEVEL_LOW>;
+ qcom,float-voltage-mv = <4200>;
+ qcom,charging-timeout = <1536>;
+ qcom,recharge-thresh-mv = <200>;
+ qcom,iterm-ma = <100>;
+ regulator-name = "smb1351_otg_supply";
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_stat_active>;
+ qcom,id-line-not-connected;
+ qcom,switch-freq = <2>;
+ };
+};
+
+&pmd9650_gpios {
+ gpio@c100 { /* GPIO 2 - VADC */
+ /* GPIO should be left off, and in the high
+ * impedance state when the pin is used with the VADC
+ */
+ status = "ok";
+ qcom,master-en = <0>; /* DISABLE GPIO */
+ };
+
+ gpio@c200 { /* GPIO 3 - LED */
+ status = "ok";
+ qcom,master-en = <0>; /* Disable GPIO */
+ };
+
+ gpio@c400 { /* GPIO 5 - USB_ID */
+ status = "ok";
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <1>; /* Pull up 1.5 uA */
+ qcom,vin-sel = <1>; /* 1.8 V */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c500 { /* GPIO 6 - Rome 3.3V control */
+ status = "ok";
+ qcom,mode = <1>; /* Digital output*/
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,invert = <1>; /* Output high */
+ qcom,vin-sel = <0>; /* VPH_PWR */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,out-strength = <1>; /* High drive strength */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c700 { /* GPIO 8 - BT_EN */
+ status = "ok";
+ qcom,mode = <1>; /* Digital output*/
+ qcom,pull = <4>; /* Pulldown 10uA */
+ qcom,vin-sel = <0>; /* VPH_PWR */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,invert = <0>; /* Invert */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+};
+
+&pmd9650_misc {
+ qcom,pwm-sel = <2>; /* PWM2 */
+ qcom,enable-gp-driver; /* Enable GP */
+};
+
+&pmd9650_pwm_1 {
+ status = "ok";
+};
+
+&pmd9650_pwm_2 {
+ status = "ok";
+};
+
+&qnand_1 {
+ status = "ok";
+};
+
+&usb3 {
+ vbus_dwc3-supply = <&smb1351_otg_supply>;
+ cpe-gpio = <&tlmm_pinmux 87 0>;
+};
+
+&pmd9650_vadc {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4c {
+ label = "xo_therm_buf";
+ reg = <0x4c>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@53 {
+ label = "ambient_therm";
+ reg = <0x53>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4d {
+ label = "mdm_case_therm";
+ reg = <0x4d>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4e {
+ label = "pa_therm1";
+ reg = <0x4e>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4f {
+ label = "pa_therm2";
+ reg = <0x4f>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-v1.1-nand-cv2x.dts b/arch/arm/boot/dts/qcom/mdm9650-v1.1-nand-cv2x.dts
new file mode 100644
index 0000000..4632607
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-v1.1-nand-cv2x.dts
@@ -0,0 +1,21 @@
+/* Copyright (c) 2017-2018, 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 "mdm9650-cv2x.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MDM 9650 v1.1 CV2X";
+ compatible = "qcom,mdm9650-ttp", "qcom,mdm9650", "qcom,ttp";
+ qcom,board-id = <0x1e 1>, <0x1e 0x101>;
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-v1.1-nand-mtp.dts b/arch/arm/boot/dts/qcom/mdm9650-v1.1-nand-mtp.dts
new file mode 100644
index 0000000..9fff2ae
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-v1.1-nand-mtp.dts
@@ -0,0 +1,40 @@
+/* Copyright (c) 2016-2018, 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 "mdm9650-v1.1-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MDM 9650 v1.1 MTP (NAND)";
+ compatible = "qcom,mdm9650-mtp", "qcom,mdm9650",
+ "qcom,mtp";
+ qcom,board-id = <8 0>, <8 0x100>;
+};
+
+&sdhc_1 {
+ vdd-supply = <&sdc_vreg>;
+
+ vdd-io-supply = <&pmd9650_l7>;
+ qcom,vdd-io-voltage-level = <1800000 2848000>;
+ qcom,vdd-io-current-level = <200 10000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>;
+
+ qcom,bus-width = <4>;
+ qcom,clk-rates = <400000 20000000 25000000
+ 50000000 100000000 200000000>;
+
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650-v1.1.dtsi b/arch/arm/boot/dts/qcom/mdm9650-v1.1.dtsi
new file mode 100644
index 0000000..c02cedc
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650-v1.1.dtsi
@@ -0,0 +1,20 @@
+/* Copyright (c) 2016-2018, 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 "mdm9650.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MDM 9650 v1.1";
+ compatible = "qcom,mdm9650";
+ qcom,msm-id = <279 0x10001>, <284 0x10001>, <285 0x10001>,
+ <286 0x10001>, <283 0x10001>;
+};
diff --git a/arch/arm/boot/dts/qcom/mdm9650.dtsi b/arch/arm/boot/dts/qcom/mdm9650.dtsi
new file mode 100644
index 0000000..fcc2377
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/mdm9650.dtsi
@@ -0,0 +1,1470 @@
+/* Copyright (c) 2015-2018, 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 "skeleton.dtsi"
+#include <dt-bindings/clock/mdm-clocks-9650.h>
+#include <dt-bindings/clock/msm-clocks-a7.h>
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
+
+/ {
+ model = "Qualcomm Technologies, Inc. MDM 9650";
+ compatible = "qcom,mdm9650";
+ qcom,msm-id = <279 0x10000>, <284 0x10000>, <285 0x10000>,
+ <286 0x10000>, <283 0x10000>;
+ interrupt-parent = <&intc>;
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ peripheral1_mem: peripheral1_region@0x87800000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0x87800000 0x400000>;
+ label = "peripheral1_mem";
+ };
+
+ peripheral2_mem: peripheral2_region@0x87d00000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0x87d00000 0x300000>;
+ label = "peripheral2_mem";
+ };
+ mss_mem: mss_region@88000000 {
+ compatible = "removed-dma-pool";
+ no-map-fixup;
+ reg = <0x88000000 0x6E00000>;
+ label = "mss_mem";
+ };
+
+ audio_mem: audio_region@0 {
+ compatible = "shared-dma-pool";
+ reusable;
+ size = <0x400000>;
+ };
+
+ qseecom_mem: qseecom_region@0 {
+ compatible = "shared-dma-pool";
+ reusable;
+ alignment = <0x400000>;
+ size = <0x0400000>;
+ };
+ };
+
+ aliases {
+ qpic_nand1 = &qnand_1;
+ sdhc1 = &sdhc_1; /* SDC1 eMMC/SD slot */
+ };
+
+ cpus {
+ #size-cells = <0>;
+ #address-cells = <1>;
+
+ CPU0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x0>;
+ };
+ };
+
+ soc: soc { };
+};
+
+#include "mdm9650-smp2p.dtsi"
+#include "msm-gdsc.dtsi"
+#include "mdm9650-blsp.dtsi"
+#include "mdm9650-bus.dtsi"
+#include "mdm9650-coresight.dtsi"
+#include "mdm9650-ion.dtsi"
+#include "mdm9650-pm.dtsi"
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ intc: interrupt-controller@b000000 {
+ compatible = "qcom,msm-qgic2";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0x0b000000 0x1000>,
+ <0x0b002000 0x1000>;
+ };
+
+ qcom,mpm2-sleep-counter@4a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0x004a3000 0x1000>;
+ clock-frequency = <32768>;
+ };
+
+ qcom,msm-imem@8600000 {
+ compatible = "qcom,msm-imem";
+ reg = <0x8600000 0x1000>; /* Address and size of IMEM */
+ ranges = <0x0 0x8600000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ mem_dump_table@10 {
+ compatible = "qcom,msm-imem-mem_dump_table";
+ reg = <0x10 8>;
+ };
+
+ restart_reason@65c {
+ compatible = "qcom,msm-imem-restart_reason";
+ reg = <0x65c 4>;
+ };
+
+ boot_stats@6b0 {
+ compatible = "qcom,msm-imem-boot_stats";
+ reg = <0x6b0 32>;
+ };
+
+ pil@94c {
+ compatible = "qcom,msm-imem-pil";
+ reg = <0x94c 200>;
+ };
+ };
+
+ mss: qcom,mss@4080000{
+ compatible = "qcom,pil-q6v55-mss";
+ reg = <0x4080000 0x100>,
+ <0x194e000 0x400>,
+ <0x4180000 0x040>,
+ <0x1810000 0x004>;
+ reg-names = "qdsp6_base", "halt_base", "rmb_base",
+ "restart_reg";
+
+ clocks = <&clock_gcc clk_xo>,
+ <&clock_gcc clk_gcc_mss_cfg_ahb_clk>,
+ <&clock_gcc clk_gcc_mss_q6_bimc_axi_clk>,
+ <&clock_gcc clk_gcc_boot_rom_ahb_clk>,
+ <&clock_gcc clk_gpll0_out_msscc>,
+ <&clock_gcc clk_qpic_clk>;
+ clock-names = "xo", "iface_clk", "bus_clk", "mem_clk",
+ "gpll0_mss_clk", "qpic";
+ qcom,proxy-clock-names = "xo";
+ qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk",
+ "gpll0_mss_clk";
+
+ vdd_cx-supply = <&pmd9650_s5_level>;
+ interrupts = <0 24 1>;
+ vdd_cx-voltage = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ vdd_mx-supply = <&pmd9650_l9_level>;
+ vdd_pll-supply = <&pmd9650_l5>;
+ qcom,vdd_pll = <1800000>;
+ qcom,firmware-name = "modem";
+ qcom,pil-self-auth;
+ qcom,sysmon-id = <0>;
+ qcom,ssctl-instance-id = <0x12>;
+ qcom,override-acc;
+ qcom,qdsp6v61-1-1;
+ memory-region = <&mss_mem>;
+
+ /* GPIO inputs from mss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>;
+
+ /* GPIO output to mss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
+
+ };
+
+ clock_gcc: qcom,gcc@1800000 {
+ compatible = "qcom,gcc-9650";
+ reg = <0x1800000 0x80000>,
+ <0xb008018 0x1c>;
+ reg-names = "cc_base", "apcs_base";
+ #clock-cells = <1>;
+
+ qcom,regulator-names = "vdd_dig", "vdd_dig_ao";
+ vdd_dig-supply = <&pmd9650_s5_level>;
+ vdd_dig_ao-supply = <&pmd9650_s5_level_ao>;
+ };
+
+ clock_debug: qcom,cc-debug@1874000 {
+ compatible = "qcom,cc-debug-9650";
+ reg = <0x1874000 0x4>;
+ reg-names = "cc_base";
+ #clock-cells = <1>;
+ };
+
+ clock_cpu: qcom,clock-a7@0b010008 {
+ compatible = "qcom,clock-a7-9650";
+ reg = <0x0b010008 0x8>;
+ reg-names = "rcg-base";
+ #clock-cells = <1>;
+
+ clock-names = "clk-1", "clk-5";
+ clocks = <&clock_gcc clk_gpll0_ao>,
+ <&clock_gcc clk_a7pll_clk>;
+
+ qcom,speed0-bin-v0 =
+ < 0 RPM_SMD_REGULATOR_LEVEL_NONE>,
+ < 200000000 RPM_SMD_REGULATOR_LEVEL_LOW_SVS>,
+ < 384000000 RPM_SMD_REGULATOR_LEVEL_SVS>,
+ < 787200000 RPM_SMD_REGULATOR_LEVEL_NOM>,
+ <1286400000 RPM_SMD_REGULATOR_LEVEL_TURBO>;
+
+ cpu-vdd-supply = <&pmd9650_s5_level_ao>;
+ qcom,a7ssmux-opp-store-vcorner = <&CPU0>;
+ };
+
+ qcom,msm-cpufreq {
+ compatible = "qcom,msm-cpufreq";
+ clocks = <&clock_cpu clk_a7ssmux>,
+ <&clock_cpu clk_a7ssmux>,
+ <&clock_cpu clk_a7ssmux>,
+ <&clock_cpu clk_a7ssmux>;
+ clock-names = "cpu0_clk", "cpu1_clk",
+ "cpu2_clk", "cpu3_clk";
+ qcom,cpufreq-table =
+ < 200000 >,
+ < 300000 >,
+ < 384000 >,
+ < 600000 >,
+ < 787200 >,
+ < 998400 >,
+ < 1190400 >,
+ < 1286400 >;
+ };
+
+ ahb_clk: qcom,ahb-clk-src {
+ compatible = "devfreq-simple-dev";
+ clock-names = "devfreq_clk";
+ clocks = <&clock_gcc clk_apss_ahb_clk_src>;
+ governor = "powersave";
+ freq-tbl-khz =
+ < 19200 >,
+ < 50000 >,
+ < 100000 >,
+ < 133330 >;
+ };
+
+ devfreq-cpufreq {
+ cpubw-cpufreq {
+ target-dev = <&cpubw>;
+ cpu-to-dev-map =
+ < 600000 1541 >,
+ < 787200 3082 >,
+ < 1286400 3952 >;
+ };
+ cpuahb-cpufreq {
+ target-dev = <&ahb_clk>;
+ cpu-to-dev-map =
+ < 200000 19200 >,
+ < 384000 50000 >,
+ < 787200 100000 >,
+ < 1286400 133330 >;
+ };
+ };
+
+ cpubw: qcom,cpubw {
+ compatible = "qcom,devbw";
+ governor = "cpufreq";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 1541 /* 202 MHz */ >,
+ < 3082 /* 404 MHz */ >,
+ < 3952 /* 518 MHz */ >;
+ };
+
+ restart@4ab000 {
+ compatible = "qcom,pshold";
+ reg = <0x4ab000 0x4>,
+ <0x0193d100 0x4>;
+ reg-names = "pshold-base", "tcsr-boot-misc-detect";
+ };
+
+ timer@b020000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ compatible = "arm,armv7-timer-mem";
+ reg = <0xb020000 0x1000>;
+ clock-frequency = <19200000>;
+
+ frame@b021000 {
+ frame-number = <0>;
+ interrupts = <0 7 0x4>,
+ <0 6 0x4>;
+ reg = <0xb021000 0x1000>,
+ <0xb022000 0x1000>;
+ };
+
+ frame@b023000 {
+ frame-number = <1>;
+ interrupts = <0 8 0x4>;
+ reg = <0xb023000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@b024000 {
+ frame-number = <2>;
+ interrupts = <0 9 0x4>;
+ reg = <0xb024000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@b025000 {
+ frame-number = <3>;
+ interrupts = <0 10 0x4>;
+ reg = <0xb025000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@b026000 {
+ frame-number = <4>;
+ interrupts = <0 11 0x4>;
+ reg = <0xb026000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@b027000 {
+ frame-number = <5>;
+ interrupts = <0 12 0x4>;
+ reg = <0xb027000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@b028000 {
+ frame-number = <6>;
+ interrupts = <0 13 0x4>;
+ reg = <0xb028000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@b029000 {
+ frame-number = <7>;
+ interrupts = <0 14 0x4>;
+ reg = <0xb029000 0x1000>;
+ status = "disabled";
+ };
+ };
+
+ pcie0: qcom,pcie@80000 {
+ compatible = "qcom,pci-msm";
+ cell-index = <0>;
+
+ reg = <0x00080000 0x2000>,
+ <0x00086000 0x1000>,
+ <0x40000000 0xf1d>,
+ <0x40000f20 0xa8>,
+ <0x40100000 0x100000>,
+ <0x40200000 0x100000>,
+ <0x40300000 0x1d00000>,
+ <0x01956044 0x4>;
+
+ reg-names = "parf", "phy", "dm_core", "elbi",
+ "conf", "io", "bars", "tcsr";
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges = <0x01000000 0x0 0x40200000 0x40200000 0x0 0x100000>,
+ <0x02000000 0x0 0x40300000 0x40300000 0x0 0x1d00000>;
+ interrupt-parent = <&pcie0>;
+ interrupts = <0 1 2 3 4 5>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0xffffffff>;
+ interrupt-map = <0 0 0 0 &intc 0 53 0
+ 0 0 0 1 &intc 0 115 0
+ 0 0 0 2 &intc 0 116 0
+ 0 0 0 3 &intc 0 117 0
+ 0 0 0 4 &intc 0 118 0
+ 0 0 0 5 &intc 0 49 0>;
+
+ interrupt-names = "int_msi", "int_a", "int_b", "int_c",
+ "int_d", "int_global_int";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie0_clkreq_default
+ &pcie0_perst_default
+ &pcie0_wake_default>;
+
+ perst-gpio = <&tlmm_pinmux 60 0>;
+ wake-gpio = <&tlmm_pinmux 61 0>;
+
+ gdsc-vdd-supply = <&gdsc_pcie>;
+ vreg-1.8-supply = <&pmd9650_l5>;
+ vreg-0.9-supply = <&pmd9650_l4>;
+
+ qcom,vreg-0.9-voltage-level = <928000 928000 24000>;
+
+ qcom,l1-supported;
+ qcom,l1ss-supported;
+ qcom,aux-clk-sync;
+
+ qcom,ep-latency = <10>;
+
+ qcom,cpl-timeout = <0x2>;
+
+ qcom,boot-option = <0x1>;
+
+ linux,pci-domain = <0>;
+
+ qcom,pcie-phy-ver = <0x10>;
+ qcom,use-19p2mhz-aux-clk;
+
+ qcom,msm-bus,name = "pcie0";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <45 512 0 0>,
+ <45 512 500 800>;
+
+ clocks = <&clock_gcc clk_gcc_pcie_pipe_clk>,
+ <&clock_gcc clk_ln_bb_clk>,
+ <&clock_gcc clk_gcc_pcie_sleep_clk>,
+ <&clock_gcc clk_gcc_pcie_cfg_ahb_clk>,
+ <&clock_gcc clk_gcc_pcie_axi_mstr_clk>,
+ <&clock_gcc clk_gcc_pcie_axi_clk>,
+ <&clock_gcc clk_gcc_pcie_ref_clk>,
+ <&clock_gcc clk_gcc_pcie_phy_reset>;
+
+ clock-names = "pcie_0_pipe_clk", "pcie_0_ref_clk_src",
+ "pcie_0_aux_clk", "pcie_0_cfg_ahb_clk",
+ "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk",
+ "pcie_0_ldo", "pcie_0_phy_reset";
+
+ max-clock-frequency-hz = <0>, <0>, <19200000>,
+ <0>, <0>, <0>, <0>, <0>, <0>;
+ };
+
+ blsp1_uart1: serial@78af000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x78af000 0x200>;
+ interrupts = <0 107 0>;
+ clocks = <&clock_gcc clk_gcc_blsp1_uart1_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ clock-names = "core", "iface";
+ status = "disabled";
+ };
+
+ bt_qca6174 {
+ compatible = "qca,qca6174";
+ qca,bt-reset-gpio = <&pmd9650_gpios 8 0>; /* BT_EN */
+ qca,bt-vdd-pa-supply = <&rome_vreg>;
+ qca,bt-vdd-xtal-supply = <&pmd9650_l4>;
+ qca,bt-vdd-core-supply = <&pmd9650_l5>;
+ };
+
+ qcom,sps {
+ compatible = "qcom,msm_sps_4k";
+ qcom,pipe-attr-ee;
+ };
+
+ pcie_ep: qcom,pcie@7fffd000 {
+ compatible = "qcom,pcie-ep";
+
+ reg = <0x7fffd000 0x1000>,
+ <0x7fffe000 0xf1d>,
+ <0x7fffef20 0xa8>,
+ <0x00080000 0x2000>,
+ <0x00086000 0x1000>,
+ <0x00087000 0x1000>;
+ reg-names = "msi", "dm_core", "elbi", "parf", "phy", "mmio";
+
+ #address-cells = <0>;
+ interrupt-parent = <&pcie_ep>;
+ interrupts = <0>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 49 0>;
+ interrupt-names = "int_global";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie0_clkreq_default &pcie_ep_perst_default
+ &pcie_ep_wake_default &pcie0_mdm2apstatus_default>;
+
+ perst-gpio = <&tlmm_pinmux 65 0>;
+ wake-gpio = <&tlmm_pinmux 61 0>;
+ clkreq-gpio = <&tlmm_pinmux 64 0>;
+ mdm2apstatus-gpio = <&tlmm_pinmux 16 0>;
+
+ gdsc-vdd-supply = <&gdsc_pcie>;
+ vreg-1.8-supply = <&pmd9650_l5>;
+ vreg-0.9-supply = <&pmd9650_l4>;
+
+ qcom,vreg-0.9-voltage-level = <928000 928000 24000>;
+
+ clocks = <&clock_gcc clk_gcc_pcie_pipe_clk>,
+ <&clock_gcc clk_gcc_pcie_cfg_ahb_clk>,
+ <&clock_gcc clk_gcc_pcie_axi_mstr_clk>,
+ <&clock_gcc clk_gcc_pcie_axi_clk>,
+ <&clock_gcc clk_gcc_pcie_sleep_clk>,
+ <&clock_gcc clk_gcc_pcie_ref_clk>,
+ <&clock_gcc clk_gcc_pcie_phy_reset>;
+
+ clock-names = "pcie_0_pipe_clk", "pcie_0_cfg_ahb_clk",
+ "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk",
+ "pcie_0_aux_clk", "pcie_0_ldo",
+ "pcie_0_phy_reset";
+ max-clock-frequency-hz = <0>, <0>, <0>, <0>, <19200000>,
+ <0>, <0>;
+
+ qcom,msm-bus,name = "pcie-ep";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <45 512 0 0>,
+ <45 512 500 800>;
+
+ qcom,pcie-link-speed = <2>;
+ qcom,pcie-phy-ver = <4>;
+ qcom,pcie-active-config;
+ qcom,pcie-aggregated-irq;
+ qcom,pcie-perst-enum;
+ status = "disabled";
+ };
+
+ qcom,msm_gsi {
+ compatible = "qcom,msm_gsi";
+ };
+
+ qcom_rng: qrng@e3000 {
+ compatible = "qcom,msm-rng";
+ reg = <0xe3000 0x1000>;
+ qcom,msm-rng-iface-clk;
+ qcom,no-qrng-config;
+ qcom,msm-bus,name = "msm-rng-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <1 618 0 0>, /* No vote */
+ <1 618 0 800>; /* 100 MB/s */
+ clocks = <&clock_gcc clk_gcc_prng_ahb_clk>;
+ clock-names = "iface_clk";
+ };
+
+ qcom_tzlog: tz-log@08600720 {
+ compatible = "qcom,tz-log";
+ reg = <0x08600720 0x2000>;
+ };
+
+ qcom,qcedev@720000 {
+ compatible = "qcom,qcedev";
+ reg = <0x720000 0x20000>,
+ <0x704000 0x20000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 207 0>;
+ qcom,bam-pipe-pair = <1>;
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ qcom,ce-hw-shared;
+ qcom,msm-bus,name = "qcedev-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <47 512 0 0>,
+ <47 512 393600 393600>;
+ clocks =
+ <&clock_gcc clk_qcedev_ce_clk>,
+ <&clock_gcc clk_qcedev_ce_clk>,
+ <&clock_gcc clk_qcedev_ce_clk>,
+ <&clock_gcc clk_qcedev_ce_clk>;
+ clock-names = "core_clk", "iface_clk",
+ "bus_clk","core_clk_src";
+ qcom,ce-opp-freq = <171430000>;
+ };
+
+ qcom,qcrypto@720000 {
+ compatible = "qcom,qcrypto";
+ reg = <0x720000 0x20000>,
+ <0x704000 0x20000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 207 0>;
+ qcom,bam-pipe-pair = <2>;
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ qcom,ce-hw-shared;
+ qcom,msm-bus,name = "qcrypto-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <47 512 0 0>,
+ <47 512 393600 393600>;
+ clocks =
+ <&clock_gcc clk_qcedev_ce_clk>,
+ <&clock_gcc clk_qcedev_ce_clk>,
+ <&clock_gcc clk_qcedev_ce_clk>,
+ <&clock_gcc clk_qcedev_ce_clk>;
+ clock-names = "core_clk", "iface_clk",
+ "bus_clk","core_clk_src";
+ qcom,use-sw-aes-cbc-ecb-ctr-algo;
+ qcom,use-sw-aes-xts-algo;
+ qcom,use-sw-aes-ccm-algo;
+ qcom,use-sw-ahash-algo;
+ qcom,use-sw-hmac-algo;
+ qcom,use-sw-aead-algo;
+ qcom,ce-opp-freq = <171430000>;
+ };
+
+ qcom_seecom: qseecom@87800000 {
+ compatible = "qcom,qseecom";
+ reg = <0x87800000 0x200000>;
+ reg-names = "secapp-region";
+ qcom,hlos-ce-hw-instance = <0>;
+ qcom,qsee-ce-hw-instance = <0>;
+ qcom,msm-bus,name = "qseecom-noc";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <47 512 0 0>,
+ <47 512 200000 400000>,
+ <47 512 300000 800000>,
+ <47 512 400000 1000000>;
+ clocks = <&clock_gcc clk_qcedev_ce_clk>,
+ <&clock_gcc clk_qcedev_ce_clk>,
+ <&clock_gcc clk_qcedev_ce_clk>,
+ <&clock_gcc clk_qcedev_ce_clk>;
+ clock-names = "core_clk", "iface_clk",
+ "bus_clk","core_clk_src";
+ qcom,ce-opp-freq = <100000000>;
+ };
+
+ qcom,rmnet-ipa {
+ compatible = "qcom,rmnet-ipa3";
+ qcom,rmnet-ipa-ssr;
+ };
+
+ ipa_hw: qcom,ipa@07b00000 {
+ compatible = "qcom,ipa";
+ reg =
+ <0x07b00000 0x34000>,
+ <0x07b84000 0x31ffff>,
+ <0x07b04000 0x2c000>;
+ reg-names = "ipa-base", "bam-base", "gsi-base";
+ interrupts =
+ <0 31 0>,
+ <0 34 0>,
+ <0 34 0>;
+ interrupt-names = "ipa-irq", "bam-irq", "gsi-irq";
+ qcom,ipa-hw-ver = <10>; /* IPA core version = IPAv3.0 */
+ qcom,ipa-hw-mode = <0>; /* IPA hw type = Normal */
+ qcom,ee = <0>;
+ qcom,use-gsi;
+ qcom,use-rg10-limitation-mitigation;
+ qcom,use-ipa-tethering-bridge;
+ qcom,modem-cfg-emb-pipe-flt;
+ clock-names = "core_clk";
+ clocks = <&clock_gcc clk_ipa_clk>;
+ qcom,msm-bus,name = "ipa";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <3>;
+ qcom,msm-bus,vectors-KBps =
+ /* No vote */
+ <90 512 0 0>,
+ <90 585 0 0>,
+ <1 676 0 0>,
+ /* SVS */
+ <90 512 80000 640000>,
+ <90 585 80000 640000>,
+ <1 676 80000 160000>,
+ /* NOMINAL */
+ <90 512 206000 960000>,
+ <90 585 206000 960000>,
+ <1 676 206000 400000>,
+ /* TURBO */
+ <90 512 206000 3600000>,
+ <90 585 206000 3600000>,
+ <1 676 206000 960000>;
+ qcom,bus-vector-names = "MIN", "SVS", "NOMINAL", "TURBO";
+ /* ipa tz unlock registers */
+ qcom,ipa-tz-unlock-reg =
+ <0x4043583c 0x1000>; /* 32-bit reg addr and size */
+
+ /* smp2p gpio information */
+ qcom,smp2pgpio_map_ipa_1_out {
+ compatible = "qcom,smp2pgpio-map-ipa-1-out";
+ gpios = <&smp2pgpio_ipa_1_out 0 0>;
+ };
+
+ qcom,smp2pgpio_map_ipa_1_in {
+ compatible = "qcom,smp2pgpio-map-ipa-1-in";
+ gpios = <&smp2pgpio_ipa_1_in 0 0>;
+ };
+ };
+
+ mhi_device: mhi_dev@87000 {
+ compatible = "qcom,msm-mhi-dev";
+ reg = <0x87000 0x1000>,
+ <0x7b22000 0x4>,
+ <0x7b22150 0x4>;
+ reg-names = "mhi_mmio_base", "ipa_uc_mbox_crdb",
+ "ipa_uc_mbox_erdb";
+ qcom,mhi-ifc-id = <0x030217cb>;
+ qcom,mhi-ep-msi = <0>;
+ qcom,mhi-version = <0x1000000>;
+ qcom,use-ipa-software-channel;
+ status = "disabled";
+ };
+
+ blsp1_uart1: serial@78af000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x78af000 0x200>;
+ interrupts = <0 107 0>;
+ clocks = <&clock_gcc clk_gcc_blsp1_uart1_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ clock-names = "core", "iface";
+ status = "disabled";
+ };
+
+ blsp1_uart2: serial@78b0000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x78b0000 0x200>;
+ interrupts = <0 108 0>;
+ clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ clock-names = "core", "iface";
+ status = "disabled";
+ };
+
+ blsp1_uart3: serial@78b1000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x78b1000 0x200>;
+ interrupts = <0 109 0>;
+ clocks = <&clock_gcc clk_gcc_blsp1_uart3_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ clock-names = "core", "iface";
+ status = "disabled";
+ };
+
+ rpm_bus: qcom,rpm-smd {
+ compatible = "qcom,rpm-smd";
+ rpm-channel-name = "rpm_requests";
+ rpm-channel-type = <15>; /* SMD_APPS_RPM */
+ };
+
+ qcom,wdt@b017000 {
+ compatible = "qcom,msm-watchdog";
+ reg = <0xb017000 0x1000>;
+ reg-names = "wdt-base";
+ interrupts = <1 3 0>, <1 2 0>;
+ qcom,bark-time = <11000>;
+ qcom,pet-time = <10000>;
+ };
+
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,rtb-size = <0x100000>;
+ };
+
+ jtag_mm0: jtagmm@842000 {
+ compatible = "qcom,jtag-mm";
+ reg = <0x842000 0x1000>,
+ <0x840000 0x1000>;
+ reg-names = "etm-base","debug-base";
+
+ qcom,coresight-jtagmm-cpu = <&CPU0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ qcom,ipc-spinlock@1905000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0x1905000 0x8000>;
+ qcom,num-locks = <8>;
+ };
+
+ qnand_1: nand@7980000 {
+ compatible = "qcom,msm-nand";
+ reg = <0x07980000 0x10000>,
+ <0x07984000 0x1a000>;
+ reg-names = "nand_phys",
+ "bam_phys";
+ qcom,reg-adjustment-offset = <0x4000>;
+
+ interrupts = <0 247 0>;
+ interrupt-names = "bam_irq";
+
+ qcom,msm-bus,name = "qpic_nand";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+
+ qcom,msm-bus,vectors-KBps =
+ <91 512 0 0>,
+ /* Voting for max b/w on PNOC bus for now */
+ <91 512 400000 800000>;
+
+ clock-names = "core_clk";
+ clocks = <&clock_gcc clk_qpic_clk>;
+ status = "disabled";
+ };
+
+ qcom,smem@87e80000 {
+ compatible = "qcom,smem";
+ reg = <0x87e80000 0xc0000>,
+ <0xb011008 0x4>,
+ <0x60000 0x6000>,
+ <0x193d000 0x8>;
+ reg-names = "smem", "irq-reg-base", "aux-mem1",
+ "smem_targ_info_reg";
+ qcom,mpu-enabled;
+
+ qcom,smd-modem {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <0>;
+ qcom,smd-irq-offset = <0x0>;
+ qcom,smd-irq-bitmask = <0x1000>;
+ interrupts = <0 25 1>;
+ label = "modem";
+ };
+
+ qcom,smd-rpm {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <15>;
+ qcom,smd-irq-offset = <0x0>;
+ qcom,smd-irq-bitmask = <0x1>;
+ interrupts = <0 168 1>;
+ label = "rpm";
+ qcom,irq-no-suspend;
+ qcom,not-loadable;
+ };
+ };
+
+ qcom,glink-smem-native-xprt-modem@87e80000 {
+ compatible = "qcom,glink-smem-native-xprt";
+ reg = <0x87e80000 0xc0000>,
+ <0xb011008 0x4>;
+ reg-names = "smem", "irq-reg-base";
+ qcom,irq-mask = <0x8000>;
+ interrupts = <0 28 1>;
+ label = "mpss";
+ };
+
+ qcom,glink-smem-native-xprt-rpm@60000 {
+ compatible = "qcom,glink-rpm-native-xprt";
+ reg = <0x60000 0x6000>,
+ <0xb011008 0x4>;
+ reg-names = "msgram", "irq-reg-base";
+ qcom,irq-mask = <0x1>;
+ interrupts = <0 168 1>;
+ label = "rpm";
+ };
+
+ glink_mpss: qcom,glink-ssr-modem {
+ compatible = "qcom,glink_ssr";
+ label = "modem";
+ qcom,edge = "mpss";
+ qcom,notify-edges = <&glink_rpm>;
+ qcom,xprt = "smem";
+ };
+
+ glink_rpm: qcom,glink-ssr-rpm {
+ compatible = "qcom,glink_ssr";
+ label = "rpm";
+ qcom,edge = "rpm";
+ qcom,notify-edges = <&glink_mpss>;
+ qcom,xprt = "smem";
+ };
+
+ qcom,glink_pkt {
+ compatible = "qcom,glinkpkt";
+
+ qcom,glinkpkt-at-mdm0 {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "DS";
+ qcom,glinkpkt-dev-name = "at_mdm0";
+ };
+
+ qcom,glinkpkt-loopback_cntl {
+ qcom,glinkpkt-transport = "lloop";
+ qcom,glinkpkt-edge = "local";
+ qcom,glinkpkt-ch-name = "LOCAL_LOOPBACK_CLNT";
+ qcom,glinkpkt-dev-name = "glink_pkt_loopback_ctrl";
+ };
+
+ qcom,glinkpkt-loopback_data {
+ qcom,glinkpkt-transport = "lloop";
+ qcom,glinkpkt-edge = "local";
+ qcom,glinkpkt-ch-name = "glink_pkt_lloop_CLNT";
+ qcom,glinkpkt-dev-name = "glink_pkt_loopback";
+ };
+
+ qcom,glinkpkt-data5-cntl {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "DATA5_CNTL";
+ qcom,glinkpkt-dev-name = "smdcntl0";
+ };
+
+ qcom,glinkpkt-apr-apps2 {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "apr_apps2";
+ qcom,glinkpkt-dev-name = "apr_apps2";
+ };
+
+ qcom,glinkpkt-data22 {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "DATA22";
+ qcom,glinkpkt-dev-name = "smd22";
+ };
+
+ qcom,glinkpkt-data40-cntl {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "DATA40_CNTL";
+ qcom,glinkpkt-dev-name = "smdcntl8";
+ };
+
+ qcom,glinkpkt-data1 {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "DATA1";
+ qcom,glinkpkt-dev-name = "smd7";
+ };
+
+ qcom,glinkpkt-data4 {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "DATA4";
+ qcom,glinkpkt-dev-name = "smd8";
+ };
+
+ qcom,glinkpkt-data11 {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "DATA11";
+ qcom,glinkpkt-dev-name = "smd11";
+ };
+
+ qcom,glinkpkt-data21 {
+ qcom,glinkpkt-transport = "smem";
+ qcom,glinkpkt-edge = "mpss";
+ qcom,glinkpkt-ch-name = "DATA21";
+ qcom,glinkpkt-dev-name = "smd21";
+ };
+ };
+
+ qcom,ipc_router {
+ compatible = "qcom,ipc_router";
+ qcom,node-id = <1>;
+ qcom,default-peripheral = "modem";
+ };
+
+ qcom,ipc_router_modem_xprt {
+ compatible = "qcom,ipc_router_glink_xprt";
+ qcom,ch-name = "IPCRTR";
+ qcom,xprt-remote = "mpss";
+ qcom,glink-xprt = "smd_trans";
+ qcom,xprt-linkid = <1>;
+ qcom,xprt-version = <1>;
+ qcom,fragmented-data;
+ };
+
+ spmi_bus: qcom,spmi@200f000 {
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0x200f000 0x1000>,
+ <0x2400000 0x800000>,
+ <0x2c00000 0x800000>,
+ <0x3800000 0x200000>,
+ <0x200a000 0x2100>; /* includes SPMI_CFG and GENI_CFG */
+ reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+ interrupts = <0 190 0>;
+ qcom,pmic-arb-channel = <0>;
+ qcom,pmic-arb-ee = <0>;
+ qcom,pmic-arb-max-peripherals = <256>;
+ qcom,pmic-arb-max-periph-interrupts = <256>;
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ };
+
+ tsens0: tsens@4a9000 {
+ compatible = "qcom,msm8996-tsens";
+ reg = <0x4a8000 0x2000>,
+ <0x74230 0x1000>;
+ reg-names = "tsens_physical", "tsens_eeprom_physical";
+ interrupts = <0 184 0>, <0 29 0>;
+ interrupt-names = "tsens-upper-lower", "tsens-critical";
+ qcom,sensors = <5>;
+ qcom,slope = <2901 2846 3200 3200 3200>;
+ qcom,client-id = <0 1 2 3 4>;
+ qcom,sensor-id = <0 1 2 3 6>;
+ };
+
+ cnss_pcie: qcom,cnss {
+ compatible = "qcom,cnss";
+ wlan-en-gpio = <&tlmm_pinmux 95 0>;
+ vdd-wlan-supply = <&rome_vreg>;
+ vdd-wlan-xtal-supply = <&pmd9650_l5>;
+ vdd-wlan-io-supply = <&pmd9650_l6>;
+ vdd-wlan-xtal-aon-supply = <&pmd9650_l4>;
+ qcom,notify-modem-status;
+ pinctrl-names = "wlan_en_active", "wlan_en_sleep";
+ pinctrl-0 = <&cnss_wlan_en_active>;
+ pinctrl-1 = <&cnss_wlan_en_sleep>;
+ qcom,wlan-rc-num = <0>;
+ qcom,wlan-ramdump-dynamic = <0x200000>;
+
+ qcom,msm-bus,name = "msm-cnss";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ <45 512 0 0>, <1 512 0 0>,
+ /* Upto 200 Mbps */
+ <45 512 41421 655360>, <1 512 41421 655360>,
+ /* Upto 400 Mbps */
+ <45 512 98572 655360>, <1 512 98572 1600000>,
+ /* Upto 800 Mbps */
+ <45 512 207108 1146880>, <1 512 207108 3124992>;
+ };
+
+ cnss_sdio: qcom,cnss_sdio {
+ compatible = "qcom,cnss_sdio";
+ subsys-name = "AR6320_SDIO";
+ vdd-wlan-supply = <&rome_vreg>;
+ vdd-wlan-xtal-supply = <&pmd9650_l5>;
+ vdd-wlan-io-supply = <&pmd9650_l6>;
+ qcom,wlan-ramdump-dynamic = <0x200000>;
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&cnss_sdio_active>;
+ pinctrl-1 = <&cnss_sdio_sleep>;
+ qcom,is-antenna-shared;
+ status = "disabled";
+ };
+
+ wcd9xxx_intc: wcd9xxx-irq {
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tlmm_pinmux>;
+ qcom,gpio-connect = <&tlmm_pinmux 94 0>;
+ };
+
+ clock_audio: audio_ext_clk {
+ compatible = "qcom,audio-ref-clk";
+ qcom,codec-mclk-clk-freq = <12288000>;
+ pinctrl-names = "sleep", "active";
+ pinctrl-0 = <&i2s_mclk_sleep>;
+ pinctrl-1 = <&i2s_mclk_active>;
+ #clock-cells = <1>;
+ };
+
+ snd_tasha: sound {
+ compatible = "qcom,mdm-audio-tasha";
+ qcom,model = "mdm-tasha-i2s-snd-card";
+
+ qcom,audio-routing =
+ "AIF4 VI", "MCLK",
+ "RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC3", "MIC BIAS2",
+ "MIC BIAS2", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2",
+ "MIC BIAS2", "ANCLeft Headset Mic",
+ "AMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Handset Mic",
+ "AMIC6", "MIC BIAS4",
+ "MIC BIAS4", "Analog Mic6",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "DMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic5",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+
+ qcom,tasha-mclk-clk-freq = <12288000>;
+
+ qcom,msm-gpios =
+ "pri_mi2s_aux_master",
+ "pri_mi2s_aux_slave",
+ "sec_mi2s_aux_master",
+ "sec_mi2s_aux_slave";
+ qcom,pinctrl-names =
+ "all_off",
+ "pri_mi2s_aux_master_active",
+ "pri_mi2s_aux_slave_active",
+ "invalid_state_1",
+ "sec_mi2s_aux_master_active",
+ "pri_master_active_sec_master_active",
+ "pri_slave_active_sec_master_active",
+ "invalid_state_2",
+ "sec_mi2s_aux_slave_active",
+ "pri_master_active_sec_slave_active",
+ "pri_slave_active_sec_slave_active";
+ pinctrl-names =
+ "all_off",
+ "pri_mi2s_aux_master_active",
+ "pri_mi2s_aux_slave_active",
+ "invalid_state_1",
+ "sec_mi2s_aux_master_active",
+ "pri_master_active_sec_master_active",
+ "pri_slave_active_sec_master_active",
+ "invalid_state_2",
+ "sec_mi2s_aux_slave_active",
+ "pri_master_active_sec_slave_active",
+ "pri_slave_active_sec_slave_active";
+ pinctrl-0 = <&pri_ws_sleep &pri_sck_sleep
+ &pri_dout_sleep &pri_din_sleep
+ &sec_ws_sleep &sec_sck_sleep
+ &sec_dout_sleep &sec_din_sleep>;
+ pinctrl-1 = <&pri_ws_active_master &pri_sck_active_master
+ &pri_dout_active &pri_din_active
+ &sec_ws_sleep &sec_sck_sleep
+ &sec_dout_sleep &sec_din_sleep>;
+ pinctrl-2 = <&pri_ws_active_slave &pri_sck_active_slave
+ &pri_dout_active &pri_din_active
+ &sec_ws_sleep &sec_sck_sleep
+ &sec_dout_sleep &sec_din_sleep>;
+ pinctrl-3 = <&pri_ws_sleep &pri_sck_sleep
+ &pri_dout_sleep &pri_din_sleep
+ &sec_ws_sleep &sec_sck_sleep
+ &sec_dout_sleep &sec_din_sleep>;
+ pinctrl-4 = <&pri_ws_sleep &pri_sck_sleep
+ &pri_dout_sleep &pri_din_sleep
+ &sec_ws_active_master &sec_sck_active_master
+ &sec_dout_active &sec_din_active>;
+ pinctrl-5 = <&pri_ws_active_master &pri_sck_active_master
+ &pri_dout_active &pri_din_active
+ &sec_ws_active_master &sec_sck_active_master
+ &sec_dout_active &sec_din_active>;
+ pinctrl-6 = <&pri_ws_active_slave &pri_sck_active_slave
+ &pri_dout_active &pri_din_active
+ &sec_ws_active_master &sec_sck_active_master
+ &sec_dout_active &sec_din_active>;
+ pinctrl-7 = <&pri_ws_sleep &pri_sck_sleep
+ &pri_dout_sleep &pri_din_sleep
+ &sec_ws_sleep &sec_sck_sleep
+ &sec_dout_sleep &sec_din_sleep>;
+ pinctrl-8 = <&pri_ws_sleep &pri_sck_sleep
+ &pri_dout_sleep &pri_din_sleep
+ &sec_ws_active_slave &sec_sck_active_slave
+ &sec_dout_active &sec_din_active>;
+ pinctrl-9 = <&pri_ws_active_master &pri_sck_active_master
+ &pri_dout_active &pri_din_active
+ &sec_ws_active_slave &sec_sck_active_slave
+ &sec_dout_active &sec_din_active>;
+ pinctrl-10 = <&pri_ws_active_slave &pri_sck_active_slave
+ &pri_dout_active &pri_din_active
+ &sec_ws_active_slave &sec_sck_active_slave
+ &sec_dout_active &sec_din_active>;
+
+ asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>,
+ <&loopback>, <&hostless>, <&afe>, <&routing>,
+ <&pcm_dtmf>, <&host_pcm>, <&compress>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-voip-dsp", "msm-pcm-voice",
+ "msm-pcm-loopback", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-pcm-routing",
+ "msm-pcm-dtmf", "msm-voice-host-pcm",
+ "msm-compress-dsp";
+ asoc-cpu = <&dai_pri_auxpcm>, <&mi2s_prim>, <&mi2s_sec>,
+ <&dtmf_tx>,
+ <&rx_capture_tx>, <&rx_playback_rx>,
+ <&tx_capture_tx>, <&tx_playback_rx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&dai_sec_auxpcm>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-stub-dev.4", "msm-dai-stub-dev.5",
+ "msm-dai-stub-dev.6", "msm-dai-stub-dev.7",
+ "msm-dai-stub-dev.8", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-auxpcm.2";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <1>;
+ qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
+ <&wsa881x_213>, <&wsa881x_214>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ };
+
+ qcom,msm-adsp-loader {
+ compatible = "qcom,adsp-loader";
+ qcom,adsp-state = <0>;
+ qcom,proc-img-to-load = "modem";
+ };
+
+ qcom,msm-audio-ion {
+ compatible = "qcom,msm-audio-ion";
+ qcom,scm-mp-enabled;
+ memory-region = <&audio_mem>;
+ };
+
+ pcm0: qcom,msm-pcm {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ routing: qcom,msm-pcm-routing {
+ compatible = "qcom,msm-pcm-routing";
+ };
+
+ pcm1: qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
+ qcom,msm-compr-dsp {
+ compatible = "qcom,msm-compr-dsp";
+ };
+
+ voip: qcom,msm-voip-dsp {
+ compatible = "qcom,msm-voip-dsp";
+ };
+
+ voice: qcom,msm-pcm-voice {
+ compatible = "qcom,msm-pcm-voice";
+ qcom,destroy-cvd;
+ };
+
+ stub_codec: qcom,msm-stub-codec {
+ compatible = "qcom,msm-stub-codec";
+ };
+
+ qcom,msm-dai-fe {
+ compatible = "qcom,msm-dai-fe";
+ };
+
+ afe: qcom,msm-pcm-afe {
+ compatible = "qcom,msm-pcm-afe";
+ };
+
+ hostless: qcom,msm-pcm-hostless {
+ compatible = "qcom,msm-pcm-hostless";
+ };
+
+ host_pcm: qcom,msm-voice-host-pcm {
+ compatible = "qcom,msm-voice-host-pcm";
+ };
+
+ loopback: qcom,msm-pcm-loopback {
+ compatible = "qcom,msm-pcm-loopback";
+ };
+
+ compress: qcom,msm-compress-dsp {
+ compatible = "qcom,msm-compress-dsp";
+ qcom,adsp-version = "MDSP 1.2";
+ };
+
+ qcom,msm-dai-stub {
+ compatible = "qcom,msm-dai-stub";
+ dtmf_tx: qcom,msm-dai-stub-dtmf-tx {
+ compatible = "qcom,msm-dai-stub-dev";
+ qcom,msm-dai-stub-dev-id = <4>;
+ };
+
+ rx_capture_tx: qcom,msm-dai-stub-host-rx-capture-tx {
+ compatible = "qcom,msm-dai-stub-dev";
+ qcom,msm-dai-stub-dev-id = <5>;
+ };
+
+ rx_playback_rx: qcom,msm-dai-stub-host-rx-playback-rx {
+ compatible = "qcom,msm-dai-stub-dev";
+ qcom,msm-dai-stub-dev-id = <6>;
+ };
+
+ tx_capture_tx: qcom,msm-dai-stub-host-tx-capture-tx {
+ compatible = "qcom,msm-dai-stub-dev";
+ qcom,msm-dai-stub-dev-id = <7>;
+ };
+
+ tx_playback_rx: qcom,msm-dai-stub-host-tx-playback-rx {
+ compatible = "qcom,msm-dai-stub-dev";
+ qcom,msm-dai-stub-dev-id = <8>;
+ };
+ };
+
+ qcom,msm-dai-q6 {
+ compatible = "qcom,msm-dai-q6";
+ afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <224>;
+ };
+
+ afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <225>;
+ };
+
+ afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <241>;
+ };
+
+ afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <240>;
+ };
+
+ incall_record_rx: qcom,msm-dai-q6-incall-record-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32771>;
+ };
+
+ incall_record_tx: qcom,msm-dai-q6-incall-record-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32772>;
+ };
+
+ incall_music_rx: qcom,msm-dai-q6-incall-music-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32773>;
+ };
+ };
+
+ pcm_dtmf: qcom,msm-pcm-dtmf {
+ compatible = "qcom,msm-pcm-dtmf";
+ };
+
+ cpu-pmu {
+ compatible = "arm,cortex-a7-pmu";
+ qcom,irq-is-percpu;
+ interrupts = <1 8 0x100>;
+ };
+
+ dai_pri_auxpcm: qcom,msm-pri-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "primary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
+ dai_sec_auxpcm: qcom,msm-sec-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "secondary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
+ qcom,msm-dai-mi2s {
+ compatible = "qcom,msm-dai-mi2s";
+ mi2s_prim: qcom,msm-dai-q6-mi2s-prim {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <0>;
+ qcom,msm-mi2s-rx-lines = <2>;
+ qcom,msm-mi2s-tx-lines = <1>;
+ };
+ mi2s_sec: qcom,msm-dai-q6-mi2s-sec {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <1>;
+ qcom,msm-mi2s-rx-lines = <2>;
+ qcom,msm-mi2s-tx-lines = <1>;
+ };
+
+ };
+
+ sdhc_1: sdhci@7824000 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0x07824900 0x500>, <0x07824000 0x800>;
+ reg-names = "hc_mem", "core_mem";
+
+ interrupts = <0 123 0>, <0 138 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ qcom,devfreq,freq-table = <50000000 200000000>;
+
+ qcom,msm-bus,name = "sdhc1";
+ qcom,msm-bus,num-cases = <8>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
+ <78 512 1600 3200>, /* 400 KB/s*/
+ <78 512 80000 160000>, /* 20 MB/s */
+ <78 512 100000 200000>, /* 25 MB/s */
+ <78 512 200000 400000>, /* 50 MB/s */
+ <78 512 400000 800000>, /* 100 MB/s */
+ <78 512 400000 800000>, /* 200 MB/s */
+ <78 512 2048000 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+ 100000000 200000000 4294967295>;
+ clocks = <&clock_gcc clk_gcc_sdcc1_ahb_clk>,
+ <&clock_gcc clk_gcc_sdcc1_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+
+ qcom,pm-qos-cpu-groups = <0x0>;
+ qcom,pm-qos-cmdq-latency-us = <70>;
+ qcom,pm-qos-legacy-latency-us = <70>;
+ qcom,pm-qos-irq-type = "affine_cores";
+ qcom,pm-qos-irq-cpu = <0>;
+ qcom,pm-qos-irq-latency = <70>;
+
+ status = "disabled";
+ };
+
+ pps {
+ compatible = "pps-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pps>;
+ gpios = <&tlmm_pinmux 39 0>;
+ status = "okay";
+ };
+
+};
+
+&gdsc_usb30 {
+ reg = <0x185e078 0x4>;
+ status = "ok";
+};
+
+&gdsc_pcie {
+ reg = <0x0185d044 0x4>;
+ status = "ok";
+};
+
+#include "msm-pmd9650-rpm-regulator.dtsi"
+#include "msm-pmd9650.dtsi"
+#include "mdm9650-regulator.dtsi"
+#include "mdm9650-usb.dtsi"
+
+&pmd9650_pon {
+ interrupts = <0x0 0x8 0x0>;
+ interrupt-names = "kpdpwr";
+ qcom,system-reset;
+
+ qcom,pon_1 {
+ qcom,pon-type = <0>;
+ qcom,pull-up = <1>;
+ linux,code = <116>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm-gdsc.dtsi b/arch/arm/boot/dts/qcom/msm-gdsc.dtsi
new file mode 100644
index 0000000..9a1f32e
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm-gdsc.dtsi
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2012-2014, 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.
+ */
+
+&soc {
+ gdsc_venus: qcom,gdsc@fd8c1024 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_venus";
+ reg = <0xfd8c1024 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_venus_core0: qcom,gdsc@fd8c1040 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_venus_core0";
+ reg = <0xfd8c1040 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_venus_core1: qcom,gdsc@fd8c1044 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_venus_core1";
+ reg = <0xfd8c1044 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_venus_core2: qcom,gdsc@fd8c1050 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_venus_core2";
+ reg = <0xfd8c1050 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_vpu: qcom,gdsc@fd8c1404 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_vpu";
+ reg = <0xfd8c1404 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_camss_top: qcom,gdsc@fd8c34a0 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_camss_top";
+ reg = <0xfd8c34a0 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_mdss: qcom,gdsc@fd8c2304 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_mdss";
+ reg = <0xfd8c2304 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_jpeg: qcom,gdsc@fd8c35a4 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_jpeg";
+ reg = <0xfd8c35a4 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_vfe: qcom,gdsc@fd8c36a4 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_vfe";
+ reg = <0xfd8c36a4 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_cpp: qcom,gdsc@fd8c36d4 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_cpp";
+ reg = <0xfd8c36d4 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_oxili_gx";
+ reg = <0xfd8c4024 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_oxili_cx: qcom,gdsc@fd8c4034 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_oxili_cx";
+ reg = <0xfd8c4034 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_usb_hsic: qcom,gdsc@fc400404 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_usb_hsic";
+ reg = <0xfc400404 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_pcie: qcom,gdsc@0xfc401e18 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_pcie";
+ reg = <0xfc401e18 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_pcie_0: qcom,gdsc@fc401ac4 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_pcie_0";
+ reg = <0xfc401ac4 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_pcie_1: qcom,gdsc@fc401b44 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_pcie_1";
+ reg = <0xfc401b44 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_usb30: qcom,gdsc@fc401e84 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_usb30";
+ reg = <0xfc401e84 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_usb30_sec: qcom,gdsc@fc401ec0 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_usb30_sec";
+ reg = <0xfc401ec0 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_vcap: qcom,gdsc@fd8c1804 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_vcap";
+ reg = <0xfd8c1804 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_bcss: qcom,gdsc@fc744128 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_bcss";
+ reg = <0xfc744128 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_ufs: qcom,gdsc@fc401d44 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_ufs";
+ reg = <0xfc401d44 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_fd: qcom,gdsc@fd8c3b64 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_fd";
+ reg = <0xfd8c3b64 0x4>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm-pmd9650-rpm-regulator.dtsi b/arch/arm/boot/dts/qcom/msm-pmd9650-rpm-regulator.dtsi
new file mode 100644
index 0000000..faac696
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm-pmd9650-rpm-regulator.dtsi
@@ -0,0 +1,301 @@
+/* Copyright (c) 2015, 2017-2018, 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.
+ */
+
+&rpm_bus {
+ rpm-regulator-smpa1 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s1 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_s1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa2 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s2 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_s2";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa3 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s3 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_s3";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa4 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s4 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_s4";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa5 { /* VDD_CX supply */
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "rwcx";
+ qcom,resource-id = <0>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s5 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_s5";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l1 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_l1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l2 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_l2";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l3 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_l3";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa4 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l4 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_l4";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <5>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l5 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_l5";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <6>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l6 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_l6";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <7>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l7 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_l7";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <8>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l8 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_l8";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa9 { /* VDD_MX supply */
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "rwmx";
+ qcom,resource-id = <0>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l9 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_l9";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <10>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l10 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_l10";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <11>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l11 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_l11";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <12>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l12 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_l12";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <13>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l13 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "9650_l13";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm-pmd9650.dtsi b/arch/arm/boot/dts/qcom/msm-pmd9650.dtsi
new file mode 100644
index 0000000..2f84eb0
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm-pmd9650.dtsi
@@ -0,0 +1,402 @@
+/* Copyright (c) 2015-2018, 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.
+ */
+
+&spmi_bus {
+ qcom,pmd9650@0 {
+ spmi-slave-container;
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ qcom,revid@100 {
+ compatible = "qcom,qpnp-revid";
+ reg = <0x100 0x100>;
+ };
+
+ pmd9650_pon: qcom,power-on@800 {
+ compatible = "qcom,qpnp-power-on";
+ reg = <0x800 0x100>;
+ qcom,pon-dbc-delay = <15625>;
+
+ };
+
+ pmd9650_misc: qcom,misc@900 {
+ compatible = "qcom,qpnp-misc";
+ reg = <0x900 0x100>;
+ };
+
+ pmd9650_gpios: gpios {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-pin";
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "pmd9650-gpio";
+
+ gpio@c000 {
+ reg = <0xc000 0x100>;
+ qcom,pin-num = <1>;
+ status = "disabled";
+ };
+
+ gpio@c100 {
+ reg = <0xc100 0x100>;
+ qcom,pin-num = <2>;
+ status = "disabled";
+ };
+
+ gpio@c200 {
+ reg = <0xc200 0x100>;
+ qcom,pin-num = <3>;
+ status = "disabled";
+ };
+
+ gpio@c300 {
+ reg = <0xc300 0x100>;
+ qcom,pin-num = <4>;
+ status = "disabled";
+ };
+
+ gpio@c400 {
+ reg = <0xc400 0x100>;
+ qcom,pin-num = <5>;
+ status = "disabled";
+ };
+
+ gpio@c500 {
+ reg = <0xc500 0x100>;
+ qcom,pin-num = <6>;
+ status = "disabled";
+ };
+
+ gpio@c600 {
+ reg = <0xc600 0x100>;
+ qcom,pin-num = <7>;
+ status = "disabled";
+ };
+
+ gpio@c700 {
+ reg = <0xc700 0x100>;
+ qcom,pin-num = <8>;
+ status = "disabled";
+ };
+
+ gpio@c800 {
+ reg = <0xc800 0x100>;
+ qcom,pin-num = <9>;
+ status = "disabled";
+ };
+
+ gpio@c900 {
+ reg = <0xc900 0x100>;
+ qcom,pin-num = <10>;
+ status = "disabled";
+ };
+
+ gpio@ca00 {
+ reg = <0xca00 0x100>;
+ qcom,pin-num = <11>;
+ status = "disabled";
+ };
+
+ gpio@cb00 {
+ reg = <0xcb00 0x100>;
+ qcom,pin-num = <12>;
+ status = "disabled";
+ };
+ };
+
+ pmd9650_vadc: vadc@3100 {
+ compatible = "qcom,qpnp-vadc-hc";
+ reg = <0x3100 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x31 0x0>;
+ interrupt-names = "eoc-int-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1875>;
+
+ chan@6 {
+ label = "die_temp";
+ reg = <6>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@0 {
+ label = "ref_gnd";
+ reg = <0>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@1 {
+ label = "ref_1250v";
+ reg = <1>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+ };
+
+ qcom,pmd9650_rtc {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-rtc";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,qpnp-rtc-write = <0>;
+ qcom,qpnp-rtc-alarm-pwrup = <0>;
+
+ qcom,pmd9650_rtc_rw@6000 {
+ reg = <0x6000 0x100>;
+ };
+
+ qcom,pmd9650_rtc_alarm@6100 {
+ reg = <0x6100 0x100>;
+ interrupts = <0x0 0x61 0x1>;
+ };
+ };
+ };
+
+ qcom,pmd9650@1 {
+ spmi-slave-container;
+ reg = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pmd9650_pwm_1: pwm@bc00 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xbc00 0x100>;
+ reg-names = "qpnp-lpg-channel-base";
+ qcom,channel-id = <0>;
+ qcom,supported-sizes = <6>, <9>;
+ #pwm-cells = <2>;
+ status = "disabled";
+ };
+
+ pmd9650_pwm_2: pwm@bd00 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xbd00 0x100>;
+ reg-names = "qpnp-lpg-channel-base";
+ qcom,channel-id = <1>;
+ qcom,supported-sizes = <6>, <9>;
+ #pwm-cells = <2>;
+ status = "disabled";
+ };
+
+ regulator@1400 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_s1";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1400 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1400 {
+ reg = <0x1400 0x100>;
+ };
+ qcom,ps@1500 {
+ reg = <0x1500 0x100>;
+ };
+ qcom,freq@1600 {
+ reg = <0x1600 0x100>;
+ };
+ };
+
+ regulator@1700 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_s2";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1700 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1700 {
+ reg = <0x1700 0x100>;
+ };
+ qcom,ps@1800 {
+ reg = <0x1800 0x100>;
+ };
+ qcom,freq@1900 {
+ reg = <0x1900 0x100>;
+ };
+ };
+
+ regulator@1a00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_s3";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1a00 0x300>;
+ status = "disabled";
+
+ qcom,ctl@x1a00 {
+ reg = <0x1a00 0x100>;
+ };
+ qcom,ps@1b00 {
+ reg = <0x1b00 0x100>;
+ };
+ qcom,freq@1c00 {
+ reg = <0x1c00 0x100>;
+ };
+ };
+
+ regulator@1d00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_s4";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1d00 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1d00 {
+ reg = <0x1d00 0x100>;
+ };
+ qcom,ps@1e00 {
+ reg = <0x1e00 0x100>;
+ };
+ qcom,freq@1f00 {
+ reg = <0x1f00 0x100>;
+ };
+ };
+
+ regulator@2000 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_s5";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x2000 0x300>;
+ status = "disabled";
+
+ qcom,ctl@2000 {
+ reg = <0x2000 0x100>;
+ };
+ qcom,ps@2100 {
+ reg = <0x2100 0x100>;
+ };
+ qcom,freq@2200 {
+ reg = <0x2200 0x100>;
+ };
+ };
+
+ regulator@4000 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_l1";
+ reg = <0x4000 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4100 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_l2";
+ reg = <0x4100 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4200 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_l3";
+ reg = <0x4200 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4300 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_l4";
+ reg = <0x4300 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4400 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_l5";
+ reg = <0x4400 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4500 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_l6";
+ reg = <0x4500 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4600 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_l7";
+ reg = <0x4600 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4700 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_l8";
+ reg = <0x4700 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4800 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_l9";
+ reg = <0x4800 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4900 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_l10";
+ reg = <0x4900 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4a00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_l11";
+ reg = <0x4a00 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4b00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_l12";
+ reg = <0x4b00 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4c00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "9650_l13";
+ reg = <0x4c00 0x100>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/pm8950.dtsi b/arch/arm/boot/dts/qcom/pm8950.dtsi
deleted file mode 100644
index f47872a..0000000
--- a/arch/arm/boot/dts/qcom/pm8950.dtsi
+++ /dev/null
@@ -1,388 +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.
- */
-
-&spmi_bus {
- qcom,pm8950@0 {
- compatible ="qcom,spmi-pmic";
- reg = <0x0 SPMI_USID>;
- #address-cells = <2>;
- #size-cells = <0>;
-
- pm8950_revid: qcom,revid@100 {
- compatible = "qcom,qpnp-revid";
- reg = <0x100 0x100>;
- };
-
- pm8950_temp_alarm: qcom,temp-alarm@2400 {
- compatible = "qcom,qpnp-temp-alarm";
- reg = <0x2400 0x100>;
- interrupts = <0x0 0x24 0x0>;
- label = "pm8950_tz";
- qcom,channel-num = <8>;
- qcom,threshold-set = <0>;
- qcom,temp_alarm-vadc = <&pm8950_vadc>;
- };
-
- qcom,power-on@800 {
- compatible = "qcom,qpnp-power-on";
- reg = <0x800 0x100>;
- interrupts = <0x0 0x8 0x0>,
- <0x0 0x8 0x1>,
- <0x0 0x8 0x4>,
- <0x0 0x8 0x5>;
- interrupt-names = "kpdpwr", "resin",
- "resin-bark", "kpdpwr-resin-bark";
- qcom,pon-dbc-delay = <15625>;
- qcom,system-reset;
-
- qcom,pon_1 {
- qcom,pon-type = <0>;
- qcom,pull-up = <1>;
- linux,code = <116>;
- };
-
- qcom,pon_2 {
- qcom,pon-type = <1>;
- qcom,pull-up = <1>;
- linux,code = <114>;
- };
- };
-
- pm8950_coincell: qcom,coincell@2800 {
- compatible = "qcom,qpnp-coincell";
- reg = <0x2800 0x100>;
- };
-
- pm8950_mpps: mpps {
- compatible = "qcom,qpnp-pin";
- spmi-dev-container;
- gpio-controller;
- #gpio-cells = <2>;
- #address-cells = <1>;
- #size-cells = <1>;
- label = "pm8950-mpp";
-
- mpp@a000 {
- reg = <0xa000 0x100>;
- qcom,pin-num = <1>;
- status = "disabled";
- };
-
- mpp@a100 {
- /* MPP2 - PA_THERM config */
- reg = <0xa100 0x100>;
- qcom,pin-num = <2>;
- qcom,mode = <4>; /* AIN input */
- qcom,invert = <1>; /* Enable MPP */
- qcom,ain-route = <1>; /* AMUX 6 */
- qcom,master-en = <1>;
- qcom,src-sel = <0>; /* Function constant */
- };
-
- mpp@a200 {
- reg = <0xa200 0x100>;
- qcom,pin-num = <3>;
- status = "disabled";
- };
-
- mpp@a300 {
- /* MPP4 - CASE_THERM config */
- reg = <0xa300 0x100>;
- qcom,pin-num = <4>;
- qcom,mode = <4>; /* AIN input */
- qcom,invert = <1>; /* Enable MPP */
- qcom,ain-route = <3>; /* AMUX 8 */
- qcom,master-en = <1>;
- qcom,src-sel = <0>; /* Function constant */
- };
- };
-
- pm8950_gpios: gpios {
- spmi-dev-container;
- compatible = "qcom,qpnp-pin";
- gpio-controller;
- #gpio-cells = <2>;
- #address-cells = <1>;
- #size-cells = <1>;
- label = "pm8950-gpio";
-
- gpio@c000 {
- reg = <0xc000 0x100>;
- qcom,pin-num = <1>;
- status = "disabled";
- };
-
- gpio@c100 {
- reg = <0xc100 0x100>;
- qcom,pin-num = <2>;
- status = "disabled";
- };
-
- gpio@c200 {
- reg = <0xc200 0x100>;
- qcom,pin-num = <3>;
- status = "disabled";
- };
-
- gpio@c300 {
- reg = <0xc300 0x100>;
- qcom,pin-num = <4>;
- status = "disabled";
- };
-
- gpio@c400 {
- reg = <0xc400 0x100>;
- qcom,pin-num = <5>;
- status = "disabled";
- };
-
- gpio@c500 {
- reg = <0xc500 0x100>;
- qcom,pin-num = <6>;
- status = "disabled";
- };
-
- gpio@c600 {
- reg = <0xc600 0x100>;
- qcom,pin-num = <7>;
- status = "disabled";
- };
-
- gpio@c700 {
- reg = <0xc700 0x100>;
- qcom,pin-num = <8>;
- status = "disabled";
- };
- };
-
- pm8950_vadc: vadc@3100 {
- compatible = "qcom,qpnp-vadc";
- reg = <0x3100 0x100>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <0x0 0x31 0x0>;
- interrupt-names = "eoc-int-en-set";
- qcom,adc-bit-resolution = <15>;
- qcom,adc-vdd-reference = <1800>;
- qcom,vadc-poll-eoc;
- qcom,pmic-revid = <&pm8950_revid>;
-
- chan@5 {
- label = "vcoin";
- reg = <5>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@7 {
- label = "vph_pwr";
- reg = <7>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@8 {
- label = "die_temp";
- reg = <8>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <3>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@9 {
- label = "ref_625mv";
- reg = <9>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@a {
- label = "ref_1250v";
- reg = <0xa>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@c {
- label = "ref_buf_625mv";
- reg = <0xc>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@36 {
- label = "pa_therm0";
- reg = <0x36>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@11 {
- label = "pa_therm1";
- reg = <0x11>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-
- chan@32 {
- label = "xo_therm";
- reg = <0x32>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <4>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-
- chan@3c {
- label = "xo_therm_buf";
- reg = <0x3c>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <4>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-
- chan@13 {
- label = "case_therm";
- reg = <0x13>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
- };
-
- pm8950_adc_tm: vadc@3400 {
- compatible = "qcom,qpnp-adc-tm";
- reg = <0x3400 0x100>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <0x0 0x34 0x0>,
- <0x0 0x34 0x3>,
- <0x0 0x34 0x4>;
- interrupt-names = "eoc-int-en-set",
- "high-thr-en-set",
- "low-thr-en-set";
- qcom,adc-bit-resolution = <15>;
- qcom,adc-vdd-reference = <1800>;
- qcom,adc_tm-vadc = <&pm8950_vadc>;
- qcom,pmic-revid = <&pm8950_revid>;
-
- chan@36 {
- label = "pa_therm0";
- reg = <0x36>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- qcom,btm-channel-number = <0x48>;
- qcom,thermal-node;
- };
-
- chan@7 {
- label = "vph_pwr";
- reg = <0x7>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- qcom,btm-channel-number = <0x68>;
- };
- };
-
- pm8950_rtc: qcom,pm8950_rtc {
- spmi-dev-container;
- compatible = "qcom,qpnp-rtc";
- #address-cells = <1>;
- #size-cells = <1>;
- qcom,qpnp-rtc-write = <0>;
- qcom,qpnp-rtc-alarm-pwrup = <0>;
-
- qcom,pm8950_rtc_rw@6000 {
- reg = <0x6000 0x100>;
- };
-
- qcom,pm8950_rtc_alarm@6100 {
- reg = <0x6100 0x100>;
- interrupts = <0x0 0x61 0x1>;
- };
- };
-
- qcom,leds@a300 {
- compatible = "qcom,leds-qpnp";
- reg = <0xa300 0x100>;
- label = "mpp";
- };
- };
-
- pm8950_1: qcom,pm8950@1 {
- compatible ="qcom,spmi-pmic";
- reg = <0x1 SPMI_USID>;
- #address-cells = <2>;
- #size-cells = <0>;
-
- pm8950_pwm: pwm@bc00 {
- status = "disabled";
- compatible = "qcom,qpnp-pwm";
- reg = <0xbc00 0x100>;
- reg-names = "qpnp-lpg-channel-base";
- qcom,channel-id = <0>;
- qcom,supported-sizes = <6>, <9>;
- #pwm-cells = <2>;
- };
- };
-};
diff --git a/arch/arm/boot/dts/qcom/pmi8950.dtsi b/arch/arm/boot/dts/qcom/pmi8950.dtsi
deleted file mode 100644
index 0ec1f0b..0000000
--- a/arch/arm/boot/dts/qcom/pmi8950.dtsi
+++ /dev/null
@@ -1,641 +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 <dt-bindings/msm/power-on.h>
-
-&spmi_bus {
- qcom,pmi8950@2 {
- compatible ="qcom,spmi-pmic";
- reg = <0x2 SPMI_USID>;
- #address-cells = <2>;
- #size-cells = <0>;
-
- pmi8950_revid: qcom,revid@100 {
- compatible = "qcom,qpnp-revid";
- reg = <0x100 0x100>;
- };
-
- qcom,power-on@800 {
- compatible = "qcom,qpnp-power-on";
- reg = <0x800 0x100>;
- qcom,secondary-pon-reset;
- qcom,hard-reset-poweroff-type =
- <PON_POWER_OFF_SHUTDOWN>;
-
- pon_perph_reg: qcom,pon_perph_reg {
- regulator-name = "pon_spare_reg";
- qcom,pon-spare-reg-addr = <0x8c>;
- qcom,pon-spare-reg-bit = <1>;
- };
- };
-
- pmi8950_vadc: vadc@3100 {
- compatible = "qcom,qpnp-vadc";
- reg = <0x3100 0x100>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <0x2 0x31 0x0>;
- interrupt-names = "eoc-int-en-set";
- qcom,adc-bit-resolution = <15>;
- qcom,adc-vdd-reference = <1800>;
- qcom,vadc-poll-eoc;
-
- chan@0 {
- label = "usbin";
- reg = <0>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <4>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@1 {
- label = "dcin";
- reg = <1>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <4>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@3 {
- label = "vchg_sns";
- reg = <3>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@9 {
- label = "ref_625mv";
- reg = <9>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@a {
- label = "ref_1250v";
- reg = <0xa>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@d {
- label = "chg_temp";
- reg = <0xd>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <16>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- qcom,vadc-thermal-node;
- };
-
- chan@43 {
- label = "usb_dp";
- reg = <0x43>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@44 {
- label = "usb_dm";
- reg = <0x44>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
- };
-
- pmi8950_gpios: gpios {
- spmi-dev-container;
- compatible = "qcom,qpnp-pin";
- gpio-controller;
- #gpio-cells = <2>;
- #address-cells = <1>;
- #size-cells = <1>;
- label = "pmi8950-gpio";
-
- gpio@c000 {
- reg = <0xc000 0x100>;
- qcom,pin-num = <1>;
- status = "disabled";
- };
-
- gpio@c100 {
- reg = <0xc100 0x100>;
- qcom,pin-num = <2>;
- status = "disabled";
- };
- };
-
- pmi8950_mpps: mpps {
- spmi-dev-container;
- compatible = "qcom,qpnp-pin";
- gpio-controller;
- #gpio-cells = <2>;
- #address-cells = <1>;
- #size-cells = <1>;
- label = "pmi8950-mpp";
-
- mpp@a000 {
- reg = <0xa000 0x100>;
- qcom,pin-num = <1>;
- status = "disabled";
- };
-
- mpp@a100 {
- reg = <0xa100 0x100>;
- qcom,pin-num = <2>;
- status = "disabled";
- };
-
- mpp@a200 {
- reg = <0xa200 0x100>;
- qcom,pin-num = <3>;
- status = "disabled";
- };
-
- mpp@a300 {
- reg = <0xa300 0x100>;
- qcom,pin-num = <4>;
- status = "disabled";
- };
- };
-
- pmi8950_charger: qcom,qpnp-smbcharger {
- spmi-dev-container;
- compatible = "qcom,qpnp-smbcharger";
- #address-cells = <1>;
- #size-cells = <1>;
-
- qcom,iterm-ma = <100>;
- qcom,float-voltage-mv = <4200>;
- qcom,resume-delta-mv = <200>;
- qcom,chg-inhibit-fg;
- qcom,rparasitic-uohm = <100000>;
- qcom,bms-psy-name = "bms";
- qcom,thermal-mitigation = <1500 700 600 0>;
- qcom,parallel-usb-min-current-ma = <1400>;
- qcom,parallel-usb-9v-min-current-ma = <900>;
- qcom,parallel-allowed-lowering-ma = <500>;
- qcom,pmic-revid = <&pmi8950_revid>;
- qcom,force-aicl-rerun;
- qcom,aicl-rerun-period-s = <180>;
- qcom,autoadjust-vfloat;
-
- qcom,chgr@1000 {
- reg = <0x1000 0x100>;
- interrupts = <0x2 0x10 0x0>,
- <0x2 0x10 0x1>,
- <0x2 0x10 0x2>,
- <0x2 0x10 0x3>,
- <0x2 0x10 0x4>,
- <0x2 0x10 0x5>,
- <0x2 0x10 0x6>,
- <0x2 0x10 0x7>;
-
- interrupt-names = "chg-error",
- "chg-inhibit",
- "chg-prechg-sft",
- "chg-complete-chg-sft",
- "chg-p2f-thr",
- "chg-rechg-thr",
- "chg-taper-thr",
- "chg-tcc-thr";
- };
-
- qcom,otg@1100 {
- reg = <0x1100 0x100>;
- interrupts = <0x2 0x11 0x0>,
- <0x2 0x11 0x1>,
- <0x2 0x11 0x3>;
- interrupt-names = "otg-fail",
- "otg-oc",
- "usbid-change";
- };
-
- qcom,bat-if@1200 {
- reg = <0x1200 0x100>;
- interrupts = <0x2 0x12 0x0>,
- <0x2 0x12 0x1>,
- <0x2 0x12 0x2>,
- <0x2 0x12 0x3>,
- <0x2 0x12 0x4>,
- <0x2 0x12 0x5>,
- <0x2 0x12 0x6>,
- <0x2 0x12 0x7>;
-
- interrupt-names = "batt-hot",
- "batt-warm",
- "batt-cold",
- "batt-cool",
- "batt-ov",
- "batt-low",
- "batt-missing",
- "batt-term-missing";
- };
-
- qcom,usb-chgpth@1300 {
- reg = <0x1300 0x100>;
- interrupts = <0x2 0x13 0x0>,
- <0x2 0x13 0x1>,
- <0x2 0x13 0x2>,
- <0x2 0x13 0x5>;
-
- interrupt-names = "usbin-uv",
- "usbin-ov",
- "usbin-src-det",
- "aicl-done";
- };
-
- qcom,dc-chgpth@1400 {
- reg = <0x1400 0x100>;
- interrupts = <0x2 0x14 0x0>,
- <0x2 0x14 0x1>;
- interrupt-names = "dcin-uv",
- "dcin-ov";
- };
-
- qcom,chgr-misc@1600 {
- reg = <0x1600 0x100>;
- interrupts = <0x2 0x16 0x0>,
- <0x2 0x16 0x1>,
- <0x2 0x16 0x2>,
- <0x2 0x16 0x3>,
- <0x2 0x16 0x4>,
- <0x2 0x16 0x5>;
-
- interrupt-names = "power-ok",
- "temp-shutdown",
- "wdog-timeout",
- "flash-fail",
- "otst2",
- "otst3";
- };
-
- smbcharger_charger_otg: qcom,smbcharger-boost-otg {
- regulator-name = "smbcharger_charger_otg";
- };
- };
-
- pmi8950_fg: qcom,fg {
- spmi-dev-container;
- compatible = "qcom,qpnp-fg";
- #address-cells = <1>;
- #size-cells = <1>;
- qcom,resume-soc = <95>;
- status = "okay";
- qcom,bcl-lm-threshold-ma = <127>;
- qcom,bcl-mh-threshold-ma = <405>;
- qcom,fg-iterm-ma = <150>;
- qcom,fg-chg-iterm-ma = <100>;
- qcom,pmic-revid = <&pmi8950_revid>;
- qcom,fg-cutoff-voltage-mv = <3500>;
- qcom,cycle-counter-en;
- qcom,capacity-learning-on;
-
- qcom,fg-soc@4000 {
- status = "okay";
- reg = <0x4000 0x100>;
- interrupts = <0x2 0x40 0x0>,
- <0x2 0x40 0x1>,
- <0x2 0x40 0x2>,
- <0x2 0x40 0x3>,
- <0x2 0x40 0x4>,
- <0x2 0x40 0x5>,
- <0x2 0x40 0x6>;
-
- interrupt-names = "high-soc",
- "low-soc",
- "full-soc",
- "empty-soc",
- "delta-soc",
- "first-est-done",
- "update-soc";
- };
-
- qcom,fg-batt@4100 {
- reg = <0x4100 0x100>;
- interrupts = <0x2 0x41 0x0>,
- <0x2 0x41 0x1>,
- <0x2 0x41 0x2>,
- <0x2 0x41 0x3>,
- <0x2 0x41 0x4>,
- <0x2 0x41 0x5>,
- <0x2 0x41 0x6>,
- <0x2 0x41 0x7>;
-
- interrupt-names = "soft-cold",
- "soft-hot",
- "vbatt-low",
- "batt-ided",
- "batt-id-req",
- "batt-unknown",
- "batt-missing",
- "batt-match";
- };
-
- qcom,revid-tp-rev@1f1 {
- reg = <0x1f1 0x1>;
- };
-
- qcom,fg-memif@4400 {
- status = "okay";
- reg = <0x4400 0x100>;
- interrupts = <0x2 0x44 0x0>,
- <0x2 0x44 0x2>;
-
- interrupt-names = "mem-avail",
- "data-rcvry-sug";
- };
- };
-
- bcl@4200 {
- compatible = "qcom,msm-bcl";
- reg = <0x4200 0xFF 0x88E 0x2>;
- reg-names = "fg_user_adc", "pon_spare";
- interrupts = <0x2 0x42 0x0>,
- <0x2 0x42 0x1>;
- interrupt-names = "bcl-high-ibat-int",
- "bcl-low-vbat-int";
- qcom,vbat-scaling-factor = <39000>;
- qcom,vbat-gain-numerator = <1>;
- qcom,vbat-gain-denominator = <128>;
- qcom,vbat-polling-delay-ms = <100>;
- qcom,ibat-scaling-factor = <39000>;
- qcom,ibat-gain-numerator = <1>;
- qcom,ibat-gain-denominator = <128>;
- qcom,ibat-offset-numerator = <1200>;
- qcom,ibat-offset-denominator = <1>;
- qcom,ibat-polling-delay-ms = <100>;
- qcom,inhibit-derating-ua = <550000>;
- };
-
- qcom,leds@a100 {
- compatible = "qcom,leds-qpnp";
- reg = <0xa100 0x100>;
- label = "mpp";
- };
- };
-
- qcom,pmi8950@3 {
- compatible ="qcom,spmi-pmic";
- reg = <0x3 SPMI_USID>;
- #address-cells = <1>;
- #size-cells = <1>;
-
- pmi8950_pwm: pwm@b000 {
- status = "disabled";
- compatible = "qcom,qpnp-pwm";
- reg = <0xb000 0x100>;
- reg-names = "qpnp-lpg-channel-base";
- qcom,channel-id = <0>;
- qcom,supported-sizes = <6>, <9>;
- #pwm-cells = <2>;
- };
-
- labibb: qpnp-labibb-regulator {
- status = "disabled";
- spmi-dev-container;
- compatible = "qcom,qpnp-labibb-regulator";
- #address-cells = <1>;
- #size-cells = <1>;
- qcom,pmic-revid = <&pmi8950_revid>;
-
- ibb_regulator: qcom,ibb@dc00 {
- reg = <0xdc00 0x100>;
- reg-names = "ibb_reg";
- regulator-name = "ibb_reg";
-
- regulator-min-microvolt = <4600000>;
- regulator-max-microvolt = <6000000>;
-
- qcom,qpnp-ibb-min-voltage = <1400000>;
- qcom,qpnp-ibb-step-size = <100000>;
- qcom,qpnp-ibb-slew-rate = <2000000>;
- qcom,qpnp-ibb-use-default-voltage;
- qcom,qpnp-ibb-init-voltage = <5500000>;
- qcom,qpnp-ibb-init-amoled-voltage = <4000000>;
- qcom,qpnp-ibb-init-lcd-voltage = <5500000>;
-
- qcom,qpnp-ibb-soft-start = <1000>;
-
- qcom,qpnp-ibb-discharge-resistor = <32>;
- qcom,qpnp-ibb-lab-pwrup-delay = <8000>;
- qcom,qpnp-ibb-lab-pwrdn-delay = <8000>;
- qcom,qpnp-ibb-en-discharge;
-
- qcom,qpnp-ibb-full-pull-down;
- qcom,qpnp-ibb-pull-down-enable;
- qcom,qpnp-ibb-switching-clock-frequency =
- <1480>;
- qcom,qpnp-ibb-limit-maximum-current = <1550>;
- qcom,qpnp-ibb-debounce-cycle = <16>;
- qcom,qpnp-ibb-limit-max-current-enable;
- qcom,qpnp-ibb-ps-enable;
- };
-
- lab_regulator: qcom,lab@de00 {
- reg = <0xde00 0x100>;
- reg-names = "lab";
- regulator-name = "lab_reg";
-
- regulator-min-microvolt = <4600000>;
- regulator-max-microvolt = <6000000>;
-
- qcom,qpnp-lab-min-voltage = <4600000>;
- qcom,qpnp-lab-step-size = <100000>;
- qcom,qpnp-lab-slew-rate = <5000>;
- qcom,qpnp-lab-use-default-voltage;
- qcom,qpnp-lab-init-voltage = <5500000>;
- qcom,qpnp-lab-init-amoled-voltage = <4600000>;
- qcom,qpnp-lab-init-lcd-voltage = <5500000>;
-
- qcom,qpnp-lab-soft-start = <800>;
-
- qcom,qpnp-lab-full-pull-down;
- qcom,qpnp-lab-pull-down-enable;
- qcom,qpnp-lab-switching-clock-frequency =
- <1600>;
- qcom,qpnp-lab-limit-maximum-current = <800>;
- qcom,qpnp-lab-limit-max-current-enable;
- qcom,qpnp-lab-ps-threshold = <40>;
- qcom,qpnp-lab-ps-enable;
- qcom,qpnp-lab-nfet-size = <100>;
- qcom,qpnp-lab-pfet-size = <100>;
- qcom,qpnp-lab-max-precharge-time = <500>;
- };
-
- };
-
- wled: qcom,leds@d800 {
- compatible = "qcom,qpnp-wled";
- reg = <0xd800 0x100>,
- <0xd900 0x100>,
- <0xdc00 0x100>,
- <0xde00 0x100>;
- reg-names = "qpnp-wled-ctrl-base",
- "qpnp-wled-sink-base",
- "qpnp-wled-ibb-base",
- "qpnp-wled-lab-base";
- interrupts = <0x3 0xd8 0x2>;
- interrupt-names = "sc-irq";
- status = "okay";
- linux,name = "wled";
- linux,default-trigger = "bkl-trigger";
- qcom,fdbk-output = "auto";
- qcom,vref-mv = <350>;
- qcom,switch-freq-khz = <800>;
- qcom,ovp-mv = <29500>;
- qcom,ilim-ma = <980>;
- qcom,boost-duty-ns = <26>;
- qcom,mod-freq-khz = <9600>;
- qcom,dim-mode = "hybrid";
- qcom,dim-method = "linear";
- qcom,hyb-thres = <625>;
- qcom,sync-dly-us = <800>;
- qcom,fs-curr-ua = <20000>;
- qcom,led-strings-list = [00 01];
- qcom,en-ext-pfet-sc-pro;
- qcom,cons-sync-write-delay-us = <1000>;
- };
-
- flash_led: qcom,leds@d300 {
- compatible = "qcom,qpnp-flash-led";
- status = "okay";
- reg = <0xd300 0x100>;
- label = "flash";
- qcom,headroom = <500>;
- qcom,startup-dly = <128>;
- qcom,clamp-curr = <200>;
- qcom,pmic-charger-support;
- qcom,self-check-enabled;
- qcom,thermal-derate-enabled;
- qcom,thermal-derate-threshold = <100>;
- qcom,thermal-derate-rate = "5_PERCENT";
- qcom,current-ramp-enabled;
- qcom,ramp_up_step = "6P7_US";
- qcom,ramp_dn_step = "6P7_US";
- qcom,vph-pwr-droop-enabled;
- qcom,vph-pwr-droop-threshold = <3000>;
- qcom,vph-pwr-droop-debounce-time = <10>;
- qcom,headroom-sense-ch0-enabled;
- qcom,headroom-sense-ch1-enabled;
- qcom,pmic-revid = <&pmi8950_revid>;
-
- pmi8950_flash0: qcom,flash_0 {
- label = "flash";
- qcom,led-name = "led:flash_0";
- qcom,default-led-trigger =
- "flash0_trigger";
- qcom,max-current = <1000>;
- qcom,duration = <1280>;
- qcom,id = <0>;
- qcom,current = <625>;
- };
-
- pmi8950_flash1: qcom,flash_1 {
- label = "flash";
- qcom,led-name = "led:flash_1";
- qcom,default-led-trigger =
- "flash1_trigger";
- qcom,max-current = <1000>;
- qcom,duration = <1280>;
- qcom,id = <1>;
- qcom,current = <625>;
- };
-
- pmi8950_torch0: qcom,torch_0 {
- label = "torch";
- qcom,led-name = "led:torch_0";
- qcom,default-led-trigger =
- "torch0_trigger";
- qcom,max-current = <200>;
- qcom,id = <0>;
- qcom,current = <120>;
- };
-
- pmi8950_torch1: qcom,torch_1 {
- label = "torch";
- qcom,led-name = "led:torch_1";
- qcom,default-led-trigger =
- "torch1_trigger";
- qcom,max-current = <200>;
- qcom,id = <1>;
- qcom,current = <120>;
- };
-
- pmi8950_switch: qcom,switch {
- label = "switch";
- qcom,led-name = "led:switch";
- qcom,default-led-trigger =
- "switch_trigger";
- qcom,max-current = <1000>;
- qcom,duration = <1280>;
- qcom,id = <2>;
- qcom,current = <625>;
- reg0 {
- regulator-name = "pon_spare_reg";
- };
- };
- };
-
- pmi_haptic: qcom,haptic@c000 {
- compatible = "qcom,qpnp-haptic";
- reg = <0xc000 0x100>;
- interrupts = <0x3 0xc0 0x0>,
- <0x3 0xc0 0x1>;
- interrupt-names = "sc-irq", "play-irq";
- qcom,pmic-revid = <&pmi8950_revid>;
- vcc_pon-supply = <&pon_perph_reg>;
- qcom,play-mode = "direct";
- qcom,wave-play-rate-us = <5263>;
- qcom,actuator-type = "erm";
- qcom,wave-shape = "square";
- qcom,vmax-mv = <2000>;
- qcom,ilim-ma = <800>;
- qcom,sc-deb-cycles = <8>;
- qcom,int-pwm-freq-khz = <505>;
- qcom,en-brake;
- qcom,brake-pattern = [03 03 00 00];
- qcom,use-play-irq;
- qcom,use-sc-irq;
- qcom,wave-samples = [3e 3e 3e 3e 3e 3e 3e 3e];
- qcom,wave-rep-cnt = <1>;
- qcom,wave-samp-rep-cnt = <1>;
- };
- };
-};
diff --git a/arch/arm/boot/dts/qcom/qpic-panel-ili-hvga.dtsi b/arch/arm/boot/dts/qcom/qpic-panel-ili-hvga.dtsi
new file mode 100644
index 0000000..e06f398
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/qpic-panel-ili-hvga.dtsi
@@ -0,0 +1,21 @@
+/* Copyright (c) 2018, 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.
+ */
+
+&soc {
+ qcom,mdss_lcdc_ili_hvga {
+ compatible = "qcom,mdss-qpic-panel";
+ label = "ili9488 hvga lcdc panel";
+ qcom,mdss-pan-res = <320 480>;
+ qcom,mdss-pan-bpp = <18>;
+ qcom,refresh_rate = <60>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts
new file mode 100644
index 0000000..04f11ce
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts
@@ -0,0 +1,22 @@
+/* Copyright (c) 2018, 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 "sdxpoorwills-cdp-256.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDXPOORWILLS CDP (256MB)";
+ compatible = "qcom,sdxpoorwills-cdp",
+ "qcom,sdxpoorwills", "qcom,cdp";
+ qcom,board-id = <1 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi
new file mode 100644
index 0000000..0f9c8bc
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi
@@ -0,0 +1,23 @@
+/* Copyright (c) 2018, 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 "sdxpoorwills-cdp.dtsi"
+
+&soc {
+ vreg_sd_mmc: vreg_sd_mmc {
+ gpio = <&tlmm 76 GPIO_ACTIVE_HIGH>;
+ };
+};
+
+&sdhc_1 {
+ cd-gpios = <&tlmm 21 0x1>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
index 38137a2..99e3faa 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
@@ -13,10 +13,12 @@
/dts-v1/;
#include "sdxpoorwills-cdp.dtsi"
+#include "sdxpoorwills-display.dtsi"
+#include "qpic-panel-ili-hvga.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDXPOORWILLS CDP";
compatible = "qcom,sdxpoorwills-cdp",
"qcom,sdxpoorwills", "qcom,cdp";
- qcom,board-id = <1 0x0>, <1 0x100>, <1 0x2>, <1 0x102>;
+ qcom,board-id = <1 0x102>;
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi
index b5944d1..19b4164 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi
@@ -141,4 +141,5 @@
&usb {
status = "okay";
extcon = <&smb1381_charger>;
+ vbus_dwc3-supply = <&smb138x_vbus>;
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-coresight.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-coresight.dtsi
index eb5c210..c652a44 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-coresight.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-coresight.dtsi
@@ -504,7 +504,7 @@
};
port@2 {
- reg = <3>;
+ reg = <1>;
funnel_in1_in_modem_etm0: endpoint {
slave-mode;
remote-endpoint =
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-display.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-display.dtsi
new file mode 100644
index 0000000..e63d9d5
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-display.dtsi
@@ -0,0 +1,37 @@
+/* Copyright (c) 2018, 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.
+ */
+
+/ {
+ mdss_qpic: qcom,msm_qpic@7980000 {
+ compatible = "qcom,mdss_qpic";
+ reg = <0x1B00000 0x24000>;
+ reg-names = "qpic_base";
+ interrupts = <0 251 0>;
+
+ qcom,msm-bus,name = "mdss_qpic";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+
+ qcom,msm-bus,vectors-KBps =
+ <91 512 0 0>,
+ /* Voting for max b/w on PNOC bus for now */
+ <91 512 400000 800000>;
+
+ vdd-supply = <&pmxpoorwills_l6>;
+
+ pinctrl-names= "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_cs_active &mdss_te_active
+ &mdss_rs_active &mdss_ad_active &mdss_bl_active>;
+ pinctrl-1 = <&mdss_cs_sleep &mdss_te_sleep
+ &mdss_rs_sleep &mdss_ad_sleep &mdss_bl_sleep>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts
new file mode 100644
index 0000000..2377d79c
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts
@@ -0,0 +1,22 @@
+/* Copyright (c) 2018, 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 "sdxpoorwills-mtp-256.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDXPOORWILLS MTP (256MB)";
+ compatible = "qcom,sdxpoorwills-mtp",
+ "qcom,sdxpoorwills", "qcom,mtp";
+ qcom,board-id = <8 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi
new file mode 100644
index 0000000..7412031
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi
@@ -0,0 +1,23 @@
+/* Copyright (c) 2018, 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 "sdxpoorwills-mtp.dtsi"
+
+&soc {
+ vreg_sd_mmc: vreg_sd_mmc {
+ gpio = <&tlmm 76 GPIO_ACTIVE_HIGH>;
+ };
+};
+
+&sdhc_1 {
+ cd-gpios = <&tlmm 21 0x1>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
index a0bcdc9..ae3de38 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
@@ -18,5 +18,5 @@
model = "Qualcomm Technologies, Inc. SDXPOORWILLS MTP";
compatible = "qcom,sdxpoorwills-mtp",
"qcom,sdxpoorwills", "qcom,mtp";
- qcom,board-id = <8 0x0>, <8 0x100>, <8 0x2>, <8 0x102>;
+ qcom,board-id = <8 0x102>;
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi
index 63cc3a4..6389e95 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi
@@ -141,4 +141,5 @@
&usb {
status = "okay";
extcon = <&smb1381_charger>;
+ vbus_dwc3-supply = <&smb138x_vbus>;
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
index e90d97d..52eaba3 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
@@ -21,6 +21,15 @@
qcom,board-id = <1 0x1>, <1 0x101>;
};
+&vbus_detect {
+ status = "okay";
+};
+
+&usb {
+ status = "okay";
+ extcon = <&vbus_detect>;
+};
+
&pcie_ep {
status = "okay";
};
@@ -28,3 +37,7 @@
&pcie0 {
status = "disabled";
};
+
+&mhi_device {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
index 86d8636..b68e401 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
@@ -21,6 +21,15 @@
qcom,board-id = <8 0x1>, <8 0x101>;
};
+&vbus_detect {
+ status = "okay";
+};
+
+&usb {
+ status = "okay";
+ extcon = <&vbus_detect>;
+};
+
&pcie_ep {
status = "okay";
};
@@ -28,3 +37,7 @@
&pcie0 {
status = "disabled";
};
+
+&mhi_device {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
index 6c172c1..08c6c3b 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
@@ -1348,6 +1348,138 @@
};
};
+ mdss_cs_active: mdss_cs_active {
+ mux {
+ pins = "gpio21";
+ function = "ebi2_lcd";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <10>; /* 10 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_cs_sleep: mdss_cs_sleep {
+ mux {
+ pins = "gpio21";
+ function = "ebi2_lcd";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_te_active: mdss_te_active {
+ mux {
+ pins = "gpio22";
+ function = "ebi2_lcd";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <10>; /* 10 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_te_sleep: mdss_te_sleep {
+ mux {
+ pins = "gpio22";
+ function = "ebi2_lcd";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_rs_active: mdss_rs_active {
+ mux {
+ pins = "gpio23";
+ function = "ebi2_lcd";
+ };
+
+ config {
+ pins = "gpio23";
+ drive-strength = <10>; /* 10 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_rs_sleep: mdss_rs_sleep {
+ mux {
+ pins = "gpio23";
+ function = "ebi2_lcd";
+ };
+
+ config {
+ pins = "gpio23";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_ad_active: mdss_ad_active {
+ mux {
+ pins = "gpio20";
+ function = "ebi2_a";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <10>; /* 10 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_ad_sleep: mdss_ad_sleep {
+ mux {
+ pins = "gpio20";
+ function = "ebi2_a";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ mdss_bl_active: mdss_bl_active {
+ mux {
+ pins = "gpio91";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio91";
+ drive-strength = <10>; /* 10 mA */
+ bias-disable; /* NO pull */
+ output-high;
+ };
+ };
+
+ mdss_bl_sleep: mdss_bl_sleep {
+ mux {
+ pins = "gpio91";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio91";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO pull */
+ output-low;
+ };
+ };
+
pmx_sec_mi2s_aux_din {
sec_din_sleep: sec_din_sleep {
mux {
@@ -1465,6 +1597,64 @@
input-enable;
};
};
+
+ cnss_pins {
+ cnss_wlan_en_active: cnss_wlan_en_active {
+ mux {
+ pins = "gpio52";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio52";
+ drive-strength = <16>;
+ output-high;
+ bias-pull-up;
+ };
+ };
+
+ cnss_wlan_en_sleep: cnss_wlan_en_sleep {
+ mux {
+ pins = "gpio52";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio52";
+ drive-strength = <2>;
+ output-low;
+ bias-pull-down;
+ };
+ };
+
+ cnss_sdio_active: cnss_sdio_active {
+ mux {
+ pins = "gpio31";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio31";
+ drive-strength = <16>;
+ output-high;
+ bias-pull-up;
+ };
+ };
+
+ cnss_sdio_sleep: cnss_sdio_sleep {
+ mux {
+ pins = "gpio31";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio31";
+ drive-strength = <2>;
+ output-low;
+ bias-pull-down;
+ };
+ };
+ };
};
};
@@ -1475,4 +1665,11 @@
bias-high-impedance;
};
};
+
+ vdd_wlan {
+ vdd_wlan_default: vdd_wlan_default {
+ pins = "gpio6";
+ bias-high-impedance;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi
index eab887c..4111071 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi
@@ -92,4 +92,10 @@
};
};
};
+
+ qcom,rpm-stats@c300000 {
+ compatible = "qcom,rpm-stats";
+ reg = <0xC300000 0x1000>, <0xC3F0004 0x4>;
+ reg-names = "phys_addr_base", "offset_addr";
+ };
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi
index 37903b9..7543f7c 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi
@@ -24,7 +24,8 @@
pmxpoorwills_s1_level: regualtor-pmxpoorwills-s1 {
regulator-name = "pmxpoorwills_s1_level";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-min-microvolt =
+ <RPMH_REGULATOR_LEVEL_MIN_SVS>;
regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
};
};
@@ -53,7 +54,8 @@
pmxpoorwills_s5_level: regualtor-pmxpoorwills-s5-level {
regulator-name = "pmxpoorwills_s5_level";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-min-microvolt =
+ <RPMH_REGULATOR_LEVEL_LOW_SVS>;
regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
qcom,min-dropout-voltage-level = <(-1)>;
};
@@ -61,7 +63,8 @@
pmxpoorwills_s5_level_ao: regualtor-pmxpoorwills-s5-level-ao {
regulator-name = "pmxpoorwills_s5_level_ao";
qcom,set = <RPMH_REGULATOR_SET_ACTIVE>;
- regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-min-microvolt =
+ <RPMH_REGULATOR_LEVEL_LOW_SVS>;
regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
qcom,min-dropout-voltage-level = <(-1)>;
};
@@ -401,4 +404,12 @@
gpio = <&tlmm 83 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
+
+ vreg_wlan: vreg_wlan {
+ compatible = "regulator-fixed";
+ regulator-name = "vreg_wlan";
+ startup-delay-us = <4000>;
+ enable-active-high;
+ gpio = <&pmxpoorwills_gpios 6 GPIO_ACTIVE_HIGH>;
+ };
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
index ec65472..3bccd8a 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
@@ -126,6 +126,9 @@
resets = <&clock_gcc GCC_QUSB2PHY_BCR>;
reset-names = "phy_reset";
+
+ /* override parameters */
+ qcom,param-override-seq = <0x43 0x70>; /* override_x1 */
};
dbm_1p5: dbm@a6f8000 {
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index c23d48b..b125e08 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -61,6 +61,12 @@
reusable;
size = <0x400000>;
};
+
+ dump_mem: mem_dump_region {
+ compatible = "shared-dma-pool";
+ reusable;
+ size = <0 0x2400000>;
+ };
};
cpus {
@@ -203,7 +209,7 @@
};
clock_gcc: qcom,gcc@100000 {
- compatible = "qcom,gcc-sdxpoorwills";
+ compatible = "qcom,gcc-sdxpoorwills", "syscon";
reg = <0x100000 0x1f0000>;
reg-names = "cc_base";
vdd_cx-supply = <&pmxpoorwills_s5_level>;
@@ -256,6 +262,14 @@
< 1 >;
};
+ clock_debug: qcom,cc-debug {
+ compatible = "qcom,debugcc-sdxpoorwills";
+ qcom,gcc = <&clock_gcc>;
+ clock-names = "xo_clk_src";
+ clocks = <&clock_rpmh RPMH_CXO_CLK>;
+ #clock-cells = <1>;
+ };
+
serial_uart: serial@831000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0x831000 0x200>;
@@ -419,6 +433,23 @@
status = "disabled";
};
+ mhi_device: mhi_dev@1c04000 {
+ compatible = "qcom,msm-mhi-dev";
+ reg = <0x1c04000 0x1000>,
+ <0x1e22000 0x4>,
+ <0x1e22148 0x4>;
+ reg-names = "mhi_mmio_base", "ipa_uc_mbox_crdb",
+ "ipa_uc_mbox_erdb";
+ qcom,mhi-ep-msi = <0>;
+ qcom,mhi-version = <0x1000000>;
+ qcom,use-ipa-software-channel;
+ interrupts = <0 145 0>;
+ interrupt-names = "mhi-device-inta";
+ qcom,mhi-ifc-id = <0x030417cb>;
+ qcom,mhi-interrupt;
+ status = "disabled";
+ };
+
gdsc_emac: qcom,gdsc@147004 {
compatible = "qcom,gdsc";
regulator-name = "gdsc_emac";
@@ -710,6 +741,56 @@
reg = <0xc37000c 8>;
};
+ mem_dump {
+ compatible = "qcom,mem-dump";
+ memory-region = <&dump_mem>;
+
+ rpmh_dump {
+ qcom,dump-size = <0x2000000>;
+ qcom,dump-id = <0xec>;
+ };
+
+ fcm_dump {
+ qcom,dump-size = <0x8400>;
+ qcom,dump-id = <0xee>;
+ };
+
+ rpm_sw_dump {
+ qcom,dump-size = <0x28000>;
+ qcom,dump-id = <0xea>;
+ };
+
+ pmic_dump {
+ qcom,dump-size = <0x10000>;
+ qcom,dump-id = <0xe4>;
+ };
+
+ tmc_etf_dump {
+ qcom,dump-size = <0x10000>;
+ qcom,dump-id = <0xf0>;
+ };
+
+ tmc_etr_reg_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0x100>;
+ };
+
+ tmc_etf_reg_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0x101>;
+ };
+
+ misc_data_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0xe8>;
+ };
+
+ tpdm_swao_dump {
+ qcom,dump-size = <0x512>;
+ qcom,dump-id = <0xf2>;
+ };
+ };
+
qcom,msm_gsi {
compatible = "qcom,msm_gsi";
};
@@ -777,6 +858,9 @@
qcom,throughput-threshold = <310 600 1000>;
qcom,scaling-exceptions = <>;
+ /* ipa tz unlock registers */
+ qcom,ipa-tz-unlock-reg =
+ <0x4043583c 0x1000>; /* 32-bit reg addr and size*/
/* IPA RAM mmap */
qcom,ipa-ram-mmap = <
@@ -895,11 +979,11 @@
#mbox-cells = <1>;
};
- usb_detect: qcom,gpio-usbdetect {
- compatible = "qcom,gpio-usbdetect";
+ vbus_detect: qcom,pmd-vbus-det {
+ compatible = "qcom,pmd-vbus-det";
interrupt-parent = <&spmi_bus>;
interrupts = <0x0 0x0d 0x0 IRQ_TYPE_NONE>;
- interrupt-names = "vbus_det_irq";
+ interrupt-names = "usb_vbus";
status = "disabled";
};
@@ -912,10 +996,130 @@
qcom,pet-time = <10000>;
};
+ qcom_rng: qrng@793000{
+ compatible = "qcom,msm-rng";
+ reg = <0x793000 0x1000>;
+ qcom,msm-rng-iface-clk;
+ qcom,no-qrng-config;
+ qcom,msm-bus,name = "msm-rng-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <1 618 0 0>, /* No vote */
+ <1 618 0 800>; /* 100 KHz */
+ clocks = <&clock_gcc GCC_PRNG_AHB_CLK>;
+ clock-names = "iface_clk";
+ };
+
+ qcom_cedev: qcedev@1de0000 {
+ compatible = "qcom,qcedev";
+ reg = <0x1de0000 0x20000>,
+ <0x1dc4000 0x24000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 252 0>;
+ qcom,bam-pipe-pair = <3>;
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ qcom,bam-ee = <0>;
+ qcom,ce-hw-shared;
+ qcom,clk-mgmt-sus-res;
+ qcom,msm-bus,name = "qcedev-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <125 512 0 0>,
+ <125 512 393600 393600>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ clocks = <&clock_gcc GCC_CE1_CLK>,
+ <&clock_gcc GCC_CE1_CLK>,
+ <&clock_gcc GCC_CE1_AHB_CLK>,
+ <&clock_gcc GCC_CE1_AXI_CLK>;
+ qcom,ce-opp-freq = <171430000>;
+ qcom,request-bw-before-clk;
+ iommus = <&apps_smmu 0x66 0x1>,
+ <&apps_smmu 0x76 0x1>;
+ };
+
+ qcom_crypto: qcrypto@1de0000 {
+ compatible = "qcom,qcrypto";
+ reg = <0x1de0000 0x20000>,
+ <0x1dc4000 0x24000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 252 0>;
+ qcom,bam-pipe-pair = <2>;
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ qcom,bam-ee = <0>;
+ qcom,ce-hw-shared;
+ qcom,clk-mgmt-sus-res;
+ qcom,msm-bus,name = "qcrypto-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <125 512 0 0>,
+ <125 512 393600 393600>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ clocks = <&clock_gcc GCC_CE1_CLK>,
+ <&clock_gcc GCC_CE1_CLK>,
+ <&clock_gcc GCC_CE1_AHB_CLK>,
+ <&clock_gcc GCC_CE1_AXI_CLK>;
+ qcom,ce-opp-freq = <171430000>;
+ qcom,request-bw-before-clk;
+ qcom,use-sw-aes-cbc-ecb-ctr-algo;
+ qcom,use-sw-aes-xts-algo;
+ qcom,use-sw-aes-ccm-algo;
+ qcom,use-sw-aead-algo;
+ qcom,use-sw-ahash-algo;
+ qcom,use-sw-hmac-algo;
+ iommus = <&apps_smmu 0x64 0x1>,
+ <&apps_smmu 0x74 0x1>;
+ };
+
qcom,msm-rtb {
compatible = "qcom,msm-rtb";
qcom,rtb-size = <0x100000>;
};
+
+ cnss_pcie: qcom,cnss {
+ compatible = "qcom,cnss";
+ wlan-en-gpio = <&tlmm 52 0>;
+ vdd-wlan-supply = <&vreg_wlan>;
+ vdd-wlan-xtal-supply = <&pmxpoorwills_l6>;
+ vdd-wlan-io-supply = <&pmxpoorwills_l6>;
+ qcom,notify-modem-status;
+ pinctrl-names = "wlan_en_active", "wlan_en_sleep";
+ pinctrl-0 = <&cnss_wlan_en_active>;
+ pinctrl-1 = <&cnss_wlan_en_sleep>;
+ qcom,wlan-rc-num = <0>;
+ qcom,wlan-ramdump-dynamic = <0x200000>;
+
+ qcom,msm-bus,name = "msm-cnss";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ <45 512 0 0>, <1 512 0 0>,
+ /* Upto 200 Mbps */
+ <45 512 41421 655360>, <1 512 41421 655360>,
+ /* Upto 400 Mbps */
+ <45 512 98572 655360>, <1 512 98572 1600000>,
+ /* Upto 800 Mbps */
+ <45 512 207108 1146880>, <1 512 207108 3124992>;
+ };
+
+ cnss_sdio: qcom,cnss_sdio {
+ compatible = "qcom,cnss_sdio";
+ subsys-name = "AR6320_SDIO";
+ vdd-wlan-supply = <&vreg_wlan>;
+ vdd-wlan-io-supply = <&pmxpoorwills_l6>;
+ qcom,wlan-ramdump-dynamic = <0x200000>;
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&cnss_sdio_active>;
+ pinctrl-1 = <&cnss_sdio_sleep>;
+ qcom,is-antenna-shared;
+ status = "disabled";
+ };
};
#include "pmxpoorwills.dtsi"
@@ -975,6 +1179,26 @@
io-interface = "rgmii";
};
};
+
+ ess-instance {
+ num_devices = <0x1>;
+ ess-switch@0 {
+ compatible = "qcom,ess-switch-qca83xx";
+ qcom,switch-access-mode = "mdio";
+ qcom,ar8327-initvals = <
+ 0x0000c 0x7600000 /* PAD6_MODE */
+ 0x00008 0x0 /* PAD5_MODE */
+ 0x000e4 0xaa545 /* MAC_POWER_SEL */
+ 0x000e0 0xc74164de /* SGMII_CTRL */
+ 0x0007c 0x4e /* PORT0_STATUS */
+ 0x00094 0x4e /* PORT6_STATUS */
+ >;
+ qcom,link-intr-gpio = <2>;
+ qcom,switch-cpu-bmp = <0x40>; /* cpu port bitmap */
+ qcom,switch-lan-bmp = <0x3e>; /* lan port bitmap */
+ qcom,switch-wan-bmp = <0x0>; /* wan port bitmap */
+ };
+ };
};
#include "pmxpoorwills.dtsi"
diff --git a/arch/arm/boot/dts/s5pv210.dtsi b/arch/arm/boot/dts/s5pv210.dtsi
index a853918..0c10ba5 100644
--- a/arch/arm/boot/dts/s5pv210.dtsi
+++ b/arch/arm/boot/dts/s5pv210.dtsi
@@ -463,6 +463,7 @@
compatible = "samsung,exynos4210-ohci";
reg = <0xec300000 0x100>;
interrupts = <23>;
+ interrupt-parent = <&vic1>;
clocks = <&clocks CLK_USB_HOST>;
clock-names = "usbhost";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts
index 84101e4..0f5f379 100644
--- a/arch/arm/boot/dts/spear1310-evb.dts
+++ b/arch/arm/boot/dts/spear1310-evb.dts
@@ -349,7 +349,7 @@
spi0: spi@e0100000 {
status = "okay";
num-cs = <3>;
- cs-gpios = <&gpio1 7 0>, <&spics 0>, <&spics 1>;
+ cs-gpios = <&gpio1 7 0>, <&spics 0 0>, <&spics 1 0>;
stmpe610@0 {
compatible = "st,stmpe610";
diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi
index df2232d..6361cbf 100644
--- a/arch/arm/boot/dts/spear1340.dtsi
+++ b/arch/arm/boot/dts/spear1340.dtsi
@@ -141,8 +141,8 @@
reg = <0xb4100000 0x1000>;
interrupts = <0 105 0x4>;
status = "disabled";
- dmas = <&dwdma0 0x600 0 0 1>, /* 0xC << 11 */
- <&dwdma0 0x680 0 1 0>; /* 0xD << 7 */
+ dmas = <&dwdma0 12 0 1>,
+ <&dwdma0 13 1 0>;
dma-names = "tx", "rx";
};
diff --git a/arch/arm/boot/dts/spear13xx.dtsi b/arch/arm/boot/dts/spear13xx.dtsi
index 449acf0..9564337 100644
--- a/arch/arm/boot/dts/spear13xx.dtsi
+++ b/arch/arm/boot/dts/spear13xx.dtsi
@@ -100,7 +100,7 @@
reg = <0xb2800000 0x1000>;
interrupts = <0 29 0x4>;
status = "disabled";
- dmas = <&dwdma0 0 0 0 0>;
+ dmas = <&dwdma0 0 0 0>;
dma-names = "data";
};
@@ -288,8 +288,8 @@
#size-cells = <0>;
interrupts = <0 31 0x4>;
status = "disabled";
- dmas = <&dwdma0 0x2000 0 0 0>, /* 0x4 << 11 */
- <&dwdma0 0x0280 0 0 0>; /* 0x5 << 7 */
+ dmas = <&dwdma0 4 0 0>,
+ <&dwdma0 5 0 0>;
dma-names = "tx", "rx";
};
diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi
index 9f60a7b..bd37903 100644
--- a/arch/arm/boot/dts/spear600.dtsi
+++ b/arch/arm/boot/dts/spear600.dtsi
@@ -194,6 +194,7 @@
rtc@fc900000 {
compatible = "st,spear600-rtc";
reg = <0xfc900000 0x1000>;
+ interrupt-parent = <&vic0>;
interrupts = <10>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
index adb1c09..1077cee 100644
--- a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
+++ b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
@@ -749,6 +749,7 @@
reg = <0x10120000 0x1000>;
interrupt-names = "combined";
interrupts = <14>;
+ interrupt-parent = <&vica>;
clocks = <&clcdclk>, <&hclkclcd>;
clock-names = "clcdclk", "apb_pclk";
status = "disabled";
diff --git a/arch/arm/boot/dts/stih407.dtsi b/arch/arm/boot/dts/stih407.dtsi
index 291ffac..fe043d3 100644
--- a/arch/arm/boot/dts/stih407.dtsi
+++ b/arch/arm/boot/dts/stih407.dtsi
@@ -8,6 +8,7 @@
*/
#include "stih407-clock.dtsi"
#include "stih407-family.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
soc {
sti-display-subsystem {
@@ -122,7 +123,7 @@
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>;
- hdmi,hpd-gpio = <&pio5 3>;
+ hdmi,hpd-gpio = <&pio5 3 GPIO_ACTIVE_LOW>;
reset-names = "hdmi";
resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>;
ddc = <&hdmiddc>;
diff --git a/arch/arm/boot/dts/stih410.dtsi b/arch/arm/boot/dts/stih410.dtsi
index 4d329b2..3c118fc 100644
--- a/arch/arm/boot/dts/stih410.dtsi
+++ b/arch/arm/boot/dts/stih410.dtsi
@@ -9,6 +9,7 @@
#include "stih410-clock.dtsi"
#include "stih407-family.dtsi"
#include "stih410-pinctrl.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
aliases {
bdisp0 = &bdisp0;
@@ -213,7 +214,7 @@
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>;
- hdmi,hpd-gpio = <&pio5 3>;
+ hdmi,hpd-gpio = <&pio5 3 GPIO_ACTIVE_LOW>;
reset-names = "hdmi";
resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>;
ddc = <&hdmiddc>;
diff --git a/arch/arm/common/bL_switcher_dummy_if.c b/arch/arm/common/bL_switcher_dummy_if.c
index 6053f64..94133e3 100644
--- a/arch/arm/common/bL_switcher_dummy_if.c
+++ b/arch/arm/common/bL_switcher_dummy_if.c
@@ -57,3 +57,7 @@
&bL_switcher_fops
};
module_misc_device(bL_switcher_device);
+
+MODULE_AUTHOR("Nicolas Pitre <nico@linaro.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("big.LITTLE switcher dummy user interface");
diff --git a/arch/arm/configs/mdm_defconfig b/arch/arm/configs/mdm_defconfig
new file mode 100644
index 0000000..d5185cb
--- /dev/null
+++ b/arch/arm/configs/mdm_defconfig
@@ -0,0 +1,355 @@
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHED=y
+# CONFIG_FAIR_GROUP_SCHED is not set
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MDM9650=y
+# CONFIG_VDSO is not set
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_CMA=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_DEBUG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMEOUT=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_SNMP=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NF_CT_NETLINK_TIMEOUT=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_IP_SET=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NATTYPE_MODULE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_ECN=y
+CONFIG_IP_NF_TARGET_TTL=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_AH=y
+CONFIG_IP6_NF_MATCH_FRAG=y
+CONFIG_IP6_NF_MATCH_OPTS=y
+CONFIG_IP6_NF_MATCH_HL=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_MATCH_MH=y
+CONFIG_IP6_NF_MATCH_RT=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_BRIDGE_EBT_T_FILTER=y
+CONFIG_BRIDGE_EBT_T_NAT=y
+CONFIG_BRIDGE_EBT_ARP=y
+CONFIG_BRIDGE_EBT_IP=y
+CONFIG_BRIDGE_EBT_IP6=y
+CONFIG_BRIDGE_EBT_ARPREPLY=y
+CONFIG_BRIDGE_EBT_DNAT=y
+CONFIG_BRIDGE_EBT_SNAT=y
+CONFIG_L2TP=y
+CONFIG_L2TP_DEBUGFS=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_CAN=y
+CONFIG_CAN_VCAN=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_DEBUGFS=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+CONFIG_CFG80211_WEXT=y
+CONFIG_RFKILL=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=12
+CONFIG_MTD=y
+CONFIG_MTD_TESTS=m
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_UBI=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_QSEECOM=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_NETDEVICES=y
+CONFIG_TUN=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+CONFIG_KS8851=y
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+CONFIG_MICREL_PHY=y
+CONFIG_PPP=y
+CONFIG_PPPOL2TP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_SMSC75XX=y
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CNSS=y
+CONFIG_CNSS_SDIO=y
+CONFIG_CLD_LL_CORE=y
+CONFIG_CNSS_LOGGER=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_SPI=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SLIMBUS=y
+CONFIG_SPMI=y
+CONFIG_PPS_CLIENT_GPIO=y
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_PINCTRL_MDM9650=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_THERMAL=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_CPR=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_FB=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_TLV320AIC3X=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_RTC_CLASS=y
+CONFIG_DMADEVICES=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
+CONFIG_GSI=y
+CONFIG_IPA3=y
+CONFIG_RMNET_IPA3=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_USB_BAM=y
+CONFIG_COMMON_CLK_MSM=y
+CONFIG_MAILBOX=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_TRACER_PKT=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_GLINK_PKT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_CNSS_CRYPTO=y
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
+CONFIG_IIO=y
+CONFIG_IIO_BUFFER=y
+CONFIG_IIO_BUFFER_CB=y
+CONFIG_IIO_ST_ACCEL_3AXIS=y
+CONFIG_IIO_ST_GYRO_3AXIS=y
+CONFIG_PWM=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_SCHEDSTATS=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_IPC_LOGGING=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_DEBUG_USER=y
diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig
new file mode 100644
index 0000000..8b6a931
--- /dev/null
+++ b/arch/arm/configs/msm8909w-perf_defconfig
@@ -0,0 +1,532 @@
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_SCHED_WALT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHEDTUNE=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
+CONFIG_SCHED_CORE_CTL=y
+CONFIG_NAMESPACES=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_TUNE=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8909=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_SECCOMP=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_DEBUG=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+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
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TEE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_RPFILTER=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_DEBUGFS=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_MULTIQ=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_NET_ACT_SKBEDIT=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_BT=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+CONFIG_RFKILL=y
+CONFIG_NFC_NQ=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_DMA_CMA=y
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_HDCP_QSEECOM=y
+CONFIG_QSEECOM=y
+CONFIG_UID_SYS_STATS=y
+CONFIG_MEMORY_STATE_TIME=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=y
+CONFIG_SCSI_UFS_QCOM_ICE=y
+CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CLD_LL_CORE=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_QPNP_POWER_ON=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_SMD_PKT=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MSM_V2=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PINCTRL_MSM8909=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_FG_GEN3=y
+CONFIG_QPNP_SMB2=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_THERMAL_TSENS=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_MFD_QCOM_RPM=y
+CONFIG_MFD_SPMI_PMIC=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_QCOM_RPM=y
+CONFIG_REGULATOR_QCOM_SPMI=y
+CONFIG_REGULATOR_CPR=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_MSM_GFX_LDO=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SOC=y
+CONFIG_UHID=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_DWC3=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_DUAL_ROLE_USB_INTF=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_QUSB_PHY=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
+CONFIG_USB_CONFIGFS_F_GSI=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_RING_BUFFER=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_REVID=y
+CONFIG_USB_BAM=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_PM=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_CORE_HANG_DETECT=y
+CONFIG_MSM_GLADIATOR_HANG_DETECT=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_QCOM_EARLY_RANDOM=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_GLINK_SPI_XPRT=y
+CONFIG_TRACER_PKT=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_GLINK_PKT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_QTI_RPM_STATS_LOG=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_IIO=y
+CONFIG_QCOM_SPMI_IADC=y
+CONFIG_QCOM_SPMI_VADC=y
+CONFIG_QCOM_RRADC=y
+CONFIG_PWM=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_SENSORS_SSC=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_WARN=2048
+CONFIG_PAGE_OWNER=y
+CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_SLUB_DEBUG_PANIC_ON=y
+CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_FREE=y
+CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_OBJECTS_WORK=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
+CONFIG_SLUB_DEBUG_ON=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_WQ_WATCHDOG=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_PANIC_ON_SCHED_BUG=y
+CONFIG_PANIC_ON_RT_THROTTLING=y
+CONFIG_SCHEDSTATS=y
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_IPC_LOGGING=y
+CONFIG_QCOM_RTB=y
+CONFIG_QCOM_RTB_SEPARATE_CPUS=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_PREEMPT_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_LKDTM=y
+CONFIG_MEMTEST=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
+CONFIG_DEBUG_USER=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_REMOTE_ETM=y
+CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_TPDA=y
+CONFIG_CORESIGHT_TPDM=y
+CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_EVENT=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+CONFIG_SECURITY_PATH=y
+CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_CTR=y
+CONFIG_CRYPTO_XTS=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
+CONFIG_CRYPTO_DEV_QCOM_ICE=y
+CONFIG_ARM_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM_NEON=y
+CONFIG_CRYPTO_SHA2_ARM_CE=y
+CONFIG_CRYPTO_AES_ARM_BS=y
+CONFIG_CRYPTO_AES_ARM_CE=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig
new file mode 100644
index 0000000..8b6a931
--- /dev/null
+++ b/arch/arm/configs/msm8909w_defconfig
@@ -0,0 +1,532 @@
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_SCHED_WALT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHEDTUNE=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
+CONFIG_SCHED_CORE_CTL=y
+CONFIG_NAMESPACES=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_TUNE=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8909=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_SECCOMP=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_DEBUG=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+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
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TEE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_RPFILTER=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_DEBUGFS=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_MULTIQ=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_NET_ACT_SKBEDIT=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_BT=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+CONFIG_RFKILL=y
+CONFIG_NFC_NQ=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_DMA_CMA=y
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_HDCP_QSEECOM=y
+CONFIG_QSEECOM=y
+CONFIG_UID_SYS_STATS=y
+CONFIG_MEMORY_STATE_TIME=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=y
+CONFIG_SCSI_UFS_QCOM_ICE=y
+CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CLD_LL_CORE=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_QPNP_POWER_ON=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_SMD_PKT=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MSM_V2=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PINCTRL_MSM8909=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_FG_GEN3=y
+CONFIG_QPNP_SMB2=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_THERMAL_TSENS=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_MFD_QCOM_RPM=y
+CONFIG_MFD_SPMI_PMIC=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_QCOM_RPM=y
+CONFIG_REGULATOR_QCOM_SPMI=y
+CONFIG_REGULATOR_CPR=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_MSM_GFX_LDO=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SOC=y
+CONFIG_UHID=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_DWC3=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_DUAL_ROLE_USB_INTF=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_QUSB_PHY=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
+CONFIG_USB_CONFIGFS_F_GSI=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_RING_BUFFER=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_REVID=y
+CONFIG_USB_BAM=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_PM=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_CORE_HANG_DETECT=y
+CONFIG_MSM_GLADIATOR_HANG_DETECT=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_QCOM_EARLY_RANDOM=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_GLINK_SPI_XPRT=y
+CONFIG_TRACER_PKT=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_GLINK_PKT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_QTI_RPM_STATS_LOG=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_IIO=y
+CONFIG_QCOM_SPMI_IADC=y
+CONFIG_QCOM_SPMI_VADC=y
+CONFIG_QCOM_RRADC=y
+CONFIG_PWM=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_SENSORS_SSC=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_WARN=2048
+CONFIG_PAGE_OWNER=y
+CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_SLUB_DEBUG_PANIC_ON=y
+CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_FREE=y
+CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_OBJECTS_WORK=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
+CONFIG_SLUB_DEBUG_ON=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_WQ_WATCHDOG=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_PANIC_ON_SCHED_BUG=y
+CONFIG_PANIC_ON_RT_THROTTLING=y
+CONFIG_SCHEDSTATS=y
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_IPC_LOGGING=y
+CONFIG_QCOM_RTB=y
+CONFIG_QCOM_RTB_SEPARATE_CPUS=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_PREEMPT_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_LKDTM=y
+CONFIG_MEMTEST=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
+CONFIG_DEBUG_USER=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_REMOTE_ETM=y
+CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_TPDA=y
+CONFIG_CORESIGHT_TPDM=y
+CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_EVENT=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+CONFIG_SECURITY_PATH=y
+CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_CTR=y
+CONFIG_CRYPTO_XTS=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
+CONFIG_CRYPTO_DEV_QCOM_ICE=y
+CONFIG_ARM_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM_NEON=y
+CONFIG_CRYPTO_SHA2_ARM_CE=y
+CONFIG_CRYPTO_AES_ARM_BS=y
+CONFIG_CRYPTO_AES_ARM_CE=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
index d539904..62c90b3 100644
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -238,6 +238,7 @@
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_HDCP_QSEECOM=y
CONFIG_QSEECOM=y
CONFIG_MEMORY_STATE_TIME=y
CONFIG_SCSI=y
@@ -275,6 +276,7 @@
CONFIG_PPPOPNS=y
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_USBNET=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_CLD_LL_CORE=y
CONFIG_INPUT_EVDEV=y
@@ -283,15 +285,18 @@
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
CONFIG_INPUT_QPNP_POWER_ON=y
CONFIG_INPUT_UINPUT=y
# CONFIG_SERIO_SERPORT is not set
# CONFIG_VT is not set
# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM=y
-CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_DIAG_USES_SMD=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_SMD_PKT=y
CONFIG_MSM_ADSPRPC=y
CONFIG_MSM_RDBG=m
CONFIG_I2C_CHARDEV=y
@@ -303,6 +308,7 @@
CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
CONFIG_PINCTRL_MSM8953=y
CONFIG_PINCTRL_MSM8937=y
+CONFIG_PINCTRL_MSM8917=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
@@ -314,8 +320,10 @@
CONFIG_QPNP_FG=y
CONFIG_SMB135X_CHARGER=y
CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
CONFIG_QPNP_SMBCHARGER=y
CONFIG_QPNP_TYPEC=y
+CONFIG_QPNP_QG=y
CONFIG_MSM_APM=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
@@ -328,6 +336,7 @@
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_CPR=y
CONFIG_REGULATOR_CPR4_APSS=y
CONFIG_REGULATOR_CPRH_KBSS=y
CONFIG_REGULATOR_MEM_ACC=y
@@ -343,7 +352,15 @@
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
+CONFIG_QCOM_KGSL=y
CONFIG_FB=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_LOGO=y
@@ -366,6 +383,7 @@
CONFIG_USB_MON=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
@@ -383,7 +401,6 @@
CONFIG_USB_STORAGE_KARMA=y
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_DWC3=y
-CONFIG_USB_DWC3_GADGET=y
CONFIG_USB_DWC3_MSM=y
CONFIG_USB_SERIAL=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
@@ -395,10 +412,12 @@
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_DEBUG_FS=y
CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CI13XXX_MSM=y
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_SERIAL=y
CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RNDIS=y
CONFIG_USB_CONFIGFS_RMNET_BAM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
@@ -407,9 +426,11 @@
CONFIG_USB_CONFIGFS_F_ACC=y
CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_DIAG=y
CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
@@ -425,12 +446,15 @@
CONFIG_MMC_CQ_HCI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QTI_TRI_LED=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_QPNP_FLASH=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
CONFIG_LEDS_QPNP_WLED=y
CONFIG_LEDS_QPNP_HAPTICS=y
CONFIG_LEDS_QPNP_VIBRATOR_LDO=y
CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_EDAC=y
CONFIG_EDAC_MM_EDAC=y
CONFIG_RTC_CLASS=y
@@ -452,8 +476,12 @@
CONFIG_QPNP_COINCELL=y
CONFIG_QPNP_REVID=y
CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_MAILBOX=y
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_LAZY_MAPPING=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
CONFIG_MSM_SPM=y
CONFIG_MSM_L2_SPM=y
CONFIG_MSM_BOOT_STATS=y
@@ -466,14 +494,10 @@
CONFIG_MSM_SMEM=y
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_DEBUG=y
-CONFIG_MSM_GLINK=y
-CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
-CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
-CONFIG_MSM_GLINK_SPI_XPRT=y
+CONFIG_MSM_TZ_SMMU=y
CONFIG_MSM_SMP2P=y
-CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_QMI_INTERFACE=y
-CONFIG_MSM_GLINK_PKT=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_PIL=y
CONFIG_MSM_PIL_SSR_GENERIC=y
@@ -481,12 +505,24 @@
CONFIG_ICNSS=y
CONFIG_MSM_PERFORMANCE=y
CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_AVTIMER=y
CONFIG_MSM_PM=y
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MEM_SHARE_QMI_SERVICE=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_SPDM_SCM=y
+CONFIG_DEVFREQ_SPDM=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
+CONFIG_PWM_QTI_LPG=y
+CONFIG_QTI_MPM=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_SENSORS_SSC=y
@@ -501,6 +537,7 @@
CONFIG_FUSE_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
CONFIG_ECRYPT_FS=y
CONFIG_ECRYPT_FS_MESSAGING=y
# CONFIG_NETWORK_FILESYSTEMS is not set
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
index 288856d..144235f 100644
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -285,6 +285,7 @@
CONFIG_PPPOPNS=y
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_USBNET=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_CLD_LL_CORE=y
CONFIG_INPUT_EVDEV=y
@@ -293,6 +294,7 @@
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
CONFIG_INPUT_QPNP_POWER_ON=y
CONFIG_INPUT_UINPUT=y
# CONFIG_SERIO_SERPORT is not set
@@ -300,8 +302,12 @@
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_DIAG_USES_SMD=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_SMD_PKT=y
CONFIG_MSM_ADSPRPC=y
CONFIG_MSM_RDBG=m
CONFIG_I2C_CHARDEV=y
@@ -313,6 +319,7 @@
CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
CONFIG_PINCTRL_MSM8953=y
CONFIG_PINCTRL_MSM8937=y
+CONFIG_PINCTRL_MSM8917=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
@@ -324,8 +331,10 @@
CONFIG_QPNP_FG=y
CONFIG_SMB135X_CHARGER=y
CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
CONFIG_QPNP_SMBCHARGER=y
CONFIG_QPNP_TYPEC=y
+CONFIG_QPNP_QG=y
CONFIG_MSM_APM=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
@@ -338,6 +347,7 @@
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_CPR=y
CONFIG_REGULATOR_CPR4_APSS=y
CONFIG_REGULATOR_CPRH_KBSS=y
CONFIG_REGULATOR_MEM_ACC=y
@@ -353,8 +363,16 @@
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
+CONFIG_QCOM_KGSL=y
CONFIG_FB=y
CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_LOGO=y
@@ -377,6 +395,7 @@
CONFIG_USB_MON=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
@@ -394,7 +413,6 @@
CONFIG_USB_STORAGE_KARMA=y
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_DWC3=y
-CONFIG_USB_DWC3_GADGET=y
CONFIG_USB_DWC3_MSM=y
CONFIG_USB_SERIAL=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
@@ -406,10 +424,12 @@
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_DEBUG_FS=y
CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CI13XXX_MSM=y
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_SERIAL=y
CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RNDIS=y
CONFIG_USB_CONFIGFS_RMNET_BAM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
@@ -418,9 +438,11 @@
CONFIG_USB_CONFIGFS_F_ACC=y
CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_DIAG=y
CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
@@ -437,12 +459,15 @@
CONFIG_MMC_CQ_HCI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QTI_TRI_LED=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_QPNP_FLASH=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
CONFIG_LEDS_QPNP_WLED=y
CONFIG_LEDS_QPNP_HAPTICS=y
CONFIG_LEDS_QPNP_VIBRATOR_LDO=y
CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_EDAC=y
CONFIG_EDAC_MM_EDAC=y
CONFIG_RTC_CLASS=y
@@ -465,9 +490,15 @@
CONFIG_QPNP_REVID=y
CONFIG_USB_BAM=y
CONFIG_MSM_EXT_DISPLAY=y
+CONFIG_MSM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_MAILBOX=y
-# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_LAZY_MAPPING=y
+CONFIG_IOMMU_DEBUG=y
+CONFIG_IOMMU_DEBUG_TRACKING=y
+CONFIG_IOMMU_TESTS=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
CONFIG_MSM_SPM=y
CONFIG_MSM_L2_SPM=y
CONFIG_MSM_BOOT_STATS=y
@@ -482,15 +513,11 @@
CONFIG_MSM_SMEM=y
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_DEBUG=y
-CONFIG_MSM_GLINK=y
-CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
-CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
-CONFIG_MSM_GLINK_SPI_XPRT=y
+CONFIG_MSM_TZ_SMMU=y
CONFIG_TRACER_PKT=y
CONFIG_MSM_SMP2P=y
-CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_QMI_INTERFACE=y
-CONFIG_MSM_GLINK_PKT=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_PIL=y
CONFIG_MSM_PIL_SSR_GENERIC=y
@@ -498,12 +525,24 @@
CONFIG_ICNSS=y
CONFIG_MSM_PERFORMANCE=y
CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_AVTIMER=y
CONFIG_MSM_PM=y
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MEM_SHARE_QMI_SERVICE=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_SPDM_SCM=y
+CONFIG_DEVFREQ_SPDM=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
+CONFIG_PWM_QTI_LPG=y
+CONFIG_QTI_MPM=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_SENSORS_SSC=y
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index 02b4c58..b2dc7f7 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -142,6 +142,7 @@
CONFIG_BRIDGE_EBT_DNAT=y
CONFIG_BRIDGE_EBT_SNAT=y
CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_PRIO=y
CONFIG_RMNET_DATA=y
@@ -199,7 +200,12 @@
CONFIG_USB_NET_SMSC75XX=y
CONFIG_USB_NET_SMSC95XX=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CNSS=y
+CONFIG_CNSS_SDIO=y
+CONFIG_CNSS_PCI=y
+CONFIG_CLD_HL_SDIO_CORE=y
CONFIG_CLD_LL_CORE=y
+CONFIG_CNSS_LOGGER=y
# CONFIG_INPUT_MOUSEDEV is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_KEYBOARD is not set
@@ -213,6 +219,7 @@
CONFIG_SERIAL_MSM_HS=y
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MSM_V2=y
@@ -230,6 +237,7 @@
CONFIG_POWER_RESET_QCOM=y
CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_SUPPLY=y
+CONFIG_SMB1351_USB_CHARGER=y
CONFIG_SMB138X_CHARGER=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
@@ -322,12 +330,12 @@
CONFIG_EP_PCIE=y
CONFIG_EP_PCIE_HW=y
CONFIG_QPNP_REVID=y
-CONFIG_GPIO_USB_DETECT=y
CONFIG_USB_BAM=y
CONFIG_MSM_CLK_RPMH=y
CONFIG_MSM_CLK_AOP_QMP=y
CONFIG_MDM_GCC_SDXPOORWILLS=y
CONFIG_MDM_CLOCK_CPU_SDXPOORWILLS=y
+CONFIG_MDM_DEBUGCC_SDXPOORWILLS=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_MSM_QMP=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
@@ -339,6 +347,7 @@
CONFIG_QCOM_SCM=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
CONFIG_QCOM_BUS_SCALING=y
CONFIG_QCOM_BUS_CONFIG_RPMH=y
CONFIG_MSM_SMEM=y
@@ -357,6 +366,8 @@
CONFIG_QCOM_COMMAND_DB=y
CONFIG_MSM_PM=y
CONFIG_QTI_RPM_STATS_LOG=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_EXTCON_QCOM_SPMI_MISC=y
CONFIG_IIO=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
@@ -389,4 +400,7 @@
CONFIG_CORESIGHT_CTI=y
CONFIG_CORESIGHT_EVENT=y
CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 855f606..ac15d6ea 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -144,6 +144,7 @@
CONFIG_BRIDGE_EBT_DNAT=y
CONFIG_BRIDGE_EBT_SNAT=y
CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_PRIO=y
CONFIG_RMNET_DATA=y
@@ -191,7 +192,12 @@
CONFIG_USB_NET_SMSC75XX=y
CONFIG_USB_NET_SMSC95XX=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CNSS=y
+CONFIG_CNSS_SDIO=y
+CONFIG_CNSS_PCI=y
+CONFIG_CLD_HL_SDIO_CORE=y
CONFIG_CLD_LL_CORE=y
+CONFIG_CNSS_LOGGER=y
# CONFIG_INPUT_MOUSEDEV is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_KEYBOARD is not set
@@ -207,6 +213,7 @@
CONFIG_SERIAL_MSM_HS=y
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MSM_V2=y
@@ -223,6 +230,7 @@
CONFIG_POWER_RESET_QCOM=y
CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_SUPPLY=y
+CONFIG_SMB1351_USB_CHARGER=y
CONFIG_SMB138X_CHARGER=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
@@ -246,6 +254,9 @@
CONFIG_REGULATOR_RPMH=y
CONFIG_REGULATOR_STUB=y
CONFIG_FB=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDP_NONE=y
+CONFIG_FB_MSM_QPIC_PANEL_DETECT=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_DYNAMIC_MINORS=y
@@ -302,6 +313,9 @@
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_MSM=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_QPNP=y
CONFIG_DMADEVICES=y
@@ -321,12 +335,12 @@
CONFIG_EP_PCIE=y
CONFIG_EP_PCIE_HW=y
CONFIG_QPNP_REVID=y
-CONFIG_GPIO_USB_DETECT=y
CONFIG_USB_BAM=y
CONFIG_MSM_CLK_RPMH=y
CONFIG_MSM_CLK_AOP_QMP=y
CONFIG_MDM_GCC_SDXPOORWILLS=y
CONFIG_MDM_CLOCK_CPU_SDXPOORWILLS=y
+CONFIG_MDM_DEBUGCC_SDXPOORWILLS=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_MSM_QMP=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
@@ -338,6 +352,7 @@
CONFIG_QCOM_SCM=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
CONFIG_QCOM_BUS_SCALING=y
CONFIG_QCOM_BUS_CONFIG_RPMH=y
CONFIG_MSM_SMEM=y
@@ -356,7 +371,9 @@
CONFIG_QCOM_COMMAND_DB=y
CONFIG_MSM_PM=y
CONFIG_QTI_RPM_STATS_LOG=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_EXTCON_QCOM_SPMI_MISC=y
CONFIG_IIO=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
@@ -407,8 +424,10 @@
CONFIG_CORESIGHT_TGU=y
CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_DUMMY=y
-CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_CMAC=y
CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_XZ_DEC=y
CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig
index 27ed1b1..72aa5ec 100644
--- a/arch/arm/crypto/Kconfig
+++ b/arch/arm/crypto/Kconfig
@@ -120,4 +120,11 @@
that uses the 64x64 to 128 bit polynomial multiplication (vmull.p64)
that is part of the ARMv8 Crypto Extensions
+config CRYPTO_SPECK_NEON
+ tristate "NEON accelerated Speck cipher algorithms"
+ depends on KERNEL_MODE_NEON
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_GF128MUL
+ select CRYPTO_SPECK
+
endif
diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile
index fc51507..1d0448a 100644
--- a/arch/arm/crypto/Makefile
+++ b/arch/arm/crypto/Makefile
@@ -8,6 +8,7 @@
obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o
obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o
obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha512-arm.o
+obj-$(CONFIG_CRYPTO_SPECK_NEON) += speck-neon.o
ce-obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o
ce-obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o
@@ -36,6 +37,7 @@
sha2-arm-ce-y := sha2-ce-core.o sha2-ce-glue.o
aes-arm-ce-y := aes-ce-core.o aes-ce-glue.o
ghash-arm-ce-y := ghash-ce-core.o ghash-ce-glue.o
+speck-neon-y := speck-neon-core.o speck-neon-glue.o
quiet_cmd_perl = PERL $@
cmd_perl = $(PERL) $(<) > $(@)
diff --git a/arch/arm/crypto/speck-neon-core.S b/arch/arm/crypto/speck-neon-core.S
new file mode 100644
index 0000000..3c1e203
--- /dev/null
+++ b/arch/arm/crypto/speck-neon-core.S
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS
+ *
+ * Copyright (c) 2018 Google, Inc
+ *
+ * Author: Eric Biggers <ebiggers@google.com>
+ */
+
+#include <linux/linkage.h>
+
+ .text
+ .fpu neon
+
+ // arguments
+ ROUND_KEYS .req r0 // const {u64,u32} *round_keys
+ NROUNDS .req r1 // int nrounds
+ DST .req r2 // void *dst
+ SRC .req r3 // const void *src
+ NBYTES .req r4 // unsigned int nbytes
+ TWEAK .req r5 // void *tweak
+
+ // registers which hold the data being encrypted/decrypted
+ X0 .req q0
+ X0_L .req d0
+ X0_H .req d1
+ Y0 .req q1
+ Y0_H .req d3
+ X1 .req q2
+ X1_L .req d4
+ X1_H .req d5
+ Y1 .req q3
+ Y1_H .req d7
+ X2 .req q4
+ X2_L .req d8
+ X2_H .req d9
+ Y2 .req q5
+ Y2_H .req d11
+ X3 .req q6
+ X3_L .req d12
+ X3_H .req d13
+ Y3 .req q7
+ Y3_H .req d15
+
+ // the round key, duplicated in all lanes
+ ROUND_KEY .req q8
+ ROUND_KEY_L .req d16
+ ROUND_KEY_H .req d17
+
+ // index vector for vtbl-based 8-bit rotates
+ ROTATE_TABLE .req d18
+
+ // multiplication table for updating XTS tweaks
+ GF128MUL_TABLE .req d19
+ GF64MUL_TABLE .req d19
+
+ // current XTS tweak value(s)
+ TWEAKV .req q10
+ TWEAKV_L .req d20
+ TWEAKV_H .req d21
+
+ TMP0 .req q12
+ TMP0_L .req d24
+ TMP0_H .req d25
+ TMP1 .req q13
+ TMP2 .req q14
+ TMP3 .req q15
+
+ .align 4
+.Lror64_8_table:
+ .byte 1, 2, 3, 4, 5, 6, 7, 0
+.Lror32_8_table:
+ .byte 1, 2, 3, 0, 5, 6, 7, 4
+.Lrol64_8_table:
+ .byte 7, 0, 1, 2, 3, 4, 5, 6
+.Lrol32_8_table:
+ .byte 3, 0, 1, 2, 7, 4, 5, 6
+.Lgf128mul_table:
+ .byte 0, 0x87
+ .fill 14
+.Lgf64mul_table:
+ .byte 0, 0x1b, (0x1b << 1), (0x1b << 1) ^ 0x1b
+ .fill 12
+
+/*
+ * _speck_round_128bytes() - Speck encryption round on 128 bytes at a time
+ *
+ * Do one Speck encryption round on the 128 bytes (8 blocks for Speck128, 16 for
+ * Speck64) stored in X0-X3 and Y0-Y3, using the round key stored in all lanes
+ * of ROUND_KEY. 'n' is the lane size: 64 for Speck128, or 32 for Speck64.
+ *
+ * The 8-bit rotates are implemented using vtbl instead of vshr + vsli because
+ * the vtbl approach is faster on some processors and the same speed on others.
+ */
+.macro _speck_round_128bytes n
+
+ // x = ror(x, 8)
+ vtbl.8 X0_L, {X0_L}, ROTATE_TABLE
+ vtbl.8 X0_H, {X0_H}, ROTATE_TABLE
+ vtbl.8 X1_L, {X1_L}, ROTATE_TABLE
+ vtbl.8 X1_H, {X1_H}, ROTATE_TABLE
+ vtbl.8 X2_L, {X2_L}, ROTATE_TABLE
+ vtbl.8 X2_H, {X2_H}, ROTATE_TABLE
+ vtbl.8 X3_L, {X3_L}, ROTATE_TABLE
+ vtbl.8 X3_H, {X3_H}, ROTATE_TABLE
+
+ // x += y
+ vadd.u\n X0, Y0
+ vadd.u\n X1, Y1
+ vadd.u\n X2, Y2
+ vadd.u\n X3, Y3
+
+ // x ^= k
+ veor X0, ROUND_KEY
+ veor X1, ROUND_KEY
+ veor X2, ROUND_KEY
+ veor X3, ROUND_KEY
+
+ // y = rol(y, 3)
+ vshl.u\n TMP0, Y0, #3
+ vshl.u\n TMP1, Y1, #3
+ vshl.u\n TMP2, Y2, #3
+ vshl.u\n TMP3, Y3, #3
+ vsri.u\n TMP0, Y0, #(\n - 3)
+ vsri.u\n TMP1, Y1, #(\n - 3)
+ vsri.u\n TMP2, Y2, #(\n - 3)
+ vsri.u\n TMP3, Y3, #(\n - 3)
+
+ // y ^= x
+ veor Y0, TMP0, X0
+ veor Y1, TMP1, X1
+ veor Y2, TMP2, X2
+ veor Y3, TMP3, X3
+.endm
+
+/*
+ * _speck_unround_128bytes() - Speck decryption round on 128 bytes at a time
+ *
+ * This is the inverse of _speck_round_128bytes().
+ */
+.macro _speck_unround_128bytes n
+
+ // y ^= x
+ veor TMP0, Y0, X0
+ veor TMP1, Y1, X1
+ veor TMP2, Y2, X2
+ veor TMP3, Y3, X3
+
+ // y = ror(y, 3)
+ vshr.u\n Y0, TMP0, #3
+ vshr.u\n Y1, TMP1, #3
+ vshr.u\n Y2, TMP2, #3
+ vshr.u\n Y3, TMP3, #3
+ vsli.u\n Y0, TMP0, #(\n - 3)
+ vsli.u\n Y1, TMP1, #(\n - 3)
+ vsli.u\n Y2, TMP2, #(\n - 3)
+ vsli.u\n Y3, TMP3, #(\n - 3)
+
+ // x ^= k
+ veor X0, ROUND_KEY
+ veor X1, ROUND_KEY
+ veor X2, ROUND_KEY
+ veor X3, ROUND_KEY
+
+ // x -= y
+ vsub.u\n X0, Y0
+ vsub.u\n X1, Y1
+ vsub.u\n X2, Y2
+ vsub.u\n X3, Y3
+
+ // x = rol(x, 8);
+ vtbl.8 X0_L, {X0_L}, ROTATE_TABLE
+ vtbl.8 X0_H, {X0_H}, ROTATE_TABLE
+ vtbl.8 X1_L, {X1_L}, ROTATE_TABLE
+ vtbl.8 X1_H, {X1_H}, ROTATE_TABLE
+ vtbl.8 X2_L, {X2_L}, ROTATE_TABLE
+ vtbl.8 X2_H, {X2_H}, ROTATE_TABLE
+ vtbl.8 X3_L, {X3_L}, ROTATE_TABLE
+ vtbl.8 X3_H, {X3_H}, ROTATE_TABLE
+.endm
+
+.macro _xts128_precrypt_one dst_reg, tweak_buf, tmp
+
+ // Load the next source block
+ vld1.8 {\dst_reg}, [SRC]!
+
+ // Save the current tweak in the tweak buffer
+ vst1.8 {TWEAKV}, [\tweak_buf:128]!
+
+ // XOR the next source block with the current tweak
+ veor \dst_reg, TWEAKV
+
+ /*
+ * Calculate the next tweak by multiplying the current one by x,
+ * modulo p(x) = x^128 + x^7 + x^2 + x + 1.
+ */
+ vshr.u64 \tmp, TWEAKV, #63
+ vshl.u64 TWEAKV, #1
+ veor TWEAKV_H, \tmp\()_L
+ vtbl.8 \tmp\()_H, {GF128MUL_TABLE}, \tmp\()_H
+ veor TWEAKV_L, \tmp\()_H
+.endm
+
+.macro _xts64_precrypt_two dst_reg, tweak_buf, tmp
+
+ // Load the next two source blocks
+ vld1.8 {\dst_reg}, [SRC]!
+
+ // Save the current two tweaks in the tweak buffer
+ vst1.8 {TWEAKV}, [\tweak_buf:128]!
+
+ // XOR the next two source blocks with the current two tweaks
+ veor \dst_reg, TWEAKV
+
+ /*
+ * Calculate the next two tweaks by multiplying the current ones by x^2,
+ * modulo p(x) = x^64 + x^4 + x^3 + x + 1.
+ */
+ vshr.u64 \tmp, TWEAKV, #62
+ vshl.u64 TWEAKV, #2
+ vtbl.8 \tmp\()_L, {GF64MUL_TABLE}, \tmp\()_L
+ vtbl.8 \tmp\()_H, {GF64MUL_TABLE}, \tmp\()_H
+ veor TWEAKV, \tmp
+.endm
+
+/*
+ * _speck_xts_crypt() - Speck-XTS encryption/decryption
+ *
+ * Encrypt or decrypt NBYTES bytes of data from the SRC buffer to the DST buffer
+ * using Speck-XTS, specifically the variant with a block size of '2n' and round
+ * count given by NROUNDS. The expanded round keys are given in ROUND_KEYS, and
+ * the current XTS tweak value is given in TWEAK. It's assumed that NBYTES is a
+ * nonzero multiple of 128.
+ */
+.macro _speck_xts_crypt n, decrypting
+ push {r4-r7}
+ mov r7, sp
+
+ /*
+ * The first four parameters were passed in registers r0-r3. Load the
+ * additional parameters, which were passed on the stack.
+ */
+ ldr NBYTES, [sp, #16]
+ ldr TWEAK, [sp, #20]
+
+ /*
+ * If decrypting, modify the ROUND_KEYS parameter to point to the last
+ * round key rather than the first, since for decryption the round keys
+ * are used in reverse order.
+ */
+.if \decrypting
+.if \n == 64
+ add ROUND_KEYS, ROUND_KEYS, NROUNDS, lsl #3
+ sub ROUND_KEYS, #8
+.else
+ add ROUND_KEYS, ROUND_KEYS, NROUNDS, lsl #2
+ sub ROUND_KEYS, #4
+.endif
+.endif
+
+ // Load the index vector for vtbl-based 8-bit rotates
+.if \decrypting
+ ldr r12, =.Lrol\n\()_8_table
+.else
+ ldr r12, =.Lror\n\()_8_table
+.endif
+ vld1.8 {ROTATE_TABLE}, [r12:64]
+
+ // One-time XTS preparation
+
+ /*
+ * Allocate stack space to store 128 bytes worth of tweaks. For
+ * performance, this space is aligned to a 16-byte boundary so that we
+ * can use the load/store instructions that declare 16-byte alignment.
+ */
+ sub sp, #128
+ bic sp, #0xf
+
+.if \n == 64
+ // Load first tweak
+ vld1.8 {TWEAKV}, [TWEAK]
+
+ // Load GF(2^128) multiplication table
+ ldr r12, =.Lgf128mul_table
+ vld1.8 {GF128MUL_TABLE}, [r12:64]
+.else
+ // Load first tweak
+ vld1.8 {TWEAKV_L}, [TWEAK]
+
+ // Load GF(2^64) multiplication table
+ ldr r12, =.Lgf64mul_table
+ vld1.8 {GF64MUL_TABLE}, [r12:64]
+
+ // Calculate second tweak, packing it together with the first
+ vshr.u64 TMP0_L, TWEAKV_L, #63
+ vtbl.u8 TMP0_L, {GF64MUL_TABLE}, TMP0_L
+ vshl.u64 TWEAKV_H, TWEAKV_L, #1
+ veor TWEAKV_H, TMP0_L
+.endif
+
+.Lnext_128bytes_\@:
+
+ /*
+ * Load the source blocks into {X,Y}[0-3], XOR them with their XTS tweak
+ * values, and save the tweaks on the stack for later. Then
+ * de-interleave the 'x' and 'y' elements of each block, i.e. make it so
+ * that the X[0-3] registers contain only the second halves of blocks,
+ * and the Y[0-3] registers contain only the first halves of blocks.
+ * (Speck uses the order (y, x) rather than the more intuitive (x, y).)
+ */
+ mov r12, sp
+.if \n == 64
+ _xts128_precrypt_one X0, r12, TMP0
+ _xts128_precrypt_one Y0, r12, TMP0
+ _xts128_precrypt_one X1, r12, TMP0
+ _xts128_precrypt_one Y1, r12, TMP0
+ _xts128_precrypt_one X2, r12, TMP0
+ _xts128_precrypt_one Y2, r12, TMP0
+ _xts128_precrypt_one X3, r12, TMP0
+ _xts128_precrypt_one Y3, r12, TMP0
+ vswp X0_L, Y0_H
+ vswp X1_L, Y1_H
+ vswp X2_L, Y2_H
+ vswp X3_L, Y3_H
+.else
+ _xts64_precrypt_two X0, r12, TMP0
+ _xts64_precrypt_two Y0, r12, TMP0
+ _xts64_precrypt_two X1, r12, TMP0
+ _xts64_precrypt_two Y1, r12, TMP0
+ _xts64_precrypt_two X2, r12, TMP0
+ _xts64_precrypt_two Y2, r12, TMP0
+ _xts64_precrypt_two X3, r12, TMP0
+ _xts64_precrypt_two Y3, r12, TMP0
+ vuzp.32 Y0, X0
+ vuzp.32 Y1, X1
+ vuzp.32 Y2, X2
+ vuzp.32 Y3, X3
+.endif
+
+ // Do the cipher rounds
+
+ mov r12, ROUND_KEYS
+ mov r6, NROUNDS
+
+.Lnext_round_\@:
+.if \decrypting
+.if \n == 64
+ vld1.64 ROUND_KEY_L, [r12]
+ sub r12, #8
+ vmov ROUND_KEY_H, ROUND_KEY_L
+.else
+ vld1.32 {ROUND_KEY_L[],ROUND_KEY_H[]}, [r12]
+ sub r12, #4
+.endif
+ _speck_unround_128bytes \n
+.else
+.if \n == 64
+ vld1.64 ROUND_KEY_L, [r12]!
+ vmov ROUND_KEY_H, ROUND_KEY_L
+.else
+ vld1.32 {ROUND_KEY_L[],ROUND_KEY_H[]}, [r12]!
+.endif
+ _speck_round_128bytes \n
+.endif
+ subs r6, r6, #1
+ bne .Lnext_round_\@
+
+ // Re-interleave the 'x' and 'y' elements of each block
+.if \n == 64
+ vswp X0_L, Y0_H
+ vswp X1_L, Y1_H
+ vswp X2_L, Y2_H
+ vswp X3_L, Y3_H
+.else
+ vzip.32 Y0, X0
+ vzip.32 Y1, X1
+ vzip.32 Y2, X2
+ vzip.32 Y3, X3
+.endif
+
+ // XOR the encrypted/decrypted blocks with the tweaks we saved earlier
+ mov r12, sp
+ vld1.8 {TMP0, TMP1}, [r12:128]!
+ vld1.8 {TMP2, TMP3}, [r12:128]!
+ veor X0, TMP0
+ veor Y0, TMP1
+ veor X1, TMP2
+ veor Y1, TMP3
+ vld1.8 {TMP0, TMP1}, [r12:128]!
+ vld1.8 {TMP2, TMP3}, [r12:128]!
+ veor X2, TMP0
+ veor Y2, TMP1
+ veor X3, TMP2
+ veor Y3, TMP3
+
+ // Store the ciphertext in the destination buffer
+ vst1.8 {X0, Y0}, [DST]!
+ vst1.8 {X1, Y1}, [DST]!
+ vst1.8 {X2, Y2}, [DST]!
+ vst1.8 {X3, Y3}, [DST]!
+
+ // Continue if there are more 128-byte chunks remaining, else return
+ subs NBYTES, #128
+ bne .Lnext_128bytes_\@
+
+ // Store the next tweak
+.if \n == 64
+ vst1.8 {TWEAKV}, [TWEAK]
+.else
+ vst1.8 {TWEAKV_L}, [TWEAK]
+.endif
+
+ mov sp, r7
+ pop {r4-r7}
+ bx lr
+.endm
+
+ENTRY(speck128_xts_encrypt_neon)
+ _speck_xts_crypt n=64, decrypting=0
+ENDPROC(speck128_xts_encrypt_neon)
+
+ENTRY(speck128_xts_decrypt_neon)
+ _speck_xts_crypt n=64, decrypting=1
+ENDPROC(speck128_xts_decrypt_neon)
+
+ENTRY(speck64_xts_encrypt_neon)
+ _speck_xts_crypt n=32, decrypting=0
+ENDPROC(speck64_xts_encrypt_neon)
+
+ENTRY(speck64_xts_decrypt_neon)
+ _speck_xts_crypt n=32, decrypting=1
+ENDPROC(speck64_xts_decrypt_neon)
diff --git a/arch/arm/crypto/speck-neon-glue.c b/arch/arm/crypto/speck-neon-glue.c
new file mode 100644
index 0000000..ea36c3a
--- /dev/null
+++ b/arch/arm/crypto/speck-neon-glue.c
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS
+ *
+ * Copyright (c) 2018 Google, Inc
+ *
+ * Note: the NIST recommendation for XTS only specifies a 128-bit block size,
+ * but a 64-bit version (needed for Speck64) is fairly straightforward; the math
+ * is just done in GF(2^64) instead of GF(2^128), with the reducing polynomial
+ * x^64 + x^4 + x^3 + x + 1 from the original XEX paper (Rogaway, 2004:
+ * "Efficient Instantiations of Tweakable Blockciphers and Refinements to Modes
+ * OCB and PMAC"), represented as 0x1B.
+ */
+
+#include <asm/hwcap.h>
+#include <asm/neon.h>
+#include <asm/simd.h>
+#include <crypto/algapi.h>
+#include <crypto/gf128mul.h>
+#include <crypto/speck.h>
+#include <crypto/xts.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+/* The assembly functions only handle multiples of 128 bytes */
+#define SPECK_NEON_CHUNK_SIZE 128
+
+/* Speck128 */
+
+struct speck128_xts_tfm_ctx {
+ struct speck128_tfm_ctx main_key;
+ struct speck128_tfm_ctx tweak_key;
+};
+
+asmlinkage void speck128_xts_encrypt_neon(const u64 *round_keys, int nrounds,
+ void *dst, const void *src,
+ unsigned int nbytes, void *tweak);
+
+asmlinkage void speck128_xts_decrypt_neon(const u64 *round_keys, int nrounds,
+ void *dst, const void *src,
+ unsigned int nbytes, void *tweak);
+
+typedef void (*speck128_crypt_one_t)(const struct speck128_tfm_ctx *,
+ u8 *, const u8 *);
+typedef void (*speck128_xts_crypt_many_t)(const u64 *, int, void *,
+ const void *, unsigned int, void *);
+
+static __always_inline int
+__speck128_xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes,
+ speck128_crypt_one_t crypt_one,
+ speck128_xts_crypt_many_t crypt_many)
+{
+ struct crypto_blkcipher *tfm = desc->tfm;
+ const struct speck128_xts_tfm_ctx *ctx = crypto_blkcipher_ctx(tfm);
+ struct blkcipher_walk walk;
+ le128 tweak;
+ int err;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ err = blkcipher_walk_virt_block(desc, &walk, SPECK_NEON_CHUNK_SIZE);
+
+ crypto_speck128_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv);
+
+ while (walk.nbytes > 0) {
+ unsigned int nbytes = walk.nbytes;
+ u8 *dst = walk.dst.virt.addr;
+ const u8 *src = walk.src.virt.addr;
+
+ if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) {
+ unsigned int count;
+
+ count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE);
+ kernel_neon_begin();
+ (*crypt_many)(ctx->main_key.round_keys,
+ ctx->main_key.nrounds,
+ dst, src, count, &tweak);
+ kernel_neon_end();
+ dst += count;
+ src += count;
+ nbytes -= count;
+ }
+
+ /* Handle any remainder with generic code */
+ while (nbytes >= sizeof(tweak)) {
+ le128_xor((le128 *)dst, (const le128 *)src, &tweak);
+ (*crypt_one)(&ctx->main_key, dst, dst);
+ le128_xor((le128 *)dst, (const le128 *)dst, &tweak);
+ gf128mul_x_ble((be128 *)&tweak, (const be128 *)&tweak);
+
+ dst += sizeof(tweak);
+ src += sizeof(tweak);
+ nbytes -= sizeof(tweak);
+ }
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+ }
+
+ return err;
+}
+
+static int speck128_xts_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return __speck128_xts_crypt(desc, dst, src, nbytes,
+ crypto_speck128_encrypt,
+ speck128_xts_encrypt_neon);
+}
+
+static int speck128_xts_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return __speck128_xts_crypt(desc, dst, src, nbytes,
+ crypto_speck128_decrypt,
+ speck128_xts_decrypt_neon);
+}
+
+static int speck128_xts_setkey(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct speck128_xts_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
+ int err;
+
+ if (keylen % 2)
+ return -EINVAL;
+
+ keylen /= 2;
+
+ err = crypto_speck128_setkey(&ctx->main_key, key, keylen);
+ if (err)
+ return err;
+
+ return crypto_speck128_setkey(&ctx->tweak_key, key + keylen, keylen);
+}
+
+/* Speck64 */
+
+struct speck64_xts_tfm_ctx {
+ struct speck64_tfm_ctx main_key;
+ struct speck64_tfm_ctx tweak_key;
+};
+
+asmlinkage void speck64_xts_encrypt_neon(const u32 *round_keys, int nrounds,
+ void *dst, const void *src,
+ unsigned int nbytes, void *tweak);
+
+asmlinkage void speck64_xts_decrypt_neon(const u32 *round_keys, int nrounds,
+ void *dst, const void *src,
+ unsigned int nbytes, void *tweak);
+
+typedef void (*speck64_crypt_one_t)(const struct speck64_tfm_ctx *,
+ u8 *, const u8 *);
+typedef void (*speck64_xts_crypt_many_t)(const u32 *, int, void *,
+ const void *, unsigned int, void *);
+
+static __always_inline int
+__speck64_xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes,
+ speck64_crypt_one_t crypt_one,
+ speck64_xts_crypt_many_t crypt_many)
+{
+ struct crypto_blkcipher *tfm = desc->tfm;
+ const struct speck64_xts_tfm_ctx *ctx = crypto_blkcipher_ctx(tfm);
+ struct blkcipher_walk walk;
+ __le64 tweak;
+ int err;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ err = blkcipher_walk_virt_block(desc, &walk, SPECK_NEON_CHUNK_SIZE);
+
+ crypto_speck64_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv);
+
+ while (walk.nbytes > 0) {
+ unsigned int nbytes = walk.nbytes;
+ u8 *dst = walk.dst.virt.addr;
+ const u8 *src = walk.src.virt.addr;
+
+ if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) {
+ unsigned int count;
+
+ count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE);
+ kernel_neon_begin();
+ (*crypt_many)(ctx->main_key.round_keys,
+ ctx->main_key.nrounds,
+ dst, src, count, &tweak);
+ kernel_neon_end();
+ dst += count;
+ src += count;
+ nbytes -= count;
+ }
+
+ /* Handle any remainder with generic code */
+ while (nbytes >= sizeof(tweak)) {
+ *(__le64 *)dst = *(__le64 *)src ^ tweak;
+ (*crypt_one)(&ctx->main_key, dst, dst);
+ *(__le64 *)dst ^= tweak;
+ tweak = cpu_to_le64((le64_to_cpu(tweak) << 1) ^
+ ((tweak & cpu_to_le64(1ULL << 63)) ?
+ 0x1B : 0));
+ dst += sizeof(tweak);
+ src += sizeof(tweak);
+ nbytes -= sizeof(tweak);
+ }
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+ }
+
+ return err;
+}
+
+static int speck64_xts_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return __speck64_xts_crypt(desc, dst, src, nbytes,
+ crypto_speck64_encrypt,
+ speck64_xts_encrypt_neon);
+}
+
+static int speck64_xts_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return __speck64_xts_crypt(desc, dst, src, nbytes,
+ crypto_speck64_decrypt,
+ speck64_xts_decrypt_neon);
+}
+
+static int speck64_xts_setkey(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct speck64_xts_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
+ int err;
+
+ if (keylen % 2)
+ return -EINVAL;
+
+ keylen /= 2;
+
+ err = crypto_speck64_setkey(&ctx->main_key, key, keylen);
+ if (err)
+ return err;
+
+ return crypto_speck64_setkey(&ctx->tweak_key, key + keylen, keylen);
+}
+
+static struct crypto_alg speck_algs[] = {
+ {
+ .cra_name = "xts(speck128)",
+ .cra_driver_name = "xts-speck128-neon",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = SPECK128_BLOCK_SIZE,
+ .cra_type = &crypto_blkcipher_type,
+ .cra_ctxsize = sizeof(struct speck128_xts_tfm_ctx),
+ .cra_alignmask = 7,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = 2 * SPECK128_128_KEY_SIZE,
+ .max_keysize = 2 * SPECK128_256_KEY_SIZE,
+ .ivsize = SPECK128_BLOCK_SIZE,
+ .setkey = speck128_xts_setkey,
+ .encrypt = speck128_xts_encrypt,
+ .decrypt = speck128_xts_decrypt,
+ }
+ }
+ }, {
+ .cra_name = "xts(speck64)",
+ .cra_driver_name = "xts-speck64-neon",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = SPECK64_BLOCK_SIZE,
+ .cra_type = &crypto_blkcipher_type,
+ .cra_ctxsize = sizeof(struct speck64_xts_tfm_ctx),
+ .cra_alignmask = 7,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = 2 * SPECK64_96_KEY_SIZE,
+ .max_keysize = 2 * SPECK64_128_KEY_SIZE,
+ .ivsize = SPECK64_BLOCK_SIZE,
+ .setkey = speck64_xts_setkey,
+ .encrypt = speck64_xts_encrypt,
+ .decrypt = speck64_xts_decrypt,
+ }
+ }
+ }
+};
+
+static int __init speck_neon_module_init(void)
+{
+ if (!(elf_hwcap & HWCAP_NEON))
+ return -ENODEV;
+ return crypto_register_algs(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+static void __exit speck_neon_module_exit(void)
+{
+ crypto_unregister_algs(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+module_init(speck_neon_module_init);
+module_exit(speck_neon_module_exit);
+
+MODULE_DESCRIPTION("Speck block cipher (NEON-accelerated)");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
+MODULE_ALIAS_CRYPTO("xts(speck128)");
+MODULE_ALIAS_CRYPTO("xts-speck128-neon");
+MODULE_ALIAS_CRYPTO("xts(speck64)");
+MODULE_ALIAS_CRYPTO("xts-speck64-neon");
diff --git a/arch/arm/include/asm/fixmap.h b/arch/arm/include/asm/fixmap.h
index 5c17d2d..92fb518 100644
--- a/arch/arm/include/asm/fixmap.h
+++ b/arch/arm/include/asm/fixmap.h
@@ -10,6 +10,7 @@
enum fixed_addresses {
FIX_EARLYCON_MEM_BASE,
+ FIX_SMP_MEM_BASE,
__end_of_permanent_fixed_addresses,
FIX_KMAP_BEGIN = __end_of_permanent_fixed_addresses,
diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
index 41e9107..62d32bc 100644
--- a/arch/arm/include/asm/topology.h
+++ b/arch/arm/include/asm/topology.h
@@ -28,6 +28,8 @@
#ifdef CONFIG_CPU_FREQ
#define arch_scale_freq_capacity cpufreq_scale_freq_capacity
+#define arch_scale_max_freq_capacity cpufreq_scale_max_freq_capacity
+#define arch_scale_min_freq_capacity cpufreq_scale_min_freq_capacity
#endif
#define arch_scale_cpu_capacity scale_cpu_capacity
extern unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu);
diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
index f555bb3..683d923 100644
--- a/arch/arm/include/asm/traps.h
+++ b/arch/arm/include/asm/traps.h
@@ -18,7 +18,6 @@
void register_undef_hook(struct undef_hook *hook);
void unregister_undef_hook(struct undef_hook *hook);
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
static inline int __in_irqentry_text(unsigned long ptr)
{
extern char __irqentry_text_start[];
@@ -27,12 +26,6 @@
return ptr >= (unsigned long)&__irqentry_text_start &&
ptr < (unsigned long)&__irqentry_text_end;
}
-#else
-static inline int __in_irqentry_text(unsigned long ptr)
-{
- return 0;
-}
-#endif
static inline int in_exception_text(unsigned long ptr)
{
diff --git a/arch/arm/include/uapi/asm/setup.h b/arch/arm/include/uapi/asm/setup.h
index 979ff40..b4d1bea 100644
--- a/arch/arm/include/uapi/asm/setup.h
+++ b/arch/arm/include/uapi/asm/setup.h
@@ -16,7 +16,7 @@
#include <linux/types.h>
-#define COMMAND_LINE_SIZE 1024
+#define COMMAND_LINE_SIZE 2048
/* The list ends with an ATAG_NONE node. */
#define ATAG_NONE 0x00000000
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index dad9fcb..aa8fc3f 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -55,13 +55,7 @@
unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu)
{
-#ifdef CONFIG_CPU_FREQ
- unsigned long max_freq_scale = cpufreq_scale_max_freq_capacity(cpu);
-
- return per_cpu(cpu_scale, cpu) * max_freq_scale >> SCHED_CAPACITY_SHIFT;
-#else
return per_cpu(cpu_scale, cpu);
-#endif
}
static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 19b5f5c..c38bfbe 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -1165,6 +1165,7 @@
cpu_hyp_reset();
return NOTIFY_OK;
+ case CPU_PM_ENTER_FAILED:
case CPU_PM_EXIT:
if (__this_cpu_read(kvm_arm_hardware_enabled))
/* The hardware was enabled before suspend. */
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index 42f5daf..4e57ebc 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -38,7 +38,7 @@
ret = kvm_psci_call(vcpu);
if (ret < 0) {
- kvm_inject_undefined(vcpu);
+ vcpu_set_reg(vcpu, 0, ~0UL);
return 1;
}
@@ -47,7 +47,16 @@
static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
- kvm_inject_undefined(vcpu);
+ /*
+ * "If an SMC instruction executed at Non-secure EL1 is
+ * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a
+ * Trap exception, not a Secure Monitor Call exception [...]"
+ *
+ * We need to advance the PC after the trap, as it would
+ * otherwise return to the same address...
+ */
+ vcpu_set_reg(vcpu, 0, ~0UL);
+ kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
return 1;
}
diff --git a/arch/arm/mach-omap2/omap-secure.c b/arch/arm/mach-omap2/omap-secure.c
index 5ac122e..9ff9205 100644
--- a/arch/arm/mach-omap2/omap-secure.c
+++ b/arch/arm/mach-omap2/omap-secure.c
@@ -73,6 +73,25 @@
return omap_secure_memblock_base;
}
+u32 omap3_save_secure_ram(void __iomem *addr, int size)
+{
+ u32 ret;
+ u32 param[5];
+
+ if (size != OMAP3_SAVE_SECURE_RAM_SZ)
+ return OMAP3_SAVE_SECURE_RAM_SZ;
+
+ param[0] = 4; /* Number of arguments */
+ param[1] = __pa(addr); /* Physical address for saving */
+ param[2] = 0;
+ param[3] = 1;
+ param[4] = 1;
+
+ ret = save_secure_ram_context(__pa(param));
+
+ return ret;
+}
+
/**
* rx51_secure_dispatcher: Routine to dispatch secure PPA API calls
* @idx: The PPA API index
diff --git a/arch/arm/mach-omap2/omap-secure.h b/arch/arm/mach-omap2/omap-secure.h
index bae263f..c509cde 100644
--- a/arch/arm/mach-omap2/omap-secure.h
+++ b/arch/arm/mach-omap2/omap-secure.h
@@ -31,6 +31,8 @@
/* Maximum Secure memory storage size */
#define OMAP_SECURE_RAM_STORAGE (88 * SZ_1K)
+#define OMAP3_SAVE_SECURE_RAM_SZ 0x803F
+
/* Secure low power HAL API index */
#define OMAP4_HAL_SAVESECURERAM_INDEX 0x1a
#define OMAP4_HAL_SAVEHW_INDEX 0x1b
@@ -65,6 +67,8 @@
extern u32 omap_smc3(u32 id, u32 process, u32 flag, u32 pargs);
extern phys_addr_t omap_secure_ram_mempool_base(void);
extern int omap_secure_ram_reserve_memblock(void);
+extern u32 save_secure_ram_context(u32 args_pa);
+extern u32 omap3_save_secure_ram(void __iomem *save_regs, int size);
extern u32 rx51_secure_dispatcher(u32 idx, u32 process, u32 flag, u32 nargs,
u32 arg1, u32 arg2, u32 arg3, u32 arg4);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index b668719..8e30772 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -81,10 +81,6 @@
/* ... and its pointer from SRAM after copy */
extern void (*omap3_do_wfi_sram)(void);
-/* save_secure_ram_context function pointer and size, for copy to SRAM */
-extern int save_secure_ram_context(u32 *addr);
-extern unsigned int save_secure_ram_context_sz;
-
extern void omap3_save_scratchpad_contents(void);
#define PM_RTA_ERRATUM_i608 (1 << 0)
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index d44e0e2..3836958 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -48,6 +48,7 @@
#include "prm3xxx.h"
#include "pm.h"
#include "sdrc.h"
+#include "omap-secure.h"
#include "sram.h"
#include "control.h"
#include "vc.h"
@@ -66,7 +67,6 @@
static LIST_HEAD(pwrst_list);
-static int (*_omap_save_secure_sram)(u32 *addr);
void (*omap3_do_wfi_sram)(void);
static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
@@ -121,8 +121,8 @@
* will hang the system.
*/
pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
- ret = _omap_save_secure_sram((u32 *)(unsigned long)
- __pa(omap3_secure_ram_storage));
+ ret = omap3_save_secure_ram(omap3_secure_ram_storage,
+ OMAP3_SAVE_SECURE_RAM_SZ);
pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state);
/* Following is for error tracking, it should not happen */
if (ret) {
@@ -434,15 +434,10 @@
*
* The minimum set of functions is pushed to SRAM for execution:
* - omap3_do_wfi for erratum i581 WA,
- * - save_secure_ram_context for security extensions.
*/
void omap_push_sram_idle(void)
{
omap3_do_wfi_sram = omap_sram_push(omap3_do_wfi, omap3_do_wfi_sz);
-
- if (omap_type() != OMAP2_DEVICE_TYPE_GP)
- _omap_save_secure_sram = omap_sram_push(save_secure_ram_context,
- save_secure_ram_context_sz);
}
static void __init pm_errata_configure(void)
@@ -554,7 +549,7 @@
clkdm_add_wkdep(neon_clkdm, mpu_clkdm);
if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
omap3_secure_ram_storage =
- kmalloc(0x803F, GFP_KERNEL);
+ kmalloc(OMAP3_SAVE_SECURE_RAM_SZ, GFP_KERNEL);
if (!omap3_secure_ram_storage)
pr_err("Memory allocation failed when allocating for secure sram context\n");
diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c
index dcb5001..973bcd7 100644
--- a/arch/arm/mach-omap2/prm33xx.c
+++ b/arch/arm/mach-omap2/prm33xx.c
@@ -176,17 +176,6 @@
return v;
}
-static int am33xx_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
-{
- u32 v;
-
- v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
- v &= AM33XX_LASTPOWERSTATEENTERED_MASK;
- v >>= AM33XX_LASTPOWERSTATEENTERED_SHIFT;
-
- return v;
-}
-
static int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
{
am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK,
@@ -357,7 +346,6 @@
.pwrdm_set_next_pwrst = am33xx_pwrdm_set_next_pwrst,
.pwrdm_read_next_pwrst = am33xx_pwrdm_read_next_pwrst,
.pwrdm_read_pwrst = am33xx_pwrdm_read_pwrst,
- .pwrdm_read_prev_pwrst = am33xx_pwrdm_read_prev_pwrst,
.pwrdm_set_logic_retst = am33xx_pwrdm_set_logic_retst,
.pwrdm_read_logic_pwrst = am33xx_pwrdm_read_logic_pwrst,
.pwrdm_read_logic_retst = am33xx_pwrdm_read_logic_retst,
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
index 1b9f052..3e0d802 100644
--- a/arch/arm/mach-omap2/sleep34xx.S
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -93,20 +93,13 @@
ENDPROC(enable_omap3630_toggle_l2_on_restore)
/*
- * Function to call rom code to save secure ram context. This gets
- * relocated to SRAM, so it can be all in .data section. Otherwise
- * we need to initialize api_params separately.
+ * Function to call rom code to save secure ram context.
+ *
+ * r0 = physical address of the parameters
*/
- .data
- .align 3
ENTRY(save_secure_ram_context)
stmfd sp!, {r4 - r11, lr} @ save registers on stack
- adr r3, api_params @ r3 points to parameters
- str r0, [r3,#0x4] @ r0 has sdram address
- ldr r12, high_mask
- and r3, r3, r12
- ldr r12, sram_phy_addr_mask
- orr r3, r3, r12
+ mov r3, r0 @ physical address of parameters
mov r0, #25 @ set service ID for PPA
mov r12, r0 @ copy secure service ID in r12
mov r1, #0 @ set task id for ROM code in r1
@@ -120,18 +113,7 @@
nop
nop
ldmfd sp!, {r4 - r11, pc}
- .align
-sram_phy_addr_mask:
- .word SRAM_BASE_P
-high_mask:
- .word 0xffff
-api_params:
- .word 0x4, 0x0, 0x0, 0x1, 0x1
ENDPROC(save_secure_ram_context)
-ENTRY(save_secure_ram_context_sz)
- .word . - save_secure_ram_context
-
- .text
/*
* ======================
diff --git a/arch/arm/mach-pxa/tosa-bt.c b/arch/arm/mach-pxa/tosa-bt.c
index 107f372..8360608 100644
--- a/arch/arm/mach-pxa/tosa-bt.c
+++ b/arch/arm/mach-pxa/tosa-bt.c
@@ -132,3 +132,7 @@
},
};
module_platform_driver(tosa_bt_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dmitry Baryshkov");
+MODULE_DESCRIPTION("Bluetooth built-in chip control");
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index 5122af2..e8d96df 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -77,6 +77,43 @@
select HAVE_CLK_PREPARE
select COMMON_CLK_MSM
+config ARCH_MSM8909
+ bool "Enable support for MSM8909"
+ select HAVE_ARM_ARCH_TIMER
+ select MAY_HAVE_SPARSE_IRQ
+ select PINCTRL_MSM_TLMM
+ select USE_PINCTRL_IRQ
+ select MSM_PM if PM
+ select MSM_RPM_SMD
+ select MSM_RPM_STATS_LOG
+ select MSM_RPM_LOG
+ select MSM_CORTEX_A7
+ select QCOM_SCM if SMP
+ select CPU_FREQ
+ select CPU_FREQ_MSM
+ select PM_DEVFREQ
+ select PM_OPP
+ select MSM_DEVFREQ_DEVBW
+ select DEVFREQ_SIMPLE_DEV
+ select DEVFREQ_GOV_MSM_BW_HWMON
+ select MSM_BIMC_BWMON
+ select CLKDEV_LOOKUP
+ select HAVE_CLK
+ select HAVE_CLK_PREPARE
+ select COMMON_CLK_MSM
+
+config ARCH_MSM8917
+ bool "Enable support for MSM8917"
+ select CPU_V7
+ select HAVE_ARM_ARCH_TIMER
+ select PINCTRL
+ select QCOM_SCM if SMP
+ select PM_DEVFREQ
+ select CLKDEV_LOOKUP
+ select HAVE_CLK
+ select HAVE_CLK_PREPARE
+ select COMMON_CLK_MSM
+
config ARCH_SDM450
bool "Enable support for SDM450"
select CPU_V7
@@ -89,5 +126,31 @@
select HAVE_CLK_PREPARE
select COMMON_CLK_MSM
+config ARCH_MDM9650
+ bool "MDM9650"
+ select ARM_GIC
+ select CPU_V7
+ select REGULATOR
+ select REGULATOR_RPM_SMD
+ select HAVE_ARM_ARCH_TIMER
+ select MSM_RPM_SMD
+ select MSM_SPM
+ select MSM_PM if PM
+ select QMI_ENCDEC
+ select MSM_CORTEX_A7
+ select PINCTRL
+ select PINCTRL_MSM_TLMM
+ select USE_PINCTRL_IRQ
+ select PCI
+ select MSM_IRQ
+ select MSM_JTAG_MM if CORESIGHT_ETM
+ select MSM_CLK_CONTROLLER_V2
+ select PM_DEVFREQ
+ select MSM_DEVFREQ_DEVBW
+ select DEVFREQ_SIMPLE_DEV
+ select MSM_RPM_LOG
+ select MSM_RPM_STATS_LOG
+ select HAVE_CLK_PREPARE
+
endmenu
endif
diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile
index cc06259..cfc4eac 100644
--- a/arch/arm/mach-qcom/Makefile
+++ b/arch/arm/mach-qcom/Makefile
@@ -3,4 +3,7 @@
obj-$(CONFIG_ARCH_SDXPOORWILLS) += board-poorwills.o
obj-$(CONFIG_ARCH_MSM8953) += board-msm8953.o
obj-$(CONFIG_ARCH_MSM8937) += board-msm8937.o
+obj-$(CONFIG_ARCH_MSM8909) += board-msm8909.o
+obj-$(CONFIG_ARCH_MSM8917) += board-msm8917.o
obj-$(CONFIG_ARCH_SDM450) += board-sdm450.o
+obj-$(CONFIG_ARCH_MDM9650) += board-9650.o
diff --git a/arch/arm/mach-qcom/board-9650.c b/arch/arm/mach-qcom/board-9650.c
new file mode 100644
index 0000000..ddc043c
--- /dev/null
+++ b/arch/arm/mach-qcom/board-9650.c
@@ -0,0 +1,32 @@
+/* Copyright (c) 2015, 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include "board-dt.h"
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+
+static const char *mdm9650_dt_match[] __initconst = {
+ "qcom,mdm9650",
+ NULL
+};
+
+static void __init mdm9650_init(void)
+{
+ board_dt_populate(NULL);
+}
+
+DT_MACHINE_START(MDM9650_DT,
+ "Qualcomm Technologies, Inc. MDM 9650 (Flattened Device Tree)")
+ .init_machine = mdm9650_init,
+ .dt_compat = mdm9650_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-qcom/board-msm8909.c b/arch/arm/mach-qcom/board-msm8909.c
new file mode 100644
index 0000000..3c5928d
--- /dev/null
+++ b/arch/arm/mach-qcom/board-msm8909.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+#include "board-dt.h"
+#include "platsmp.h"
+
+static const char *msm8909_dt_match[] __initconst = {
+ "qcom,msm8909",
+ NULL
+};
+
+static void __init msm8909_init(void)
+{
+ board_dt_populate(NULL);
+}
+
+DT_MACHINE_START(MSM8909_DT,
+ "Qualcomm Technologies, Inc. MSM 8909 (Flattened Device Tree)")
+ .init_machine = msm8909_init,
+ .dt_compat = msm8909_dt_match,
+ .smp = &msm8909_smp_ops,
+MACHINE_END
diff --git a/arch/arm/mach-qcom/board-msm8917.c b/arch/arm/mach-qcom/board-msm8917.c
new file mode 100644
index 0000000..63bc43b
--- /dev/null
+++ b/arch/arm/mach-qcom/board-msm8917.c
@@ -0,0 +1,32 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include "board-dt.h"
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+
+static const char *msm8917_dt_match[] __initconst = {
+ "qcom,msm8917",
+ NULL
+};
+
+static void __init msm8917_init(void)
+{
+ board_dt_populate(NULL);
+}
+
+DT_MACHINE_START(MSM8917_DT,
+ "Qualcomm Technologies, Inc. MSM8917-PMI8950 MTP")
+ .init_machine = msm8917_init,
+ .dt_compat = msm8917_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-qcom/board-msm8953.c b/arch/arm/mach-qcom/board-msm8953.c
index cae3bf7..04b0bcc 100644
--- a/arch/arm/mach-qcom/board-msm8953.c
+++ b/arch/arm/mach-qcom/board-msm8953.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -17,6 +17,7 @@
static const char *msm8953_dt_match[] __initconst = {
"qcom,msm8953",
+ "qcom,apq8053",
NULL
};
diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c
index 5494c9e..c422ac3 100644
--- a/arch/arm/mach-qcom/platsmp.c
+++ b/arch/arm/mach-qcom/platsmp.c
@@ -20,7 +20,13 @@
#include <linux/qcom_scm.h>
#include <asm/smp_plat.h>
+#include <asm/fixmap.h>
+#include "platsmp.h"
+#define MSM_APCS_IDR 0x0B011030
+
+/* Base Address of APC IPC block */
+#define APCS_ALIAS0_APC_SECURE 0x0B088000
#define VDD_SC1_ARRAY_CLAMP_GFS_CTL 0x35a0
#define SCSS_CPU1CORE_RESET 0x2d80
@@ -29,9 +35,12 @@
#define APCS_CPU_PWR_CTL 0x04
#define PLL_CLAMP BIT(8)
#define CORE_PWRD_UP BIT(7)
+#define GATE_CLK BIT(6)
#define COREPOR_RST BIT(5)
#define CORE_RST BIT(4)
#define L2DT_SLP BIT(3)
+#define L1_RST_DIS BIT(2)
+#define CORE_MEM_CLAMP BIT(1)
#define CLAMP BIT(0)
#define APC_PWR_GATE_CTL 0x14
@@ -270,6 +279,67 @@
static DEFINE_PER_CPU(int, cold_boot_done);
+/*
+ * writing to physical address:
+ * 0xb088000 + (cpu * 0x10000) + 0x04 and
+ * 0xb088000 + (cpu * 0x10000) + 0x014
+ * For each secondary cpu
+ */
+
+static int arm_release_secondary(unsigned int cpu)
+{
+ phys_addr_t base = APCS_ALIAS0_APC_SECURE;
+ void __iomem *base_ptr;
+ unsigned int reg_val;
+
+ base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
+
+ if (!base_ptr)
+ return -ENODEV;
+
+ reg_val = COREPOR_RST | CORE_RST | CORE_MEM_CLAMP | CLAMP;
+ writel_relaxed(reg_val, base_ptr + APCS_CPU_PWR_CTL);
+ /* memory barrier */
+ mb();
+
+ /* Turn on the BHS, set the BHS_CNT value with 16 */
+ reg_val = (0x10 << BHS_CNT_SHIFT) | BHS_EN;
+ writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
+ /* memory barrier */
+ mb();
+ udelay(2);
+
+ reg_val = COREPOR_RST | CORE_RST | CLAMP;
+ writel_relaxed(reg_val, base_ptr + APCS_CPU_PWR_CTL);
+ /* memory barrier */
+ mb();
+
+ reg_val = COREPOR_RST | CORE_RST | L2DT_SLP | CLAMP;
+ writel_relaxed(reg_val, base_ptr + APCS_CPU_PWR_CTL);
+ /* memory barrier */
+ mb();
+ udelay(2);
+
+ reg_val = COREPOR_RST | CORE_RST | L2DT_SLP;
+ writel_relaxed(reg_val, base_ptr + APCS_CPU_PWR_CTL);
+ /* memory barrier */
+ mb();
+ udelay(2);
+
+ reg_val = L2DT_SLP;
+ writel_relaxed(reg_val, base_ptr + APCS_CPU_PWR_CTL);
+ /* memory barrier */
+ mb();
+
+ reg_val = CORE_PWRD_UP | L2DT_SLP;
+ writel_relaxed(reg_val, base_ptr + APCS_CPU_PWR_CTL);
+ /* memory barrier */
+ mb();
+
+ iounmap(base_ptr);
+ return 0;
+}
+
static int qcom_boot_secondary(unsigned int cpu, int (*func)(unsigned int))
{
int ret = 0;
@@ -302,6 +372,40 @@
return ret;
}
+/*
+ * Initialise the CPU possible map early - this describes the CPUs
+ * which may be present or become present in the system.
+ */
+
+static void __init arm_smp_init_cpus(void)
+{
+ unsigned int i, ncores;
+ void __iomem *base;
+
+ set_fixmap_io(FIX_SMP_MEM_BASE, MSM_APCS_IDR & PAGE_MASK);
+ base = (void __iomem *)__fix_to_virt(FIX_SMP_MEM_BASE);
+
+ if (!base)
+ return;
+
+ base += MSM_APCS_IDR & ~PAGE_MASK;
+
+ ncores = (__raw_readl(base)) & 0xF;
+ if (ncores > nr_cpu_ids) {
+ pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+ ncores, nr_cpu_ids);
+ ncores = nr_cpu_ids;
+ }
+ for (i = 0; i < ncores; i++)
+ set_cpu_possible(i, true);
+}
+
+static int msm8909_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ pr_debug("Starting secondary CPU %d\n", cpu);
+ return qcom_boot_secondary(cpu, arm_release_secondary);
+}
+
static int msm8660_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
return qcom_boot_secondary(cpu, scss_release_secondary);
@@ -361,3 +465,15 @@
#endif
};
CPU_METHOD_OF_DECLARE(qcom_smp_kpssv2, "qcom,kpss-acc-v2", &qcom_smp_kpssv2_ops);
+
+struct smp_operations msm8909_smp_ops __initdata = {
+ .smp_init_cpus = arm_smp_init_cpus,
+ .smp_prepare_cpus = qcom_smp_prepare_cpus,
+ .smp_secondary_init = qcom_secondary_init,
+ .smp_boot_secondary = msm8909_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_die = qcom_cpu_die,
+#endif
+};
+
+CPU_METHOD_OF_DECLARE(qcom_smp_8909, "qcom,apss-8909", &msm8909_smp_ops);
diff --git a/arch/arm/mach-qcom/platsmp.h b/arch/arm/mach-qcom/platsmp.h
new file mode 100644
index 0000000..a497693
--- /dev/null
+++ b/arch/arm/mach-qcom/platsmp.h
@@ -0,0 +1,13 @@
+/* Copyright (c) 2012-2016, 2018, 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.
+ */
+
+extern struct smp_operations msm8909_smp_ops;
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 0a05c0a..b57aafc 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -1024,9 +1024,10 @@
.page = page,
.want_vaddr = ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0),
};
+ void *addr = (args.want_vaddr) ? cpu_addr : page;
- buf = arm_dma_buffer_find(cpu_addr);
- if (WARN(!buf, "Freeing invalid buffer %p\n", cpu_addr))
+ buf = arm_dma_buffer_find(addr);
+ if (WARN(!buf, "Freeing invalid buffer %pK\n", addr))
return;
buf->allocator->free(&args);
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index cf5311f..80d2628 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1163,7 +1163,7 @@
config COMPAT
bool "Kernel support for 32-bit EL0"
depends on ARM64_4K_PAGES || EXPERT
- select COMPAT_BINFMT_ELF
+ select COMPAT_BINFMT_ELF if BINFMT_ELF
select HAVE_UID16
select OLD_SIGSUSPEND3
select COMPAT_OLD_SIGACTION
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 1de858e..cc75e7f 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -2,9 +2,11 @@
config ARCH_SUNXI
bool "Allwinner sunxi 64-bit SoC Family"
+ select ARCH_HAS_RESET_CONTROLLER
select GENERIC_IRQ_CHIP
select PINCTRL
select PINCTRL_SUN50I_A64
+ select RESET_CONTROLLER
help
This enables support for Allwinner sunxi based SoCs like the A64.
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index b5e154e..712352b 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -41,7 +41,14 @@
endif
endif
-KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr)
+ifeq ($(cc-name),clang)
+# This is a workaround for https://bugs.llvm.org/show_bug.cgi?id=30792.
+# TODO: revert when this is fixed in LLVM.
+KBUILD_CFLAGS += -mno-implicit-float
+else
+KBUILD_CFLAGS += -mgeneral-regs-only
+endif
+KBUILD_CFLAGS += $(lseinstr)
KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
KBUILD_CFLAGS += $(call cc-option, -mpc-relative-literal-loads)
KBUILD_CFLAGS += -fno-pic
@@ -81,6 +88,10 @@
TEXT_OFFSET := 0x00080000
endif
+ifeq ($(cc-name),clang)
+KBUILD_CFLAGS += $(call cc-disable-warning, asm-operand-widths)
+endif
+
# KASAN_SHADOW_OFFSET = VA_START + (1 << (VA_BITS - 3)) - (1 << 61)
# in 32-bit arithmetic
KASAN_SHADOW_OFFSET := $(shell printf "0x%08x00000000\n" $$(( \
diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 6c03c17..b307d6b 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -73,6 +73,7 @@
reg = <0x000>;
enable-method = "psci";
cpu-idle-states = <&CPU_SLEEP_0>;
+ #cooling-cells = <2>;
};
cpu1: cpu@1 {
@@ -89,6 +90,7 @@
reg = <0x100>;
enable-method = "psci";
cpu-idle-states = <&CPU_SLEEP_0>;
+ #cooling-cells = <2>;
};
cpu3: cpu@101 {
diff --git a/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi b/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi
new file mode 100644
index 0000000..211e28c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi
@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/thermal/thermal.h>
+
+&soc {
+ qcom,csid@1b08000 {
+ /delete-property/ qcom,mipi-csi-vdd-supply;
+ };
+
+ qcom,csid@1b08400 {
+ /delete-property/ qcom,mipi-csi-vdd-supply;
+ };
+
+ i2c@78b9000 {
+ synaptics@20 {
+ /delete-property/ avdd-supply;
+ /delete-property/ vdd-supply;
+ };
+ };
+
+ qcom,wcnss-wlan@a000000 {
+ /delete-property/ qcom,iris-vddpa-voltage-level;
+ /delete-property/ qcom,iris-vddpa-supply;
+ /delete-property/ qcom,wcnss-adc_tm;
+ /delete-property/ qcom,is-dual-band-disabled;
+ /delete-property/ qcom,iris-vddpa-current;
+ qcom,pronto-vddmx-supply = <&pm660_s2_corner_ao>;
+ qcom,pronto-vddcx-supply = <&pm660_s3_corner>;
+ qcom,pronto-vddpx-supply = <&pm660_l13>;
+ qcom,iris-vddxo-supply = <&pm660_l12>;
+ qcom,iris-vddrfa-supply = <&pm660_l6>;
+ qcom,iris-vdddig-supply = <&pm660_l13>;
+ qcom,wcn-external-gpio-support;
+ };
+
+ qcom,pronto@a21b000 {
+ vdd_pronto_pll-supply = <&pm660_l12>;
+ };
+
+ qcom,mss@4080000 {
+ vdd_cx-supply = <&pm660_s2_corner>;
+ vdd_mx-supply = <&pm660_s3_corner_ao>;
+ vdd_pll-supply = <&pm660_l12>;
+ };
+
+ tpiu@820000 {
+ /delete-property/ vdd-supply;
+ /delete-property/ vdd-io-supply;
+ };
+
+ qpdi@1941000 {
+ /delete-property/ vdd-supply;
+ /delete-property/ vdd-io-supply;
+ };
+
+ qcom,msm-thermal {
+ /delete-property/ vdd-dig-supply;
+ };
+
+ msm8x16_wcd_codec@f000 {
+ /delete-property/ cdc-vdda-cp-supply;
+ /delete-property/ cdc-vdda-h-supply;
+ /delete-property/ cdc-vdd-px-supply;
+ /delete-property/ cdc-vdd-pa-supply;
+ /delete-property/ cdc-vdd-mic-bias-supply;
+ };
+};
+
+&i2c_3 {
+ qcom,actuator@0 {
+ /delete-property/ cam_vaf-supply;
+ };
+
+ qcom,eeprom@6c {
+ /delete-property/ cam_vdig-supply;
+ /delete-property/ cam_vana-supply;
+ /delete-property/ cam_vio-supply;
+ /delete-property/ cam_vaf-supply;
+ };
+
+ qcom,camera@0 {
+ /delete-property/ cam_vdig-supply;
+ /delete-property/ cam_vana-supply;
+ /delete-property/ cam_vio-supply;
+ /delete-property/ cam_vaf-supply;
+ };
+
+ qcom,camera@1 {
+ /delete-property/ cam_vana-supply;
+ /delete-property/ cam_vio-supply;
+ };
+};
+
+
+&sdhc_2 {
+ /delete-property/ vdd-supply;
+ /delete-property/ vdd-io-supply;
+};
+
+&soc {
+ /delete-node/ qcom,rpm-smd;
+ rpm_bus: qcom,rpm-smd {
+ compatible = "qcom,rpm-smd";
+ rpm-channel-name = "rpm_requests";
+ rpm-channel-type = <15>;
+ };
+};
+
+#include "pm660.dtsi"
+#include "pm660-rpm-regulator.dtsi"
+
+/* over-write the PM660 GPIO mappings for 8909w */
+&pm660_gpios {
+ interrupts = <0x0 0xc3 0 IRQ_TYPE_NONE>,
+ <0x0 0xc4 0 IRQ_TYPE_NONE>,
+ <0x0 0xcb 0 IRQ_TYPE_NONE>;
+ interrupt-names = "pm660_gpio4", "pm660_gpio5", "pm660_gpio12";
+ qcom,gpios-disallowed = <1 2 3 6 7 8 9 10 11 13>;
+};
+
+#include "msm8909w-pm660-regulator.dtsi"
+#include "msm8909-pm660-pm.dtsi"
+
+&soc {
+ qcom,gcc@1800000 {
+ vdd_dig-supply = <&pm660_s2_corner>;
+ vdd_sr2_dig-supply = <&pm660_s2_corner_ao>;
+ vdd_sr2_pll-supply = <&pm660_l12_ao>;
+
+ };
+
+ usb@78d9000 {
+ hsusb_vdd_dig-supply = <&pm660_l5>;
+ HSUSB_1p8-supply = <&pm660_l12>;
+ HSUSB_3p3-supply = <&pm660_l16>;
+ };
+
+ qcom,clock-a7@0b011050 {
+ cpu-vdd-supply = <&apc_vreg_corner>;
+ };
+
+ qcom,rpmcc@1800000 {
+ compatible = "qcom,rpmcc-8909-pm660";
+ };
+};
+
+&sdhc_1 {
+ vdd-supply = <&pm660_l19>;
+ vdd-io-supply = <&pm660_l13>;
+};
+
+&pm660_vadc {
+ /delete-node/ chan@1d;
+};
+
+&mdss_dsi{
+ vdda-supply = <&pm660_l5>; /*1.2V*/
+ vddio-supply = <&pm660_l12>; /*1.8V*/
+ qcom,mdss_dsi_ctrl0@1ac8000 {
+ bklt-supply = <&bob_vreg>;
+ vdd-supply = <&pm660_l18>; /*1.8*/
+ vddio-supply = <&pm660_l11>;
+ };
+};
+
+&mdss_dsi0_pll {
+ vddio-supply = <&pm660_l12>; /*1.8V*/
+};
+
+&pm660_0 {
+ pm660_charger: qcom,qpnp-smb2 {
+ compatible = "qcom,qpnp-smb2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #cooling-cells = <2>;
+
+ qcom,pmic-revid = <&pm660_revid>;
+
+ io-channels = <&pm660_rradc 8>,
+ <&pm660_rradc 10>,
+ <&pm660_rradc 3>,
+ <&pm660_rradc 4>;
+ io-channel-names = "charger_temp",
+ "charger_temp_max",
+ "usbin_i",
+ "usbin_v";
+
+ qcom,wipower-max-uw = <5000000>;
+
+ qcom,thermal-mitigation
+ = <3000000 2500000 2000000 1500000
+ 1000000 500000>;
+ qcom,auto-recharge-soc;
+
+ qcom,use-extcon;
+
+ qcom,chgr@1000 {
+ reg = <0x1000 0x100>;
+ interrupts =
+ <0x0 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x10 0x4 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "chg-error",
+ "chg-state-change",
+ "step-chg-state-change",
+ "step-chg-soc-update-fail",
+ "step-chg-soc-update-request";
+ };
+
+ qcom,otg@1100 {
+ reg = <0x1100 0x100>;
+ interrupts = <0x0 0x11 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x11 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x11 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x11 0x3 IRQ_TYPE_EDGE_BOTH>;
+
+ interrupt-names = "otg-fail",
+ "otg-overcurrent",
+ "otg-oc-dis-sw-sts",
+ "testmode-change-detect";
+ };
+
+ qcom,bat-if@1200 {
+ reg = <0x1200 0x100>;
+ interrupts =
+ <0x0 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x12 0x5 IRQ_TYPE_EDGE_BOTH>;
+
+ interrupt-names = "bat-temp",
+ "bat-ocp",
+ "bat-ov",
+ "bat-low",
+ "bat-therm-or-id-missing",
+ "bat-terminal-missing";
+ };
+
+ qcom,usb-chgpth@1300 {
+ reg = <0x1300 0x100>;
+ interrupts =
+ <0x0 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x13 0x5 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "usbin-collapse",
+ "usbin-lt-3p6v",
+ "usbin-uv",
+ "usbin-ov",
+ "usbin-plugin",
+ "usbin-src-change",
+ "usbin-icl-change",
+ "type-c-change";
+ };
+
+ qcom,dc-chgpth@1400 {
+ reg = <0x1400 0x100>;
+ interrupts =
+ <0x0 0x14 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x14 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x14 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x14 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x14 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x14 0x5 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x14 0x6 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "dcin-collapse",
+ "dcin-lt-3p6v",
+ "dcin-uv",
+ "dcin-ov",
+ "dcin-plugin",
+ "div2-en-dg",
+ "dcin-icl-change";
+ };
+
+ qcom,chgr-misc@1600 {
+ reg = <0x1600 0x100>;
+ interrupts =
+ <0x0 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x16 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x16 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x16 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x16 0x5 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+ <0x0 0x16 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+ interrupt-names = "wdog-snarl",
+ "wdog-bark",
+ "aicl-fail",
+ "aicl-done",
+ "high-duty-cycle",
+ "input-current-limiting",
+ "temperature-change",
+ "switcher-power-ok";
+ };
+ smb2_vbus: qcom,smb2-vbus {
+ regulator-name = "smb2-vbus";
+ };
+
+ smb2_vconn: qcom,smb2-vconn {
+ regulator-name = "smb2-vconn";
+ };
+ };
+
+ pm660_rradc: rradc@4500 {
+ compatible = "qcom,rradc";
+ reg = <0x4500 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+ qcom,pmic-revid = <&pm660_revid>;
+ };
+
+ pm660_fg: qpnp,fg {
+ compatible = "qcom,fg-gen3";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,pmic-revid = <&pm660_revid>;
+ io-channels = <&pm660_rradc 0>,
+ <&pm660_rradc 7>;
+ io-channel-names = "rradc_batt_id",
+ "rradc_die_temp";
+ qcom,rradc-base = <0x4500>;
+ qcom,fg-esr-timer-awake = <64 96>;
+ qcom,fg-esr-timer-asleep = <224 256>;
+ qcom,fg-esr-timer-charging = <0 96>;
+ qcom,cycle-counter-en;
+ qcom,hold-soc-while-full;
+ qcom,fg-auto-recharge-soc;
+ qcom,fg-recharge-soc-thr = <98>;
+ status = "okay";
+
+ qcom,fg-batt-soc@4000 {
+ status = "okay";
+ reg = <0x4000 0x100>;
+ interrupts = <0x0 0x40 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x40 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x40 0x2
+ IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x40 0x3
+ IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x40 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x40 0x5
+ IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x40 0x6 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x40 0x7 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "soc-update",
+ "soc-ready",
+ "bsoc-delta",
+ "msoc-delta",
+ "msoc-low",
+ "msoc-empty",
+ "msoc-high",
+ "msoc-full";
+ };
+
+ qcom,fg-batt-info@4100 {
+ status = "okay";
+ reg = <0x4100 0x100>;
+ interrupts = <0x0 0x41 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x41 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x41 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x41 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x41 0x6 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "vbatt-pred-delta",
+ "vbatt-low",
+ "esr-delta",
+ "batt-missing",
+ "batt-temp-delta";
+ };
+
+ qcom,fg-memif@4400 {
+ status = "okay";
+ reg = <0x4400 0x100>;
+ interrupts = <0x0 0x44 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x44 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x44 0x2 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "ima-rdy",
+ "mem-xcp",
+ "dma-grant";
+ };
+ };
+};
+
+&pm660_1 {
+ pm660_haptics: qcom,haptics@c000 {
+ compatible = "qcom,qpnp-haptics";
+ reg = <0xc000 0x100>;
+ interrupts = <0x1 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x1 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "hap-sc-irq", "hap-play-irq";
+ qcom,pmic-revid = <&pm660_revid>;
+ qcom,pmic-misc = <&pm660_misc>;
+ qcom,misc-clk-trim-error-reg = <0xf3>;
+ qcom,actuator-type = <1>;
+ qcom,play-mode = "direct";
+ qcom,vmax-mv = <3200>;
+ qcom,ilim-ma = <800>;
+ qcom,sc-dbc-cycles = <8>;
+ qcom,wave-play-rate-us = <6667>;
+ qcom,en-brake;
+ qcom,lra-high-z = "opt0";
+ qcom,lra-auto-res-mode = "qwd";
+ qcom,lra-res-cal-period = <4>;
+ };
+};
+
+/* pm660 gpio pinctrl configuration */
+&pm660_gpios {
+ /* GPIO 4 (NFC_CLK_REQ) */
+ nfc_clk {
+ nfc_clk_default: nfc_clk_default {
+ pins = "gpio4";
+ function = "normal";
+ input-enable;
+ power-source = <1>;
+ };
+ };
+
+ vreg_bob {
+ vreg_regulator_bob: vreg_regulator-bob {
+ pins = "gpio12";
+ function = "normal";
+ output-enable;
+ qcom,drive-strength = "medium";
+ };
+ };
+
+ bg_daemon_reset {
+ bg_daemon_reset_msm: bg_daemon_reset_msm {
+ pins = "gpio5";
+ function = "func1";
+ output-enable;
+ qcom,drive-strength = "medium";
+ bias-disable;
+ };
+ };
+};
+
+&pm660_misc {
+ qcom,support-twm-config;
+};
+
+/ {
+ /delete-node/ qcom,battery-data;
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "fg-gen3-batterydata-palladium-1500mah.dtsi"
+ };
+};
+
+&pm660_charger {
+ qcom,pd-not-supported;
+};
+
+&usb_otg {
+ extcon = <&pm660_charger>;
+};
+
+&pm660_fg {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&pm660_pdphy {
+ /delete-property/ vdd-pdphy-supply;
+};
+
+&thermal_zones {
+ vbat_adc {
+ cooling-maps {
+ /delete-node/ vbat_map6;
+ /delete-node/ vbat_map7;
+ };
+ };
+ soc {
+ cooling-maps {
+ /delete-node/ soc_map6;
+ /delete-node/ soc_map7;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index caed4e1..8675d09 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -289,6 +289,8 @@
msm8953-cdp-1200p.dtb \
msm8953-iot-mtp.dtb \
apq8053-iot-mtp.dtb \
+ apq8053-lite-dragon-v1.0.dtb \
+ apq8053-lite-dragon-v2.0.dtb \
msm8953-pmi8940-cdp.dtb \
msm8953-pmi8940-mtp.dtb \
msm8953-pmi8937-cdp.dtb \
@@ -297,7 +299,14 @@
msm8953-pmi8937-ext-codec-mtp.dtb \
msm8953-pmi632-cdp-s2.dtb
-dtb-$(CONFIG_ARCH_MSM8937) += msm8937-pmi8950-mtp.dtb
+dtb-$(CONFIG_ARCH_MSM8937) += msm8937-pmi8950-mtp.dtb \
+ msm8937-interposer-sdm439-cdp.dtb \
+ msm8937-interposer-sdm439-mtp.dtb \
+ msm8937-interposer-sdm439-qrd.dtb
+
+dtb-$(CONFIG_ARCH_MSM8917) += msm8917-pmi8950-mtp.dtb
+
+dtb-$(CONFIG_ARCH_MSM8909) += msm8909w-bg-wtp-v2.dtb
dtb-$(CONFIG_ARCH_SDM450) += sdm450-rcm.dtb \
sdm450-cdp.dtb \
@@ -315,6 +324,14 @@
sdm632-mtp-s3.dtb \
sdm632-qrd-sku4.dtb
+dtb-$(CONFIG_ARCH_SDM439) += sdm439-mtp.dtb \
+ sdm439-cdp.dtb \
+ sdm439-qrd.dtb
+
+dtb-$(CONFIG_ARCH_SDM429) += sdm429-mtp.dtb \
+ sdm429-cdp.dtb \
+ sdm429-qrd.dtb
+
endif
always := $(dtb-y)
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v1.0.dts
new file mode 100644
index 0000000..c507f3c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v1.0.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017-2018, 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 "apq8053-lite.dtsi"
+#include "apq8053-lite-dragon.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 Lite DragonBoard";
+ compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+ "qcom,dragonboard";
+ qcom,board-id = <0x0102000a 0>;
+};
+
+&blsp2_uart0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts
new file mode 100644
index 0000000..d7836e5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017-2018, 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 "apq8053-lite.dtsi"
+#include "apq8053-lite-dragon-v2.0.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 Lite DragonBoard V2.0";
+ compatible = "qcom,apq8053-lite-dragonboard",
+ "qcom,apq8053", "qcom,dragonboard";
+ qcom,board-id = <0x0103000a 0>;
+};
+
+&blsp2_uart0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi
new file mode 100644
index 0000000..0c70cf1
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017-2018, 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 "apq8053-lite-dragon.dtsi"
+
+&i2c_3 {
+ status = "okay";
+ himax_ts@48 {
+ compatible = "himax,hxcommon";
+ reg = <0x48>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <65 0x2>;
+ vdd-supply = <&pm8953_l10>;
+ avdd-supply = <&pm8953_l5>;
+ pinctrl-names = "pmx_ts_active","pmx_ts_suspend",
+ "pmx_ts_release";
+ pinctrl-0 = <&ts_int_active &ts_reset_active>;
+ pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+ pinctrl-2 = <&ts_release>;
+ himax,panel-coords = <0 800 0 1280>;
+ himax,display-coords = <0 800 0 1280>;
+ himax,irq-gpio = <&tlmm 65 0x2008>;
+ report_type = <1>;
+ };
+};
+
+&labibb {
+ status = "okay";
+ qpnp,qpnp-labibb-mode = "lcd";
+};
+
+&wled {
+ qcom,cons-sync-write-delay-us = <1000>;
+ qcom,led-strings-list = [00 01 02 03];
+};
+
+&pm8953_l4 {
+ status = "okay";
+ regulator-always-on;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi
new file mode 100644
index 0000000..76b1fa2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2015-2018, 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 "msm8953-pinctrl.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
+
+&soc {
+ vreg_5p0: vreg_5p0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vreg_5p0";
+ status = "ok";
+ enable-active-high;
+ };
+
+ eldo_cam0_vreg: eldo_cam0_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "eldo_cam0_vreg";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ status = "ok";
+ enable-active-high;
+ vin-supply = <&pm8953_l5>;
+ };
+
+ eldo_cam1_vreg: eldo_cam1_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "eldo_cam1_vreg";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ status = "ok";
+ enable-active-high;
+ vin-supply = <&pm8953_l5>;
+ };
+
+ eldo_cam2_vreg: eldo_cam2_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "eldo_cam2_vreg";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ status = "ok";
+ enable-active-high;
+ vin-supply = <&pm8953_l5>;
+ };
+
+ eldo_cam1_vcm_vreg: eldo_cam1_vcm_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "eldo_cam1_vcm_vreg";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ status = "ok";
+ enable-active-high;
+ };
+
+ cnss_sdio: qcom,cnss_sdio {
+ compatible = "qcom,cnss_sdio";
+ subsys-name = "AR6320";
+
+ /**
+ * There is no vdd-wlan on board and this is not for DSRC.
+ * IO and XTAL share the same vreg.
+ */
+ vdd-wlan-io-supply = <&pm8953_l6>;
+ qcom,wlan-ramdump-dynamic = <0x200000>;
+ qcom,msm-bus,name = "msm-cnss";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <79 512 0 0>, /* No vote */
+ <79 512 6250 200000>, /* 50 Mbps */
+ <79 512 25000 200000>, /* 200 Mbps */
+ <79 512 2048000 4096000>; /* MAX */
+ };
+
+ bluetooth: bt_qca9379 {
+ compatible = "qca,qca6174";
+ qca,bt-reset-gpio = <&tlmm 76 0>; /* BT_EN */
+ };
+};
+
+&rpm_bus {
+ rpm-regulator-ldoa4 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "okay";
+
+ pm8953_l4: regulator-l4 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l4";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+};
+
+&spi_3 {
+ status = "disabled";
+};
+
+&i2c_2 {
+ status = "okay";
+};
+
+&i2c_3 {
+ status = "okay";
+ focaltech@38 {
+ compatible = "focaltech,5x06";
+ reg = <0x38>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <65 0x2>;
+ vdd-supply = <&pm8953_l10>;
+ vcc_i2c-supply = <&pm8953_l5>;
+ /* pins used by touchscreen */
+ pinctrl-names = "pmx_ts_active","pmx_ts_suspend",
+ "pmx_ts_release";
+ pinctrl-0 = <&ts_int_active &ts_reset_active>;
+ pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+ pinctrl-2 = <&ts_release>;
+ focaltech,name = "ft5606";
+ focaltech,family-id = <0x08>;
+ focaltech,reset-gpio = <&tlmm 64 0x0>;
+ focaltech,irq-gpio = <&tlmm 65 0x2008>;
+ focaltech,display-coords = <0 0 1919 1199>;
+ focaltech,panel-coords = <0 0 1919 1199>;
+ focaltech,no-force-update;
+ focaltech,i2c-pull-up;
+ focaltech,group-id = <1>;
+ focaltech,hard-reset-delay-ms = <20>;
+ focaltech,soft-reset-delay-ms = <200>;
+ focaltech,num-max-touches = <5>;
+ focaltech,fw-delay-aa-ms = <30>;
+ focaltech,fw-delay-55-ms = <30>;
+ focaltech,fw-upgrade-id1 = <0x79>;
+ focaltech,fw-upgrade-id2 = <0x08>;
+ focaltech,fw-delay-readid-ms = <10>;
+ focaltech,fw-delay-era-flsh-ms = <2000>;
+ focaltech,fw-auto-cal;
+ focaltech,resume-in-workqueue;
+ };
+};
+
+&soc {
+ /delete-node/ hbtp;
+};
+
+&i2c_5 {
+ status = "disabled";
+};
+
+&blsp1_uart0 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_console_active>;
+};
+
+&sdhc_1 {
+ /* device core power supply */
+ vdd-supply = <&pm8953_l8>;
+ qcom,vdd-voltage-level = <2900000 2900000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8953_l5>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+ 384000000>;
+ qcom,nonremovable;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+ status = "ok";
+};
+
+&tlmm{
+ sdc2_wlan_gpio_on: sdc2_wlan_gpio_on {
+ mux {
+ pins = "gpio75";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio75";
+ drive-strength = <10>;
+ bias-pull-up;
+ output-high;
+ };
+ };
+ sdc2_wlan_gpio_off: sdc2_wlan_gpio_off {
+ mux {
+ pins = "gpio75";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio75";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+ };
+};
+
+&sdhc_2 {
+ /* device core power supply */
+ vdd-supply = <&pm8953_l11>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 800000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8953_l12>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 22000>;
+ qcom,core_3_0v_support;
+ qcom,nonremovable;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on
+ &sdc2_wlan_gpio_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
+ &sdc2_wlan_gpio_off>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &tlmm 133 0>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
+
+&spmi_bus {
+ qcom,pm8953@0 {
+ qcom,power-on@800 {
+ qcom,resin-gpiobase = <1019>;
+ qcom,pon_2 {
+ /delete-property/ linux,code;
+ };
+ };
+ };
+ qcom,pmi8950@2 {
+ qcom,leds@a100 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xa100 0x100>;
+ label = "mpp";
+
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "green";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "manual";
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
+ qcom,leds@a300 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xa300 0x100>;
+ label = "mpp";
+
+ qcom,led_mpp_4 {
+ label = "mpp";
+ linux,name = "blue";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "manual";
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+ };
+};
+
+&pm8953_typec {
+ ss-mux-supply = <&pm8953_l13>;
+ qcom,ssmux-gpio = <&tlmm 139 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&typec_ssmux_config>;
+};
+
+/{
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "batterydata-itech-3000mah.dtsi"
+ #include "batterydata-ascent-3450mAh.dtsi"
+ };
+};
+
+&pmi_haptic{
+ status = "disabled";
+ qcom,actuator-type = "lra";
+ qcom,lra-auto-res-mode="qwd";
+ qcom,lra-high-z="opt1";
+ qcom,lra-res-cal-period = <0>;
+ qcom,wave-play-rate-us = <4165>;
+};
+
+&flash_led {
+ status = "disabled";
+};
+
+&pm8953_pwm {
+ status = "ok";
+};
+
+&pm8953_vadc {
+ /delete-node/ chan@13;
+};
+
+&pmi8950_gpios {
+ gpio@c000 { /* GPIO_1 */
+ status = "ok";
+ };
+};
+
+&pmi8950_mpps {
+ mpp@a200 { /* MPP_3 */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,vin-sel = <2>; /* 1.8V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,master-en = <1>; /* Enable GPIO */
+ qcom,invert = <0>;
+ status = "ok";
+ };
+};
+
+&pm8953_gpios {
+ gpio@c000 { /* GPIO_1 */
+ status = "ok";
+ };
+};
+
+&pm8953_mpps {
+ mpp@a000 { /* MPP_1 */ /* VDD_PX */
+ status = "disabled";
+ };
+ mpp@a100 { /* MPP_2 */
+ status = "disabled";
+ };
+ mpp@a200 { /* MPP_3 */
+ status = "disabled";
+ };
+
+ mpp@a300 { /* MPP_4 */ /* WLED_PWM_CTRL */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,vin-sel = <0>; /* VPH_PWR */
+ qcom,src-sel = <4>; /* DTEST1 */
+ qcom,master-en = <1>; /* Enable GPIO */
+ qcom,invert = <0>;
+ status = "ok";
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite.dtsi
new file mode 100644
index 0000000..5be35e7
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite.dtsi
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2017-2018, 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 "skeleton64.dtsi"
+#include "msm8953.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ 8953 Lite";
+ compatible = "qcom,apq8053";
+ qcom,msm-id = <304 0x0>;
+ interrupt-parent = <&intc>;
+
+ soc: soc { };
+};
+
+&clock_gcc_gfx {
+ compatible = "qcom,gcc-gfx-sdm450";
+ qcom,gfxfreq-corner =
+ < 0 0 >,
+ < 133330000 1 >, /* Min SVS */
+ < 216000000 2 >, /* Low SVS */
+ < 320000000 3 >, /* SVS */
+ < 400000000 4 >, /* SVS Plus */
+ < 510000000 5 >, /* NOM */
+ < 560000000 6 >, /* Nom Plus */
+ < 600000000 7 >; /* Turbo */
+};
+
+/* GPU Overrides*/
+&msm_gpu {
+
+ /delete-node/qcom,gpu-pwrlevels;
+
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ /* TURBO */
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <600000000>;
+ qcom,bus-freq = <10>;
+ qcom,bus-min = <10>;
+ qcom,bus-max = <10>;
+ };
+
+ /* NOM+ */
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <560000000>;
+ qcom,bus-freq = <10>;
+ qcom,bus-min = <8>;
+ qcom,bus-max = <10>;
+ };
+
+ /* NOM */
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <510000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <6>;
+ qcom,bus-max = <10>;
+ };
+
+ /* SVS+ */
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <400000000>;
+ qcom,bus-freq = <7>;
+ qcom,bus-min = <5>;
+ qcom,bus-max = <8>;
+ };
+
+ /* SVS */
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
+ qcom,gpu-freq = <320000000>;
+ qcom,bus-freq = <4>;
+ qcom,bus-min = <2>;
+ qcom,bus-max = <6>;
+ };
+
+ /* Low SVS */
+ qcom,gpu-pwrlevel@5 {
+ reg = <5>;
+ qcom,gpu-freq = <216000000>;
+ qcom,bus-freq = <1>;
+ qcom,bus-min = <1>;
+ qcom,bus-max = <4>;
+ };
+
+ /* Min SVS */
+ qcom,gpu-pwrlevel@6 {
+ reg = <6>;
+ qcom,gpu-freq = <133300000>;
+ qcom,bus-freq = <1>;
+ qcom,bus-min = <1>;
+ qcom,bus-max = <4>;
+ };
+ /* XO */
+ qcom,gpu-pwrlevel@7 {
+ reg = <7>;
+ qcom,gpu-freq = <19200000>;
+ qcom,bus-freq = <0>;
+ qcom,bus-min = <0>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi
index 77f2a1d..9b703fe 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi
@@ -20,13 +20,13 @@
qcom,mdss-dsi-stream = <0>;
qcom,mdss-dsi-panel-width = <1080>;
qcom,mdss-dsi-panel-height = <2160>;
- qcom,mdss-dsi-h-front-porch = <24>;
- qcom,mdss-dsi-h-back-porch = <24>;
- qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-front-porch = <42>;
+ qcom,mdss-dsi-h-back-porch = <42>;
+ qcom,mdss-dsi-h-pulse-width = <10>;
qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <40>;
- qcom,mdss-dsi-v-front-porch = <36>;
- qcom,mdss-dsi-v-pulse-width = <2>;
+ qcom,mdss-dsi-v-back-porch = <15>;
+ qcom,mdss-dsi-v-front-porch = <10>;
+ qcom,mdss-dsi-v-pulse-width = <3>;
qcom,mdss-dsi-h-left-border = <0>;
qcom,mdss-dsi-h-right-border = <0>;
qcom,mdss-dsi-v-top-border = <0>;
@@ -40,21 +40,21 @@
b9 ff 83 99
39 01 00 00 00 00 02
d2 88
- 39 01 00 00 00 00 10
- b1 02 04 74 94 01 32 33
- 11 11 e6 5d 56 73 02 02
+ 39 01 00 00 00 00 0c
+ b1 02 04 72 92 01
+ 32 aa 11 11 52 57
39 01 00 00 00 00 10
b2 00 80 80 cc 05 07 5a
- 11 10 10 00 1e 70 03 D4
+ 11 10 10 00 1e 70 03 d4
39 01 00 00 00 00 2d
- b4 00 ff 59 59 0c ac 00
- 00 0c 00 07 0a 00 28 07
- 08 0c 21 03 00 00 00 ae
- 87 59 59 0c ac 00 00 0c
- 00 07 0a 00 28 07 08 0c
- 01 00 00 ae 01
+ b4 00 ff 59 59 01 ab 00
+ 00 09 00 03 05 00 28 03
+ 0b 0d 21 03 02 00 0c a3
+ 80 59 59 02 ab 00 00 09
+ 00 03 05 00 28 03 0b 0d
+ 02 00 0c a3 01
39 01 00 00 05 00 22
- d3 00 00 01 01 00 00 10
+ d3 00 0c 03 03 00 00 10
10 00 00 03 00 03 00 08
78 08 78 00 00 00 00 00
24 02 05 05 03 00 00 00
@@ -80,8 +80,8 @@
39 01 00 00 00 00 02
bd 01
39 01 00 00 00 00 11
- d8 82 ea aa aa 82 ea aa
- aa 82 ea aa aa 82 ea aa
+ d8 00 00 00 00 00 00 00
+ 00 82 ea aa aa 82 ea aa
aa
39 01 00 00 00 00 02
bd 02
@@ -91,26 +91,22 @@
39 01 00 00 00 00 02
bd 00
39 01 00 00 05 00 37
- e0 08 2a 39 35 74 7c 87
- 7f 84 8a 8e 91 93 96 9b
- 9c 9e a5 a6 ae a1 af b2
- 5c 58 63 74 08 2a 39 35
- 74 7c 87 7f 84 8a 8e 91
- 93 96 9b 9c 9e a5 a6 ae
- a1 af b2 5c 58 63 74
+ e0 01 21 31 2d 66 6f 7b
+ 75 7a 81 86 89 8c 90 95
+ 97 9a a1 a2 aa 9e ad b0
+ 5b 57 63 7a 01 21 31 2d
+ 66 6f 7b 75 7a 81 86 89
+ 8c 90 95 97 9a a1 a2 aa
+ 9e ad b0 5b 57 63 7a
39 01 00 00 00 00 03
b6 7e 7e
39 01 00 00 00 00 02
cc 08
- 39 01 00 00 00 00 06
- c7 00 08 00 01 08
- 39 01 00 00 00 00 03
- c0 25 5a
- 05 01 00 00 78 00 02 11 00
- 05 01 00 00 14 00 02 29 00];
+ 05 01 00 00 96 00 02 11 00
+ 05 01 00 00 32 00 02 29 00];
qcom,mdss-dsi-off-command = [
- 05 01 00 00 14 00 02 28 00
- 05 01 00 00 78 00 02 10 00];
+ 05 01 00 00 32 00 02 28 00
+ 05 01 00 00 96 00 02 10 00];
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-h-sync-pulse = <0>;
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi
new file mode 100644
index 0000000..fc09a65
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi
@@ -0,0 +1,137 @@
+/* Copyright (c) 2018, 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.
+ */
+
+&mdss_mdp {
+ dsi_hx8399c_hd_vid: qcom,mdss_dsi_hx8399c_hd_video{
+ qcom,mdss-dsi-panel-name =
+ "hx8399c video mode dsi hd panel";
+ qcom,mdss-dsi-panel-type = "dsi_video_mode";
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-panel-width = <720>;
+ qcom,mdss-dsi-panel-height = <1440>;
+ qcom,mdss-dsi-h-front-porch = <24>;
+ qcom,mdss-dsi-h-back-porch = <24>;
+ qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <40>;
+ qcom,mdss-dsi-v-front-porch = <36>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+ qcom,mdss-dsi-underflow-color = <0xff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-on-command = [
+ 39 01 00 00 00 00 04
+ b9 ff 83 99
+ 39 01 00 00 00 00 02
+ d2 88
+ 39 01 00 00 00 00 10
+ b1 02 04 74 94 01 32 33
+ 11 11 e6 5d 56 73 02 02
+ 39 01 00 00 00 00 10
+ b2 00 80 80 cc 05 07 5a
+ 11 10 10 00 1e 70 03 D4
+ 39 01 00 00 00 00 2d
+ b4 00 ff 59 59 0c ac 00
+ 00 0c 00 07 0a 00 28 07
+ 08 0c 21 03 00 00 00 ae
+ 87 59 59 0c ac 00 00 0c
+ 00 07 0a 00 28 07 08 0c
+ 01 00 00 ae 01
+ 39 01 00 00 05 00 22
+ d3 00 00 01 01 00 00 10
+ 10 00 00 03 00 03 00 08
+ 78 08 78 00 00 00 00 00
+ 24 02 05 05 03 00 00 00
+ 05 40
+ 39 01 00 00 05 00 21
+ d5 20 20 19 19 18 18 02
+ 03 00 01 24 24 18 18 18
+ 18 24 24 00 00 00 00 00
+ 00 00 00 2f 2f 30 30 31
+ 31
+ 39 01 00 00 05 00 21
+ d6 24 24 18 18 19 19 01
+ 00 03 02 24 24 18 18 18
+ 18 20 20 40 40 40 40 40
+ 40 40 40 2f 2f 30 30 31
+ 31
+ 39 01 00 00 00 00 02
+ bd 00
+ 39 01 00 00 00 00 11
+ d8 aa aa aa aa aa aa aa
+ aa aa ba aa aa aa ba aa
+ aa
+ 39 01 00 00 00 00 02
+ bd 01
+ 39 01 00 00 00 00 11
+ d8 82 ea aa aa 82 ea aa
+ aa 82 ea aa aa 82 ea aa
+ aa
+ 39 01 00 00 00 00 02
+ bd 02
+ 39 01 00 00 00 00 09
+ d8 ff ff c0 3f ff ff c0
+ 3f
+ 39 01 00 00 00 00 02
+ bd 00
+ 39 01 00 00 00 00 02
+ dd 03
+ 39 01 00 00 05 00 37
+ e0 08 2a 39 35 74 7c 87
+ 7f 84 8a 8e 91 93 96 9b
+ 9c 9e a5 a6 ae a1 af b2
+ 5c 58 63 74 08 2a 39 35
+ 74 7c 87 7f 84 8a 8e 91
+ 93 96 9b 9c 9e a5 a6 ae
+ a1 af b2 5c 58 63 74
+ 39 01 00 00 00 00 03
+ b6 7e 7e
+ 39 01 00 00 00 00 02
+ cc 08
+ 39 01 00 00 00 00 06
+ c7 00 08 00 01 08
+ 39 01 00 00 00 00 03
+ c0 25 5a
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 14 00 02 29 00];
+ qcom,mdss-dsi-off-command = [
+ 05 01 00 00 14 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+ qcom,mdss-dsi-lane-map = "lane_map_0123";
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-tx-eot-append;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-panel-timings =
+ [7a 1a 12 00 3e 42 16 1e 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x0a>;
+ qcom,mdss-dsi-t-clk-pre = <0x1d>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
+ qcom,mdss-dsi-lp11-init;
+ qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi
index 1b38d06..ca28261 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi
@@ -27,7 +27,6 @@
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-tx-eot-append;
- qcom,cmd-sync-wait-broadcast;
qcom,mdss-dsi-lane-0-state;
qcom,mdss-dsi-lane-1-state;
qcom,mdss-dsi-lane-2-state;
diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-palladium-1500mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-palladium-1500mah.dtsi
new file mode 100644
index 0000000..251440a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-palladium-1500mah.dtsi
@@ -0,0 +1,81 @@
+/* Copyright (c) 2017-2018, 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.
+ */
+
+qcom,palladium_1500mah_averaged_masterslave_nov28th2017 {
+ /* #Palladium_1500mAh_averaged_MasterSlave_Nov28th2017*/
+ qcom,max-voltage-uv = <4200000>;
+ qcom,fg-cc-cv-threshold-mv = <4180>;
+ qcom,fastchg-current-ma = <1500>;
+ qcom,batt-id-kohm = <75>;
+ qcom,battery-beta = <3435>;
+ qcom,battery-type = "palladium_1500mah_averaged_masterslave_nov28th2017";
+ qcom,checksum = <0x1C13>;
+ qcom,gui-version = "PM660GUI - 0.0.0.45";
+ qcom,fg-profile-data = [
+ A6 1F B2 05
+ 1F 0A F7 FC
+ 22 1D 32 F2
+ B9 02 1C 0D
+ 25 11 FB 2B
+ 88 4C 0A 62
+ 65 00 00 00
+ 0E 00 00 00
+ 00 00 3D C4
+ 5D C5 A4 C2
+ 2A 00 08 00
+ 0F C5 76 D4
+ 71 FC 36 F3
+ 7D 06 C4 03
+ EB DD F0 22
+ 1E 06 09 20
+ 27 00 14 00
+ 47 1F 5F FC
+ 9B 03 BE 06
+ EE 1C 17 02
+ F6 0D 27 03
+ 22 11 0B 32
+ 6D 4C 19 62
+ 7D 00 00 00
+ 0E 00 00 00
+ 00 00 6E CC
+ 03 CA FB BC
+ 26 00 00 00
+ E9 DB 76 D4
+ 41 FD 89 EB
+ 3E 06 A9 F3
+ C3 05 F3 13
+ 9C 33 CC FF
+ 07 10 00 00
+ BD 05 33 43
+ 26 00 40 00
+ 35 02 0A FA
+ FF 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ ];
+};
diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-vrcamera-1300mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-vrcamera-1300mah.dtsi
new file mode 100644
index 0000000..0676019
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-vrcamera-1300mah.dtsi
@@ -0,0 +1,90 @@
+/* Copyright (c) 2018, 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.
+ */
+
+qcom,kayo_1300mah {
+ /* #kayo_1300mah_averaged_masterslave_feb26th2018 */
+ qcom,max-voltage-uv = <4200000>;
+ qcom,nom-batt-capacity-mah = <1300>;
+ qcom,batt-id-kohm = <100>;
+ qcom,jeita-fcc-ranges = <0 100 975000
+ 101 450 1300000
+ 451 600 1105000>;
+ qcom,jeita-fv-ranges = <0 100 4000000
+ 101 200 4100000
+ 201 450 4200000
+ 451 500 4100000
+ 501 600 4000000>;
+ qcom,step-chg-ranges = <3600000 4200000 2600000>;
+ qcom,battery-beta = <4250>;
+ qcom,fg-cc-cv-threshold-mv = <4190>;
+ qcom,battery-type = "kayo_1300mah_averaged_masterslave_feb26th2018";
+ qcom,checksum = <0xBFF4>;
+ qcom,gui-version = "PM660GUI - 0.0.0.45";
+ qcom,fg-profile-data = [
+ 02 1F 9A 06
+ 9A 02 A5 F5
+ DF 1C 91 FB
+ 4A 04 97 03
+ 29 19 F0 1B
+ 80 3D 35 4A
+ 81 00 00 00
+ 18 00 00 00
+ 00 00 74 CD
+ 92 BC 65 CA
+ 2E 00 08 00
+ EF 07 A5 E5
+ D7 F4 D8 E2
+ FF F5 C3 F3
+ 20 0C 1E 4B
+ 0A 06 09 20
+ 27 00 14 00
+ 50 1F BB FC
+ 00 03 B9 F4
+ B1 1C D6 02
+ 6A 0C 73 0B
+ BD 18 E4 22
+ 7E 45 08 53
+ 70 00 00 00
+ 11 00 00 00
+ 00 00 B0 CC
+ AA AA 86 CA
+ 2A 00 00 00
+ E4 EA A5 E5
+ 4D F5 2B DB
+ 69 00 AE 02
+ 96 05 6B 1A
+ A5 33 CC FF
+ 07 10 00 00
+ 5C 05 33 43
+ 2A 00 40 00
+ 31 01 0A FA
+ FF 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ ];
+};
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-8937.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-8937.dtsi
new file mode 100644
index 0000000..e862b0f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-8937.dtsi
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+
+&soc {
+ kgsl_smmu: arm,smmu-kgsl@1c40000 {
+ status = "ok";
+ compatible = "qcom,smmu-v2";
+ qcom,tz-device-id = "GPU";
+ reg = <0x1c40000 0x10000>;
+ #iommu-cells = <1>;
+ #global-interrupts = <0>;
+ interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 233 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 234 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,dynamic;
+ qcom,use-3-lvl-tables;
+ qcom,enable-smmu-halt;
+ qcom,skip-init;
+ vdd-supply = <&gdsc_oxili_cx>;
+ qcom,regulator-names = "vdd";
+ clocks = <&clock_gcc clk_gcc_oxili_ahb_clk>,
+ <&clock_gcc clk_gcc_bimc_gfx_clk>;
+ clock-names = "gpu_ahb_clk", "gcc_bimc_gfx_clk";
+ };
+
+ /* A test device to test the SMMU operation */
+ kgsl_iommu_test_device0 {
+ status = "disabled";
+ compatible = "iommu-debug-test";
+ /* The SID should be valid one to get the proper
+ *SMR,S2CR indices.
+ */
+ iommus = <&kgsl_smmu 0x0>;
+ };
+
+ apps_iommu: qcom,iommu@1e00000 {
+ status = "okay";
+ compatible = "qcom,qsmmu-v500";
+ reg = <0x1e00000 0x40000>,
+ <0x1ee2000 0x20>;
+ reg-names = "base", "tcu-base";
+ #iommu-cells = <2>;
+ qcom,tz-device-id = "APPS";
+ qcom,skip-init;
+ qcom,enable-static-cb;
+ qcom,use-3-lvl-tables;
+ qcom,disable-atos;
+ #global-interrupts = <0>;
+ #size-cells = <1>;
+ #address-cells = <1>;
+ ranges;
+ interrupts = <GIC_SPI 253 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clock_gcc clk_gcc_smmu_cfg_clk>,
+ <&clock_gcc clk_gcc_apss_tcu_clk>;
+ clock-names = "iface_clk", "core_clk";
+ };
+};
+
+#include "msm-arm-smmu-impl-defs-8937.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-impl-defs-8937.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-impl-defs-8937.dtsi
new file mode 100644
index 0000000..ce3e1c3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-impl-defs-8937.dtsi
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&kgsl_smmu {
+ attach-impl-defs = <0x6000 0x270>,
+ <0x6060 0x1055>,
+ <0x6800 0x6>,
+ <0x6900 0x3ff>,
+ <0x6924 0x204>,
+ <0x6928 0x10800>,
+ <0x6930 0x400>,
+ <0x6960 0xffffffff>,
+ <0x6b64 0xa0000>,
+ <0x6b68 0xaaab92a>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm-gdsc-8916.dtsi b/arch/arm64/boot/dts/qcom/msm-gdsc-8916.dtsi
index 49e148c..0e58559 100644
--- a/arch/arm64/boot/dts/qcom/msm-gdsc-8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-gdsc-8916.dtsi
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, 2017-2018, 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
diff --git a/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi b/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi
new file mode 100644
index 0000000..f2cea32
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi
@@ -0,0 +1,195 @@
+/* Copyright (c) 2017-2018 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.
+ */
+
+&soc {
+ audio_codec_bg: sound {
+ status = "disabled";
+ compatible = "qcom,msm-bg-audio-codec";
+ qcom,model = "msm-bg-snd-card";
+ reg = <0x7702000 0x4>,
+ <0x7702004 0x4>,
+ <0x7702008 0x4>,
+ <0x770200c 0x4>;
+ reg-names = "csr_gp_io_mux_mic_ctl",
+ "csr_gp_io_mux_spkr_ctl",
+ "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+ "csr_gp_io_lpaif_sec_pcm_sec_mode_muxsel";
+
+ qcom,msm-snd-card-id = <0>;
+ qcom,msm-ext-pa = "primary";
+ qcom,tdm-audio-intf;
+ qcom,msm-afe-clk-ver = <1>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&lpa>,
+ <&voice_svc>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-pcm-lpa",
+ "msm-voice-svc";
+ asoc-cpu = <&dai_pri_auxpcm>,
+ <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>,
+ <&dai_mi2s3>, <&dai_mi2s5>, <&dai_mi2s6>,
+ <&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>,
+ <&int_fm_rx>, <&int_fm_tx>, <&afe_pcm_rx>,
+ <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>,
+ <&incall_music_rx>, <&incall_music_2_rx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_pri_tdm_rx_1>, <&dai_pri_tdm_tx_1>,
+ <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_tx_2>,
+ <&dai_pri_tdm_rx_3>, <&dai_pri_tdm_tx_3>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.5", "msm-dai-q6-mi2s.6",
+ "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+ "msm-dai-q6-dev.12290", "msm-dai-q6-dev.12292",
+ "msm-dai-q6-dev.12293", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770", "msm-dai-q6-tdm.36864",
+ "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36866",
+ "msm-dai-q6-tdm.36867", "msm-dai-q6-tdm.36868",
+ "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36870",
+ "msm-dai-q6-tdm.36871";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ };
+
+ pri_tdm_rx: qcom,msm-dai-tdm-pri-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37120>;
+ qcom,msm-cpudai-tdm-group-num-ports = <4>;
+ qcom,msm-cpudai-tdm-group-port-id = <36864 36866 36868 36870>;
+ qcom,msm-cpudai-tdm-clk-rate = <0>;
+ qcom,msm-cpudai-tdm-afe-ebit-unsupported;
+ qcom,msm-cpudai-tdm-sec-port-enable;
+ qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>;
+ pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>;
+ dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36864>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ dai_pri_tdm_rx_1: qcom,msm-dai-q6-tdm-pri-rx-1 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36866>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ dai_pri_tdm_rx_2: qcom,msm-dai-q6-tdm-pri-rx-2 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36868>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ dai_pri_tdm_rx_3: qcom,msm-dai-q6-tdm-pri-rx-3 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36870>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ pri_tdm_tx: qcom,msm-dai-tdm-pri-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37121>;
+ qcom,msm-cpudai-tdm-group-num-ports = <4>;
+ qcom,msm-cpudai-tdm-group-port-id = <36865 36867 36869 36871>;
+ qcom,msm-cpudai-tdm-clk-rate = <0>;
+ qcom,msm-cpudai-tdm-afe-ebit-unsupported;
+ qcom,msm-cpudai-tdm-sec-port-enable;
+ qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>;
+ pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>;
+ dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36865>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ dai_pri_tdm_tx_1: qcom,msm-dai-q6-tdm-pri-tx-1 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36867>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ dai_pri_tdm_tx_2: qcom,msm-dai-q6-tdm-pri-tx-2 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36869>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ dai_pri_tdm_tx_3: qcom,msm-dai-q6-tdm-pri-tx-3 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36871>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ wdsp_glink: qcom,wcd-dsp-glink {
+ compatible = "qcom,wcd-dsp-glink";
+ qcom,msm-codec-glink-edge = "bg";
+ };
+
+ bg_cdc: bg_codec {
+ status = "disabled";
+ compatible = "qcom,bg-codec";
+ qcom,subsys-name = "modem";
+ qcom,bg-glink {
+ compatible = "qcom,bg-cdc-glink";
+ qcom,msm-glink-channels = <4>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-bus.dtsi b/arch/arm64/boot/dts/qcom/msm8909-bus.dtsi
new file mode 100644
index 0000000..eea1a85
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-bus.dtsi
@@ -0,0 +1,1064 @@
+/* Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/msm/msm-bus-ids.h>
+#include <dt-bindings/msm/msm-bus-rule-ops.h>
+
+&soc {
+ static-rules {
+ compatible = "qcom,msm-bus-static-bw-rules";
+
+ rule0 {
+ qcom,src-nodes = <&mas_apps_proc>;
+ qcom,src-field = <FLD_CLK>;
+ qcom,src-op = <OP_LE>;
+ qcom,thresh = <200000>;
+ qcom,mode = <THROTTLE_ON>;
+ qcom,dest-node = <&mas_apps_proc>;
+ qcom,dest-bw = <600000>;
+ };
+
+ rule1 {
+ qcom,src-nodes = <&mas_apps_proc>;
+ qcom,src-field = <FLD_CLK>;
+ qcom,src-op = <OP_LE>;
+ qcom,thresh = <400000>;
+ qcom,mode = <THROTTLE_ON>;
+ qcom,dest-node = <&mas_apps_proc>;
+ qcom,dest-bw = <1200000>;
+ };
+
+ rule2 {
+ qcom,src-nodes = <&mas_apps_proc>;
+ qcom,src-field = <FLD_CLK>;
+ qcom,src-op = <OP_GT>;
+ qcom,thresh = <400000>;
+ qcom,mode = <THROTTLE_OFF>;
+ qcom,dest-node = <&mas_apps_proc>;
+ };
+
+ rule3 {
+ qcom,src-nodes = <&mas_oxili>;
+ qcom,src-field = <FLD_CLK>;
+ qcom,src-op = <OP_LE>;
+ qcom,thresh = <200000>;
+ qcom,mode = <THROTTLE_ON>;
+ qcom,dest-node = <&mas_oxili>;
+ qcom,dest-bw = <600000>;
+ };
+
+ rule4 {
+ qcom,src-nodes = <&mas_oxili>;
+ qcom,src-field = <FLD_CLK>;
+ qcom,src-op = <OP_LE>;
+ qcom,thresh = <400000>;
+ qcom,mode = <THROTTLE_ON>;
+ qcom,dest-node = <&mas_oxili>;
+ qcom,dest-bw = <1200000>;
+ };
+
+ rule5 {
+ qcom,src-nodes = <&mas_oxili>;
+ qcom,src-field = <FLD_CLK>;
+ qcom,src-op = <OP_GT>;
+ qcom,thresh = <400000>;
+ qcom,mode = <THROTTLE_OFF>;
+ qcom,dest-node = <&mas_oxili>;
+ };
+ };
+
+ /* Version = 2 */
+ ad_hoc_bus: ad-hoc-bus {
+ compatible = "qcom,msm-bus-device";
+ reg = <0x580000 0x13000>,
+ <0x580000 0x13000>,
+ <0x400000 0x62000>,
+ <0x500000 0x11000>;
+ reg-names = "snoc-base", "snoc-mm-base",
+ "bimc-base", "pcnoc-base";
+
+ /*Buses*/
+
+ fab_bimc: fab-bimc {
+ cell-id = <MSM_BUS_FAB_BIMC>;
+ label = "fab-bimc";
+ qcom,fab-dev;
+ qcom,base-name = "bimc-base";
+ qcom,bus-type = <2>;
+ qcom,util-fact = <154>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_rpm clk_bimc_msmbus_clk>,
+ <&clock_rpm clk_bimc_msmbus_a_clk>;
+ };
+
+ fab_pcnoc: fab-pcnoc {
+ cell-id = <MSM_BUS_FAB_PERIPH_NOC>;
+ label = "fab-pcnoc";
+ qcom,fab-dev;
+ qcom,base-name = "pcnoc-base";
+ qcom,base-offset = <0x7000>;
+ qcom,qos-delta = <0x1000>;
+ qcom,bus-type = <1>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_rpm clk_pcnoc_msmbus_clk>,
+ <&clock_rpm clk_pcnoc_msmbus_a_clk>;
+ };
+
+ fab_snoc: fab-snoc {
+ cell-id = <MSM_BUS_FAB_SYS_NOC>;
+ label = "fab-snoc";
+ qcom,fab-dev;
+ qcom,base-name = "snoc-base";
+ qcom,base-offset = <0x7000>;
+ qcom,qos-off = <0x1000>;
+ qcom,bus-type = <1>;
+ clock-names = "bus_clk", "bus_a_clk", "bus_qos_clk";
+ clocks = <&clock_rpm clk_snoc_msmbus_clk>,
+ <&clock_rpm clk_snoc_msmbus_a_clk>,
+ <&clock_gcc clk_gcc_snoc_qosgen_clk>;
+ };
+
+ fab_snoc_mm: fab-snoc-mm {
+ cell-id = <MSM_BUS_FAB_MMSS_NOC>;
+ label = "fab-snoc-mm";
+ qcom,fab-dev;
+ qcom,base-name = "snoc-mm-base";
+ qcom,base-offset = <0x7000>;
+ qcom,qos-off = <0x1000>;
+ qcom,bus-type = <1>;
+ qcom,util-fact = <167>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_rpm clk_snoc_mm_msmbus_clk>,
+ <&clock_rpm clk_snoc_mm_msmbus_a_clk>;
+ };
+
+ /* Masters */
+ mas_apps_proc: mas-apps-proc {
+ cell-id = <MSM_BUS_MASTER_AMPSS_M0>;
+ label = "mas-apps-proc";
+ qcom,buswidth = <8>;
+ qcom,ap-owned;
+ qcom,qport = <0>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_bimc_snoc &slv_ebi>;
+ qcom,prio-lvl = <0>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
+ qcom,ws = <10000>;
+ qcom,gp = <5000>;
+ qcom,thmp = <50>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_APPSS_PROC>;
+ };
+
+ mas_oxili: mas-oxili {
+ cell-id = <MSM_BUS_MASTER_GRAPHICS_3D>;
+ label = "mas-oxili";
+ qcom,buswidth = <8>;
+ qcom,ap-owned;
+ qcom,qport = <2>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_bimc_snoc &slv_ebi>;
+ qcom,prio-lvl = <0>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
+ qcom,ws = <10000>;
+ qcom,gp = <5000>;
+ qcom,thmp = <50>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_GFX3D>;
+ };
+
+ mas_snoc_bimc_0: mas-snoc-bimc-0 {
+ cell-id = <MSM_BUS_SNOC_BIMC_0_MAS>;
+ label = "mas-snoc-bimc-0";
+ qcom,buswidth = <8>;
+ qcom,qport = <3>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_ebi>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC_0>;
+ };
+
+ mas_snoc_bimc_1: mas-snoc-bimc-1 {
+ cell-id = <MSM_BUS_SNOC_BIMC_1_MAS>;
+ label = "mas-snoc-bimc-1";
+ qcom,buswidth = <8>;
+ qcom,ap-owned;
+ qcom,qport = <4>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_ebi>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC_1>;
+ };
+
+ mas_tcu_0: mas-tcu-0 {
+ cell-id = <MSM_BUS_MASTER_TCU_0>;
+ label = "mas-tcu-0";
+ qcom,buswidth = <8>;
+ qcom,ap-owned;
+ qcom,qport = <5>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_bimc_snoc &slv_ebi>;
+ qcom,prio-lvl = <2>;
+ qcom,prio-rd = <2>;
+ qcom,prio-wr = <2>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_TCU_0>;
+ };
+
+ mas_tcu_1: mas-tcu-1 {
+ cell-id = <MSM_BUS_MASTER_TCU_1>;
+ label = "mas-tcu-1";
+ qcom,buswidth = <8>;
+ qcom,ap-owned;
+ qcom,qport = <6>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_bimc_snoc &slv_ebi>;
+ qcom,prio-lvl = <2>;
+ qcom,prio-rd = <2>;
+ qcom,prio-wr = <2>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_TCU_1>;
+ };
+
+ mas_audio: mas-audio {
+ cell-id = <MSM_BUS_MASTER_AUDIO>;
+ label = "mas-audio";
+ qcom,buswidth = <4>;
+ qcom,connections = <&pcnoc_m_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_AUDIO>;
+ qcom,blacklist =
+ <&slv_blsp_1 &slv_message_ram &slv_usb_hs
+ &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+ &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+ &slv_pdm &slv_snoc_cfg &slv_qpic
+ &slv_tcsr &slv_prng &slv_sdcc_2
+ &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+ &slv_sdcc_1 &slv_audio>;
+ };
+
+ mas_spdm: mas-spdm {
+ cell-id = <MSM_BUS_MASTER_SPDM>;
+ label = "mas-spdm";
+ qcom,buswidth = <4>;
+ qcom,connections = <&pcnoc_m_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SPDM>;
+ qcom,blacklist =
+ <&slv_blsp_1 &slv_message_ram &slv_usb_hs
+ &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+ &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+ &slv_pdm &slv_snoc_cfg &slv_qpic
+ &slv_tcsr &slv_prng &slv_sdcc_2
+ &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+ &slv_sdcc_1 &slv_audio>;
+ };
+
+ mas_dehr: mas-dehr {
+ cell-id = <MSM_BUS_MASTER_DEHR>;
+ label = "mas-dehr";
+ qcom,buswidth = <4>;
+ qcom,connections = <&pcnoc_m_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_DEHR>;
+ qcom,blacklist =
+ <&slv_blsp_1 &slv_message_ram &slv_usb_hs
+ &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+ &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+ &slv_pdm &slv_snoc_cfg &slv_qpic
+ &slv_tcsr &slv_prng &slv_sdcc_2
+ &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+ &slv_sdcc_1 &slv_audio>;
+ };
+
+ mas_qpic: mas-qpic {
+ cell-id = <MSM_BUS_MASTER_QPIC>;
+ label = "mas-qpic";
+ qcom,buswidth = <4>;
+ qcom,connections = <&pcnoc_m_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_QPIC>;
+ qcom,blacklist =
+ <&slv_blsp_1 &slv_message_ram &slv_usb_hs
+ &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+ &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+ &slv_pdm &slv_snoc_cfg &slv_qpic
+ &slv_tcsr &slv_prng &slv_sdcc_2
+ &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+ &slv_sdcc_1 &slv_audio>;
+ };
+
+ mas_blsp_1: mas-blsp-1 {
+ cell-id = <MSM_BUS_MASTER_BLSP_1>;
+ label = "mas-blsp-1";
+ qcom,buswidth = <4>;
+ qcom,connections = <&pcnoc_m_1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_BLSP_1>;
+ qcom,blacklist =
+ <&slv_blsp_1 &slv_message_ram &slv_usb_hs
+ &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+ &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+ &slv_pdm &slv_snoc_cfg &slv_qpic
+ &slv_tcsr &slv_prng &slv_sdcc_2
+ &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+ &slv_sdcc_1 &slv_audio>;
+ };
+
+ mas_usb_hs: mas-usb-hs {
+ cell-id = <MSM_BUS_MASTER_USB_HS>;
+ label = "mas-usb-hs";
+ qcom,buswidth = <4>;
+ qcom,connections = <&pcnoc_m_1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_USB_HS>;
+ qcom,blacklist =
+ <&slv_blsp_1 &slv_message_ram &slv_usb_hs
+ &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+ &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+ &slv_pdm &slv_snoc_cfg &slv_qpic
+ &slv_tcsr &slv_prng &slv_sdcc_2
+ &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+ &slv_sdcc_1 &slv_audio>;
+ };
+
+ mas_crypto: mas-crypto {
+ cell-id = <MSM_BUS_MASTER_CRYPTO_CORE0>;
+ label = "mas-crypto";
+ qcom,buswidth = <8>;
+ qcom,ap-owned;
+ qcom,qport = <0>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_1>;
+ qcom,prio1 = <0>;
+ qcom,prio0 = <0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_CRYPTO>;
+ qcom,blacklist =
+ <&slv_blsp_1 &slv_message_ram &slv_usb_hs
+ &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+ &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+ &slv_pdm &slv_snoc_cfg &slv_qpic
+ &slv_tcsr &slv_prng &slv_sdcc_2
+ &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+ &slv_sdcc_1 &slv_audio>;
+ };
+
+ mas_sdcc_1: mas-sdcc-1 {
+ cell-id = <MSM_BUS_MASTER_SDCC_1>;
+ label = "mas-sdcc-1";
+ qcom,buswidth = <8>;
+ qcom,qport = <7>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SDCC_1>;
+ qcom,blacklist =
+ <&slv_blsp_1 &slv_message_ram &slv_usb_hs
+ &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+ &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+ &slv_pdm &slv_snoc_cfg &slv_qpic
+ &slv_tcsr &slv_prng &slv_sdcc_2
+ &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+ &slv_sdcc_1 &slv_audio>;
+ };
+
+ mas_sdcc_2: mas-sdcc-2 {
+ cell-id = <MSM_BUS_MASTER_SDCC_2>;
+ label = "mas-sdcc-2";
+ qcom,buswidth = <8>;
+ qcom,qport = <8>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SDCC_2>;
+ qcom,blacklist =
+ <&slv_blsp_1 &slv_message_ram &slv_usb_hs
+ &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+ &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+ &slv_pdm &slv_snoc_cfg &slv_qpic
+ &slv_tcsr &slv_prng &slv_sdcc_2
+ &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+ &slv_sdcc_1 &slv_audio>;
+ };
+
+ mas_snoc_pcnoc: mas-snoc-pcnoc {
+ cell-id = <MSM_BUS_SNOC_PNOC_MAS>;
+ label = "mas-snoc-pcnoc";
+ qcom,buswidth = <8>;
+ qcom,qport = <9>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_PCNOC>;
+ };
+
+ mas_qdss_bam: mas-qdss-bam {
+ cell-id = <MSM_BUS_MASTER_QDSS_BAM>;
+ label = "mas-qdss-bam";
+ qcom,buswidth = <4>;
+ qcom,ap-owned;
+ qcom,qport = <11>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&qdss_int>;
+ qcom,prio1 = <1>;
+ qcom,prio0 = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_QDSS_BAM>;
+ qcom,blacklist =
+ <&slv_kpss_ahb &slv_cats_1 &slv_qdss_stm
+ &slv_cats_0>;
+ };
+
+ mas_bimc_snoc: mas-bimc-snoc {
+ cell-id = <MSM_BUS_BIMC_SNOC_MAS>;
+ label = "mas-bimc-snoc";
+ qcom,buswidth = <8>;
+ qcom,connections = <&snoc_int_0 &snoc_int_1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_BIMC_SNOC>;
+ };
+
+ mas_mdp: mas-mdp {
+ cell-id = <MSM_BUS_MASTER_MDP_PORT0>;
+ label = "mas-mdp";
+ qcom,buswidth = <16>;
+ qcom,ap-owned;
+ qcom,qport = <7>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&mm_int_1 &mm_int_2>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_MDP>;
+ qcom,blacklist = <&slv_kpss_ahb &slv_imem &slv_cats_1
+ &slv_qdss_stm &slv_cats_0>;
+ };
+
+ mas_pcnoc_snoc: mas-pcnoc-snoc {
+ cell-id = <MSM_BUS_PNOC_SNOC_MAS>;
+ label = "mas-pcnoc-snoc";
+ qcom,buswidth = <8>;
+ qcom,qport = <5>;
+ qcom,qos-mode = "fixed";
+ qcom,connections =
+ <&snoc_int_0 &snoc_int_1 &snoc_int_bimc>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PNOC_SNOC>;
+ qcom,blacklist = <&slv_cats_1 &slv_cats_0>;
+ };
+
+ mas_venus: mas-venus {
+ cell-id = <MSM_BUS_MASTER_VIDEO_P0>;
+ label = "mas-venus";
+ qcom,buswidth = <16>;
+ qcom,ap-owned;
+ qcom,qport = <8>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&mm_int_0 &mm_int_2>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_VIDEO>;
+ qcom,blacklist = <&slv_kpss_ahb &slv_imem &slv_cats_1
+ &slv_qdss_stm &slv_cats_0>;
+ };
+
+ mas_vfe: mas-vfe {
+ cell-id = <MSM_BUS_MASTER_VFE>;
+ label = "mas-vfe";
+ qcom,buswidth = <16>;
+ qcom,ap-owned;
+ qcom,qport = <9>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&mm_int_1 &mm_int_2>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_VFE>;
+ qcom,blacklist = <&slv_kpss_ahb &slv_imem &slv_cats_1
+ &slv_qdss_stm &slv_cats_0>;
+ };
+
+ mas_qdss_etr: mas-qdss-etr {
+ cell-id = <MSM_BUS_MASTER_QDSS_ETR>;
+ label = "mas-qdss-etr";
+ qcom,buswidth = <8>;
+ qcom,ap-owned;
+ qcom,qport = <10>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&qdss_int>;
+ qcom,prio1 = <1>;
+ qcom,prio0 = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_QDSS_ETR>;
+ qcom,blacklist =
+ <&slv_kpss_ahb &slv_cats_1 &slv_qdss_stm
+ &slv_cats_0>;
+ };
+
+ /*Internal nodes*/
+ pcnoc_m_0: pcnoc-m-0 {
+ cell-id = <MSM_BUS_PNOC_M_0>;
+ label = "pcnoc-m-0";
+ qcom,buswidth = <8>;
+ qcom,qport = <5>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_pcnoc_snoc>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_M_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_M_0>;
+ };
+
+ pcnoc_m_1: pcnoc-m-1 {
+ cell-id = <MSM_BUS_PNOC_M_1>;
+ label = "pcnoc-m-1";
+ qcom,buswidth = <8>;
+ qcom,qport = <6>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_pcnoc_snoc>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_M_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_M_1>;
+ };
+
+ pcnoc_int_0: pcnoc-int-0 {
+ cell-id = <MSM_BUS_PNOC_INT_0>;
+ label = "pcnoc-int-0";
+ qcom,buswidth = <8>;
+ qcom,connections = <&pcnoc_s_3 &pcnoc_s_2 &pcnoc_s_1 \
+ &pcnoc_s_0 &pcnoc_s_7 &pcnoc_s_5 &pcnoc_s_4 &slv_tcu>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_0>;
+ };
+
+ pcnoc_int_1: pcnoc-int-1 {
+ cell-id = <MSM_BUS_PNOC_INT_1>;
+ label = "pcnoc-int-1";
+ qcom,buswidth = <8>;
+ qcom,connections = <&slv_pcnoc_snoc>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_1>;
+ };
+
+ pcnoc_s_0: pcnoc-s-0 {
+ cell-id = <MSM_BUS_PNOC_SLV_0>;
+ label = "pcnoc-s-0";
+ qcom,buswidth = <4>;
+ qcom,connections = <&slv_sdcc_1 &slv_tcsr &slv_blsp_1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_0>;
+ };
+
+ pcnoc_s_1: pcnoc-s-1 {
+ cell-id = <MSM_BUS_PNOC_SLV_1>;
+ label = "pcnoc-s-1";
+ qcom,buswidth = <4>;
+ qcom,connections = <&slv_message_ram &slv_crypto_0_cfg \
+ &slv_usb_hs &slv_pdm &slv_prng &slv_qpic>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_1>;
+ };
+
+ pcnoc_s_2: pcnoc-s-2 {
+ cell-id = <MSM_BUS_PNOC_SLV_2>;
+ label = "pcnoc-s-2";
+ qcom,buswidth = <4>;
+ qcom,connections = <&slv_spdm &slv_sdcc_2 \
+ &slv_audio &slv_dehr_cfg>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_2>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_2>;
+ };
+
+ pcnoc_s_3: pcnoc-s-3 {
+ cell-id = <MSM_BUS_PNOC_SLV_3>;
+ label = "pcnoc-s-3";
+ qcom,buswidth = <4>;
+ qcom,connections = <&slv_qdss_cfg &slv_usb_phy \
+ &slv_snoc_cfg>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_3>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_3>;
+ };
+
+ pcnoc_s_4: pcnoc-s-4 {
+ cell-id = <MSM_BUS_PNOC_SLV_4>;
+ label = "pcnoc-s-4";
+ qcom,buswidth = <4>;
+ qcom,ap-owned;
+ qcom,connections =
+ <&slv_camera_ss_cfg &slv_disp_ss_cfg \
+ &slv_venus_cfg>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_4>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_4>;
+ };
+
+ pcnoc_s_5: pcnoc-s-5 {
+ cell-id = <MSM_BUS_PNOC_SLV_5>;
+ label = "pcnoc-s-5";
+ qcom,buswidth = <4>;
+ qcom,connections = <&slv_tlmm>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_5>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_5>;
+ };
+
+ pcnoc_s_7: pcnoc-s-7 {
+ cell-id = <MSM_BUS_PNOC_SLV_7>;
+ label = "pcnoc-s-7";
+ qcom,buswidth = <4>;
+ qcom,connections = <&slv_gpu_cfg &slv_imem_cfg \
+ &slv_bimc_cfg &slv_pmic_arb>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_7>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_7>;
+ };
+
+ mm_int_0: mm-int-0 {
+ cell-id = <MSM_BUS_SNOC_MM_INT_0>;
+ label = "mm-int-0";
+ qcom,buswidth = <16>;
+ qcom,ap-owned;
+ qcom,connections = <&mm_int_bimc>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_MM_INT_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_MM_INT_0>;
+ };
+
+ mm_int_1: mm-int-1 {
+ cell-id = <MSM_BUS_SNOC_MM_INT_1>;
+ label = "mm-int-1";
+ qcom,buswidth = <16>;
+ qcom,ap-owned;
+ qcom,connections = <&mm_int_bimc>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_MM_INT_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_MM_INT_1>;
+ };
+
+ mm_int_2: mm-int-2 {
+ cell-id = <MSM_BUS_SNOC_MM_INT_2>;
+ label = "mm-int-2";
+ qcom,buswidth = <16>;
+ qcom,ap-owned;
+ qcom,connections = <&snoc_int_0>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_MM_INT_2>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_MM_INT_2>;
+ };
+
+ mm_int_bimc: mm-int-bimc {
+ cell-id = <MSM_BUS_SNOC_MM_INT_BIMC>;
+ label = "mm-int-bimc";
+ qcom,buswidth = <16>;
+ qcom,ap-owned;
+ qcom,connections = <&slv_snoc_bimc_1>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_MM_INT_BIMC>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_MM_INT_BIMC>;
+ };
+
+ qdss_int: qdss-int {
+ cell-id = <MSM_BUS_SNOC_QDSS_INT>;
+ label = "qdss-int";
+ qcom,buswidth = <8>;
+ qcom,ap-owned;
+ qcom,connections = <&snoc_int_0 &snoc_int_bimc>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_QDSS_INT>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_QDSS_INT>;
+ };
+
+ snoc_int_0: snoc-int-0 {
+ cell-id = <MSM_BUS_SNOC_INT_0>;
+ label = "snoc-int-0";
+ qcom,buswidth = <8>;
+ qcom,connections = <&slv_imem &slv_qdss_stm \
+ &slv_snoc_pcnoc>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_0>;
+ };
+
+ snoc_int_1: snoc-int-1 {
+ cell-id = <MSM_BUS_SNOC_INT_1>;
+ label = "snoc-int-1";
+ qcom,buswidth = <8>;
+ qcom,ap-owned;
+ qcom,connections = <&slv_cats_0 &slv_kpss_ahb \
+ &slv_cats_1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_1>;
+ };
+
+ snoc_int_bimc: snoc-int-bimc {
+ cell-id = <MSM_BUS_SNOC_INT_BIMC>;
+ label = "snoc-int-bimc";
+ qcom,buswidth = <8>;
+ qcom,connections = <&slv_snoc_bimc_0>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_BIMC>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_BIMC>;
+ };
+
+ /*Slaves*/
+ slv_ebi:slv-ebi {
+ cell-id = <MSM_BUS_SLAVE_EBI_CH0>;
+ label = "slv-ebi";
+ qcom,buswidth = <8>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_EBI1>;
+ };
+
+ slv_bimc_snoc:slv-bimc-snoc {
+ cell-id = <MSM_BUS_BIMC_SNOC_SLV>;
+ label = "slv-bimc-snoc";
+ qcom,buswidth = <8>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,connections = <&mas_bimc_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_BIMC_SNOC>;
+ };
+
+ slv_tcsr:slv-tcsr {
+ cell-id = <MSM_BUS_SLAVE_TCSR>;
+ label = "slv-tcsr";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_TCSR>;
+ };
+
+ slv_sdcc_1:slv-sdcc-1 {
+ cell-id = <MSM_BUS_SLAVE_SDCC_1>;
+ label = "slv-sdcc-1";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SDCC_1>;
+ };
+
+ slv_blsp_1:slv-blsp-1 {
+ cell-id = <MSM_BUS_SLAVE_BLSP_1>;
+ label = "slv-blsp-1";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_BLSP_1>;
+ };
+
+ slv_crypto_0_cfg:slv-crypto-0-cfg {
+ cell-id = <MSM_BUS_SLAVE_CRYPTO_0_CFG>;
+ label = "slv-crypto-0-cfg";
+ qcom,buswidth = <4>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CRYPTO_0_CFG>;
+ };
+
+ slv_message_ram:slv-message-ram {
+ cell-id = <MSM_BUS_SLAVE_MESSAGE_RAM>;
+ label = "slv-message-ram";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_MESSAGE_RAM>;
+ };
+
+ slv_pdm:slv-pdm {
+ cell-id = <MSM_BUS_SLAVE_PDM>;
+ label = "slv-pdm";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PDM>;
+ };
+
+ slv_prng:slv-prng {
+ cell-id = <MSM_BUS_SLAVE_PRNG>;
+ label = "slv-prng";
+ qcom,buswidth = <4>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PRNG>;
+ };
+
+ slv_usb_hs:slv-usb-hs {
+ cell-id = <MSM_BUS_SLAVE_USB_HS>;
+ label = "slv-usb-hs";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_USB_HS>;
+ };
+
+ slv_qpic:slv-qpic {
+ cell-id = <MSM_BUS_SLAVE_QPIC>;
+ label = "slv-qpic";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_QPIC>;
+ };
+
+ slv_spdm: slv-spdm {
+ cell-id = <MSM_BUS_SLAVE_SPDM>;
+ label = "slv-spdm";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SPDM_WRAPPER>;
+ };
+
+ slv_sdcc_2:slv-sdcc-2 {
+ cell-id = <MSM_BUS_SLAVE_SDCC_2>;
+ label = "slv-sdcc-2";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SDCC_2>;
+ };
+
+ slv_audio:slv-audio {
+ cell-id = <MSM_BUS_SLAVE_AUDIO>;
+ label = "slv-audio";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_AUDIO>;
+ };
+
+ slv_dehr_cfg: slv-dehr-cfg {
+ cell-id = <MSM_BUS_SLAVE_DEHR_CFG>;
+ label = "slv-dehr-cfg";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_DEHR_CFG>;
+ };
+
+ slv_snoc_cfg:slv-snoc-cfg {
+ cell-id = <MSM_BUS_SLAVE_SNOC_CFG>;
+ label = "slv-snoc-cfg";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_CFG>;
+ };
+
+ slv_qdss_cfg: slv-qdss-cfg {
+ cell-id = <MSM_BUS_SLAVE_QDSS_CFG>;
+ label = "slv-qdss-cfg";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_QDSS_CFG>;
+ };
+
+ slv_usb_phy:slv-usb-phy {
+ cell-id = <MSM_BUS_SLAVE_USB_PHYS_CFG>;
+ label = "slv-usb-phy";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_USB_PHY_CFG>;
+ };
+
+ slv_camera_ss_cfg:slv-camera-ss-cfg {
+ cell-id = <MSM_BUS_SLAVE_CAMERA_CFG>;
+ label = "slv-camera-ss-cfg";
+ qcom,buswidth = <4>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CAMERA_CFG>;
+ };
+
+ slv_disp_ss_cfg:slv-disp-ss-cfg {
+ cell-id = <MSM_BUS_SLAVE_DISPLAY_CFG>;
+ label = "slv-disp-ss-cfg";
+ qcom,buswidth = <4>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_DISPLAY_CFG>;
+ };
+
+ slv_venus_cfg:slv-venus-cfg {
+ cell-id = <MSM_BUS_SLAVE_VENUS_CFG>;
+ label = "slv-venus-cfg";
+ qcom,buswidth = <4>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_VENUS_CFG>;
+ };
+
+ slv_tlmm:slv-tlmm {
+ cell-id = <MSM_BUS_SLAVE_TLMM>;
+ label = "slv-tlmm";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_TLMM>;
+ };
+
+ slv_gpu_cfg:slv-gpu-cfg {
+ cell-id = <MSM_BUS_SLAVE_GRAPHICS_3D_CFG>;
+ label = "slv-gpu-cfg";
+ qcom,buswidth = <4>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_GFX3D_CFG>;
+ };
+
+ slv_imem_cfg: slv-imem-cfg {
+ cell-id = <MSM_BUS_SLAVE_IMEM_CFG>;
+ label = "slv-imem-cfg";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_IMEM_CFG>;
+ };
+
+ slv_bimc_cfg: slv-bimc-cfg {
+ cell-id = <MSM_BUS_SLAVE_BIMC_CFG>;
+ label = "slv-bimc-cfg";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_BIMC_CFG>;
+ };
+
+ slv_pmic_arb:slv-pmic-arb {
+ cell-id = <MSM_BUS_SLAVE_PMIC_ARB>;
+ label = "slv-pmic-arb";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PMIC_ARB>;
+ };
+
+ slv_tcu:slv-tcu {
+ cell-id = <MSM_BUS_SLAVE_TCU>;
+ label = "slv-tcu";
+ qcom,buswidth = <8>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_TCU>;
+ };
+
+ slv_pcnoc_snoc:slv-pcnoc-snoc {
+ cell-id = <MSM_BUS_PNOC_SNOC_SLV>;
+ label = "slv-pcnoc-snoc";
+ qcom,buswidth = <8>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,connections = <&mas_pcnoc_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_SNOC>;
+ };
+
+ slv_kpss_ahb:slv-kpss-ahb {
+ cell-id = <MSM_BUS_SLAVE_APPSS>;
+ label = "slv-kpss-ahb";
+ qcom,buswidth = <4>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_APPSS>;
+ };
+
+ slv_snoc_bimc_0:slv-snoc-bimc-0 {
+ cell-id = <MSM_BUS_SNOC_BIMC_0_SLV>;
+ label = "slv-snoc-bimc-0";
+ qcom,buswidth = <8>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,connections = <&mas_snoc_bimc_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC_0>;
+ };
+
+ slv_snoc_bimc_1:slv-snoc-bimc-1 {
+ cell-id = <MSM_BUS_SNOC_BIMC_1_SLV>;
+ label = "slv-snoc-bimc-1";
+ qcom,buswidth = <16>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,connections = <&mas_snoc_bimc_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC_1>;
+ };
+
+ slv_imem:slv-imem {
+ cell-id = <MSM_BUS_SLAVE_SYSTEM_IMEM>;
+ label = "slv-imem";
+ qcom,buswidth = <8>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_IMEM>;
+ };
+
+ slv_snoc_pcnoc:slv-snoc-pcnoc {
+ cell-id = <MSM_BUS_SNOC_PNOC_SLV>;
+ label = "slv-snoc-pcnoc";
+ qcom,buswidth = <8>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,connections = <&mas_snoc_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_PCNOC>;
+ };
+
+ slv_qdss_stm:slv-qdss-stm {
+ cell-id = <MSM_BUS_SLAVE_QDSS_STM>;
+ label = "slv-qdss-stm";
+ qcom,buswidth = <4>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_QDSS_STM>;
+ };
+
+ slv_cats_0:slv-cats-0 {
+ cell-id = <MSM_BUS_SLAVE_CATS_128>;
+ label = "slv-cats-0";
+ qcom,buswidth = <16>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CATS_0>;
+ };
+
+ slv_cats_1:slv-cats-1 {
+ cell-id = <MSM_BUS_SLAVE_OCMEM_64>;
+ label = "slv-cats-1";
+ qcom,buswidth = <8>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CATS_1>;
+ };
+ };
+
+ devfreq_spdm_cpu {
+ compatible = "qcom,devfreq_spdm";
+ qcom,msm-bus,name = "devfreq_spdm";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <1 512 0 0>,
+ <1 512 0 0>;
+ qcom,msm-bus,active-only;
+ qcom,spdm-client = <0>;
+
+ clock-names = "cci_clk";
+ clocks = <&clock_cpu clk_a7ssmux>;
+
+ qcom,bw-upstep = <400>;
+ qcom,bw-dwnstep = <400>;
+ qcom,max-vote = <4000>;
+ qcom,up-step-multp = <3>;
+ qcom,spdm-interval = <100>;
+
+ qcom,ports = <11>;
+ qcom,alpha-up = <8>;
+ qcom,alpha-down = <15>;
+ qcom,bucket-size = <8>;
+
+ /*max pl1 freq, max pl2 freq*/
+ qcom,pl-freqs = <390000000 410000000>;
+
+ /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+ qcom,reject-rate = <5000 5000 5000 5000 5000 5000>;
+ /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+ qcom,response-time-us = <5000 5000 5000 5000 3000 3000>;
+ /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+ qcom,cci-response-time-us = <5000 5000 5000 5000 1000 1000>;
+ qcom,max-cci-freq = <1090000000>;
+ };
+
+ devfreq_spdm_gov {
+ compatible = "qcom,gov_spdm_hyp";
+ interrupt-names = "spdm-irq";
+ interrupts = <0 192 0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi
new file mode 100644
index 0000000..4e7d6f8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi
@@ -0,0 +1,623 @@
+/* Copyright (c) 2014-2018, 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.
+ */
+
+&soc {
+ tmc_etr: tmc@826000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0x826000 0x1000>,
+ <0x884000 0x15000>;
+ reg-names = "tmc-base", "bam-base";
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
+
+ qcom,memory-size = <0x100000>;
+ qcom,sg-enable;
+
+ coresight-id = <0>;
+ coresight-name = "coresight-tmc-etr";
+ coresight-nr-inports = <1>;
+ coresight-ctis = <&cti0 &cti8>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ tpiu: tpiu@820000 {
+ compatible = "arm,coresight-tpiu";
+ reg = <0x820000 0x1000>,
+ <0x1100000 0xb0000>;
+ reg-names = "tpiu-base", "nidnt-base";
+
+ coresight-id = <1>;
+ coresight-name = "coresight-tpiu";
+ coresight-nr-inports = <1>;
+
+ qcom,nidnthw;
+ qcom,nidnt-swduart;
+ qcom,nidnt-swdtrc;
+ qcom,nidnt-jtag;
+ qcom,nidnt-spmi;
+ nidnt-gpio = <38>;
+ nidnt-gpio-polarity = <1>;
+
+ interrupts = <0 82 0>;
+ interrupt-names = "nidnt-irq";
+
+ vdd-supply = <&pm8909_l11>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 400000>;
+
+ vdd-io-supply = <&pm8909_l12>;
+ qcom,vdd-io-voltage-level = <2950000 2950000>;
+ qcom,vdd-io-current-level = <200 50000>;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ replicator: replicator@824000 {
+ compatible = "qcom,coresight-replicator";
+ reg = <0x824000 0x1000>;
+ reg-names = "replicator-base";
+
+ coresight-id = <2>;
+ coresight-name = "coresight-replicator";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0 1>;
+ coresight-child-list = <&tmc_etr &tpiu>;
+ coresight-child-ports = <0 0>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ tmc_etf: tmc@825000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0x825000 0x1000>;
+ reg-names = "tmc-base";
+
+ coresight-id = <3>;
+ coresight-name = "coresight-tmc-etf";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0>;
+ coresight-child-list = <&replicator>;
+ coresight-child-ports = <0>;
+ coresight-default-sink;
+ coresight-ctis = <&cti0 &cti8>;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ funnel_in0: funnel@821000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0x821000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <4>;
+ coresight-name = "coresight-funnel-in0";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&tmc_etf>;
+ coresight-child-ports = <0>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ funnel_in2: funnel@869000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0x869000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <5>;
+ coresight-name = "coresight-funnel-in2";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in0>;
+ coresight-child-ports = <6>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ funnel_in3: funnel@868000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0x868000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <6>;
+ coresight-name = "coresight-funnel-in3";
+ coresight-nr-inports = <2>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in2>;
+ coresight-child-ports = <7>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti0: cti@810000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x810000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <7>;
+ coresight-name = "coresight-cti0";
+ coresight-nr-inports = <0>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti1: cti@811000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x811000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <8>;
+ coresight-name = "coresight-cti1";
+ coresight-nr-inports = <0>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti2: cti@812000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x812000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <9>;
+ coresight-name = "coresight-cti2";
+ coresight-nr-inports = <0>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti3: cti@813000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x813000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <10>;
+ coresight-name = "coresight-cti3";
+ coresight-nr-inports = <0>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti4: cti@814000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x814000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <11>;
+ coresight-name = "coresight-cti4";
+ coresight-nr-inports = <0>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti5: cti@815000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x815000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <12>;
+ coresight-name = "coresight-cti5";
+ coresight-nr-inports = <0>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti6: cti@816000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x816000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <13>;
+ coresight-name = "coresight-cti6";
+ coresight-nr-inports = <0>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+
+ qcom,cti-gpio-trigout = <2>;
+ pinctrl-names = "cti-trigout-pctrl";
+ pinctrl-0 = <&trigout_a0>;
+ };
+
+ cti7: cti@817000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x817000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <14>;
+ coresight-name = "coresight-cti7";
+ coresight-nr-inports = <0>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti8: cti@818000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x818000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <15>;
+ coresight-name = "coresight-cti8";
+ coresight-nr-inports = <0>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_cpu0: cti@851000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x851000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <16>;
+ coresight-name = "coresight-cti-cpu0";
+ coresight-nr-inports = <0>;
+ coresight-cti-cpu = <&CPU0>;
+
+ qcom,cti-save;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_cpu1: cti@852000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x852000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <17>;
+ coresight-name = "coresight-cti-cpu1";
+ coresight-nr-inports = <0>;
+ coresight-cti-cpu = <&CPU1>;
+
+ qcom,cti-save;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_cpu2: cti@853000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x853000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <18>;
+ coresight-name = "coresight-cti-cpu2";
+ coresight-nr-inports = <0>;
+ coresight-cti-cpu = <&CPU2>;
+
+ qcom,cti-save;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_cpu3: cti@854000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x854000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <19>;
+ coresight-name = "coresight-cti-cpu3";
+ coresight-nr-inports = <0>;
+ coresight-cti-cpu = <&CPU3>;
+
+ qcom,cti-save;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_rpm_cpu0: cti@83c000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x83c000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <20>;
+ coresight-name = "coresight-cti-rpm-cpu0";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_modem_cpu0: cti@838000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x838000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <21>;
+ coresight-name = "coresight-cti-modem-cpu0";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_wcn_cpu0: cti@835000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x835000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <22>;
+ coresight-name = "coresight-cti-wcn-cpu0";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_video_cpu0: cti@830000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x830000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <23>;
+ coresight-name = "coresight-cti-video-cpu0";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ stm: stm@802000 {
+ compatible = "arm,coresight-stm";
+ reg = <0x802000 0x1000>,
+ <0x9280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
+
+ coresight-id = <24>;
+ coresight-name = "coresight-stm";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in0>;
+ coresight-child-ports = <7>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ csr: csr@801000 {
+ compatible = "qcom,coresight-csr";
+ reg = <0x801000 0x1000>;
+ reg-names = "csr-base";
+
+ coresight-id = <25>;
+ coresight-name = "coresight-csr";
+ coresight-nr-inports = <0>;
+
+ qcom,blk-size = <1>;
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ funnel_apss: funnel@855000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0x855000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <26>;
+ coresight-name = "coresight-funnel-apss";
+ coresight-nr-inports = <4>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in0>;
+ coresight-child-ports = <4>;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ etm0: etm@84c000 {
+ compatible = "arm,coresight-etm";
+ reg = <0x84c000 0x1000>;
+ reg-names = "etm-base";
+
+ coresight-id = <27>;
+ coresight-name = "coresight-etm0";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_apss>;
+ coresight-child-ports = <0>;
+ coresight-etm-cpu = <&CPU0>;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ etm1: etm@84d000 {
+ compatible = "arm,coresight-etm";
+ reg = <0x84d000 0x1000>;
+ reg-names = "etm-base";
+
+ coresight-id = <28>;
+ coresight-name = "coresight-etm1";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_apss>;
+ coresight-child-ports = <1>;
+ coresight-etm-cpu = <&CPU1>;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ etm2: etm@84e000 {
+ compatible = "arm,coresight-etm";
+ reg = <0x84e000 0x1000>;
+ reg-names = "etm-base";
+
+ coresight-id = <29>;
+ coresight-name = "coresight-etm2";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_apss>;
+ coresight-child-ports = <2>;
+ coresight-etm-cpu = <&CPU2>;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ etm3: etm@84f000 {
+ compatible = "arm,coresight-etm";
+ reg = <0x84f000 0x1000>;
+ reg-names = "etm-base";
+
+ coresight-id = <30>;
+ coresight-name = "coresight-etm3";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_apss>;
+ coresight-child-ports = <3>;
+ coresight-etm-cpu = <&CPU3>;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ hwevent: hwevent@86c000 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0x86c000 0x108>,
+ <0x86cfb0 0x4>,
+ <0x78c5010 0x4>,
+ <0x7885010 0x4>;
+ reg-names = "wrapper-mux", "wrapper-lockaccess", "usbbam-mux",
+ "blsp-mux";
+ coresight-id = <31>;
+ coresight-name = "coresight-hwevent";
+ coresight-nr-inports = <0>;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ rpm_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+
+ coresight-id = <32>;
+ coresight-name = "coresight-rpm-etm0";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in0>;
+ coresight-child-ports = <0>;
+
+ qcom,inst-id = <4>;
+ };
+
+ wcn_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+
+ coresight-id = <33>;
+ coresight-name = "coresight-wcn-etm0";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in3>;
+ coresight-child-ports = <0>;
+
+ qcom,inst-id = <3>;
+ };
+
+ modem_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+
+ coresight-id = <34>;
+ coresight-name = "coresight-modem-etm0";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in0>;
+ coresight-child-ports = <2>;
+
+ qcom,inst-id = <2>;
+ };
+
+ fuse: fuse@5e01c {
+ compatible = "arm,coresight-fuse-v2";
+ reg = <0x5e01c 0x8>,
+ <0x58040 0x4>,
+ <0x5e00c 0x4>;
+ reg-names = "fuse-base", "nidnt-fuse-base", "qpdi-fuse-base";
+
+ coresight-id = <35>;
+ coresight-name = "coresight-fuse";
+ coresight-nr-inports = <0>;
+ };
+
+ qpdi: qpdi@1941000 {
+ compatible = "qcom,coresight-qpdi";
+ reg = <0x1941000 0x4>;
+ reg-names = "qpdi-base";
+
+ coresight-id = <36>;
+ coresight-name = "coresight-qpdi";
+ coresight-nr-inports = <0>;
+
+ vdd-supply = <&pm8909_l11>;
+ qcom,vdd-voltage-level = <2800000 2950000>;
+ qcom,vdd-current-level = <15000 400000>;
+
+ vdd-io-supply = <&pm8909_l12>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 50000>;
+ };
+
+ dbgui: dbgui@86d000 {
+ compatible = "qcom,coresight-dbgui";
+ reg = <0x86d000 0x1000>;
+ reg-names = "dbgui-base";
+
+ coresight-id = <37>;
+ coresight-name = "coresight-dbgui";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in2>;
+ coresight-child-ports = <2>;
+
+ qcom,dbgui-addr-offset = <0x30>;
+ qcom,dbgui-data-offset = <0xB0>;
+ qcom,dbgui-size = <32>;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi
new file mode 100644
index 0000000..74f2be0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi
@@ -0,0 +1,48 @@
+/* Copyright (c) 2014, 2016-2018, 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.
+ */
+
+&soc {
+ qcom,ion {
+ compatible = "qcom,msm-ion";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ion-heap@25 {
+ reg = <25>;
+ qcom,ion-heap-type = "SYSTEM";
+ };
+
+ qcom,ion-heap@27 { /* QSEECOM HEAP */
+ reg = <27>;
+ memory-region = <&venus_qseecom_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
+
+ qcom,ion-heap@28 { /* AUDIO HEAP */
+ reg = <28>;
+ memory-region = <&audio_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
+
+ modem_heap: qcom,ion-heap@26 { /* MODEM HEAP */
+ reg = <26>;
+ memory-region = <&modem_adsp_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
+
+ adsp_heap: qcom,ion-heap@22 { /* MODEM HEAP */
+ reg = <22>;
+ memory-region = <&adsp_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-ipcrouter.dtsi b/arch/arm64/boot/dts/qcom/msm8909-ipcrouter.dtsi
new file mode 100644
index 0000000..aceefdf
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-ipcrouter.dtsi
@@ -0,0 +1,37 @@
+/* Copyright (c) 2016,2018, 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.
+ */
+
+&soc {
+ qcom,ipc_router {
+ compatible = "qcom,ipc_router";
+ qcom,node-id = <1>;
+ };
+
+ qcom,ipc_router_modem_xprt {
+ compatible = "qcom,ipc_router_smd_xprt";
+ qcom,ch-name = "IPCRTR";
+ qcom,xprt-remote = "modem";
+ qcom,xprt-linkid = <1>;
+ qcom,xprt-version = <1>;
+ qcom,fragmented-data;
+ qcom,disable-pil-loading;
+ };
+
+ qcom,ipc_router_wcnss_xprt {
+ compatible = "qcom,ipc_router_smd_xprt";
+ qcom,ch-name = "IPCRTR";
+ qcom,xprt-remote = "wcnss";
+ qcom,xprt-linkid = <1>;
+ qcom,xprt-version = <1>;
+ qcom,fragmented-data;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-mdss-pll.dtsi b/arch/arm64/boot/dts/qcom/msm8909-mdss-pll.dtsi
new file mode 100644
index 0000000..aa81972
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-mdss-pll.dtsi
@@ -0,0 +1,53 @@
+/* Copyright (c) 2016,2018, 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.
+ */
+
+&soc {
+ mdss_dsi0_pll: qcom,mdss_dsi_pll@1ac8300 {
+ compatible = "qcom,mdss_dsi_pll_8909";
+ label = "MDSS DSI 0 PLL";
+ cell-index = <0>;
+ #clock-cells = <1>;
+
+ reg = <0x1ac8300 0xd4>, <0x0184d074 0x8>;
+ reg-names = "pll_base", "gdsc_base";
+
+ gdsc-supply = <&gdsc_mdss>;
+ vddio-supply = <&pm8909_l6>;
+
+ clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>;
+ clock-names = "iface_clk";
+ clock-rate = <0>;
+
+ qcom,platform-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,platform-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+
+ qcom,platform-supply-entry@1 {
+ reg = <1>;
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1800000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-mdss.dtsi b/arch/arm64/boot/dts/qcom/msm8909-mdss.dtsi
new file mode 100644
index 0000000..0d824e0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-mdss.dtsi
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014-2016,2018, 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.
+ */
+
+&soc {
+ mdss_mdp: qcom,mdss_mdp@1a00000 {
+ compatible = "qcom,mdss_mdp3";
+ reg = <0x1a00000 0x100000>,
+ <0x1ab0000 0x3000>;
+ reg-names = "mdp_phys", "vbif_phys";
+ interrupts = <0 72 0>;
+
+ vdd-supply = <&gdsc_mdss>;
+ clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>,
+ <&clock_gcc clk_gcc_mdss_axi_clk>,
+ <&clock_gcc clk_mdp_clk_src>,
+ <&clock_gcc clk_gcc_mdss_mdp_clk>,
+ <&clock_gcc clk_gcc_mdss_vsync_clk>;
+ clock-names = "iface_clk", "bus_clk", "core_clk_src",
+ "core_clk", "vsync_clk";
+
+ mdss_fb0: qcom,mdss_fb_primary {
+ cell-index = <0>;
+ compatible = "qcom,mdss-fb";
+ qcom,cont-splash-memory {
+ linux,contiguous-region = <&cont_splash_mem>;
+ };
+ };
+
+ smmu_mdp_unsec: qcom,smmu_mdp_unsec_cb {
+ compatible = "qcom,smmu_mdp_unsec";
+ };
+ smmu_mdp_sec: qcom,smmu_mdp_sec_cb {
+ compatible = "qcom,smmu_mdp_sec";
+ };
+ };
+
+ mdss_dsi: qcom,mdss_dsi@0 {
+ compatible = "qcom,mdss-dsi";
+ hw-config = "single_dsi";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,mdss-fb-map-prim = <&mdss_fb0>;
+ gdsc-supply = <&gdsc_mdss>;
+ vdda-supply = <&pm8909_l2>;
+ vddio-supply = <&pm8909_l6>;
+
+ /* Bus Scale Settings */
+ qcom,msm-bus,name = "mdss_dsi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <22 512 0 0>,
+ <22 512 0 1000>;
+
+ ranges = <0x1ac8000 0x1ac8000 0x25c
+ 0x1ac8500 0x1ac8500 0x280
+ 0x1ac8780 0x1ac8780 0x30
+ 0x193e000 0x193e000 0x30>;
+
+ clocks = <&clock_gcc clk_gcc_mdss_mdp_clk>,
+ <&clock_gcc clk_gcc_mdss_ahb_clk>,
+ <&clock_gcc clk_gcc_mdss_axi_clk>;
+ clock-names = "mdp_core_clk", "iface_clk", "bus_clk";
+
+ qcom,mmss-ulp-clamp-ctrl-offset = <0x20>;
+ qcom,mmss-phyreset-ctrl-offset = <0x24>;
+
+ qcom,core-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,core-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+
+ qcom,ctrl-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ctrl-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda";
+ qcom,supply-min-voltage = <1200000>;
+ qcom,supply-max-voltage = <1200000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-post-on-sleep = <5>;
+ };
+ };
+
+ qcom,phy-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,phy-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1800000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+ };
+
+ mdss_dsi0: qcom,mdss_dsi_ctrl0@1ac8000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ label = "MDSS DSI CTRL->0";
+ cell-index = <0>;
+ reg = <0x1ac8000 0x25c>,
+ <0x1ac8500 0x280>,
+ <0x1ac8780 0x30>,
+ <0x193e000 0x30>;
+ reg-names = "dsi_ctrl", "dsi_phy",
+ "dsi_phy_regulator", "mmss_misc_phys";
+
+ qcom,dsi-irq-line;
+ interrupts = <0 80 0>;
+
+ qcom,mdss-mdp = <&mdss_mdp>;
+ vdd-supply = <&pm8909_l17>;
+ vddio-supply = <&pm8909_l6>;
+
+ clocks = <&clock_gcc_mdss clk_gcc_mdss_byte0_clk>,
+ <&clock_gcc_mdss clk_gcc_mdss_pclk0_clk>,
+ <&clock_gcc clk_gcc_mdss_esc0_clk>;
+ clock-names = "byte_clk", "pixel_clk", "core_clk";
+
+ qcom,regulator-ldo-mode;
+
+ qcom,platform-strength-ctrl = [ff 06];
+ qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
+ qcom,platform-regulator-settings =
+ [00 01 01 00 20 07 00];
+ qcom,platform-lane-config =
+ [00 00 00 00 00 00 00 01 97
+ 00 00 00 00 05 00 00 01 97
+ 00 00 00 00 0a 00 00 01 97
+ 00 00 00 00 0f 00 00 01 97
+ 00 c0 00 00 00 00 00 01 bb];
+ };
+ };
+};
+
+/* #include "msm8909-mdss-panels.dtsi" */
diff --git a/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi
new file mode 100644
index 0000000..7f18173
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi
@@ -0,0 +1,428 @@
+/* Copyright (c) 2014-2018, 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 "msm8909.dtsi"
+#include "msm8909-pinctrl.dtsi"
+#include "msm8909-regulator.dtsi"
+
+&soc {
+ /*
+ * DT node to add support for SMB135x charger and integrate
+ * with VM-BMS.
+ */
+ i2c@78b8000 {
+ smb1357_otg_vreg: smb1357-charger@57 {
+ compatible = "qcom,smb1357-charger";
+ reg = <0x57>;
+ interrupt-parent = <&msm_gpio>;
+ interrupts = <58 8>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default>;
+
+ qcom,bmd-algo-disabled;
+ qcom,float-voltage-mv = <4200>;
+ qcom,charging-timeout = <1536>;
+ qcom,recharge-thresh-mv = <100>;
+ regulator-name = "smb1357_otg_vreg";
+ qcom,soft-vfloat-comp-disabled;
+ qcom,thermal-mitigation = <1500 700 600 0>;
+
+ qcom,bms-psy-name = "bms";
+
+ /*
+ * Disable SMB1357 based charging termination as BMS
+ * controls charging.
+ */
+ qcom,iterm-disabled;
+
+ /*
+ * Disable charge inhibit feature to start chargin on
+ * charger insertion independent of battery voltage.
+ */
+ qcom,inhibit-disabled;
+
+ /* BMS is controlling charging/re-charge */
+ qcom,bms-controlled-charging;
+
+ /*
+ * To enable charger node:
+ * set status = "ok" and
+ * add 'qcom,use-external-charger' to pm8909_chg node
+ */
+ status = "disabled";
+ };
+ };
+
+ /*
+ * DT node to add support for SMB358 charger and integrate
+ * with VM-BMS.
+ */
+ i2c@78b8000 {
+ };
+
+ i2c@78b9000 { /* BLSP1 QUP5 */
+ synaptics@20 {
+ compatible = "synaptics,dsx";
+ reg = <0x20>;
+ interrupt-parent = <&msm_gpio>;
+ interrupts = <13 0x2008>;
+ avdd-supply = <&pm8909_l17>;
+ vdd-supply = <&pm8909_l6>;
+ /* pins used by touchscreen */
+ pinctrl-names = "pmx_ts_active",
+ "pmx_ts_suspend","pmx_ts_release";
+ pinctrl-0 = <&ts_int_active &ts_reset_active>;
+ pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+ pinctrl-2 = <&ts_release>;
+ synaptics,irq-gpio = <&msm_gpio 13 0x2008>;
+ synaptics,reset-gpio = <&msm_gpio 12 0x0>;
+ synaptics,disable-gpios;
+ synaptics,display-coords = <0 0 719 1279>;
+ synaptics,panel-coords = <0 0 719 1405>;
+ };
+ };
+
+ i2c@78b6000 { /* BLSP1 QUP2 */
+ nq@28 {
+ compatible = "qcom,nq-nci";
+ reg = <0x28>;
+ qcom,nq-irq = <&msm_gpio 21 0x00>;
+ qcom,nq-ven = <&msm_gpio 20 0x00>;
+ qcom,nq-firm = <&msm_gpio 45 0x00>;
+ qcom,clk-src = "BBCLK2";
+ interrupt-parent = <&msm_gpio>;
+ interrupts = <21 0>;
+ interrupt-names = "nfc_irq";
+ pinctrl-names = "nfc_active","nfc_suspend";
+ pinctrl-0 = <&nfc_int_active &nfc_disable_active>;
+ pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>;
+ clocks = <&clock_rpm clk_bb_clk2_pin>;
+ clock-names = "ref_clk";
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+ pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
+ pinctrl-0 = <&gpio_key_active>;
+ pinctrl-1 = <&gpio_key_suspend>;
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&msm_gpio 91 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&msm_gpio 92 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&msm_gpio 90 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+
+ audio_codec_mtp: sound {
+ compatible = "qcom,msm8952-audio-codec";
+ qcom,model = "msm8909-snd-card";
+ reg = <0x7702000 0x4>,
+ <0x7702004 0x4>,
+ <0x7702008 0x4>;
+ reg-names = "csr_gp_io_mux_mic_ctl",
+ "csr_gp_io_mux_spkr_ctl",
+ "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel";
+
+ qcom,msm-snd-card-id = <0>;
+ qcom,msm-codec-type = "internal";
+ qcom,msm-ext-pa = "primary";
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,msm-hs-micbias-type = "internal";
+ qcom,msm-micbias1-ext-cap;
+ qcom,split-a2dp;
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "SPK_RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS Internal2", "Headset Mic",
+ "MIC BIAS External", "Secondary Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS Internal2",
+ "AMIC3", "MIC BIAS External";
+ qcom,msm-gpios =
+ "pri_i2s",
+ "us_eu_gpio";
+ qcom,pinctrl-names =
+ "all_off",
+ "pri_i2s_act",
+ "us_eu_gpio_act",
+ "pri_i2s_us_eu_gpio_act";
+ pinctrl-names =
+ "all_off",
+ "pri_i2s_act",
+ "us_eu_gpio_act",
+ "pri_i2s_us_eu_gpio_act";
+ pinctrl-0 = <&cdc_pdm_lines_sus &cross_conn_det_sus
+ &vdd_spkdrv_sus>;
+ pinctrl-1 = <&cdc_pdm_lines_act &cross_conn_det_sus
+ &vdd_spkdrv_act>;
+ pinctrl-2 = <&cdc_pdm_lines_sus &cross_conn_det_act
+ &vdd_spkdrv_sus>;
+ pinctrl-3 = <&cdc_pdm_lines_act &cross_conn_det_act
+ &vdd_spkdrv_act>;
+ qcom,cdc-us-euro-gpios = <&msm_gpio 97 0>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&lpa>,
+ <&voice_svc>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-pcm-lpa",
+ "msm-voice-svc";
+ asoc-cpu = <&dai_pri_auxpcm>,
+ <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>,
+ <&dai_mi2s3>, <&dai_mi2s5>, <&dai_mi2s6>,
+ <&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>,
+ <&int_fm_rx>, <&int_fm_tx>, <&afe_pcm_rx>,
+ <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>,
+ <&incall_music_rx>, <&incall_music_2_rx>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.5", "msm-dai-q6-mi2s.6",
+ "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+ "msm-dai-q6-dev.12290", "msm-dai-q6-dev.12292",
+ "msm-dai-q6-dev.12293", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770";
+ asoc-codec = <&stub_codec>, <&pm8909_conga_dig>;
+ asoc-codec-names = "msm-stub-codec.1", "cajon_codec";
+ };
+};
+
+&blsp1_uart1 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_console_sleep>;
+};
+
+&qcom_rng {
+ status = "okay";
+};
+
+&qcom_crypto {
+ status = "okay";
+};
+
+&qcom_cedev {
+ status = "okay";
+};
+
+&qcom_seecom {
+ status = "okay";
+};
+
+&qcom_tzlog {
+ status = "okay";
+};
+
+&qnand_1 {
+ status = "ok";
+};
+
+&sdhc_1 {
+ vdd-supply = <&pm8909_l8>;
+ qcom,vdd-voltage-level = <2900000 2900000>;
+ qcom,vdd-current-level = <200 400000>;
+
+ vdd-io-supply = <&pm8909_l5>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 60000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>;
+
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+
+ status = "ok";
+};
+
+&sdhc_2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msm_gpio 38 0>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msm_gpio 38 0x1>;
+
+ vdd-supply = <&pm8909_l11>;
+ qcom,vdd-voltage-level = <1800000 2950000>;
+ qcom,vdd-current-level = <15000 400000>;
+
+ vdd-io-supply = <&pm8909_l12>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 50000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
+
+ status = "ok";
+};
+
+&i2c_1 { /* BLSP1 QUP1 */
+};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&msm_gpio {
+ pmx_mdss {
+ mdss_dsi_active: mdss_dsi_active {
+ mux {
+ pins = "gpio25", "gpio37";
+ };
+ config {
+ pins = "gpio25", "gpio37";
+ };
+ };
+ mdss_dsi_suspend: mdss_dsi_suspend {
+ mux {
+ pins = "gpio25", "gpio37";
+ };
+ config {
+ pins = "gpio25", "gpio37";
+ };
+ };
+ };
+ pmx_mdss_te {
+ mdss_te_active: mdss_te_active {
+ mux {
+ pins = "gpio24";
+ };
+ config {
+ pins = "gpio24";
+ };
+ };
+ mdss_te_suspend: mdss_te_suspend {
+ mux {
+ pins = "gpio24";
+ };
+ config {
+ pins = "gpio24";
+ };
+ };
+ };
+ mpu6050_int_pin {
+ mpu6050_default: mpu6050_default {
+ mux {
+ pins = "gpio96";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio96";
+ drive-dtrength = <6>;
+ bias-pull-down;
+ };
+ };
+ mpu6050_sleep: mpu6050_sleep {
+ mux {
+ pins = "gpio96";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio96";
+ drive-dtrength = <2>;
+ bias-pull-down;
+ };
+ };
+ };
+ ak8963_int_pin {
+ ak8963_default: ak8963_default {
+ mux {
+ pins = "gpio65";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio65";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+ };
+ ak8963_sleep: ak8963_sleep {
+ mux {
+ pins = "gpio65";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio65";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+ };
+};
+
+/* CoreSight */
+&tpiu {
+ pinctrl-names = "sdcard", "trace", "swduart",
+ "swdtrc", "jtag", "spmi";
+ /* NIDnT */
+ pinctrl-0 = <&qdsd_clk_sdcard &qdsd_cmd_sdcard
+ &qdsd_data0_sdcard &qdsd_data1_sdcard
+ &qdsd_data2_sdcard &qdsd_data3_sdcard>;
+ pinctrl-1 = <&qdsd_clk_trace &qdsd_cmd_trace
+ &qdsd_data0_trace &qdsd_data1_trace
+ &qdsd_data2_trace &qdsd_data3_trace>;
+ pinctrl-2 = <&qdsd_cmd_swduart &qdsd_data0_swduart
+ &qdsd_data1_swduart &qdsd_data2_swduart
+ &qdsd_data3_swduart>;
+ pinctrl-3 = <&qdsd_clk_swdtrc &qdsd_cmd_swdtrc
+ &qdsd_data0_swdtrc &qdsd_data1_swdtrc
+ &qdsd_data2_swdtrc &qdsd_data3_swdtrc>;
+ pinctrl-4 = <&qdsd_cmd_jtag &qdsd_data0_jtag
+ &qdsd_data1_jtag &qdsd_data2_jtag
+ &qdsd_data3_jtag>;
+ pinctrl-5 = <&qdsd_clk_spmi &qdsd_cmd_spmi
+ &qdsd_data0_spmi &qdsd_data3_spmi>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8909-pinctrl.dtsi
new file mode 100644
index 0000000..25688ff
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-pinctrl.dtsi
@@ -0,0 +1,2193 @@
+/* Copyright (c) 2014-2018, 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.
+ */
+
+&soc {
+ msm_gpio: pinctrl@1000000 {
+ compatible = "qcom,msm8909-pinctrl";
+ reg = <0x1000000 0x300000>;
+ interrupts = <0 208 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ /* sensors */
+ cam_sensor_mclk0_default: cam_sensor_mclk0_default {
+ /* MCLK0 */
+ mux {
+ /* CLK, DATA */
+ pins = "gpio26";
+ function = "cam_mclk";
+ };
+
+ config {
+ pins = "gpio26";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_mclk0_sleep: cam_sensor_mclk0_sleep {
+ /* MCLK0 */
+ mux {
+ /* CLK, DATA */
+ pins = "gpio26";
+ function = "cam_mclk";
+ };
+
+ config {
+ pins = "gpio26";
+ bias-pull-down; /* PULL DOWN */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_rear_default: cam_sensor_rear_default {
+ /* RESET, STANDBY */
+ mux {
+ pins = "gpio35", "gpio34";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio35","gpio34";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_rear_sleep: cam_sensor_rear_sleep {
+ /* RESET, STANDBY */
+ mux {
+ pins = "gpio35","gpio34";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio35","gpio34";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_mclk1_default: cam_sensor_mclk1_default {
+ /* MCLK1 */
+ mux {
+ /* CLK, DATA */
+ pins = "gpio27";
+ function = "cam_mclk";
+ };
+
+ config {
+ pins = "gpio27";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_mclk1_sleep: cam_sensor_mclk1_sleep {
+ /* MCLK1 */
+ mux {
+ /* CLK, DATA */
+ pins = "gpio27";
+ function = "cam_mclk";
+ };
+
+ config {
+ pins = "gpio27";
+ bias-pull-down; /* PULL DOWN */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_front_default: cam_sensor_front_default {
+ /* RESET, STANDBY */
+ mux {
+ pins = "gpio28","gpio33";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio28","gpio33";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_front_sleep: cam_sensor_front_sleep {
+ /* RESET, STANDBY */
+ mux {
+ pins = "gpio28","gpio33";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio28","gpio33";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_flash_default: cam_sensor_flash_default {
+ /* FLASH_RESET,FLASH_EN,FLASH_NOW */
+ mux {
+ pins = "gpio36", "gpio31", "gpio32";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio36", "gpio31", "gpio32";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_flash_sleep: cam_sensor_flash_sleep {
+ mux {
+ pins = "gpio36", "gpio31", "gpio32";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio36", "gpio31", "gpio32";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ uart_console_active: uart_console_active {
+ mux {
+ pins = "gpio4", "gpio5";
+ function = "blsp_uart1";
+ };
+ config {
+ pins = "gpio4", "gpio5";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ uart_console_sleep: uart_console_sleep {
+ mux {
+ pins = "gpio4", "gpio5";
+ function = "blsp_uart1";
+ };
+ config {
+ pins = "gpio4", "gpio5";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ uart_console2_active: uart_console2_active {
+ mux {
+ pins = "gpio20", "gpio21";
+ function = "blsp_uart2";
+ };
+ config {
+ pins = "gpio20", "gpio21";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ uart_console2_sleep: uart_console2_sleep {
+ mux {
+ pins = "gpio20", "gpio21";
+ function = "blsp_uart2";
+ };
+ config {
+ pins = "gpio20", "gpio21";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ blsp1_uart2_tx_active: blsp1_uart2_tx_active {
+ mux {
+ pins = "gpio20";
+ function = "blsp_uart2";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart2_tx_sleep: blsp1_uart2_tx_sleep {
+ mux {
+ pins = "gpio20";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio20";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ blsp1_uart2_rxcts_active: blsp1_uart2_rxcts_active {
+ mux {
+ pins = "gpio21", "gpio111";
+ function = "blsp_uart2";
+ };
+
+ config {
+ pins = "gpio21", "gpio111";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart2_rxcts_sleep: blsp1_uart2_rxcts_sleep {
+ mux {
+ pins = "gpio21", "gpio111";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio21", "gpio111";
+ drive-strength = <2>;
+ bias-no-pull;
+ };
+ };
+
+ blsp1_uart2_rfr_active: blsp1_uart2_rfr_active {
+ mux {
+ pins = "gpio112";
+ function = "blsp_uart2";
+ };
+
+ config {
+ pins = "gpio112";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart2_rfr_sleep: blsp1_uart2_rfr_sleep {
+ mux {
+ pins = "gpio112";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio112";
+ drive-strength = <2>;
+ bias-no-pull;
+ };
+ };
+
+ pmx_mdss {
+ mdss_dsi_active: mdss_dsi_active {
+ mux {
+ pins = "gpio25", "gpio37";
+ function = "gpio";
+ };
+
+ config {
+ drive-strength = <8>; /* 8 mA */
+ bias-disable = <0>; /* no pull */
+ output-high;
+ };
+ };
+
+ mdss_dsi_suspend: mdss_dsi_suspend {
+ mux {
+ pins = "gpio25", "gpio37";
+ function = "gpio";
+ };
+
+ config {
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* pull down */
+ output-low;
+ };
+ };
+ };
+
+ pmx_mdss_te {
+ mdss_te_active: mdss_te_active {
+ mux {
+ pins = "gpio24";
+ function = "mdp_vsync";
+ };
+
+ config {
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* pull down */
+ };
+ };
+
+ mdss_te_suspend: mdss_te_suspend {
+ mux {
+ pins = "gpio24";
+ function = "mdp_vsync";
+ };
+
+ config {
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* pull down */
+ };
+ };
+ };
+
+ spi0 {
+ spi0_default: spi0_default {
+ mux {
+ pins = "gpio8", "gpio9",
+ "gpio11";
+ function = "blsp_spi6";
+ };
+ config {
+ pins = "gpio8", "gpio9",
+ "gpio11";
+ drive-strength = <12>; /* 12 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ spi0_sleep: spi0_sleep {
+ mux {
+ pins = "gpio8", "gpio9",
+ "gpio11";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio8", "gpio9",
+ "gpio11";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down; /* pull down */
+ };
+ };
+ spi0_cs0_active: spi0_cs0_active {
+ mux {
+ pins = "gpio10";
+ function = "blsp_spi6";
+ };
+ config {
+ pins = "gpio10";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ spi0_cs0_sleep: spi0_cs0_sleep {
+ mux {
+ pins = "gpio10";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio10";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ spi2 {
+ spi2_default: spi2_default {
+ mux {
+ pins = "gpio20", "gpio21",
+ "gpio112";
+ function = "blsp_spi2";
+ };
+ config {
+ pins = "gpio20", "gpio21",
+ "gpio112";
+ drive-strength = <12>; /* 12 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ spi2_sleep: spi2_sleep {
+ mux {
+ pins = "gpio20", "gpio21",
+ "gpio112";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio20", "gpio21",
+ "gpio112";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down; /* pull down */
+ };
+ };
+ spi2_cs0_active: spi2_cs0_active {
+ mux {
+ pins = "gpio111";
+ function = "blsp_spi2";
+ };
+ config {
+ pins = "gpio111";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ spi2_cs0_sleep: spi2_cs0_sleep {
+ mux {
+ pins = "gpio111";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio111";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ spi4 {
+ spi4_default: spi4_default {
+ mux {
+ pins = "gpio12", "gpio13",
+ "gpio15";
+ function = "blsp_spi4";
+ };
+ config {
+ pins = "gpio12", "gpio13",
+ "gpio15";
+ drive-strength = <12>; /* 12 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ spi4_sleep: spi4_sleep {
+ mux {
+ pins = "gpio12", "gpio13",
+ "gpio15";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio12", "gpio13",
+ "gpio15";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down; /* pull down */
+ };
+ };
+ spi4_cs0_active: spi4_cs0_active {
+ mux {
+ pins = "gpio14";
+ function = "blsp_spi4";
+ };
+ config {
+ pins = "gpio14";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ spi4_cs0_sleep: spi4_cs0_sleep {
+ mux {
+ pins = "gpio14";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio14";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ pmx_i2c_1 {
+ i2c_1_active: i2c_1_active {
+ mux {
+ pins = "gpio6", "gpio7";
+ function = "blsp_i2c1";
+ };
+ config {
+ pins = "gpio6", "gpio7";
+ drive-strength = <2>; /* 2 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ i2c_1_sleep: i2c_1_sleep {
+ mux {
+ pins = "gpio6", "gpio7";
+ function = "blsp_i2c1";
+ };
+ config {
+ pins = "gpio6", "gpio7";
+ drive-strength = <2>; /* 2 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ };
+
+ pmx_i2c_2 {
+ i2c_2_active: i2c_2_active {
+ mux {
+ pins = "gpio111", "gpio112";
+ function = "blsp_i2c2";
+ };
+ config {
+ pins = "gpio111", "gpio112";
+ drive-strength = <2>; /* 2 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ i2c_2_sleep: i2c_2_sleep {
+ mux {
+ pins = "gpio111", "gpio112";
+ function = "blsp_i2c2";
+ };
+ config {
+ pins = "gpio111", "gpio112";
+ drive-strength = <2>; /* 2 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ };
+
+ nfc {
+ nfcw_int_active: nfcw_int_active {
+ mux {
+ pins = "gpio50";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio50";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+ };
+
+ nfcw_int_suspend: nfcw_int_suspend {
+ mux {
+ pins = "gpio50";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio50";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+ };
+
+ nfcw_disable_active: nfcw_disable_active {
+ mux {
+ pins = "gpio36";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio36";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+ };
+
+ nfcw_disable_suspend: nfcw_disable_suspend {
+ mux {
+ pins = "gpio36";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio36";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ nfcv2k_disable_active: nfcv2k_disable_active {
+ mux {
+ pins = "gpio52";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio52";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+ };
+
+ nfcv2k_disable_suspend: nfcv2k_disable_suspend {
+ mux {
+ pins = "gpio52";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio52";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ nfc_int_active: nfc_int_active {
+ mux {
+ pins = "gpio21";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio21";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+ };
+
+ nfc_int_suspend: nfc_int_suspend {
+ mux {
+ pins = "gpio21";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio21";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+ };
+
+ nfc_disable_active: nfc_disable_active {
+ mux {
+ pins = "gpio20";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio20";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+ };
+
+ nfc_disable_suspend: nfc_disable_suspend {
+ mux {
+ pins = "gpio20";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio20";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ pmx_i2c_3 {
+ i2c_3_active: i2c_3_active {
+ mux {
+ pins = "gpio29", "gpio30";
+ function = "blsp_i2c3";
+ };
+ config {
+ pins = "gpio29", "gpio30";
+ drive-strength = <2>; /* 2 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ i2c_3_sleep: i2c_3_sleep {
+ mux {
+ pins = "gpio29", "gpio30";
+ function = "blsp_i2c3";
+ };
+ config {
+ pins = "gpio29", "gpio30";
+ drive-strength = <2>; /* 2 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ };
+
+ pmx_i2c_4 {
+ i2c_4_active: i2c_4_active {
+ mux {
+ pins = "gpio14", "gpio15";
+ function = "blsp_i2c4";
+ };
+ config {
+ pins = "gpio14", "gpio15";
+ drive-strength = <2>; /* 2 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ i2c_4_sleep: i2c_4_sleep {
+ mux {
+ pins = "gpio14", "gpio15";
+ function = "blsp_i2c4";
+ };
+ config {
+ pins = "gpio14", "gpio15";
+ drive-strength = <2>; /* 2 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ };
+
+ pmx_i2c_5 {
+ i2c_5_active: i2c_5_active {
+ mux {
+ pins = "gpio19", "gpio18";
+ function = "blsp_i2c5";
+ };
+ config {
+ pins = "gpio19", "gpio18";
+ drive-strength = <2>; /* 2 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ i2c_5_sleep: i2c_5_sleep {
+ mux {
+ pins = "gpio19", "gpio18";
+ function = "blsp_i2c5";
+ };
+ config {
+ pins = "gpio19", "gpio18";
+ drive-strength = <2>; /* 2 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ };
+
+ smb_int_pin {
+ smb_int_default: smb_int_default {
+ mux {
+ pins = "gpio58";
+ function ="smb_int";
+ };
+ config {
+ pins = "gpio58";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-up; /* PULL UP*/
+ };
+ };
+ smb_int_sleep: smb_int_sleep {
+ mux {
+ pins = "gpio58";
+ function ="smb_int";
+ };
+ config {
+ pins = "gpio58";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-up; /* PULL UP*/
+ };
+ };
+ };
+
+ pmx_sdc1_clk {
+ sdc1_clk_on: sdc1_clk_on {
+ config {
+ pins = "sdc1_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <16>; /* 16 MA */
+ };
+ };
+ sdc1_clk_off: sdc1_clk_off {
+ config {
+ pins = "sdc1_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ pmx_sdc1_cmd {
+ sdc1_cmd_on: sdc1_cmd_on {
+ config {
+ pins = "sdc1_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+ sdc1_cmd_off: sdc1_cmd_off {
+ config {
+ pins = "sdc1_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ pmx_sdc1_data {
+ sdc1_data_on: sdc1_data_on {
+ config {
+ pins = "sdc1_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+ sdc1_data_off: sdc1_data_off {
+ config {
+ pins = "sdc1_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ pmx_sdc2_clk {
+ sdc2_clk_on: sdc2_clk_on {
+ config {
+ pins = "sdc2_clk";
+ drive-strength = <16>; /* 16 MA */
+ bias-disable; /* NO pull */
+ };
+ };
+ sdc2_clk_off: sdc2_clk_off {
+ config {
+ pins = "sdc2_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ pmx_sdc2_cmd {
+ sdc2_cmd_on: sdc2_cmd_on {
+ config {
+ pins = "sdc2_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+ sdc2_cmd_off: sdc2_cmd_off {
+ config {
+ pins = "sdc2_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ pmx_sdc2_data {
+ sdc2_data_on: sdc2_data_on {
+ config {
+ pins = "sdc2_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+ sdc2_data_off: sdc2_data_off {
+ config {
+ pins = "sdc2_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ sdhc2_cd_pin {
+ sdc2_cd_on: cd_on {
+ mux {
+ pins = "gpio38";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio38";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ sdc2_cd_off: cd_off {
+ mux {
+ pins = "gpio38";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio38";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* add pingrp for touchscreen */
+ pmx_ts_int_active {
+ ts_int_active: ts_int_active {
+ mux {
+ pins = "gpio13";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio13";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ pmx_ts_int_suspend {
+ ts_int_suspend: ts_int_suspend {
+ mux {
+ pins = "gpio13";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio13";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+ };
+
+ pmx_ts_reset_active {
+ ts_reset_active: ts_reset_active {
+ mux {
+ pins = "gpio12";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio12";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ pmx_ts_reset_suspend {
+ ts_reset_suspend: ts_reset_suspend {
+ mux {
+ pins = "gpio12";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio12";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+ };
+
+ /* Pinctrl dt nodes for reset gpio for ITE tech controller */
+ pmx_ts_ite_reset_active {
+ ts_ite_reset_active: ts_ite_reset_active {
+ mux {
+ pins = "gpio12";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio12";
+ drive-strength = <8>;
+ bias-pull-down;
+ output-high;
+ };
+ };
+ };
+
+ pmx_ts_ite_reset_suspend {
+ ts_ite_reset_suspend: ts_ite_reset_suspend {
+ mux {
+ pins = "gpio12";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio12";
+ drive-strength = <2>;
+ bias-pull-down;
+ output-low;
+ };
+ };
+ };
+
+ pmx_ts_release {
+ ts_release: ts_release {
+ mux {
+ pins = "gpio13", "gpio12";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio13", "gpio12";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+ };
+
+ tlmm_gpio_key {
+ gpio_key_active: gpio_key_active {
+ mux {
+ pins = "gpio90", "gpio91", "gpio92";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio90", "gpio91", "gpio92";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ gpio_key_suspend: gpio_key_suspend {
+ mux {
+ pins = "gpio90", "gpio91", "gpio92";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio90", "gpio91", "gpio92";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ wcnss_pmux_5wire {
+ wcnss_default: wcnss_default {
+ wcss_wlan2 {
+ pins = "gpio40";
+ function = "wcss_wlan2";
+ };
+ wcss_wlan1 {
+ pins = "gpio41";
+ function = "wcss_wlan1";
+ };
+ wcss_wlan0 {
+ pins = "gpio42";
+ function = "wcss_wlan0";
+ };
+ wcss_wlan {
+ pins = "gpio43", "gpio44";
+ function = "wcss_wlan";
+ };
+ config {
+ pins = "gpio40", "gpio41",
+ "gpio42", "gpio43",
+ "gpio44";
+ drive-strength = <6>; /* 6 MA */
+ bias-pull-up; /* PULL UP */
+ };
+ };
+
+ wcnss_sleep: wcnss_sleep {
+ wcss_wlan2 {
+ pins = "gpio40";
+ function = "wcss_wlan2";
+ };
+ wcss_wlan1 {
+ pins = "gpio41";
+ function = "wcss_wlan1";
+ };
+ wcss_wlan0 {
+ pins = "gpio42";
+ function = "wcss_wlan0";
+ };
+ wcss_wlan {
+ pins = "gpio43", "gpio44";
+ function = "wcss_wlan";
+ };
+
+ config {
+ pins = "gpio40", "gpio41",
+ "gpio42", "gpio43",
+ "gpio44";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down; /* PULL Down */
+ };
+ };
+ };
+
+ wcnss_pmux_gpio: wcnss_pmux_gpio {
+ wcnss_gpio_default: wcnss_gpio_default {
+ mux {
+ pins = "gpio40", "gpio41",
+ "gpio42", "gpio43",
+ "gpio44";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio40", "gpio41",
+ "gpio42", "gpio43",
+ "gpio44";
+ drive-strength = <6>; /* 6 MA */
+ bias-pull-up; /* PULL UP */
+ };
+ };
+ };
+
+ trigout_a0: trigout_a0 {
+ mux {
+ pins = "gpio23";
+ function = "qdss_cti_trig_out_a0";
+ };
+
+ config {
+ pins = "gpio23";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ pmx_qdsd_clk {
+ qdsd_clk_sdcard: clk_sdcard {
+ config {
+ pins = "qdsd_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <7>; /* 7 MA */
+ };
+ };
+ qdsd_clk_trace: clk_trace {
+ config {
+ pins = "qdsd_clk";
+ bias-pull-down; /* pull down */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_clk_swdtrc: clk_swdtrc {
+ config {
+ pins = "qdsd_clk";
+ bias-pull-down; /* pull down */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_clk_spmi: clk_spmi {
+ config {
+ pins = "qdsd_clk";
+ bias-pull-down; /* pull down */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ };
+
+ pmx_qdsd_cmd {
+ qdsd_cmd_sdcard: cmd_sdcard {
+ config {
+ pins = "qdsd_cmd";
+ bias-pull-down; /* pull down */
+ drive-strength = <3>; /* 3 MA */
+ };
+ };
+ qdsd_cmd_trace: cmd_trace {
+ config {
+ pins = "qdsd_cmd";
+ bias-pull-down; /* pull down */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_cmd_swduart: cmd_uart {
+ config {
+ pins = "qdsd_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_cmd_swdtrc: cmd_swdtrc {
+ config {
+ pins = "qdsd_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_cmd_jtag: cmd_jtag {
+ config {
+ pins = "qdsd_cmd";
+ bias-disable; /* NO pull */
+ drive-strength = <3>; /* 3 MA */
+ };
+ };
+ qdsd_cmd_spmi: cmd_spmi {
+ config {
+ pins = "qdsd_cmd";
+ bias-pull-down; /* pull down */
+ drive-strength = <4>; /* 4 MA */
+ };
+ };
+ };
+
+ pmx_qdsd_data0 {
+ qdsd_data0_sdcard: data0_sdcard {
+ config {
+ pins = "qdsd_data0";
+ bias-pull-down; /* pull down */
+ drive-strength = <3>; /* 3 MA */
+ };
+ };
+ qdsd_data0_trace: data0_trace {
+ config {
+ pins = "qdsd_data0";
+ bias-pull-down; /* pull down */
+ drive-strength = <3>; /* 3 MA */
+ };
+ };
+ qdsd_data0_swduart: data0_uart {
+ config {
+ pins = "qdsd_data0";
+ bias-pull-down; /* pull down */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_data0_swdtrc: data0_swdtrc {
+ config {
+ pins = "qdsd_data0";
+ bias-pull-down; /* pull down */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_data0_jtag: data0_jtag {
+ config {
+ pins = "qdsd_data0";
+ bias-pull-up; /* pull up */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_data0_spmi: data0_spmi {
+ config {
+ pins = "qdsd_data0";
+ bias-pull-down; /* pull down */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ };
+
+ pmx_qdsd_data1 {
+ qdsd_data1_sdcard: data1_sdcard {
+ config {
+ pins = "qdsd_data1";
+ bias-pull-down; /* pull down */
+ drive-strength = <3>; /* 3 MA */
+ };
+ };
+ qdsd_data1_trace: data1_trace {
+ config {
+ pins = "qdsd_data1";
+ bias-pull-down; /* pull down */
+ drive-strength = <3>; /* 3 MA */
+ };
+ };
+ qdsd_data1_swduart: data1_uart {
+ config {
+ pins = "qdsd_data1";
+ bias-pull-down; /* pull down */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_data1_swdtrc: data1_swdtrc {
+ config {
+ pins = "qdsd_data1";
+ bias-pull-down; /* pull down */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_data1_jtag: data1_jtag {
+ config {
+ pins = "qdsd_data1";
+ bias-pull-down; /* pull down */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ };
+
+ pmx_qdsd_data2 {
+ qdsd_data2_sdcard: data2_sdcard {
+ config {
+ pins = "qdsd_data2";
+ bias-pull-down; /* pull down */
+ drive-strength = <3>; /* 3 MA */
+ };
+ };
+ qdsd_data2_trace: data2_trace {
+ config {
+ pins = "qdsd_data2";
+ bias-pull-down; /* pull down */
+ drive-strength = <3>; /* 3 MA */
+ };
+ };
+ qdsd_data2_swduart: data2_uart {
+ config {
+ pins = "qdsd_data2";
+ bias-pull-down; /* pull down */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_data2_swdtrc: data2_swdtrc {
+ config {
+ pins = "qdsd_data2";
+ bias-pull-down; /* pull down */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_data2_jtag: data2_jtag {
+ config {
+ pins = "qdsd_data2";
+ bias-pull-up; /* pull up */
+ drive-strength = <3>; /* 3 MA */
+ };
+ };
+ };
+
+ pmx_qdsd_data3 {
+ qdsd_data3_sdcard: data3_sdcard {
+ config {
+ pins = "qdsd_data3";
+ bias-pull-down; /* pull down */
+ drive-strength = <3>; /* 3 MA */
+ };
+ };
+ qdsd_data3_trace: data3_trace {
+ config {
+ pins = "qdsd_data3";
+ bias-pull-down; /* pull down */
+ drive-strength = <3>; /* 3 MA */
+ };
+ };
+ qdsd_data3_swduart: data3_uart {
+ config {
+ pins = "qdsd_data3";
+ bias-pull-up; /* pull up */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_data3_swdtrc: data3_swdtrc {
+ config {
+ pins = "qdsd_data3";
+ bias-pull-up; /* pull up */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_data3_jtag: data3_jtag {
+ config {
+ pins = "qdsd_data3";
+ bias-pull-up; /* pull up */
+ drive-strength = <0>; /* 0 MA */
+ };
+ };
+ qdsd_data3_spmi: data3_spmi {
+ config {
+ pins = "qdsd_data3";
+ bias-pull-down; /* pull down */
+ drive-strength = <3>; /* 3 MA */
+ };
+ };
+ };
+
+ /* CoreSight */
+ tpiu_seta_1 {
+ seta_1: seta {
+ mux {
+ pins = "gpio6";
+ function = "qdss_traceclk_a";
+ };
+ config {
+ pins = "gpio6";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_2 {
+ seta_2: seta {
+ mux {
+ pins = "gpio8";
+ function = "qdss_tracectl_a";
+ };
+ config {
+ pins = "gpio8";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_3 {
+ seta_3: seta {
+ mux {
+ pins = "gpio9";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio9";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_4 {
+ seta_4: seta {
+ mux {
+ pins = "gpio10";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio10";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_5 {
+ seta_5: seta {
+ mux {
+ pins = "gpio39";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio39";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_6 {
+ seta_6: seta {
+ mux {
+ pins = "gpio40";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio40";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_7 {
+ seta_7: seta {
+ mux {
+ pins = "gpio41";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio41";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_8 {
+ seta_8: seta {
+ mux {
+ pins = "gpio42";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio42";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_9 {
+ seta_9: seta {
+ mux {
+ pins = "gpio43";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio43";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_10 {
+ seta_10: seta {
+ mux {
+ pins = "gpio45";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio45";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_11 {
+ seta_11: seta {
+ mux {
+ pins = "gpio46";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio46";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_12 {
+ seta_12: seta {
+ mux {
+ pins = "gpio47";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio47";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_13 {
+ seta_13: seta {
+ mux {
+ pins = "gpio48";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio48";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_14 {
+ seta_14: seta {
+ mux {
+ pins = "gpio58";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio58";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_15 {
+ seta_15: seta {
+ mux {
+ pins = "gpio65";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio65";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_16 {
+ seta_16: seta {
+ mux {
+ pins = "gpio94";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio94";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_17 {
+ seta_17: seta {
+ mux {
+ pins = "gpio96";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio96";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_seta_18 {
+ seta_18: seta {
+ mux {
+ pins = "gpio97";
+ function = "qdss_tracedata_a";
+ };
+ config {
+ pins = "gpio97";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_1 {
+ setb_1: setb {
+ mux {
+ pins = "gpio4";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio4";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_2 {
+ setb_2: setb {
+ mux {
+ pins = "gpio5";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio5";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_3 {
+ setb_3: setb {
+ mux {
+ pins = "gpio14";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio14";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_4 {
+ setb_4: setb {
+ mux {
+ pins = "gpio16";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio16";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_5 {
+ setb_5: setb {
+ mux {
+ pins = "gpio17";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio17";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_6 {
+ setb_6: setb {
+ mux {
+ pins = "gpio26";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio26";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_7 {
+ setb_7: setb {
+ mux {
+ pins = "gpio27";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio27";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_8 {
+ setb_8: setb {
+ mux {
+ pins = "gpio28";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio28";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_9 {
+ setb_9: setb {
+ mux {
+ pins = "gpio29";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio29";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_10 {
+ setb_10: setb {
+ mux {
+ pins = "gpio30";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio30";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_11 {
+ setb_11: setb {
+ mux {
+ pins = "gpio31";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio31";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_12 {
+ setb_12: setb {
+ mux {
+ pins = "gpio32";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio32";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_13 {
+ setb_13: setb {
+ mux {
+ pins = "gpio33";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio33";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_14 {
+ setb_14: setb {
+ mux {
+ pins = "gpio34";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio34";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_15 {
+ setb_15: setb {
+ mux {
+ pins = "gpio35";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio35";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_16 {
+ setb_16: setb {
+ mux {
+ pins = "gpio36";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio36";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_17 {
+ setb_17: setb {
+ mux {
+ pins = "gpio37";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio37";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ tpiu_setb_18 {
+ setb_18: setb {
+ mux {
+ pins = "gpio93";
+ function = "qdss_tracedata_b";
+ };
+ config {
+ pins = "gpio93";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+
+ vdd_spkdrv {
+ vdd_spkdrv_act: vdd_spkdrv_on {
+ mux {
+ pins = "gpio4";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio4";
+ drive-strength = <8>;
+ };
+ };
+ vdd_spkdrv_sus: vdd_spkdrv_off {
+ mux {
+ pins = "gpio4";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio4";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ cdc-dmic-lines {
+ cdc_dmic0_clk_act: dmic0_clk_on {
+ mux {
+ pins = "gpio4";
+ function = "dmic0_clk";
+ };
+
+ config {
+ pins = "gpio4";
+ drive-strength = <8>;
+ bias-pull-none;
+ };
+ };
+
+ cdc_dmic0_clk_sus: dmic0_clk_off {
+ mux {
+ pins = "gpio4";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio4";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ cdc_dmic0_data_act: dmic0_data_on {
+ mux {
+ pins = "gpio5";
+ function = "dmic0_data";
+ };
+
+ config {
+ pins = "gpio5";
+ drive-strength = <8>;
+ bias-pull-none;
+ };
+ };
+
+ cdc_dmic0_data_sus: dmic0_data_off {
+ mux {
+ pins = "gpio5";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio5";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ cdc-pdm-lines {
+ cdc_pdm_lines_act: pdm_lines_on {
+ mux {
+ pins = "gpio59", "gpio60", "gpio61",
+ "gpio62", "gpio63", "gpio64";
+ function = "cdc_pdm0";
+ };
+
+ config {
+ pins = "gpio59", "gpio60", "gpio61",
+ "gpio62", "gpio63", "gpio64";
+ drive-strength = <8>;
+ };
+ };
+ cdc_pdm_lines_sus: pdm_lines_off {
+ mux {
+ pins = "gpio59", "gpio60", "gpio61",
+ "gpio62", "gpio63", "gpio64";
+ function = "cdc_pdm0";
+ };
+
+ config {
+ pins = "gpio59", "gpio60", "gpio61",
+ "gpio62", "gpio63", "gpio64";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ cross-conn-det {
+ cross_conn_det_act: lines_on {
+ mux {
+ pins = "gpio97";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio97";
+ drive-strength = <8>;
+ output-low;
+ bias-pull-down;
+ };
+ };
+
+ cross_conn_det_sus: lines_off {
+ mux {
+ pins = "gpio97";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio97";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+ };
+
+ pmx_i2s_mclk {
+ label = "i2s_mclk";
+ i2s_mclk_active: i2s_mclk_active {
+ mux {
+ pins = "gpio59";
+ function = "pri_mi2s_mclk_a";
+ };
+ config {
+ pins = "gpio59";
+ drive-strength = <8>; /* 8 MA */
+ bias-disable; /* No PULL */
+ output-high;
+ };
+ };
+
+ i2s_mclk_sleep: i2s_mclk_sleep {
+ mux {
+ pins = "gpio59";
+ function = "pri_mi2s_mclk_a";
+ };
+ configs {
+ pins = "gpio59";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ };
+
+ pmx_pri_mi2s {
+ label = "pri_mi2s";
+ pri_mi2s_active: pri_mi2s_active {
+ mux {
+ pins = "gpio60";
+ function = "pri_mi2s_sck_a";
+ };
+ configs {
+ pins = "gpio60";
+ drive-strength = <8>; /* 8 MA */
+ bias-disable; /* No PULL */
+ output-high;
+ };
+ };
+ pri_mi2s_sleep: pri_mi2s_sleep {
+ mux {
+ pins = "gpio60";
+ function = "pri_mi2s_sck_a";
+ };
+ configs {
+ pins = "gpio60";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+
+ pri_mi2s_ws_active: pri_mi2s_ws_active {
+ mux {
+ pins = "gpio61";
+ function = "pri_mi2s_ws_a";
+ };
+
+ config {
+ pins = "gpio61";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+
+ pri_mi2s_ws_sleep: pri_mi2s_ws_sleep {
+ mux {
+ pins = "gpio61";
+ function = "pri_mi2s_ws_a";
+ };
+
+ config {
+ pins = "gpio61";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+
+ pri_mi2s_dout_active: pri_mi2s_dout_active {
+ mux {
+ pins = "gpio63";
+ function = "pri_mi2s_data1_a";
+ };
+
+ config {
+ pins = "gpio63";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL*/
+ output-high;
+ };
+ };
+
+ pri_mi2s_dout_sleep: pri_mi2s_dout_sleep {
+ mux {
+ pins = "gpio63";
+ function = "pri_mi2s_data1_a";
+ };
+
+ config {
+ pins = "gpio63";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+
+ pri_mi2s_din_sleep: pri_mi2s_din_sleep {
+ mux {
+ pins = "gpio62";
+ function = "pri_mi2s_data0_a";
+ };
+
+ config {
+ pins = "gpio62";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+
+ pri_mi2s_din_active: pri_mi2s_din_active {
+ mux {
+ pins = "gpio62";
+ function = "pri_mi2s_data0_a";
+ };
+
+ config {
+ pins = "gpio62";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ pmx_quat_mi2s {
+ label = "quat_mi2s";
+ quat_mi2s_active: quat_mi2s_active {
+ mux {
+ pins = "gpio0", "gpio1";
+ function = "sec_mi2s";
+ };
+ configs {
+ pins = "gpio0", "gpio1";
+ drive-strength = <8>; /* 8 MA */
+ bias-disable; /* No PULL */
+ };
+ };
+ quat_mi2s_sleep: quat_mi2s_sleep {
+ mux {
+ pins = "gpio0", "gpio1";
+ function = "sec_mi2s";
+ };
+ configs {
+ pins = "gpio0", "gpio1";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ };
+
+ pmx_quat_mi2s_din {
+ label = "quat_mi2s_din";
+ quat_mi2s_din_active: quat_mi2s_din_active {
+ mux {
+ pins = "gpio2", "gpio3";
+ function = "sec_mi2s";
+ };
+ configs {
+ pins = "gpio2", "gpio3";
+ drive-strength = <8>; /* 8 MA */
+ bias-disable; /* No PULL */
+ output-high;
+ };
+ };
+ quat_mi2s_din_sleep: quat_mi2s_din_sleep {
+ mux {
+ pins = "gpio2", "gpio3";
+ function = "sec_mi2s";
+ };
+ configs {
+ pins = "gpio2", "gpio3";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ };
+
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-pm660-pm.dtsi b/arch/arm64/boot/dts/qcom/msm8909-pm660-pm.dtsi
new file mode 100644
index 0000000..dc2e850
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-pm660-pm.dtsi
@@ -0,0 +1,303 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/msm/pm.h>
+
+&soc {
+ qcom,spm@b089000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xb089000 0x1000>;
+ qcom,name = "cpu0";
+ qcom,cpu = <&CPU0>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-spm-dly= <0x3c102800>;
+ qcom,saw2-spm-ctl = <0xe>;
+ qcom,mode0 {
+ qcom,label = "qcom,saw2-spm-cmd-wfi";
+ qcom,sequence = [60 03 60 0b 0f];
+ qcom,spm_en;
+ };
+ qcom,mode1 {
+ qcom,label = "qcom,saw2-spm-cmd-spc";
+ qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,spm_en;
+ qcom,pc_mode;
+ };
+ qcom,mode2 {
+ qcom,label = "qcom,saw2-spm-cmd-pc";
+ qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,spm_en;
+ qcom,pc_mode;
+ };
+ };
+
+ qcom,spm@b099000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xb099000 0x1000>;
+ qcom,name = "cpu1";
+ qcom,cpu = <&CPU1>;
+ qcom,core-id = <1>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-spm-dly= <0x3c102800>;
+ qcom,saw2-spm-ctl = <0xe>;
+ qcom,mode0 {
+ qcom,label = "qcom,saw2-spm-cmd-wfi";
+ qcom,sequence = [60 03 60 0b 0f];
+ qcom,spm_en;
+ };
+ qcom,mode1 {
+ qcom,label = "qcom,saw2-spm-cmd-spc";
+ qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,spm_en;
+ qcom,pc_mode;
+ };
+ qcom,mode2 {
+ qcom,label = "qcom,saw2-spm-cmd-pc";
+ qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,spm_en;
+ qcom,pc_mode;
+ };
+ };
+
+ qcom,spm@b0a9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xb0a9000 0x1000>;
+ qcom,name = "cpu2";
+ qcom,cpu = <&CPU2>;
+ qcom,core-id = <2>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-spm-dly= <0x3c102800>;
+ qcom,saw2-spm-ctl = <0xe>;
+ qcom,mode0 {
+ qcom,label = "qcom,saw2-spm-cmd-wfi";
+ qcom,sequence = [60 03 60 0b 0f];
+ qcom,spm_en;
+ };
+ qcom,mode1 {
+ qcom,label = "qcom,saw2-spm-cmd-spc";
+ qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,spm_en;
+ qcom,pc_mode;
+ };
+ qcom,mode2 {
+ qcom,label = "qcom,saw2-spm-cmd-pc";
+ qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,spm_en;
+ qcom,pc_mode;
+ };
+ };
+
+ qcom,spm@b0b9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xb0b9000 0x1000>;
+ qcom,name = "cpu3";
+ qcom,cpu = <&CPU3>;
+ qcom,core-id = <3>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-spm-dly= <0x3c102800>;
+ qcom,saw2-spm-ctl = <0xe>;
+ qcom,mode0 {
+ qcom,label = "qcom,saw2-spm-cmd-wfi";
+ qcom,sequence = [60 03 60 0b 0f];
+ qcom,spm_en;
+ };
+ qcom,mode1 {
+ qcom,label = "qcom,saw2-spm-cmd-spc";
+ qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,spm_en;
+ qcom,pc_mode;
+ };
+ qcom,mode2 {
+ qcom,label = "qcom,saw2-spm-cmd-pc";
+ qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,spm_en;
+ qcom,pc_mode;
+ };
+ };
+
+ qcom,spm@b012000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xb012000 0x1000>;
+ qcom,name = "system-l2";
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x14>;
+ qcom,saw2-spm-dly= <0x3c102800>;
+ qcom,saw2-spm-ctl = <0xe>;
+ qcom,saw2-pmic-data0 = <0x05030080>;
+ qcom,saw2-pmic-data1 = <0x00030000>;
+ qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
+ qcom,vctl-timeout-us = <500>;
+ qcom,vctl-port = <0x0>;
+ qcom,vctl-port-ub = <0x1>;
+ qcom,pfm-port = <0x2>;
+ qcom,mode0 {
+ qcom,label = "qcom,saw2-spm-cmd-ret";
+ qcom,sequence = [00 03 00 0f];
+ qcom,spm_en;
+ };
+ qcom,mode1 {
+ qcom,label = "qcom,saw2-spm-cmd-gdhs";
+ qcom,sequence = [00 20 32 6b c0 e0 d0 42 03 50 4e 02
+ 02 d0 e0 c0 22 6b 02 32 50 0f];
+ qcom,spm_en;
+ qcom,pc_mode;
+ };
+ qcom,mode2 {
+ qcom,label = "qcom,saw2-spm-cmd-pc";
+ qcom,sequence = [00 20 32 b0 6b c0 e0 d0 42 11 07
+ 01 b0 50 4e 02 02 d0 e0 c0 22 6b 02 32 52
+ 0f]; /*APC_L2RAM_ON */
+ qcom,spm_en;
+ qcom,pc_mode;
+ };
+ };
+
+ qcom,lpm-levels {
+ compatible = "qcom,lpm-levels";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,pm-cluster@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ label = "system";
+ qcom,spm-device-names = "l2";
+ qcom,default-level = <0>;
+
+ qcom,pm-cluster-level@0 {
+ reg = <0>;
+ label = "l2-cache-active";
+ qcom,spm-l2-mode = "active";
+ qcom,latency-us = <270>;
+ qcom,ss-power = <455>;
+ qcom,energy-overhead = <250621>;
+ qcom,time-overhead = <500>;
+ };
+
+ qcom,pm-cluster-level@1{
+ reg = <1>;
+ label = "l2-gdhs";
+ qcom,spm-l2-mode = "gdhs";
+ qcom,latency-us = <500>;
+ qcom,ss-power = <427>;
+ qcom,energy-overhead = <431578>;
+ qcom,time-overhead = <900>;
+ qcom,min-child-idx = <1>;
+ qcom,reset-level = <LPM_RESET_LVL_GDHS>;
+ };
+
+ qcom,pm-cluster-level@2{
+ reg = <2>;
+ label = "l2-pc";
+ qcom,spm-l2-mode = "pc";
+ qcom,latency-us = <11530>;
+ qcom,ss-power = <400>;
+ qcom,energy-overhead = <800000>;
+ qcom,time-overhead = <2500>;
+ qcom,min-child-idx = <2>;
+ qcom,notify-rpm;
+ qcom,no-cache-flush;
+ qcom,reset-level = <LPM_RESET_LVL_PC>;
+ };
+
+ qcom,pm-cpu {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,pm-cpu-level@0{
+ reg = <0>;
+ qcom,spm-cpu-mode = "wfi";
+ qcom,latency-us = <1>;
+ qcom,ss-power = <473>;
+ qcom,energy-overhead = <100000>;
+ qcom,time-overhead = <50>;
+ };
+
+ qcom,pm-cpu-level@1 {
+ reg = <1>;
+ qcom,spm-cpu-mode = "standalone_pc";
+ qcom,latency-us = <240>;
+ qcom,ss-power = <467>;
+ qcom,energy-overhead = <202781>;
+ qcom,time-overhead = <420>;
+ qcom,use-broadcast-timer;
+ qcom,reset-level =
+ <LPM_RESET_LVL_PC>;
+ };
+
+ qcom,pm-cpu-level@2 {
+ reg = <2>;
+ qcom,spm-cpu-mode = "pc";
+ qcom,latency-us = <270>;
+ qcom,ss-power = <455>;
+ qcom,energy-overhead = <250621>;
+ qcom,time-overhead = <500>;
+ qcom,use-broadcast-timer;
+ qcom,reset-level =
+ <LPM_RESET_LVL_PC>;
+ };
+ };
+ };
+ };
+
+ qcom,pm@8600664 {
+ compatible = "qcom,pm";
+ reg = <0x8600664 0x40>;
+ clocks = <&clock_cpu clk_a7ssmux>,
+ <&clock_cpu clk_a7ssmux>,
+ <&clock_cpu clk_a7ssmux>,
+ <&clock_cpu clk_a7ssmux>;
+ clock-names = "cpu0_clk", "cpu1_clk",
+ "cpu2_clk", "cpu3_clk";
+ qcom,pc-mode = "tz_l2_int";
+ qcom,use-sync-timer;
+ qcom,synced-clocks;
+ };
+
+ qcom,rpm-stats@29dba0 {
+ compatible = "qcom,rpm-stats";
+ reg = <0x29dba0 0x1000>;
+ reg-names = "phys_addr_base";
+ qcom,sleep-stats-version = <2>;
+ };
+
+ qcom,rpm-master-stats@60150 {
+ compatible = "qcom,rpm-master-stats";
+ reg = <0x60150 0x2030>;
+ qcom,masters = "APSS", "MPSS", "PRONTO";
+ qcom,master-stats-version = <2>;
+ qcom,master-offset = <4096>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8909-regulator.dtsi
new file mode 100644
index 0000000..7197f88
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-regulator.dtsi
@@ -0,0 +1,280 @@
+/* Copyright (c) 2014-2015, 2018 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.
+ */
+
+/* RPM controlled regulators */
+&rpm_bus {
+ rpm-regulator-smpa1 {
+ status = "okay";
+ pm8909_s1_corner: regulator-s1-corner {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_s1_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ };
+ pm8909_s1_corner_ao: regulator-s1-corner-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_s1_corner_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ };
+ pm8909_s1_floor_corner: regulator-s1-floor-corner {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_s1_floor_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-floor-corner;
+ qcom,always-send-voltage;
+ };
+ pm8909_s1_corner_so: regulator-s1-corner-so {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_s1_corner_so";
+ qcom,set = <2>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,init-voltage = <1>;
+ qcom,use-voltage-corner;
+ };
+ };
+
+ rpm-regulator-smpa2 {
+ status = "okay";
+ pm8909_s2: regulator-s2 {
+ status = "okay";
+ regulator-min-microvolt = <1850000>;
+ regulator-max-microvolt = <1850000>;
+ qcom,init-voltage = <1850000>;
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ status = "okay";
+ pm8909_l1: regulator-l1 {
+ status = "okay";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ qcom,init-voltage = <1000000>;
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ status = "okay";
+ pm8909_l2: regulator-l2 {
+ status = "okay";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <12000000>;
+ };
+ };
+
+ /* PM8909 L3 VDD_MX supply */
+ rpm-regulator-ldoa3 {
+ status = "okay";
+ pm8909_l3: regulator-l3 {
+ status = "okay";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1350000>;
+ };
+
+ pm8909_l3_corner_ao: regulator-l3-corner-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l3_corner_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ };
+
+ pm8909_l3_corner_so: regulator-l3-corner-so {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l3_corner_so";
+ qcom,set = <2>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,init-voltage = <1>;
+ qcom,use-voltage-corner;
+ };
+ };
+
+ rpm-regulator-ldoa4 {
+ status = "okay";
+ pm8909_l4: regulator-l4 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ status = "okay";
+ pm8909_l5: regulator-l5 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ status = "okay";
+ pm8909_l6: regulator-l6 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ status = "okay";
+ pm8909_l7: regulator-l7 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ };
+
+ pm8909_l7_ao: regulator-l7-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l7_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ };
+
+ pm8909_l7_so: regulator-l7-so {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l7_so";
+ qcom,set = <2>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-enable = <0>;
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ status = "okay";
+ pm8909_l8: regulator-l8 {
+ status = "okay";
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2900000>;
+ qcom,init-voltage = <2850000>;
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ status = "okay";
+ pm8909_l9: regulator-l9 {
+ status = "okay";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <3000000>;
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ status = "okay";
+ pm8909_l10: regulator-l10 {
+ status = "okay";
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,init-voltage = <1225000>;
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ status = "okay";
+ pm8909_l11: regulator-l11 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <1800000>;
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ status = "okay";
+ pm8909_l12: regulator-l12 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <1800000>;
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ status = "okay";
+ pm8909_l13: regulator-l13 {
+ status = "okay";
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ qcom,init-voltage = <3075000>;
+ };
+ };
+
+ rpm-regulator-ldoa14 {
+ status = "okay";
+ pm8909_l14: regulator-l14 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,init-voltage = <1800000>;
+ };
+ };
+
+ rpm-regulator-ldoa15 {
+ status = "okay";
+ pm8909_l15: regulator-l15 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,init-voltage = <1800000>;
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ status = "okay";
+ pm8909_l17: regulator-l17 {
+ status = "okay";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,init-voltage = <2800000>;
+ };
+ };
+
+ rpm-regulator-ldoa18 {
+ status = "okay";
+ pm8909_l18: regulator-l18 {
+ status = "okay";
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ qcom,init-voltage = <2700000>;
+ };
+ };
+};
+
+&soc {
+ spk_vreg: regulator_spk {
+ status = "disabled";
+ compatible = "regulator-fixed";
+ regulator-name = "spk_vreg";
+ startup-delay-us = <0>;
+ enable-active-high;
+ gpio = <&msm_gpio 4 0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-smp2p.dtsi b/arch/arm64/boot/dts/qcom/msm8909-smp2p.dtsi
new file mode 100644
index 0000000..fe5d707
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-smp2p.dtsi
@@ -0,0 +1,164 @@
+/* Copyright (c) 2014-2015,2018, 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.
+ */
+
+&soc {
+ qcom,smp2p-modem {
+ compatible = "qcom,smp2p";
+ reg = <0x0b011008 0x4>;
+ qcom,remote-pid = <1>;
+ qcom,irq-bitmask = <0x4000>;
+ interrupts = <0 27 1>;
+ };
+
+ qcom,smp2p-wcnss {
+ compatible = "qcom,smp2p";
+ reg = <0x0b011008 0x4>;
+ qcom,remote-pid = <4>;
+ qcom,irq-bitmask = <0x40000>;
+ interrupts = <0 143 1>;
+ };
+
+ smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <15>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_15_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+ gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <15>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_15_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+ gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+ gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+ gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+ gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+ gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+ };
+
+ smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ 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>;
+ };
+
+ 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/msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm8909.dtsi
new file mode 100644
index 0000000..7b38370
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909.dtsi
@@ -0,0 +1,1917 @@
+/* Copyright (c) 2014-2018, 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 "skeleton64.dtsi"
+#include <dt-bindings/clock/msm-clocks-8909.h>
+#include <dt-bindings/clock/msm-clocks-a7.h>
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8909";
+ compatible = "qcom,msm8909";
+ qcom,msm-id = <245 0>,
+ <258 0>,
+ <265 0>,
+ <275 0>;
+ interrupt-parent = <&intc>;
+
+ aliases {
+ /* smdtty devices */
+ smd1 = &smdtty_apps_fm;
+ smd2 = &smdtty_apps_riva_bt_acl;
+ smd3 = &smdtty_apps_riva_bt_cmd;
+ smd5 = &smdtty_apps_riva_ant_cmd;
+ smd6 = &smdtty_apps_riva_ant_data;
+ smd7 = &smdtty_data1;
+ smd8 = &smdtty_data4;
+ smd11 = &smdtty_data11;
+ smd21 = &smdtty_data21;
+ smd36 = &smdtty_loopback;
+
+ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
+ sdhc2 = &sdhc_2; /* SDC2 SD card slot */
+ spi0 = &spi_0; /* SPI0 controller device */
+ spi2 = &spi_2;
+ spi4 = &spi_4;
+ i2c5 = &i2c_5; /* I2c5 cntroller device */
+ i2c3 = &i2c_3; /* I2C3 controller */
+ i2c1 = &i2c_1; /* I2C1 controller */
+ i2c2 = &i2c_2; /* I2C2 NFC qup2 device */
+ i2c4 = &i2c_4; /* I2C4 controller device */
+ qpic_nand1 = &qnand_1; /* qpic nand controller */
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&CPU0>;
+ };
+ core1 {
+ cpu = <&CPU1>;
+ };
+ core2 {
+ cpu = <&CPU2>;
+ };
+ core3 {
+ cpu = <&CPU3>;
+ };
+ };
+ };
+
+ CPU0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x0>;
+ efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ qcom,sleep-status = <&cpu0_slp_sts>;
+ qcom,limits-info = <&mitigation_profile0>;
+ };
+
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x1>;
+ efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ qcom,sleep-status = <&cpu1_slp_sts>;
+ qcom,limits-info = <&mitigation_profile2>;
+ };
+
+ CPU2: cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x2>;
+ efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ qcom,sleep-status = <&cpu2_slp_sts>;
+ qcom,limits-info = <&mitigation_profile1>;
+ };
+
+ CPU3: cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x3>;
+ efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ qcom,sleep-status = <&cpu3_slp_sts>;
+ qcom,limits-info = <&mitigation_profile2>;
+ };
+ };
+
+ energy_costs: energy-costs {
+ compatible = "sched-energy";
+
+ CPU_COST_0: core-cost0 {
+ busy-cost-data = <
+ 400000 82
+ 800000 164
+ 1094400 290
+ >;
+ idle-cost-data = <
+ 40 20 12 8
+ >;
+ };
+ CLUSTER_COST_0: cluster-cost0 {
+ busy-cost-data = <
+ 400000 23
+ 800000 48
+ 1094400 87
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ };
+
+ firmware: firmware {
+ android {
+ compatible = "android,firmware";
+ fstab {
+ compatible = "android,fstab";
+ vendor_fstab: vendor {
+ compatible = "android,vendor";
+ dev =
+ "/dev/block/platform/soc/7824900.sdhci/by-name/vendor";
+ type = "ext4";
+ mnt_flags = "ro,barrier=1,discard";
+ fsmgr_flags = "wait,verify";
+ status = "ok";
+ };
+ system_fstab: system {
+ compatible = "android,system";
+ dev =
+ "/dev/block/platform/soc/7824900.sdhci/by-name/system";
+ type = "ext4";
+ mnt_flags = "ro,barrier=1,discard";
+ fsmgr_flags = "wait,verify";
+ status = "ok";
+ };
+ };
+ };
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ external_image_mem: external_image__region@0 {
+ reg = <0x0 0x87a00000 0x0 0x0600000>;
+ compatible = "removed-dma-pool";
+ no-map;
+ };
+
+ modem_adsp_mem: modem_adsp_region@0 {
+ reg = <0x0 0x88000000 0x0 0x05500000>;
+ compatible = "removed-dma-pool";
+ no-map;
+ };
+
+ peripheral_mem: pheripheral_region@0 {
+ reg = <0x0 0x8d500000 0x0 0x0700000>;
+ compatible = "removed-dma-pool";
+ no-map;
+ };
+
+ venus_qseecom_mem: venus_qseecom_region@0 {
+ compatible = "shared-dma-pool";
+ reusable;
+ alloc-ranges = <0x0 0x80000000 0x0 0x10000000>;
+ alignment = <0 0x400000>;
+ size = <0 0x0800000>;
+ };
+
+ audio_mem: audio_region@0 {
+ compatible = "shared-dma-pool";
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0x400000>;
+ };
+
+ adsp_mem: adsp_region@0 {
+ compatible = "shared-dma-pool";
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0x400000>;
+ };
+
+ cont_splash_mem: splash_region@83000000 {
+ reg = <0x0 0x83000000 0x0 0xc00000>;
+ };
+ };
+
+ soc: soc { };
+};
+
+#include "msm8909-ion.dtsi"
+#include "msm8909-smp2p.dtsi"
+#include "msm8909-ipcrouter.dtsi"
+#include "msm-gdsc-8916.dtsi"
+#include "msm8909-coresight.dtsi"
+#include "msm8909-bus.dtsi"
+#include "msm8909-mdss.dtsi"
+#include "msm8909-mdss-pll.dtsi"
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0xffffffff>;
+ compatible = "simple-bus";
+
+ intc: interrupt-controller@b000000 {
+ compatible = "qcom,msm-qgic2";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0x0b000000 0x1000>,
+ <0x0b002000 0x1000>;
+ };
+
+ restart@4ab000 {
+ compatible = "qcom,pshold";
+ reg = <0x4ab000 0x4>,
+ <0x193d100 0x4>;
+ reg-names = "pshold-base", "tcsr-boot-misc-detect";
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <1 2 0xf08>,
+ <1 3 0xf08>,
+ <1 4 0xf08>,
+ <1 1 0xf08>;
+ clock-frequency = <19200000>;
+ };
+
+ timer@b020000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ compatible = "arm,armv7-timer-mem";
+ reg = <0xb020000 0x1000>;
+ clock-frequency = <19200000>;
+
+ frame@b021000 {
+ frame-number = <0>;
+ interrupts = <0 8 0x4>,
+ <0 7 0x4>;
+ reg = <0xb021000 0x1000>,
+ <0xb022000 0x1000>;
+ };
+ frame@b023000 {
+ frame-number = <1>;
+ interrupts = <0 9 0x4>;
+ reg = <0xb023000 0x1000>;
+ status = "disabled";
+ };
+ frame@b024000 {
+ frame-number = <2>;
+ interrupts = <0 10 0x4>;
+ reg = <0xb024000 0x1000>;
+ status = "disabled";
+ };
+ frame@b025000 {
+ frame-number = <3>;
+ interrupts = <0 11 0x4>;
+ reg = <0xb025000 0x1000>;
+ status = "disabled";
+ };
+ frame@b026000 {
+ frame-number = <4>;
+ interrupts = <0 12 0x4>;
+ reg = <0xb026000 0x1000>;
+ status = "disabled";
+ };
+ frame@b027000 {
+ frame-number = <5>;
+ interrupts = <0 13 0x4>;
+ reg = <0xb027000 0x1000>;
+ status = "disabled";
+ };
+ frame@b028000 {
+ frame-number = <6>;
+ interrupts = <0 14 0x4>;
+ reg = <0xb028000 0x1000>;
+ status = "disabled";
+ };
+ };
+
+ clock_rpm: qcom,rpmcc@1800000 {
+ compatible = "qcom,rpmcc-8909";
+ reg = <0x1800000 0x80000>;
+ reg-names = "cc_base";
+ #clock-cells = <1>;
+ };
+
+ clock_gcc: qcom,gcc@1800000 {
+ compatible = "qcom,gcc-8909";
+ reg = <0x1800000 0x80000>,
+ <0xb016000 0x00040>;
+ reg-names = "cc_base", "apcs_base";
+ vdd_dig-supply = <&pm8909_s1_corner>;
+ vdd_sr2_dig-supply = <&pm8909_s1_corner_ao>;
+ vdd_sr2_pll-supply = <&pm8909_l7_ao>;
+ clocks = <&clock_rpm clk_xo_clk_src>,
+ <&clock_rpm clk_xo_a_clk_src>;
+ clock-names = "xo", "xo_a";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ clock_gcc_mdss: qcom,gcc-mdss@1ac8300 {
+ compatible = "qcom,gcc-mdss-8909";
+ clocks = <&mdss_dsi0_pll clk_dsi_pll0_pixel_clk_src>,
+ <&mdss_dsi0_pll clk_dsi_pll0_byte_clk_src>;
+ clock-names = "pixel_src", "byte_src";
+ #clock-cells = <1>;
+ };
+
+ clock_debug: qcom,cc-debug@1874000 {
+ compatible = "qcom,cc-debug-8909";
+ reg = <0x1874000 0x4>,
+ <0xb01101c 0x8>;
+ reg-names = "cc_base", "meas";
+ clocks = <&clock_rpm clk_rpm_debug_mux>;
+ clock-names = "rpm_debug_mux";
+ #clock-cells = <1>;
+ };
+
+ clock_cpu: qcom,clock-a7@0b011050 {
+ compatible = "qcom,clock-a53-8916";
+ reg = <0x0b011050 0x8>,
+ <0x0005c00c 0x8>;
+ reg-names = "rcg-base", "efuse";
+ qcom,safe-freq = < 400000000 >;
+ cpu-vdd-supply = <&pm8909_s1_corner_ao>;
+ qcom,enable-opp;
+ clocks = <&clock_gcc clk_gpll0_ao_clk_src>,
+ <&clock_gcc clk_a7sspll>;
+ clock-names = "clk-4", "clk-5";
+ qcom,speed0-bin-v0 =
+ < 0 0>,
+ < 400000000 4>,
+ < 800000000 5>,
+ < 1267200000 7>;
+ qcom,speed2-bin-v0 =
+ < 0 0>,
+ < 400000000 4>,
+ < 800000000 5>,
+ < 1094400000 7>;
+ #clock-cells = <1>;
+ };
+
+ cpubw: qcom,cpubw {
+ compatible = "qcom,devbw";
+ governor = "cpufreq";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 762 /* 100 MHz */>,
+ < 1525 /* 200 MHz */>,
+ < 3051 /* 400 MHz */>,
+ < 4066 /* 533 MHz */>;
+ };
+
+ devfreq-cpufreq {
+ cpubw-cpufreq {
+ target-dev = <&cpubw>;
+ cpu-to-dev-map =
+ < 400000 762>,
+ < 800000 1525>,
+ < 998400 3051>,
+ < 1094400 4066>;
+ };
+ };
+
+ qcom,cpu-bwmon {
+ compatible = "qcom,bimc-bwmon2";
+ reg = <0x408000 0x300>, <0x401000 0x200>;
+ reg-names = "base", "global_base";
+ interrupts = <0 183 4>;
+ qcom,mport = <0>;
+ qcom,target-dev = <&cpubw>;
+ };
+
+ qcom,msm-cpufreq {
+ reg = <0 4>;
+ compatible = "qcom,msm-cpufreq";
+ clocks = <&clock_cpu clk_a7ssmux>,
+ <&clock_cpu clk_a7ssmux>,
+ <&clock_cpu clk_a7ssmux>,
+ <&clock_cpu clk_a7ssmux>;
+ clock-names = "cpu0_clk", "cpu1_clk",
+ "cpu2_clk", "cpu3_clk";
+ qcom,cpufreq-table =
+ < 200000 >,
+ < 400000 >,
+ < 533330 >,
+ < 800000 >,
+ < 998400 >,
+ < 1094400 >,
+ < 1190400 >,
+ < 1248000 >,
+ < 1267200 >;
+ };
+
+
+ blsp1_uart1: serial@78af000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uart";
+ reg = <0x78af000 0x200>;
+ interrupts = <0 107 0>;
+ status = "disabled";
+ clocks = <&clock_gcc clk_gcc_blsp1_uart1_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ clock-names = "core", "iface";
+ };
+
+ blsp1_uart2_hs: uart@78b0000 { /*BLSP1 UART2*/
+ compatible = "qcom,msm-hsuart-v14";
+ reg = <0x78b0000 0x200>,
+ <0x7884000 0x1f000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+ #address-cells = <0>;
+ interrupt-parent = <&blsp1_uart2_hs>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 108 0
+ 1 &intc 0 238 0
+ 2 &msm_gpio 21 0>;
+ qcom,inject-rx-on-wakeup;
+ qcom,rx-char-to-inject = <0xfd>;
+ qcom,master-id = <86>;
+ clock-names = "core_clk", "iface_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ pinctrl-names = "sleep", "default";
+ pinctrl-0 = <&blsp1_uart2_tx_sleep>, <&blsp1_uart2_rxcts_sleep>,
+ <&blsp1_uart2_rfr_sleep>;
+ pinctrl-1 = <&blsp1_uart2_tx_active>,
+ <&blsp1_uart2_rxcts_active>, <&blsp1_uart2_rfr_active>;
+
+ qcom,bam-tx-ep-pipe-index = <2>;
+ qcom,bam-rx-ep-pipe-index = <3>;
+ qcom,msm-bus,name = "blsp1_uart2_hs";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <86 512 0 0>,
+ <86 512 500 800>;
+ status = "disabled";
+ };
+
+ qcom,sps {
+ compatible = "qcom,msm_sps_4k";
+ qcom,device-type = <3>;
+ qcom,pipe-attr-ee;
+ };
+
+ thermal_zones: thermal-zones {};
+
+ qcom,sensor-information {
+ compatible = "qcom,sensor-information";
+ sensor_information0: qcom,sensor-information-0 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor0";
+ qcom,alias-name = "pop_mem";
+ };
+
+ sensor_information1: qcom,sensor-information-1 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor1";
+ };
+
+ sensor_information2: qcom,sensor-information-2 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor2";
+ };
+
+ sensor_information3: qcom,sensor-information-3 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor3";
+ };
+
+ sensor_information4: qcom,sensor-information-4 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor4";
+ };
+
+ sensor_information5: qcom,sensor-information-5 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "pa_therm0";
+ };
+
+ sensor_information6: qcom,sensor-information-6 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "case_therm";
+ };
+
+ sensor_information7: qcom,sensor-information-7 {
+ qcom,sensor-type = "alarm";
+ qcom,sensor-name = "pm8909_tz";
+ qcom,scaling-factor = <1000>;
+ };
+
+ sensor_information8: qcom,sensor-information-8 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "xo_therm";
+ };
+
+ sensor_information9: qcom,sensor-information-9 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "xo_therm_buf";
+ };
+ };
+
+ mitigation_profile0: qcom,limit_info-0 {
+ qcom,temperature-sensor = <&sensor_information3>;
+ qcom,boot-frequency-mitigate;
+ qcom,emergency-frequency-mitigate;
+ };
+
+ mitigation_profile1: qcom,limit_info-1 {
+ qcom,temperature-sensor = <&sensor_information3>;
+ qcom,boot-frequency-mitigate;
+ qcom,hotplug-mitigation-enable;
+ };
+
+ mitigation_profile2: qcom,limit_info-2 {
+ qcom,temperature-sensor = <&sensor_information4>;
+ qcom,boot-frequency-mitigate;
+ qcom,hotplug-mitigation-enable;
+ };
+
+ qcom,ipc-spinlock@1905000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0x1905000 0x8000>;
+ qcom,num-locks = <8>;
+ };
+
+ qcom,smem@87d00000 {
+ compatible = "qcom,smem";
+ reg = <0x87d00000 0x100000>,
+ <0x0b011008 0x4>,
+ <0x60000 0x8000>,
+ <0x193D000 0x8>;
+ reg-names = "smem", "irq-reg-base",
+ "aux-mem1", "smem_targ_info_reg";
+ qcom,mpu-enabled;
+
+ qcom,smd-modem {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <0>;
+ qcom,smd-irq-offset = <0x0>;
+ qcom,smd-irq-bitmask = <0x1000>;
+ interrupts = <0 25 1>;
+ label = "modem";
+ qcom,not-loadable;
+ };
+
+ qcom,smsm-modem {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <0>;
+ qcom,smsm-irq-offset = <0x0>;
+ qcom,smsm-irq-bitmask = <0x2000>;
+ interrupts = <0 26 1>;
+ };
+
+ qcom,smd-wcnss {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <6>;
+ qcom,smd-irq-offset = <0x0>;
+ qcom,smd-irq-bitmask = <0x20000>;
+ interrupts = <0 142 1>;
+ label = "wcnss";
+ };
+
+ qcom,smsm-wcnss {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <6>;
+ qcom,smsm-irq-offset = <0x0>;
+ qcom,smsm-irq-bitmask = <0x80000>;
+ interrupts = <0 144 1>;
+ };
+
+ qcom,smd-rpm {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <15>;
+ qcom,smd-irq-offset = <0x0>;
+ qcom,smd-irq-bitmask = <0x1>;
+ interrupts = <0 168 1>;
+ label = "rpm";
+ qcom,irq-no-suspend;
+ qcom,not-loadable;
+ };
+ };
+
+ rpm_bus: qcom,rpm-smd {
+ compatible = "qcom,rpm-smd";
+ rpm-channel-name = "rpm_requests";
+ rpm-channel-type = <15>; /* SMD_APPS_RPM */
+ };
+
+ qcom,smdtty {
+ compatible = "qcom,smdtty";
+
+ smdtty_apps_fm: qcom,smdtty-apps-fm {
+ qcom,smdtty-remote = "wcnss";
+ qcom,smdtty-port-name = "APPS_FM";
+ };
+
+ smdtty_apps_riva_bt_acl: smdtty-apps-riva-bt-acl {
+ qcom,smdtty-remote = "wcnss";
+ qcom,smdtty-port-name = "APPS_RIVA_BT_ACL";
+ };
+
+ smdtty_apps_riva_bt_cmd: qcom,smdtty-apps-riva-bt-cmd {
+ qcom,smdtty-remote = "wcnss";
+ qcom,smdtty-port-name = "APPS_RIVA_BT_CMD";
+ };
+
+ smdtty_apps_riva_ant_cmd: smdtty-apps-riva-ant-cmd {
+ qcom,smdtty-remote = "wcnss";
+ qcom,smdtty-port-name = "APPS_RIVA_ANT_CMD";
+ };
+
+ smdtty_apps_riva_ant_data: smdtty-apps-riva-ant-data {
+ qcom,smdtty-remote = "wcnss";
+ qcom,smdtty-port-name = "APPS_RIVA_ANT_DATA";
+ };
+
+ smdtty_data1: qcom,smdtty-data1 {
+ qcom,smdtty-remote = "modem";
+ qcom,smdtty-port-name = "DATA1";
+ };
+
+ smdtty_data4: qcom,smdtty-data4 {
+ qcom,smdtty-remote = "modem";
+ qcom,smdtty-port-name = "DATA4";
+ };
+
+ smdtty_data11: qcom,smdtty-data11 {
+ qcom,smdtty-remote = "modem";
+ qcom,smdtty-port-name = "DATA11";
+ };
+
+ smdtty_data21: qcom,smdtty-data21 {
+ qcom,smdtty-remote = "modem";
+ qcom,smdtty-port-name = "DATA21";
+ };
+
+ smdtty_loopback: smdtty-loopback {
+ qcom,smdtty-remote = "modem";
+ qcom,smdtty-port-name = "LOOPBACK";
+ qcom,smdtty-dev-name = "LOOPBACK_TTY";
+ };
+ };
+
+ qcom,smdpkt {
+ compatible = "qcom,smdpkt";
+
+ qcom,smdpkt-data5-cntl {
+ qcom,smdpkt-remote = "modem";
+ qcom,smdpkt-port-name = "DATA5_CNTL";
+ qcom,smdpkt-dev-name = "smdcntl0";
+ };
+
+ qcom,smdpkt-data22 {
+ qcom,smdpkt-remote = "modem";
+ qcom,smdpkt-port-name = "DATA22";
+ qcom,smdpkt-dev-name = "smd22";
+ };
+
+ qcom,smdpkt-data40-cntl {
+ qcom,smdpkt-remote = "modem";
+ qcom,smdpkt-port-name = "DATA40_CNTL";
+ qcom,smdpkt-dev-name = "smdcntl8";
+ };
+
+ qcom,smdpkt-apr-apps2 {
+ qcom,smdpkt-remote = "modem";
+ qcom,smdpkt-port-name = "apr_apps2";
+ qcom,smdpkt-dev-name = "apr_apps2";
+ };
+
+ qcom,smdpkt-loopback {
+ qcom,smdpkt-remote = "modem";
+ qcom,smdpkt-port-name = "LOOPBACK";
+ qcom,smdpkt-dev-name = "smd_pkt_loopback";
+ };
+ };
+
+ wcnss: qcom,wcnss-wlan@a000000 {
+ compatible = "qcom,wcnss_wlan";
+ reg = <0x0a000000 0x280000>,
+ <0xb011008 0x04>,
+ <0x0a21b000 0x3000>,
+ <0x03204000 0x00000100>,
+ <0x03200800 0x00000200>,
+ <0x0A100400 0x00000200>,
+ <0x0A205050 0x00000200>,
+ <0x0A219000 0x00000020>,
+ <0x0A080488 0x00000008>,
+ <0x0A080fb0 0x00000008>,
+ <0x0A08040c 0x00000008>,
+ <0x0A0120a8 0x00000008>,
+ <0x0A012448 0x00000008>,
+ <0x0A080c00 0x00000001>,
+ <0x0005E000 0x00000064>;
+
+ reg-names = "wcnss_mmio", "wcnss_fiq",
+ "pronto_phy_base", "riva_phy_base",
+ "riva_ccu_base", "pronto_a2xb_base",
+ "pronto_ccpu_base", "pronto_saw2_base",
+ "wlan_tx_phy_aborts","wlan_brdg_err_source",
+ "wlan_tx_status", "alarms_txctl",
+ "alarms_tactl", "pronto_mcu_base",
+ "pronto_qfuse";
+
+ interrupts = <0 145 0 0 146 0>;
+ interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+ qcom,pronto-vddmx-supply = <&pm8909_l3_corner_ao>;
+ qcom,pronto-vddcx-supply = <&pm8909_s1_corner>;
+ qcom,pronto-vddpx-supply = <&pm8909_l7>;
+ qcom,iris-vddxo-supply = <&pm8909_l7>;
+ qcom,iris-vddrfa-supply = <&pm8909_l10>;
+ qcom,iris-vddpa-supply = <&pm8909_l9>;
+ qcom,iris-vdddig-supply = <&pm8909_l5>;
+
+ qcom,iris-vddxo-voltage-level = <1800000 0 1800000>;
+ qcom,iris-vddrfa-voltage-level = <1300000 0 1300000>;
+ qcom,iris-vddpa-voltage-level = <3300000 0 3300000>;
+ qcom,iris-vdddig-voltage-level = <1800000 0 1800000>;
+
+ qcom,vddmx-voltage-level = <5 1 7>;
+ qcom,vddcx-voltage-level = <5 1 7>;
+ qcom,vddpx-voltage-level = <1800000 0 1800000>;
+
+ qcom,iris-vddxo-current = <10000>;
+ qcom,iris-vddrfa-current = <100000>;
+ qcom,iris-vddpa-current = <515000>;
+ qcom,iris-vdddig-current = <10000>;
+
+ qcom,pronto-vddmx-current = <0>;
+ qcom,pronto-vddcx-current = <0>;
+ qcom,pronto-vddpx-current = <0>;
+
+ pinctrl-names = "wcnss_default", "wcnss_sleep",
+ "wcnss_gpio_default";
+ pinctrl-0 = <&wcnss_default>;
+ pinctrl-1 = <&wcnss_sleep>;
+ pinctrl-2 = <&wcnss_gpio_default>;
+
+ gpios = <&msm_gpio 40 0>, <&msm_gpio 41 0>, <&msm_gpio 42 0>,
+ <&msm_gpio 43 0>, <&msm_gpio 44 0>;
+
+ clocks = <&clock_rpm clk_xo_wlan_clk>,
+ <&clock_rpm clk_rf_clk2>,
+ <&clock_debug clk_gcc_debug_mux>,
+ <&clock_gcc clk_wcnss_m_clk>;
+ clock-names = "xo", "rf_clk", "measure", "wcnss_debug";
+
+ qcom,wlan-rx-buff-count = <512>;
+ qcom,has-autodetect-xo;
+ qcom,is-pronto-v3;
+ qcom,is-dual-band-disabled;
+ qcom,is-pronto-vadc;
+ qcom,has-pronto-hw;
+ qcom,wcnss-adc_tm = <&pm8909_adc_tm>;
+ };
+
+ usb_otg: usb@78d9000 {
+ compatible = "qcom,hsusb-otg";
+ reg = <0x78d9000 0x400>, <0x6c000 0x200>;
+ reg-names = "core", "phy_csr";
+
+ interrupts = <0 134 0>,<0 140 0>;
+ interrupt-names = "core_irq", "async_irq";
+
+ hsusb_vdd_dig-supply = <&pm8909_l2>;
+ HSUSB_1p8-supply = <&pm8909_l7>;
+ HSUSB_3p3-supply = <&pm8909_l13>;
+ qcom,vdd-voltage-level = <0 1200000 1200000>;
+
+ qcom,hsusb-otg-phy-init-seq = <0x73 0x80 0xffffffff>;
+ qcom,hsusb-otg-phy-type = <3>; /* SNPS Femto PHY */
+ qcom,hsusb-otg-mode = <1>; /* DEVICE only */
+ qcom,hsusb-otg-otg-control = <2>; /* PMIC */
+ qcom,dp-manual-pullup;
+ qcom,phy-dvdd-always-on;
+ qcom,hsusb-otg-mpm-dpsehv-int = <49>;
+ qcom,hsusb-otg-mpm-dmsehv-int = <58>;
+
+ qcom,msm-bus,name = "usb2";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <87 512 0 0>,
+ <87 512 80000 0>,
+ <87 512 6000 6000>;
+ clocks = <&clock_gcc clk_gcc_usb_hs_ahb_clk>,
+ <&clock_gcc clk_gcc_usb_hs_system_clk>,
+ <&clock_gcc clk_gcc_usb2a_phy_sleep_clk>,
+ <&clock_rpm clk_bimc_usb_a_clk>,
+ <&clock_rpm clk_snoc_usb_a_clk>,
+ <&clock_rpm clk_pcnoc_usb_a_clk>,
+ <&clock_gcc clk_gcc_qusb2_phy_clk>,
+ <&clock_gcc clk_gcc_usb2_hs_phy_only_clk>,
+ <&clock_gcc clk_gcc_usb_hs_phy_cfg_ahb_clk>,
+ <&clock_rpm clk_xo_otg_clk>;
+ clock-names = "iface_clk", "core_clk", "sleep_clk",
+ "bimc_clk", "snoc_clk", "pcnoc_clk",
+ "phy_reset_clk", "phy_por_clk", "phy_csr_clk",
+ "xo";
+ qcom,bus-clk-rate = <400000000 200000000 100000000>;
+ qcom,max-nominal-sysclk-rate = <100000000>;
+ qcom,boost-sysclk-with-streaming;
+ resets = <&clock_gcc GCC_USB_HS_BCR>,
+ <&clock_gcc GCC_QUSB2_PHY_BCR>,
+ <&clock_gcc GCC_USB2_HS_PHY_ONLY_BCR>;
+ reset-names = "core_reset", "phy_reset", "phy_por_reset";
+ };
+
+ android_usb: android_usb@086000c8 {
+ compatible = "qcom,android-usb";
+ reg = <0x086000c8 0xc8>;
+ qcom,pm-qos-latency = <2 1001 12701>;
+ };
+
+ qcom,usbbam@78c4000 {
+ compatible = "qcom,usb-bam-msm";
+ reg = <0x78c4000 0x15000>;
+ reg-names = "hsusb";
+ interrupts = <0 135 0>;
+ interrupt-names = "hsusb";
+ qcom,bam-type = <1>;
+ qcom,usb-bam-num-pipes = <2>;
+ qcom,usb-bam-fifo-baseaddr = <0x08603800>;
+ qcom,ignore-core-reset-ack;
+ qcom,disable-clk-gating;
+ qcom,reset-bam-on-disconnect;
+
+ qcom,pipe0 {
+ label = "hsusb-qdss-in-0";
+ qcom,usb-bam-mem-type = <2>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <0>;
+ qcom,peer-bam-physical-address = <0x884000>;
+ qcom,src-bam-pipe-index = <0>;
+ qcom,dst-bam-pipe-index = <0>;
+ qcom,data-fifo-offset = <0x0>;
+ qcom,data-fifo-size = <0x600>;
+ qcom,descriptor-fifo-offset = <0x600>;
+ qcom,descriptor-fifo-size = <0x200>;
+ };
+ };
+
+ spmi_bus: qcom,spmi@200f000 {
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0x200f000 0x1000>,
+ <0x2400000 0x400000>,
+ <0x2c00000 0x400000>,
+ <0x3800000 0x200000>,
+ <0x200a000 0x2100>;
+ reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+ interrupt-names = "periph_irq";
+ interrupts = <0 190 0>;
+ qcom,ee = <0>;
+ qcom,channel = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <4>;
+ interrupt-controller;
+ cell-index = <0>;
+ };
+
+ qcom,rmtfs_sharedmem@87c00000 {
+
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x87c00000 0xe0000>;
+ reg-names = "rmtfs";
+ qcom,client-id = <0x00000001>;
+ };
+
+ qcom,dsp_sharedmem@87ce0000 {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x87ce0000 0x10000>;
+ reg-names = "rfsa_dsp";
+ qcom,client-id = <0x011013ec>;
+ };
+
+ qcom,mdm_sharedmem@87cf0000 {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x87cf0000 0x10000>;
+ reg-names = "rfsa_mdm";
+ qcom,client-id = <0x011013ed>;
+ };
+
+ cpu-pmu {
+ compatible = "arm,cortex-a7-pmu";
+ qcom,irq-is-percpu;
+ interrupts = <1 7 0xf00>;
+ };
+
+ jtag_fuse: jtagfuse@5e01c {
+ compatible = "qcom,jtag-fuse-v2";
+ reg = <0x5e01c 0x8>;
+ reg-names = "fuse-base";
+ };
+
+ jtag_mm0: jtagmm@84c000 {
+ compatible = "qcom,jtag-mm";
+ reg = <0x84c000 0x1000>,
+ <0x840000 0x1000>;
+ reg-names = "etm-base","debug-base";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+
+ qcom,coresight-jtagmm-cpu = <&CPU0>;
+ };
+
+ jtag_mm1: jtagmm@84d000 {
+ compatible = "qcom,jtag-mm";
+ reg = <0x84d000 0x1000>,
+ <0x842000 0x1000>;
+ reg-names = "etm-base","debug-base";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+
+ qcom,coresight-jtagmm-cpu = <&CPU1>;
+ };
+
+ jtag_mm2: jtagmm@84e000 {
+ compatible = "qcom,jtag-mm";
+ reg = <0x84e000 0x1000>,
+ <0x844000 0x1000>;
+ reg-names = "etm-base","debug-base";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+
+ qcom,coresight-jtagmm-cpu = <&CPU2>;
+ };
+
+ jtag_mm3: jtagmm@84f000 {
+ compatible = "qcom,jtag-mm";
+ reg = <0x84f000 0x1000>,
+ <0x846000 0x1000>;
+ reg-names = "etm-base","debug-base";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+
+ qcom,coresight-jtagmm-cpu = <&CPU3>;
+ };
+
+ qnand_1: nand@7980000 {
+ compatible = "qcom,msm-nand";
+ reg = <0x7980000 0x1000>,
+ <0x7984000 0x1a000>,
+ <0x5e02c 0x4>;
+ reg-names = "nand_phys",
+ "bam_phys", "boot_cfg";
+ qcom,reg-adjustment-offset = <0>;
+ interrupts = <0 132 0>;
+ interrupt-names = "bam_irq";
+
+ qcom,msm-bus,name = "qpic_nand";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <91 512 0 0>,
+ /* Voting for max b/w on PNOC bus for now */
+ <91 512 400000 800000>;
+
+ clock-names = "core_clk";
+ clocks = <&clock_rpm clk_qpic_clk>;
+ status = "disabled";
+ };
+
+ sdhc_1: sdhci@7824000 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0x07824900 0x11c>, <0x07824000 0x800>;
+ reg-names = "hc_mem", "core_mem";
+
+ interrupts = <0 123 0>, <0 138 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ qcom,bus-width = <8>;
+
+ qcom,pm-qos-irq-type = "affine_irq";
+ qcom,pm-qos-irq-latency = <2 250>;
+
+ qcom,msm-bus,name = "sdhc1";
+ qcom,msm-bus,num-cases = <8>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
+ <78 512 1046 3200>, /* 400 KB/s*/
+ <78 512 52286 160000>, /* 20 MB/s */
+ <78 512 65360 200000>, /* 25 MB/s */
+ <78 512 130718 400000>, /* 50 MB/s */
+ <78 512 261438 800000>, /* 100 MB/s */
+ <78 512 261438 800000>, /* 200 MB/s */
+ <78 512 1338562 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+ 100000000 200000000 4294967295>;
+
+
+ clocks = <&clock_gcc clk_gcc_sdcc1_ahb_clk>,
+ <&clock_gcc clk_gcc_sdcc1_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+ qcom,clk-rates = <400000 25000000 50000000 100000000 177770000>;
+ qcom,devfreq,freq-table = <50000000 177770000>;
+
+ status = "disabled";
+ };
+
+ sdhc_2: sdhci@07864000 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0x07864900 0x11c>, <0x07864000 0x800>;
+ reg-names = "hc_mem", "core_mem";
+
+ interrupts = <0 125 0>, <0 221 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ qcom,bus-width = <4>;
+
+ qcom,pm-qos-irq-type = "affine_irq";
+ qcom,pm-qos-irq-latency = <2 250>;
+
+ qcom,msm-bus,name = "sdhc2";
+ qcom,msm-bus,num-cases = <8>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
+ <81 512 1046 3200>, /* 400 KB/s*/
+ <81 512 52286 160000>, /* 20 MB/s */
+ <81 512 65360 200000>, /* 25 MB/s */
+ <81 512 130718 400000>, /* 50 MB/s */
+ <81 512 261438 800000>, /* 100 MB/s */
+ <81 512 261438 800000>, /* 200 MB/s */
+ <81 512 1338562 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+ 100000000 200000000 4294967295>;
+
+ clocks = <&clock_gcc clk_gcc_sdcc2_ahb_clk>,
+ <&clock_gcc clk_gcc_sdcc2_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,devfreq,freq-table = <50000000 200000000>;
+
+ status = "disabled";
+ };
+
+ qcom,wdt@b017000 {
+ compatible = "qcom,msm-watchdog";
+ reg = <0xb017000 0x1000>;
+ reg-names = "wdt-base";
+ interrupts = <0 3 0>, <0 4 0>;
+ qcom,bark-time = <11000>;
+ qcom,pet-time = <10000>;
+ qcom,ipi-ping;
+ };
+
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,rtb-size = <0x100000>; /* 1M EBI1 buffer */
+ };
+
+ qcom,msm-imem@8600000 {
+ compatible = "qcom,msm-imem";
+ reg = <0x08600000 0x1000>; /* Address and size of IMEM */
+ ranges = <0x0 0x08600000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ mem_dump_table@10 {
+ compatible = "qcom,msm-imem-mem_dump_table";
+ reg = <0x10 8>;
+ };
+
+ boot_stats@6b0 {
+ compatible = "qcom,msm-imem-boot_stats";
+ reg = <0x6b0 32>;
+ };
+
+ pil@94c {
+ compatible = "qcom,msm-imem-pil";
+ reg = <0x94c 200>;
+ };
+
+ restart_reason@65c {
+ compatible = "qcom,msm-imem-restart_reason";
+ reg = <0x65c 4>;
+ };
+ };
+
+ qcom,mpm2-sleep-counter@4a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0x4a3000 0x1000>;
+ clock-frequency = <32768>;
+ };
+
+ spi_0: spi@78ba000 { /* BLSP1 QUP6 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0x78ba000 0x600>,
+ <0x7884000 0x23000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 100 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi0_default &spi0_cs0_active>;
+ pinctrl-1 = <&spi0_sleep &spi0_cs0_sleep>;
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup6_spi_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,use-pinctrl;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <14>;
+ qcom,bam-producer-pipe-index = <15>;
+ qcom,master-id = <86>;
+ };
+
+ spi_2: spi@78b6000 { /* BLSP1 QUP2 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0x78b6000 0x600>,
+ <0x7884000 0x23000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 96 0>, <0 238 0>;
+ spi-max-frequency = <50000000>;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi2_default &spi2_cs0_active>;
+ pinctrl-1 = <&spi2_sleep &spi2_cs0_sleep>;
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup2_spi_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,use-pinctrl;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <6>;
+ qcom,bam-producer-pipe-index = <7>;
+ qcom,master-id = <86>;
+ status = "disabled";
+ };
+
+ spi_4: spi@78B8000{ /* BLSP1 QUP4 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0x78b8000 0x600>,
+ <0x7884000 0x23000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 98 0>, <0 238 0>;
+ spi-max-frequency = <50000000>;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi4_default &spi4_cs0_active>;
+ pinctrl-1 = <&spi4_sleep &spi4_cs0_sleep>;
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup4_spi_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,use-pinctrl;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <10>;
+ qcom,bam-producer-pipe-index = <11>;
+ qcom,master-id = <86>;
+ status = "disabled";
+ };
+
+ dma_blsp1: qcom,sps-dma@7884000 { /* BLSP1 */
+ #dma-cells = <4>;
+ compatible = "qcom,sps-dma";
+ reg = <0x7884000 0x23000>;
+ interrupts = <0 238 0>;
+ qcom,summing-threshold = <10>;
+ };
+
+ i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b6000 0x1000>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 96 0>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup2_i2c_apps_clk>;
+
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_2_active>;
+ pinctrl-1 = <&i2c_2_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ dmas = <&dma_blsp1 6 64 0x20000020 0x20>,
+ <&dma_blsp1 7 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ qcom,master-id = <86>;
+ };
+
+ i2c_4: i2c@78b8000 { /* BLSP1 QUP4 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b8000 0x1000>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 98 0>;
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup4_i2c_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_4_active>;
+ pinctrl-1 = <&i2c_4_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ dmas = <&dma_blsp1 10 64 0x20000020 0x20>,
+ <&dma_blsp1 11 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ qcom,master-id = <86>;
+ };
+
+ i2c_5: i2c@78b9000 { /* BLSP1 QUP5 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b9000 0x1000>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 99 0>;
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup5_i2c_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+ qcom,clk-freq-out = <100000>;
+ qcom,clk-freq-in = <19200000>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_5_active>;
+ pinctrl-1 = <&i2c_5_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ dmas = <&dma_blsp1 12 64 0x20000020 0x20>,
+ <&dma_blsp1 13 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ qcom,master-id = <86>;
+};
+
+ i2c_3: i2c@78b7000 { /* BLSP1 QUP3 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b7000 0x1000>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 97 0>;
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+ qcom,clk-freq-out = <100000>;
+ qcom,clk-freq-in = <19200000>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_3_active>;
+ pinctrl-1 = <&i2c_3_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ dmas = <&dma_blsp1 8 64 0x20000020 0x20>,
+ <&dma_blsp1 9 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ qcom,master-id = <86>;
+ };
+
+ i2c_1: i2c@78b5000 { /* BLSP1 QUP1 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b5000 0x1000>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 95 0>;
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup1_i2c_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+ qcom,clk-freq-out = <100000>;
+ qcom,clk-freq-in = <19200000>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_1_active>;
+ pinctrl-1 = <&i2c_1_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ dmas = <&dma_blsp1 4 64 0x20000020 0x20>,
+ <&dma_blsp1 5 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ qcom,master-id = <86>;
+ };
+
+ qcom,venus@1de0000 {
+ compatible = "qcom,pil-tz-generic";
+ reg = <0x1de0000 0x4000>;
+
+ vdd-supply = <&gdsc_venus>;
+ qcom,proxy-reg-names = "vdd";
+
+ clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>,
+ <&clock_gcc clk_gcc_venus0_ahb_clk>,
+ <&clock_gcc clk_gcc_venus0_axi_clk>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>,
+ <&clock_gcc clk_crypto_clk_src>;
+
+ clock-names = "core_clk", "iface_clk", "bus_clk",
+ "scm_core_clk", "scm_iface_clk",
+ "scm_bus_clk", "scm_core_clk_src";
+
+ qcom,proxy-clock-names = "core_clk", "iface_clk",
+ "bus_clk", "scm_core_clk",
+ "scm_iface_clk", "scm_bus_clk",
+ "scm_core_clk_src";
+ qcom,scm_core_clk_src-freq = <80000000>;
+
+ qcom,pas-id = <9>;
+ qcom,proxy-timeout-ms = <100>;
+ qcom,firmware-name = "venus";
+ memory-region = <&venus_qseecom_mem>;
+ };
+
+ pcm0: qcom,msm-pcm {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ routing: qcom,msm-pcm-routing {
+ compatible = "qcom,msm-pcm-routing";
+ };
+
+ pcm1: qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "regular";
+ };
+
+ pcm2: qcom,msm-ultra-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <2>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
+ lpa: qcom,msm-pcm-lpa {
+ compatible = "qcom,msm-pcm-lpa";
+ };
+
+ compress: qcom,msm-compress-dsp {
+ compatible = "qcom,msm-compress-dsp";
+ };
+
+ voip: qcom,msm-voip-dsp {
+ compatible = "qcom,msm-voip-dsp";
+ };
+
+ voice: qcom,msm-pcm-voice {
+ compatible = "qcom,msm-pcm-voice";
+ qcom,destroy-cvd;
+ qcom,vote-bms;
+ };
+
+ stub_codec: qcom,msm-stub-codec {
+ compatible = "qcom,msm-stub-codec";
+ };
+
+ qcom,msm-dai-fe {
+ compatible = "qcom,msm-dai-fe";
+ };
+
+ afe: qcom,msm-pcm-afe {
+ compatible = "qcom,msm-pcm-afe";
+ };
+
+ voice_svc: qcom,msm-voice-svc {
+ compatible = "qcom,msm-voice-svc";
+ };
+
+ loopback: qcom,msm-pcm-loopback {
+ compatible = "qcom,msm-pcm-loopback";
+ };
+
+ qcom,msm-dai-mi2s {
+ compatible = "qcom,msm-dai-mi2s";
+ dai_mi2s0: qcom,msm-dai-q6-mi2s-prim {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <0>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_mi2s1: qcom,msm-dai-q6-mi2s-sec {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <1>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_mi2s3: qcom,msm-dai-q6-mi2s-quat {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <3>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_mi2s5: qcom,msm-dai-q6-mi2s-quin {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <5>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <2>;
+ };
+
+ dai_mi2s2: qcom,msm-dai-q6-mi2s-tert {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <2>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_mi2s6: qcom,msm-dai-q6-mi2s-senary {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <6>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+ };
+
+ dai_hdmi: qcom,msm-dai-q6-hdmi {
+ compatible = "qcom,msm-dai-q6-hdmi";
+ qcom,msm-dai-q6-dev-id = <8>;
+ };
+
+ lsm: qcom,msm-lsm-client {
+ compatible = "qcom,msm-lsm-client";
+ };
+
+ qcom,msm-dai-q6 {
+ compatible = "qcom,msm-dai-q6";
+ sb_0_rx: qcom,msm-dai-q6-sb-0-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16384>;
+ };
+
+ sb_0_tx: qcom,msm-dai-q6-sb-0-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16385>;
+ };
+
+ sb_1_rx: qcom,msm-dai-q6-sb-1-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16386>;
+ };
+
+ sb_1_tx: qcom,msm-dai-q6-sb-1-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16387>;
+ };
+
+ sb_3_rx: qcom,msm-dai-q6-sb-3-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16390>;
+ };
+
+ sb_3_tx: qcom,msm-dai-q6-sb-3-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16391>;
+ };
+
+ sb_4_rx: qcom,msm-dai-q6-sb-4-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16392>;
+ };
+
+ sb_4_tx: qcom,msm-dai-q6-sb-4-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16393>;
+ };
+
+ bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12288>;
+ };
+
+ bt_sco_tx: qcom,msm-dai-q6-bt-sco-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12289>;
+ };
+
+ bt_a2dp_rx: qcom,msm-dai-q6-bt-a2dp-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12290>;
+ };
+
+ int_fm_rx: qcom,msm-dai-q6-int-fm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12292>;
+ };
+
+ int_fm_tx: qcom,msm-dai-q6-int-fm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12293>;
+ };
+
+ afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <224>;
+ };
+
+ afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <225>;
+ };
+
+ afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <241>;
+ };
+
+ afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <240>;
+ };
+
+ afe_loopback_tx: qcom,msm-dai-q6-afe-loopback-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <24577>;
+ };
+
+ incall_record_rx: qcom,msm-dai-q6-incall-record-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32771>;
+ };
+
+ incall_record_tx: qcom,msm-dai-q6-incall-record-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32772>;
+ };
+
+ incall_music_rx: qcom,msm-dai-q6-incall-music-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32773>;
+ };
+
+ incall_music_2_rx: qcom,msm-dai-q6-incall-music-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32770>;
+ };
+ };
+
+ hostless: qcom,msm-pcm-hostless {
+ compatible = "qcom,msm-pcm-hostless";
+ };
+
+ dai_pri_auxpcm: qcom,msm-pri-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "primary";
+ };
+
+ qcom,msm-audio-ion {
+ compatible = "qcom,msm-audio-ion";
+ };
+
+ qcom,mdsprpc-mem {
+ compatible = "qcom,msm-mdsprpc-mem-region";
+ memory-region = <&adsp_mem>;
+ };
+
+ qcom,msm-adsp-loader {
+ compatible = "qcom,adsp-loader";
+ qcom,adsp-state = <0>;
+ qcom,proc-img-to-load = "modem";
+ };
+
+ qcom,avtimer@770600c {
+ compatible = "qcom,avtimer";
+ reg = <0x0770600C 0x4>,
+ <0x07706010 0x4>;
+ reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+ qcom,clk-div = <27>;
+ };
+
+ qcom,memshare {
+ compatible = "qcom,memshare";
+
+ qcom,client_1 {
+ compatible = "qcom,memshare-peripheral";
+ qcom,peripheral-size = <0x200000>;
+ qcom,client-id = <0>;
+ qcom,allocate-boot-time;
+ label = "modem";
+ };
+
+ qcom,client_2 {
+ compatible = "qcom,memshare-peripheral";
+ qcom,peripheral-size = <0x300000>;
+ qcom,client-id = <2>;
+ label = "modem";
+ };
+
+ qcom,client_3 {
+ compatible = "qcom,memshare-peripheral";
+ qcom,peripheral-size = <0>;
+ qcom,client-id = <1>;
+ label = "modem";
+ };
+ };
+
+
+ qcom_tzlog: tz-log@8600720 {
+ compatible = "qcom,tz-log";
+ reg = <0x08600720 0x1000>;
+ status = "disabled";
+ };
+
+ qcom_rng: qrng@22000 {
+ compatible = "qcom,msm-rng";
+ reg = <0x22000 0x200>;
+ qcom,msm-rng-iface-clk;
+ qcom,msm-bus,name = "msm-rng-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <1 618 0 0>, /* No vote */
+ <1 618 0 800>; /* 100 MB/s */
+ clocks = <&clock_gcc clk_gcc_prng_ahb_clk>;
+ clock-names = "iface_clk";
+ status = "disabled";
+ };
+
+ qcom_crypto: qcrypto@720000 {
+ compatible = "qcom,qcrypto";
+ reg = <0x720000 0x20000>,
+ <0x704000 0x20000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 207 0>;
+ qcom,bam-pipe-pair = <2>;
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ qcom,clk-mgmt-sus-res;
+ qcom,msm-bus,name = "qcrypto-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 393600 800000>; /* 49.2MHz & 100MHz */
+ clocks = <&clock_gcc clk_crypto_clk_src>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ qcom,use-sw-aes-cbc-ecb-ctr-algo;
+ qcom,use-sw-aes-xts-algo;
+ qcom,use-sw-ahash-algo;
+ status = "disabled";
+ qcom,ce-opp-freq = <100000000>;
+ };
+
+ qcom_cedev: qcedev@720000 {
+ compatible = "qcom,qcedev";
+ reg = <0x720000 0x20000>,
+ <0x704000 0x20000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 207 0>;
+ qcom,bam-pipe-pair = <1>;
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ qcom,ce-hw-shared;
+ qcom,msm-bus,name = "qcedev-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 3936000 393600>;
+ clocks = <&clock_gcc clk_crypto_clk_src>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ status = "disabled";
+ qcom,ce-opp-freq = <100000000>;
+ };
+
+ qcom_seecom: qseecom@87a00000 {
+ compatible = "qcom,qseecom";
+ reg = <0x87a00000 0x200000>;
+ reg-names = "secapp-region";
+ qcom,disk-encrypt-pipe-pair = <2>;
+ qcom,hlos-ce-hw-instance = <0>;
+ qcom,qsee-ce-hw-instance = <0>;
+ qcom,msm-bus,name = "qseecom-noc";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,support-bus-scaling;
+ qcom,support-fde;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 0 0>,
+ <55 512 120000 1200000>,
+ <55 512 393600 3936000>;
+ clocks = <&clock_gcc clk_crypto_clk_src>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ status = "disabled";
+ qcom,ce-opp-freq = <100000000>;
+ };
+
+ qcom,pronto@a21b000 {
+ compatible = "qcom,pil-tz-generic";
+ reg = <0x0a21b000 0x3000>;
+ interrupts = <0 149 1>;
+
+ vdd_pronto_pll-supply = <&pm8909_l7>;
+ proxy-reg-names = "vdd_pronto_pll";
+ vdd_pronto_pll-uV-uA = <1800000 18000>;
+ clocks = <&clock_rpm clk_xo_pil_pronto_clk>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>,
+ <&clock_gcc clk_crypto_clk_src>;
+
+ clock-names = "xo", "scm_core_clk", "scm_iface_clk",
+ "scm_bus_clk", "scm_core_clk_src";
+ qcom,proxy-clock-names = "xo", "scm_core_clk", "scm_iface_clk",
+ "scm_bus_clk", "scm_core_clk_src";
+ qcom,scm_core_clk_src = <80000000>;
+
+ qcom,pas-id = <6>;
+ qcom,proxy-timeout-ms = <10000>;
+ qcom,smem-id = <422>;
+ qcom,sysmon-id = <6>;
+ qcom,ssctl-instance-id = <0x13>;
+ qcom,firmware-name = "wcnss";
+
+ /* GPIO inputs from wcnss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_4_in 3 0>;
+
+ /* GPIO output to wcnss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
+ memory-region = <&peripheral_mem>;
+ };
+
+ qcom,mss@4080000 {
+ compatible = "qcom,pil-q6v55-mss";
+ reg = <0x04080000 0x100>,
+ <0x0194f000 0x010>,
+ <0x01950000 0x008>,
+ <0x01951000 0x008>,
+ <0x04020000 0x040>,
+ <0x0183e000 0x004>;
+ reg-names = "qdsp6_base", "halt_q6", "halt_modem", "halt_nc",
+ "rmb_base", "restart_reg";
+
+ interrupts = <0 24 1>;
+ vdd_cx-supply = <&pm8909_s1_corner>;
+ vdd_cx-voltage = <7>;
+ vdd_mx-supply = <&pm8909_l3_corner_ao>;
+ vdd_mx-uV = <3>;
+ vdd_pll-supply = <&pm8909_l7>;
+ qcom,vdd_pll = <1800000>;
+
+ clocks = <&clock_rpm clk_xo_pil_mss_clk>,
+ <&clock_gcc clk_gcc_mss_cfg_ahb_clk>,
+ <&clock_gcc clk_gcc_mss_q6_bimc_axi_clk>,
+ <&clock_gcc clk_gcc_boot_rom_ahb_clk>;
+ clock-names = "xo", "iface_clk", "bus_clk", "mem_clk";
+ qcom,proxy-clock-names = "xo";
+ qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk";
+
+ qcom,firmware-name = "modem";
+ qcom,pil-self-auth;
+ qcom,sysmon-id = <0>;
+ qcom,ssctl-instance-id = <0x12>;
+
+ /* GPIO inputs from mss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>;
+
+ /* GPIO output to mss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
+ memory-region = <&modem_adsp_mem>;
+ };
+
+ mcd {
+ compatible = "qcom,mcd";
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ clocks = <&clock_gcc clk_crypto_clk_src>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ qcom,ce-opp-freq = <100000000>;
+ };
+
+ cpu0_slp_sts: cpu-sleep-status@b088008 {
+ reg = <0xb088008 0x100>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
+
+ cpu1_slp_sts: cpu-sleep-status@b098008 {
+ reg = <0xb098008 0x100>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
+
+ cpu2_slp_sts: cpu-sleep-status@b0a8008 {
+ reg = <0xb0a8008 0x100>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
+
+ cpu3_slp_sts: cpu-sleep-status@b0b8008 {
+ reg = <0xb0b8008 0x100>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
+};
+
+&gdsc_venus {
+ clock-names = "bus_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_venus0_axi_clk>,
+ <&clock_gcc clk_gcc_venus0_vcodec0_clk>;
+ status = "okay";
+};
+
+&gdsc_venus_core0 {
+ qcom,support-hw-trigger;
+ clock-names = "core0_clk";
+ clocks = <&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>;
+ status = "okay";
+};
+
+&gdsc_mdss {
+ clock-names = "core_clk", "bus_clk";
+ clocks = <&clock_gcc clk_gcc_mdss_mdp_clk>,
+ <&clock_gcc clk_gcc_mdss_axi_clk>;
+ status = "okay";
+};
+
+&gdsc_vfe {
+ clock-names = "core_clk", "bus_clk", "csi_clk";
+ clocks = <&clock_gcc clk_gcc_camss_vfe0_clk>,
+ <&clock_gcc clk_gcc_camss_vfe_axi_clk>,
+ <&clock_gcc clk_gcc_camss_csi_vfe0_clk>;
+ status = "okay";
+};
+
+&gdsc_oxili_gx {
+ clock-names = "core_clk";
+ clocks = <&clock_gcc clk_gcc_oxili_gfx3d_clk>;
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi b/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi
new file mode 100644
index 0000000..945b945
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017-2018 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.
+ */
+
+&external_image_mem {
+ reg = <0x0 0x87b00000 0x0 0x0500000>;
+};
+
+&modem_adsp_mem {
+ reg = <0x0 0x88000000 0x0 0x05200000>;
+};
+
+&peripheral_mem {
+ reg = <0x0 0x8d200000 0x0 0x0600000>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
new file mode 100644
index 0000000..8bcbe68
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2017-2018 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 "msm8909-mtp.dtsi"
+#include "msm8909w.dtsi"
+#include "msm8909w-bg-memory.dtsi"
+#include "8909w-pm660.dtsi"
+#include "msm8909-audio-bg_codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8909W-PM660 BLACKGHOST WTP";
+ compatible = "qcom,msm8909-mtp", "qcom,msm8909", "qcom,mtp";
+ qcom,msm-id = <245 0>,
+ <258 0>,
+ <275 0>,
+ <300 0>;
+ qcom,board-id = <8 0x10f>;
+ qcom,pmic-id = <0x0001001b 0x0 0x0 0x0>,
+ <0x0001011b 0x0 0x0 0x0>;
+};
+
+&soc {
+ i2c@78b9000 { /* BLSP1 QUP5 */
+ synaptics@20 {
+ compatible = "synaptics,dsx-i2c";
+ reg = <0x20>;
+ interrupt-parent = <&msm_gpio>;
+ interrupts = <98 0x2008>;
+ vdd_ana-supply = <&pm660_l18>;
+ vcc_i2c-supply = <&pm660_l13>;
+ synaptics,pwr-reg-name = "vdd_ana";
+ synaptics,bus-reg-name = "vcc_i2c";
+ pinctrl-names = "pmx_ts_active", "pmx_ts_suspend",
+ "pmx_ts_release";
+ pinctrl-0 = <&ts_int_active &ts_reset_active>;
+ pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+ pinctrl-2 = <&ts_release>;
+ synaptics,irq-gpio = <&msm_gpio 98 0x2008>;
+ synaptics,irq-on-state = <0>;
+ synaptics,irq-flags = <0x2008>;
+ synaptics,power-delay-ms = <200>;
+ synaptics,reset-delay-ms = <200>;
+ synaptics,max-y-for-2d = <389>;
+ synaptics,wakeup-gestures-en;
+ synaptics,resume-in-workqueue;
+ synaptics,x-flip;
+ synaptics,y-flip;
+ /delete-property/ synaptics,reset-gpio;
+ /delete-property/ synaptics,display-coords;
+ /delete-property/ synaptics,panel-coords;
+ /delete-property/ synaptics,power-down;
+ /delete-property/ synaptics,disable-gpios;
+ /delete-property/ synaptics,is_wake;
+ };
+
+ /delete-node/ it7260@46;
+ };
+
+ qcom,msm-ssc-sensors {
+ compatible = "qcom,msm-ssc-sensors";
+ };
+
+ qcom,glink-bgcom-xprt-bg {
+ compatible = "qcom,glink-bgcom-xprt";
+ label = "bg";
+ qcom,qos-config = <&glink_qos_bg>;
+ qcom,ramp-time = <0x10>,
+ <0x20>,
+ <0x30>,
+ <0x40>;
+ };
+
+ glink_qos_bg: qcom,glink-qos-config-bg {
+ compatible = "qcom,glink-qos-config";
+ qcom,flow-info = <0x80 0x0>,
+ <0x70 0x1>,
+ <0x60 0x2>,
+ <0x50 0x3>;
+ qcom,mtu-size = <0x800>;
+ qcom,tput-stats-cycle = <0xa>;
+ };
+
+ qcom,glink_pkt {
+ compatible = "qcom,glinkpkt";
+
+ qcom,glinkpkt-bg-daemon {
+ qcom,glinkpkt-transport = "bgcom";
+ qcom,glinkpkt-edge = "bg";
+ qcom,glinkpkt-ch-name = "bg-daemon";
+ qcom,glinkpkt-dev-name = "glink_pkt_bg_daemon";
+ };
+
+ qcom,glinkpkt-bg-display-ctrl {
+ qcom,glinkpkt-transport = "bgcom";
+ qcom,glinkpkt-edge = "bg";
+ qcom,glinkpkt-ch-name = "display-ctrl";
+ qcom,glinkpkt-dev-name = "glink_pkt_bg_display_ctrl";
+ };
+
+ qcom,glinkpkt-bg-display-data {
+ qcom,glinkpkt-transport = "bgcom";
+ qcom,glinkpkt-edge = "bg";
+ qcom,glinkpkt-ch-name = "display-data";
+ qcom,glinkpkt-dev-name = "glink_pkt_bg_display_data";
+ };
+
+ qcom,glinkpkt-bg-rsb-ctrl {
+ qcom,glinkpkt-transport = "bgcom";
+ qcom,glinkpkt-edge = "bg";
+ qcom,glinkpkt-ch-name = "RSB_CTRL";
+ qcom,glinkpkt-dev-name = "glink_pkt_bg_rsb_ctrl";
+ };
+ };
+
+ spi@78B8000 { /* BLSP1 QUP4 */
+ status = "ok";
+ qcom,bg-spi {
+ compatible = "qcom,bg-spi";
+ reg = <0>;
+ spi-max-frequency = <16000000>;
+ interrupt-parent = <&msm_gpio>;
+ qcom,irq-gpio = <&msm_gpio 110 1>;
+ };
+ };
+
+ qcom,msm-thermal {
+ vdd-dig-supply = <&pm660_s2_floor_corner>;
+
+ msm_thermal_freq: qcom,vdd-apps-rstr {
+ qcom,vdd-rstr-reg = "vdd-apps";
+ qcom,levels = <1094400>;
+ qcom,freq-req;
+ };
+ };
+
+ qcom,bg-rsb {
+ compatible = "qcom,bg-rsb";
+ vdd-ldo1-supply = <&pm660_l11>;
+ vdd-ldo2-supply = <&pm660_l15>;
+ };
+
+ qcom,bg-daemon {
+ compatible = "qcom,bg-daemon";
+ qcom,bg-reset-gpio = <&pm660_gpios 5 0>;
+ };
+
+ qcom,bcl {
+ compatible = "qcom,bcl";
+ qcom,bcl-enable;
+ qcom,bcl-framework-interface;
+ qcom,bcl-freq-control-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
+ qcom,bcl-hotplug-list = <&CPU2 &CPU3>;
+ qcom,bcl-soc-hotplug-list = <&CPU2 &CPU3>;
+ qcom,ibat-monitor {
+ qcom,low-threshold-uamp = <1000000>;
+ qcom,high-threshold-uamp = <2000000>;
+ qcom,mitigation-freq-khz = <1094400>;
+ qcom,vph-high-threshold-uv = <3500000>;
+ qcom,vph-low-threshold-uv = <3200000>;
+ qcom,soc-low-threshold = <10>;
+ qcom,thermal-handle = <&msm_thermal_freq>;
+ };
+ };
+};
+
+&audio_codec_mtp {
+ status = "disabled";
+};
+
+&audio_codec_bg {
+ status = "ok";
+};
+
+&bg_cdc {
+ status = "ok";
+ vdd-spkr-supply = <&pm660_l11>;
+};
+
+&i2c_1 {
+ status = "okay";
+ nq@28 {
+ compatible = "qcom,nq-nci";
+ reg = <0x28>;
+ qcom,nq-irq = <&msm_gpio 50 0x00>;
+ qcom,nq-ven = <&msm_gpio 36 0x00>;
+ qcom,nq-firm = <&msm_gpio 38 0x00>;
+ qcom,nq-esepwr = <&msm_gpio 49 0x00>;
+ qcom,nq-clkreq = <&pm660_gpios 4 0x00>;
+ qcom,clk-src = "BBCLK3";
+ interrupt-parent = <&msm_gpio>;
+ interrupts = <50 0>;
+ interrupt-names = "nfc_irq";
+ pinctrl-names = "nfc_active","nfc_suspend";
+ pinctrl-0 = <&nfcw_int_active
+ &nfcw_disable_active
+ &nfc_clk_default>;
+ pinctrl-1 = <&nfcw_int_suspend &nfcw_disable_suspend>;
+ clock-names = "ref_clk";
+ };
+};
+
+&spi_0 {
+ status = "disabled";
+};
+
+&i2c_3 {
+ status = "disabled";
+};
+
+&i2c_4 {
+ status = "disabled";
+};
+
+&i2c_2 {
+ status = "disabled";
+};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&blsp1_uart1 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_console_sleep>;
+};
+
+/* Pinctrl dt nodes for interrupt & reset gpio for Synaptics touch controller */
+&ts_int_active {
+ mux {
+ pins = "gpio98";
+ };
+
+ config {
+ pins = "gpio98";
+ };
+};
+
+&ts_int_suspend {
+ mux {
+ pins = "gpio98";
+ };
+
+ config {
+ pins = "gpio98";
+ /delete-property/ bias-pull-down;
+ bias-disable; /* No PULL */
+ };
+};
+
+&ts_reset_active {
+ mux {
+ pins = "gpio16";
+ };
+
+ config {
+ pins = "gpio16";
+ };
+};
+
+&ts_reset_suspend {
+ mux {
+ pins = "gpio16";
+ };
+
+ config {
+ pins = "gpio16";
+ };
+};
+
+&ts_release {
+ mux {
+ pins = "gpio98", "gpio16";
+ };
+
+ config {
+ pins = "gpio98", "gpio16";
+ };
+};
+
+&spi4_cs0_active {
+ mux {
+ pins = "gpio14";
+ function = "blsp_spi4";
+ };
+ config {
+ pins = "gpio14";
+ drive-strength = <2>;
+ bias-disable; /* No PULL */
+ output-high;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909w-pm660-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8909w-pm660-regulator.dtsi
new file mode 100644
index 0000000..512b0fb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909w-pm660-regulator.dtsi
@@ -0,0 +1,411 @@
+/* Copyright (c) 2017-2018, 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.
+ */
+
+&rpm_bus {
+ /* CX supply */
+ rpm-regulator-smpa2 {
+ status = "okay";
+ pm660_s2_corner: regulator-s2-corner {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_s2_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ status = "okay";
+ };
+
+ pm660_s2_corner_ao: regulator-s2-corner-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_s2_corner_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ };
+
+ pm660_s2_floor_corner: regulator-s2-floor-corner {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_s2_floor_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-floor-corner;
+ qcom,always-send-voltage;
+ };
+
+ pm660_s2_corner_so: regulator-s2-corner-so {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_s2_corner_so";
+ qcom,set = <2>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,init-voltage = <1>;
+ qcom,use-voltage-corner;
+ };
+ };
+
+ /* MX supply */
+ rpm-regulator-smpa3 {
+ status = "okay";
+ pm660_s3_corner: regulator-s3-corner {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_s3_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ status = "okay";
+ };
+
+ pm660_s3_corner_ao: regulator-s3-corner-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_s3_corner_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ };
+
+ pm660_s3_corner_so: regulator-s3-corner-so {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_s3_corner_so";
+ qcom,set = <2>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,init-voltage = <1>;
+ qcom,use-voltage-corner;
+ };
+ };
+
+ rpm-regulator-smpa4 {
+ status = "okay";
+ pm660_s4: regulator-s4 {
+ regulator-min-microvolt = <2040000>;
+ regulator-max-microvolt = <2040000>;
+ qcom,init-voltage = <2040000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa5 {
+ status = "okay";
+ pm660_s5: regulator-s5 {
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ qcom,init-voltage = <1350000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa6 {
+ status = "okay";
+ pm660_s6: regulator-s6 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1225000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ status = "okay";
+ pm660_l1: regulator-l1 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ qcom,init-voltage = <1000000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ status = "okay";
+ pm660_l2: regulator-l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1200000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ status = "okay";
+ pm660_l3: regulator-l3 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1050000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ status = "okay";
+ pm660_l5: regulator-l5 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1200000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ status = "okay";
+ pm660_l6: regulator-l6 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,init-voltage = <1300000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ status = "okay";
+ pm660_l7: regulator-l7 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1200000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ status = "okay";
+ pm660_l8: regulator-l8 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ status = "okay";
+ pm660_l9: regulator-l9 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ status = "okay";
+ pm660_l10: regulator-l10 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ status = "okay";
+ pm660_l11: regulator-l11 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ status = "okay";
+ pm660_l12: regulator-l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+
+ pm660_l12_ao: regulator-l12-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l12_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ status = "okay";
+ pm660_l13: regulator-l13 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa14 {
+ status = "okay";
+ pm660_l14: regulator-l14 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa15 {
+ status = "okay";
+ pm660_l15: regulator-l15 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <3300000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa16 {
+ status = "okay";
+ pm660_l16: regulator-l16 {
+ regulator-min-microvolt = <3100000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <3100000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ status = "okay";
+ pm660_l17: regulator-l17 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ qcom,init-voltage = <2700000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa18 {
+ status = "okay";
+ pm660_l18: regulator-l18 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,init-voltage = <3000000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa19 {
+ status = "okay";
+ pm660_l19: regulator-l19 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ qcom,init-voltage = <2900000>;
+ status = "okay";
+ };
+ };
+};
+
+/* SPM controlled regulators */
+&spmi_bus {
+ qcom,pm660@1 {
+ pm660_s1: spm-regulator@1400 {
+ compatible = "qcom,spm-regulator";
+ regulator-name = "pm660_s1";
+ reg = <0x1400 0x100>;
+ regulator-min-microvolt = <1052000>;
+ regulator-max-microvolt = <1352000>;
+ };
+ };
+};
+
+/* CPR controlled regulator */
+&soc {
+ mem_acc_vreg_corner: regulator@1942130 {
+ compatible = "qcom,mem-acc-regulator";
+ reg = <0x1942130 0x4>;
+ reg-names = "acc-sel-l1";
+ regulator-name = "mem_acc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <3>;
+
+ qcom,acc-sel-l1-bit-pos = <0>;
+ qcom,corner-acc-map = <0 1 1>;
+ };
+
+ apc_vreg_corner: regulator@b018000 {
+ compatible = "qcom,cpr-regulator";
+ reg = <0xb018000 0x1000>, <0xb011064 4>, <0x58000 0x1000>;
+ reg-names = "rbcpr", "rbcpr_clk", "efuse_addr";
+ interrupts = <0 15 0>;
+ regulator-name = "apc_corner";
+ qcom,cpr-fuse-corners = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <9>;
+
+ qcom,cpr-voltage-ceiling = <1052000 1228000 1352000>;
+ qcom,cpr-voltage-floor = <1052000 1052000 1156000>;
+ vdd-apc-supply = <&pm660_s1>;
+
+ qcom,vdd-mx-corner-map = <4 5 7>;
+ qcom,vdd-mx-vmin-method = <4>;
+ vdd-mx-supply = <&pm660_s3_corner_ao>;
+ qcom,vdd-mx-vmax = <7>;
+
+ mem-acc-supply = <&mem_acc_vreg_corner>;
+
+ qcom,cpr-ref-clk = <19200>;
+ qcom,cpr-timer-delay = <5000>;
+ qcom,cpr-timer-cons-up = <0>;
+ qcom,cpr-timer-cons-down = <2>;
+ qcom,cpr-irq-line = <0>;
+ qcom,cpr-step-quotient = <10>;
+ qcom,cpr-up-threshold = <0>;
+ qcom,cpr-down-threshold = <2>;
+ qcom,cpr-idle-clocks = <15>;
+ qcom,cpr-gcnt-time = <1>;
+ qcom,vdd-apc-step-up-limit = <1>;
+ qcom,vdd-apc-step-down-limit = <1>;
+ qcom,cpr-apc-volt-step = <4000>;
+
+ qcom,cpr-fuse-row = <26 0>;
+ qcom,cpr-fuse-target-quot = <42 24 6>;
+ qcom,cpr-fuse-ro-sel = <61 61 54>;
+ qcom,cpr-fuse-bp-cpr-disable = <58>;
+ qcom,cpr-fuse-init-voltage =
+ <26 36 6 0>,
+ <26 18 6 0>,
+ <26 0 6 0>;
+ qcom,cpr-fuse-revision = <26 59 2 0>;
+ qcom,cpr-init-voltage-ref = <1052000 1228000 1352000>;
+ qcom,cpr-init-voltage-step = <10000>;
+ qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3>;
+ qcom,cpr-init-voltage-as-ceiling;
+ qcom,cpr-corner-frequency-map =
+ <1 200000000>,
+ <2 400000000>,
+ <3 533330000>,
+ <4 800000000>,
+ <5 998400000>,
+ <6 1094400000>,
+ <7 1190400000>,
+ <8 1248000000>,
+ <9 1267200000>;
+ qcom,speed-bin-fuse-sel = <1 34 3 0>;
+ qcom,cpr-speed-bin-max-corners =
+ <0 (-1) 2 4 9>,
+ <2 (-1) 2 4 6>;
+ qcom,cpr-quot-adjust-scaling-factor-max = <1400>;
+ };
+
+ bob_vreg: bob_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "bob_vreg";
+ startup-delay-us = <400>;
+ enable-active-high;
+ gpio = <&pm660_gpios 12 0>;
+ status = "okay";
+ regulator-boot-on;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909w.dtsi b/arch/arm64/boot/dts/qcom/msm8909w.dtsi
new file mode 100644
index 0000000..707b56e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909w.dtsi
@@ -0,0 +1,96 @@
+/* Copyright (c) 2015-2018, 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.
+ */
+
+&soc {
+ /delete-node/ qcom,clock-a7@0b011050;
+ clock_cpu: qcom,clock-a7@0b011050 {
+ compatible = "qcom,clock-a53-8916";
+ reg = <0x0b011050 0x8>,
+ <0x0005c00c 0x8>;
+ reg-names = "rcg-base", "efuse";
+ qcom,safe-freq = < 400000000 >;
+ cpu-vdd-supply = <&apc_vreg_corner>;
+ clocks = <&clock_gcc clk_gpll0_ao_clk_src>,
+ <&clock_gcc clk_a7sspll>;
+ clock-names = "clk-4", "clk-5";
+ qcom,enable-opp;
+ qcom,speed0-bin-v0 =
+ < 0 0>,
+ < 800000000 4>,
+ < 1267200000 9>;
+
+ qcom,speed2-bin-v0 =
+ < 0 0>,
+ < 800000000 4>,
+ < 1094400000 6>;
+ #clock-cells = <1>;
+ };
+
+ /delete-node/ qcom,msm-cpufreq;
+ qcom,msm-cpufreq {
+ reg = <0 4>;
+ compatible = "qcom,msm-cpufreq";
+ clocks = <&clock_cpu clk_a7ssmux>,
+ <&clock_cpu clk_a7ssmux>,
+ <&clock_cpu clk_a7ssmux>,
+ <&clock_cpu clk_a7ssmux>;
+ clock-names = "cpu0_clk", "cpu1_clk",
+ "cpu2_clk", "cpu3_clk";
+ qcom,cpufreq-table =
+ < 800000 >,
+ < 1094400 >,
+ < 1267200 >;
+ };
+
+ /delete-node/ qcom,cpubw;
+ cpubw: qcom,cpubw {
+ compatible = "qcom,devbw";
+ governor = "cpufreq";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 732 /* 96 MHz */>,
+ < 1464 /* 192 MHz */>,
+ < 2929 /* 384 MHz */>;
+ };
+
+ /delete-node/ devfreq-cpufreq;
+ devfreq-cpufreq {
+ cpubw-cpufreq {
+ target-dev = <&cpubw>;
+ cpu-to-dev-map =
+ < 800000 1464>,
+ < 1094400 2929>,
+ < 1267200 2929>;
+ };
+ };
+};
+
+&qcom_crypto {
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 393600 393600>; /* 49.2MHz & 49.2MHz */
+};
+
+&qcom_cedev {
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 393600 393600>; /* 49.2MHz & 49.2MHz */
+};
+
+&qcom_seecom {
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 0 0>,
+ <55 512 196800 196800>,
+ <55 512 393600 393600>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 466ca57..08b88f6 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -796,6 +796,7 @@
"dsi_phy_regulator";
#clock-cells = <1>;
+ #phy-cells = <0>;
clocks = <&gcc GCC_MDSS_AHB_CLK>;
clock-names = "iface_clk";
@@ -906,8 +907,8 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,ipc-1 = <&apcs 0 13>;
- qcom,ipc-6 = <&apcs 0 19>;
+ qcom,ipc-1 = <&apcs 8 13>;
+ qcom,ipc-3 = <&apcs 8 19>;
apps_smsm: apps@0 {
reg = <0>;
diff --git a/arch/arm64/boot/dts/qcom/msm8917-bus.dtsi b/arch/arm64/boot/dts/qcom/msm8917-bus.dtsi
new file mode 100644
index 0000000..4a860e7
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-bus.dtsi
@@ -0,0 +1,987 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/msm/msm-bus-ids.h>
+
+&soc {
+ /* Version = 11 */
+ ad_hoc_bus: ad-hoc-bus@580000 {
+ compatible = "qcom,msm-bus-device";
+ reg = <0x580000 0x16080>,
+ <0x580000 0x16080>,
+ <0x400000 0x5a000>,
+ <0x500000 0x13080>;
+ reg-names = "snoc-base", "snoc-mm-base",
+ "bimc-base", "pcnoc-base";
+
+ /* Buses */
+ fab_bimc: fab-bimc {
+ cell-id = <MSM_BUS_FAB_BIMC>;
+ label = "fab-bimc";
+ qcom,fab-dev;
+ qcom,base-name = "bimc-base";
+ qcom,bus-type = <2>;
+ qcom,util-fact = <154>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_gcc clk_bimc_msmbus_clk>,
+ <&clock_gcc clk_bimc_msmbus_a_clk>;
+ };
+
+ fab_pcnoc: fab-pcnoc {
+ cell-id = <MSM_BUS_FAB_PERIPH_NOC>;
+ label = "fab-pcnoc";
+ qcom,fab-dev;
+ qcom,base-name = "pcnoc-base";
+ qcom,base-offset = <0x7000>;
+ qcom,qos-off = <0x1000>;
+ qcom,bus-type = <1>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_gcc clk_pnoc_msmbus_clk>,
+ <&clock_gcc clk_pnoc_msmbus_a_clk>;
+ };
+
+ fab_snoc: fab-snoc {
+ cell-id = <MSM_BUS_FAB_SYS_NOC>;
+ label = "fab-snoc";
+ qcom,fab-dev;
+ qcom,base-name = "snoc-base";
+ qcom,base-offset = <0x7000>;
+ qcom,qos-off = <0x1000>;
+ qcom,bus-type = <1>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_gcc clk_snoc_msmbus_clk>,
+ <&clock_gcc clk_snoc_msmbus_a_clk>;
+ };
+
+ fab_snoc_mm: fab-snoc-mm {
+ cell-id = <MSM_BUS_FAB_MMSS_NOC>;
+ label = "fab-snoc-mm";
+ qcom,fab-dev;
+ qcom,base-name = "snoc-mm-base";
+ qcom,base-offset = <0x7000>;
+ qcom,qos-off = <0x1000>;
+ qcom,bus-type = <1>;
+ qcom,util-fact = <154>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_gcc clk_sysmmnoc_msmbus_clk>,
+ <&clock_gcc clk_sysmmnoc_msmbus_a_clk>;
+ };
+
+ /* BIMC Masters */
+ mas_apps_proc: mas-apps-proc {
+ cell-id = <MSM_BUS_MASTER_AMPSS_M0>;
+ label = "mas-apps-proc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <0>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+ qcom,prio-lvl = <0>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_APPSS_PROC>;
+ };
+
+ mas_oxili: mas-oxili {
+ cell-id = <MSM_BUS_MASTER_GRAPHICS_3D>;
+ label = "mas-oxili";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <2>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+ qcom,prio-lvl = <0>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_GFX3D>;
+ };
+
+ mas_snoc_bimc_0: mas-snoc-bimc-0 {
+ cell-id = <MSM_BUS_SNOC_BIMC_0_MAS>;
+ label = "mas-snoc-bimc-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <3>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC_0>;
+ };
+
+ mas_snoc_bimc_2: mas-snoc-bimc-2 {
+ cell-id = <MSM_BUS_SNOC_BIMC_2_MAS>;
+ label = "mas-snoc-bimc-2";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <4>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC_2>;
+ };
+
+ mas_snoc_bimc_1: mas-snoc-bimc-1 {
+ cell-id = <MSM_BUS_SNOC_BIMC_1_MAS>;
+ label = "mas-snoc-bimc-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <5>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_ebi>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC_1>;
+ };
+
+ mas_tcu_0: mas-tcu-0 {
+ cell-id = <MSM_BUS_MASTER_TCU_0>;
+ label = "mas-tcu-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <6>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+ qcom,prio-lvl = <2>;
+ qcom,prio-rd = <2>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_TCU_0>;
+ };
+
+ /* PCNOC Masters */
+ mas_spdm: mas-spdm {
+ cell-id = <MSM_BUS_MASTER_SPDM>;
+ label = "mas-spdm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,connections = <&pcnoc_m_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SPDM>;
+ };
+
+ mas_blsp_1: mas-blsp-1 {
+ cell-id = <MSM_BUS_MASTER_BLSP_1>;
+ label = "mas-blsp-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_m_1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_BLSP_1>;
+ };
+
+ mas_blsp_2: mas-blsp-2 {
+ cell-id = <MSM_BUS_MASTER_BLSP_2>;
+ label = "mas-blsp-2";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_m_1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_BLSP_2>;
+ };
+
+ mas_usb_hs1: mas-usb-hs1 {
+ cell-id = <MSM_BUS_MASTER_USB_HS>;
+ label = "mas-usb-hs1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <12>;
+ qcom,qos-mode = "fixed";
+ qcom,prio1 = <1>;
+ qcom,prio0 = <1>;
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_USB_HS1>;
+ };
+
+ mas_xi_usb_hs1: mas-xi-usb-hs1 {
+ cell-id = <MSM_BUS_MASTER_XM_USB_HS1>;
+ label = "mas-xi-usb-hs1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <11>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_XI_USB_HS1>;
+ };
+
+ mas_crypto: mas-crypto {
+ cell-id = <MSM_BUS_MASTER_CRYPTO_CORE0>;
+ label = "mas-crypto";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <0>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,prio1 = <1>;
+ qcom,prio0 = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_CRYPTO>;
+ };
+
+ mas_sdcc_1: mas-sdcc-1 {
+ cell-id = <MSM_BUS_MASTER_SDCC_1>;
+ label = "mas-sdcc-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <7>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SDCC_1>;
+ };
+
+ mas_sdcc_2: mas-sdcc-2 {
+ cell-id = <MSM_BUS_MASTER_SDCC_2>;
+ label = "mas-sdcc-2";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <8>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SDCC_2>;
+ };
+
+ mas_snoc_pcnoc: mas-snoc-pcnoc {
+ cell-id = <MSM_BUS_SNOC_PNOC_MAS>;
+ label = "mas-snoc-pcnoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <9>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_s_7
+ &pcnoc_int_2 &pcnoc_int_3>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_PCNOC>;
+ };
+
+ /* SNOC Masters */
+ mas_qdss_bam: mas-qdss-bam {
+ cell-id = <MSM_BUS_MASTER_QDSS_BAM>;
+ label = "mas-qdss-bam";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <11>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&qdss_int>;
+ qcom,prio1 = <1>;
+ qcom,prio0 = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_QDSS_BAM>;
+ };
+
+ mas_bimc_snoc: mas-bimc-snoc {
+ cell-id = <MSM_BUS_BIMC_SNOC_MAS>;
+ label = "mas-bimc-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&snoc_int_0
+ &snoc_int_1 &snoc_int_2>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_BIMC_SNOC>;
+ };
+
+ mas_jpeg: mas-jpeg {
+ cell-id = <MSM_BUS_MASTER_JPEG>;
+ label = "mas-jpeg";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <6>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_snoc_bimc_2>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_JPEG>;
+ };
+
+ mas_mdp: mas-mdp {
+ cell-id = <MSM_BUS_MASTER_MDP_PORT0>;
+ label = "mas-mdp";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <7>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_snoc_bimc_0>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_MDP>;
+ };
+
+ mas_pcnoc_snoc: mas-pcnoc-snoc {
+ cell-id = <MSM_BUS_PNOC_SNOC_MAS>;
+ label = "mas-pcnoc-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <5>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&snoc_int_0
+ &snoc_int_1 &slv_snoc_bimc_1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PNOC_SNOC>;
+ qcom,blacklist = <&slv_snoc_pcnoc>;
+ };
+
+ mas_venus: mas-venus {
+ cell-id = <MSM_BUS_MASTER_VIDEO_P0>;
+ label = "mas-venus";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <8>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_snoc_bimc_2>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_VIDEO>;
+ };
+
+ mas_vfe0: mas-vfe0 {
+ cell-id = <MSM_BUS_MASTER_VFE>;
+ label = "mas-vfe0";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <9>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_snoc_bimc_0>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_VFE>;
+ };
+
+ mas_vfe1: mas-vfe1 {
+ cell-id = <MSM_BUS_MASTER_VFE1>;
+ label = "mas-vfe1";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <13>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_snoc_bimc_0>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_VFE1>;
+ };
+
+ mas_cpp: mas-cpp {
+ cell-id = <MSM_BUS_MASTER_CPP>;
+ label = "mas-cpp";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <12>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_snoc_bimc_2>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_CPP>;
+ };
+
+ mas_qdss_etr: mas-qdss-etr {
+ cell-id = <MSM_BUS_MASTER_QDSS_ETR>;
+ label = "mas-qdss-etr";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <10>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&qdss_int>;
+ qcom,prio1 = <1>;
+ qcom,prio0 = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_QDSS_ETR>;
+ };
+
+ /* Internal nodes */
+ pcnoc_m_0: pcnoc-m-0 {
+ cell-id = <MSM_BUS_PNOC_M_0>;
+ label = "pcnoc-m-0";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <5>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,prio1 = <1>;
+ qcom,prio0 = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_M_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_M_0>;
+ };
+
+ pcnoc_m_1: pcnoc-m-1 {
+ cell-id = <MSM_BUS_PNOC_M_1>;
+ label = "pcnoc-m-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_M_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_M_1>;
+ };
+
+ pcnoc_int_0: pcnoc-int-0 {
+ cell-id = <MSM_BUS_PNOC_INT_0>;
+ label = "pcnoc-int-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_pcnoc_snoc
+ &pcnoc_s_7 &pcnoc_int_3 &pcnoc_int_2>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_0>;
+ };
+
+ pcnoc_int_1: pcnoc-int-1 {
+ cell-id = <MSM_BUS_PNOC_INT_1>;
+ label = "pcnoc-int-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_pcnoc_snoc
+ &pcnoc_s_7 &pcnoc_int_3 &pcnoc_int_2>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_1>;
+ };
+
+ pcnoc_int_2: pcnoc-int-2 {
+ cell-id = <MSM_BUS_PNOC_INT_2>;
+ label = "pcnoc-int-2";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_s_2
+ &pcnoc_s_3 &pcnoc_s_6 &pcnoc_s_8>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_2>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_2>;
+ };
+
+ pcnoc_int_3: pcnoc-int-3 {
+ cell-id = <MSM_BUS_PNOC_INT_3>;
+ label = "pcnoc-int-3";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = < &pcnoc_s_1 &pcnoc_s_0 &pcnoc_s_4
+ &slv_gpu_cfg &slv_tcu >;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_3>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_3>;
+ };
+
+ pcnoc_s_0: pcnoc-s-0 {
+ cell-id = <MSM_BUS_PNOC_SLV_0>;
+ label = "pcnoc-s-0";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_spdm &slv_pdm &slv_prng
+ &slv_sdcc_2>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_0>;
+ };
+
+ pcnoc_s_1: pcnoc-s-1 {
+ cell-id = <MSM_BUS_PNOC_SLV_1>;
+ label = "pcnoc-s-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_tcsr>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_1>;
+ };
+
+ pcnoc_s_2: pcnoc-s-2 {
+ cell-id = <MSM_BUS_PNOC_SLV_2>;
+ label = "pcnoc-s-2";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_snoc_cfg>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_2>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_2>;
+ };
+
+ pcnoc_s_3: pcnoc-s-3 {
+ cell-id = <MSM_BUS_PNOC_SLV_3>;
+ label = "pcnoc-s-3";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_message_ram>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_3>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_3>;
+ };
+
+ pcnoc_s_4: pcnoc-s-4 {
+ cell-id = <MSM_BUS_PNOC_SLV_4>;
+ label = "pcnoc-s-4";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,connections = <&slv_camera_ss_cfg
+ &slv_disp_ss_cfg &slv_venus_cfg>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_4>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_4>;
+ };
+
+ pcnoc_s_6: pcnoc-s-6 {
+ cell-id = <MSM_BUS_PNOC_SLV_6>;
+ label = "pcnoc-s-6";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_tlmm &slv_blsp_1 &slv_blsp_2>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_6>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_6>;
+ };
+
+ pcnoc_s_7: pcnoc-s-7 {
+ cell-id = <MSM_BUS_PNOC_SLV_7>;
+ label = "pcnoc-s-7";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = < &slv_sdcc_1 &slv_pmic_arb>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_7>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_7>;
+ };
+
+ pcnoc_s_8: pcnoc-s-8 {
+ cell-id = <MSM_BUS_PNOC_SLV_8>;
+ label = "pcnoc-s-8";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_usb_hs &slv_crypto_0_cfg>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_8>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_8>;
+ };
+
+ qdss_int: qdss-int {
+ cell-id = <MSM_BUS_SNOC_QDSS_INT>;
+ label = "qdss-int";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,connections = <&snoc_int_1 &slv_snoc_bimc_1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_QDSS_INT>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_QDSS_INT>;
+ };
+
+ snoc_int_0: snoc-int-0 {
+ cell-id = <MSM_BUS_SNOC_INT_0>;
+ label = "snoc-int-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,connections = <&slv_lpass
+ &slv_wcss &slv_kpss_ahb>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_0>;
+ };
+
+ snoc_int_1: snoc-int-1 {
+ cell-id = <MSM_BUS_SNOC_INT_1>;
+ label = "snoc-int-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qdss_stm
+ &slv_imem &slv_snoc_pcnoc>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_1>;
+ };
+
+ snoc_int_2: snoc-int-2 {
+ cell-id = <MSM_BUS_SNOC_INT_2>;
+ label = "snoc-int-2";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,connections = <&slv_cats_0 &slv_cats_1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_2>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_2>;
+ };
+
+ /* Slaves */
+ slv_ebi:slv-ebi {
+ cell-id = <MSM_BUS_SLAVE_EBI_CH0>;
+ label = "slv-ebi";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_EBI1>;
+ };
+
+ slv_bimc_snoc:slv-bimc-snoc {
+ cell-id = <MSM_BUS_BIMC_SNOC_SLV>;
+ label = "slv-bimc-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,connections = <&mas_bimc_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_BIMC_SNOC>;
+ };
+
+ slv_sdcc_2:slv-sdcc-2 {
+ cell-id = <MSM_BUS_SLAVE_SDCC_2>;
+ label = "slv-sdcc-2";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SDCC_2>;
+ };
+
+ slv_spdm:slv-spdm {
+ cell-id = <MSM_BUS_SLAVE_SPDM_WRAPPER>;
+ label = "slv-spdm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SPDM_WRAPPER>;
+ };
+
+ slv_pdm:slv-pdm {
+ cell-id = <MSM_BUS_SLAVE_PDM>;
+ label = "slv-pdm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PDM>;
+ };
+
+ slv_prng:slv-prng {
+ cell-id = <MSM_BUS_SLAVE_PRNG>;
+ label = "slv-prng";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PRNG>;
+ };
+
+ slv_tcsr:slv-tcsr {
+ cell-id = <MSM_BUS_SLAVE_TCSR>;
+ label = "slv-tcsr";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_TCSR>;
+ };
+
+ slv_snoc_cfg:slv-snoc-cfg {
+ cell-id = <MSM_BUS_SLAVE_SNOC_CFG>;
+ label = "slv-snoc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_CFG>;
+ };
+
+ slv_message_ram:slv-message-ram {
+ cell-id = <MSM_BUS_SLAVE_MESSAGE_RAM>;
+ label = "slv-message-ram";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_MESSAGE_RAM>;
+ };
+
+ slv_camera_ss_cfg:slv-camera-ss-cfg {
+ cell-id = <MSM_BUS_SLAVE_CAMERA_CFG>;
+ label = "slv-camera-ss-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CAMERA_CFG>;
+ };
+
+ slv_disp_ss_cfg:slv-disp-ss-cfg {
+ cell-id = <MSM_BUS_SLAVE_DISPLAY_CFG>;
+ label = "slv-disp-ss-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_DISPLAY_CFG>;
+ };
+
+ slv_venus_cfg:slv-venus-cfg {
+ cell-id = <MSM_BUS_SLAVE_VENUS_CFG>;
+ label = "slv-venus-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_VENUS_CFG>;
+ };
+
+ slv_gpu_cfg:slv-gpu-cfg {
+ cell-id = <MSM_BUS_SLAVE_GRAPHICS_3D_CFG>;
+ label = "slv-gpu-cfg";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_GFX3D_CFG>;
+ };
+
+ slv_tlmm:slv-tlmm {
+ cell-id = <MSM_BUS_SLAVE_TLMM>;
+ label = "slv-tlmm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_TLMM>;
+ };
+
+ slv_blsp_1:slv-blsp-1 {
+ cell-id = <MSM_BUS_SLAVE_BLSP_1>;
+ label = "slv-blsp-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_BLSP_1>;
+ };
+
+ slv_blsp_2:slv-blsp-2 {
+ cell-id = <MSM_BUS_SLAVE_BLSP_2>;
+ label = "slv-blsp-2";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_BLSP_2>;
+ };
+
+ slv_pmic_arb:slv-pmic-arb {
+ cell-id = <MSM_BUS_SLAVE_PMIC_ARB>;
+ label = "slv-pmic-arb";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PMIC_ARB>;
+ };
+
+ slv_sdcc_1:slv-sdcc-1 {
+ cell-id = <MSM_BUS_SLAVE_SDCC_1>;
+ label = "slv-sdcc-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SDCC_1>;
+ };
+
+ slv_crypto_0_cfg:slv-crypto-0-cfg {
+ cell-id = <MSM_BUS_SLAVE_CRYPTO_0_CFG>;
+ label = "slv-crypto-0-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CRYPTO_0_CFG>;
+ };
+
+ slv_usb_hs:slv-usb-hs {
+ cell-id = <MSM_BUS_SLAVE_USB_HS>;
+ label = "slv-usb-hs";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_USB_HS>;
+ };
+
+ slv_tcu:slv-tcu {
+ cell-id = <MSM_BUS_SLAVE_TCU>;
+ label = "slv-tcu";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_TCU>;
+ };
+
+ slv_pcnoc_snoc:slv-pcnoc-snoc {
+ cell-id = <MSM_BUS_PNOC_SNOC_SLV>;
+ label = "slv-pcnoc-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,connections = <&mas_pcnoc_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_SNOC>;
+ };
+
+ slv_kpss_ahb:slv-kpss-ahb {
+ cell-id = <MSM_BUS_SLAVE_APPSS>;
+ label = "slv-kpss-ahb";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_APPSS>;
+ };
+
+ slv_wcss:slv-wcss {
+ cell-id = <MSM_BUS_SLAVE_WCSS>;
+ label = "slv-wcss";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_WCSS>;
+ };
+
+ slv_snoc_bimc_0:slv-snoc-bimc-0 {
+ cell-id = <MSM_BUS_SNOC_BIMC_0_SLV>;
+ label = "slv-snoc-bimc-0";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,connections = <&mas_snoc_bimc_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC_0>;
+ };
+
+ slv_snoc_bimc_1:slv-snoc-bimc-1 {
+ cell-id = <MSM_BUS_SNOC_BIMC_1_SLV>;
+ label = "slv-snoc-bimc-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,connections = <&mas_snoc_bimc_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC_1>;
+ };
+
+ slv_snoc_bimc_2:slv-snoc-bimc-2 {
+ cell-id = <MSM_BUS_SNOC_BIMC_2_SLV>;
+ label = "slv-snoc-bimc-2";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,connections = <&mas_snoc_bimc_2>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC_2>;
+ };
+
+ slv_imem:slv-imem {
+ cell-id = <MSM_BUS_SLAVE_OCIMEM>;
+ label = "slv-imem";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_IMEM>;
+ };
+
+ slv_snoc_pcnoc:slv-snoc-pcnoc {
+ cell-id = <MSM_BUS_SNOC_PNOC_SLV>;
+ label = "slv-snoc-pcnoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,connections = <&mas_snoc_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_PCNOC>;
+ };
+
+ slv_qdss_stm:slv-qdss-stm {
+ cell-id = <MSM_BUS_SLAVE_QDSS_STM>;
+ label = "slv-qdss-stm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_QDSS_STM>;
+ };
+
+ slv_cats_0:slv-cats-0 {
+ cell-id = <MSM_BUS_SLAVE_CATS_128>;
+ label = "slv-cats-0";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CATS_0>;
+ };
+
+ slv_cats_1:slv-cats-1 {
+ cell-id = <MSM_BUS_SLAVE_OCMEM_64>;
+ label = "slv-cats-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CATS_1>;
+ };
+
+ slv_lpass:slv-lpass {
+ cell-id = <MSM_BUS_SLAVE_LPASS>;
+ label = "slv-lpass";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_LPASS>;
+ };
+ };
+
+ devfreq_spdm_cpu {
+ compatible = "qcom,devfreq_spdm";
+ qcom,msm-bus,name = "devfreq_spdm";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <1 512 0 0>,
+ <1 512 0 0>;
+ qcom,msm-bus,active-only;
+ qcom,spdm-client = <0>;
+
+ clock-names = "cci_clk";
+ clocks = <&clock_cpu clk_a53_bc_clk>;
+
+ qcom,bw-upstep = <400>;
+ qcom,bw-dwnstep = <2800>;
+ qcom,max-vote = <2800>;
+ qcom,up-step-multp = <2>;
+ qcom,spdm-interval = <50>;
+
+ qcom,ports = <11>;
+ qcom,alpha-up = <8>;
+ qcom,alpha-down = <15>;
+ qcom,bucket-size = <8>;
+
+ /* max pl1 freq, max pl2 freq */
+ qcom,pl-freqs = <310000 570000>;
+
+ /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+ qcom,reject-rate = <5000 5000 5000 5000 5000 5000>;
+ /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+ qcom,response-time-us = <5000 5000 5000 5000 2000 2000>;
+ /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+ qcom,cci-response-time-us = <3000 3000 4000 4000 2000 2000>;
+ qcom,max-cci-freq = <1300000>;
+ };
+
+ devfreq_spdm_gov {
+ compatible = "qcom,gov_spdm_hyp";
+ interrupt-names = "spdm-irq";
+ interrupts = <0 192 0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi
new file mode 100644
index 0000000..792d5d1
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+/ {
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu-map {
+
+ cluster0 {
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&CPU0>;
+ };
+ core1 {
+ cpu = <&CPU1>;
+ };
+ core2 {
+ cpu = <&CPU2>;
+ };
+ core3 {
+ cpu = <&CPU3>;
+ };
+ };
+ };
+
+ CPU0: cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x100>;
+ enable-method = "psci";
+ cpu-release-addr = <0x0 0x90000000>;
+ next-level-cache = <&L2_1>;
+ L2_1: l2-cache {
+ compatible = "arm,arch-cache";
+ cache-level = <2>;
+ /* A53 L2 dump not supported */
+ qcom,dump-size = <0x0>;
+ };
+ L1_I_100: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x8800>;
+ };
+ L1_D_100: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9000>;
+ };
+ };
+
+ CPU1: cpu@101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x101>;
+ enable-method = "psci";
+ cpu-release-addr = <0x0 0x90000000>;
+ next-level-cache = <&L2_1>;
+ L1_I_101: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x8800>;
+ };
+ L1_D_101: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9000>;
+ };
+ };
+
+ CPU2: cpu@102 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x102>;
+ enable-method = "psci";
+ cpu-release-addr = <0x0 0x90000000>;
+ next-level-cache = <&L2_1>;
+ L1_I_102: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x8800>;
+ };
+ L1_D_102: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9000>;
+ };
+ };
+
+ CPU3: cpu@103 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x103>;
+ enable-method = "psci";
+ cpu-release-addr = <0x0 0x90000000>;
+ next-level-cache = <&L2_1>;
+ L1_I_103: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x8800>;
+ };
+ L1_D_103: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9000>;
+ };
+ };
+
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8917-ion.dtsi
new file mode 100644
index 0000000..96e7166
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-ion.dtsi
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015-2016, 2018, 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.
+ */
+
+&soc {
+ qcom,ion {
+ compatible = "qcom,msm-ion";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ion-heap@25 {
+ reg = <25>;
+ qcom,ion-heap-type = "SYSTEM";
+ };
+
+ qcom,ion-heap@8 { /* CP_MM HEAP */
+ reg = <8>;
+ memory-region = <&secure_mem>;
+ qcom,ion-heap-type = "SECURE_DMA";
+ };
+
+ qcom,ion-heap@27 { /* QSEECOM HEAP */
+ reg = <27>;
+ memory-region = <&qseecom_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
+
+ qcom,ion-heap@19 { /* QSEECOM TA HEAP */
+ reg = <19>;
+ memory-region = <&qseecom_ta_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
new file mode 100644
index 0000000..a558c8e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&blsp1_uart2 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_console_active>;
+};
+
+&sdhc_1 {
+ /* device core power supply */
+ vdd-supply = <&pm8937_l8>;
+ qcom,vdd-voltage-level = <2900000 2900000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8937_l5>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+ 384000000>;
+ qcom,nonremovable;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+ status = "ok";
+};
+
+&sdhc_2 {
+ /* device core power supply */
+ vdd-supply = <&pm8937_l11>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 800000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8937_l12>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+ cd-gpios = <&tlmm 67 0x1>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+ 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi
new file mode 100644
index 0000000..b8516d5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi
@@ -0,0 +1,1669 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&soc {
+ tlmm: pinctrl@1000000 {
+ compatible = "qcom,msm8917-pinctrl";
+ reg = <0x1000000 0x300000>;
+ interrupts = <0 208 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+
+ /* add pingrp for touchscreen */
+ pmx_ts_int_active {
+ ts_int_active: ts_int_active {
+ mux {
+ pins = "gpio65";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio65";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ pmx_ts_int_suspend {
+ ts_int_suspend: ts_int_suspend {
+ mux {
+ pins = "gpio65";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio65";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+ };
+
+ pmx_ts_reset_active {
+ ts_reset_active: ts_reset_active {
+ mux {
+ pins = "gpio64";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio64";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ pmx_ts_reset_suspend {
+ ts_reset_suspend: ts_reset_suspend {
+ mux {
+ pins = "gpio64";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio64";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+ };
+
+ pmx_ts_release {
+ ts_release: ts_release {
+ mux {
+ pins = "gpio65", "gpio64";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio65", "gpio64";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+ };
+
+ pmx-uartconsole {
+ uart_console_active: uart_console_active {
+ mux {
+ pins = "gpio4", "gpio5";
+ function = "blsp_uart2";
+ };
+
+ config {
+ pins = "gpio4", "gpio5";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ uart_console_sleep: uart_console_sleep {
+ mux {
+ pins = "gpio4", "gpio5";
+ function = "blsp_uart2";
+ };
+
+ config {
+ pins = "gpio4", "gpio5";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ };
+
+ blsp1_uart1 {
+ blsp1_uart1_active: blsp1_uart1_active {
+ mux {
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ function = "blsp_uart1";
+ };
+
+ config {
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart1_sleep: blsp1_uart1_sleep {
+ mux {
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ wcnss_pmux_5wire {
+ /* Active configuration of bus pins */
+ wcnss_default: wcnss_default {
+ wcss_wlan2 {
+ pins = "gpio76";
+ function = "wcss_wlan2";
+ };
+ wcss_wlan1 {
+ pins = "gpio77";
+ function = "wcss_wlan1";
+ };
+ wcss_wlan0 {
+ pins = "gpio78";
+ function = "wcss_wlan0";
+ };
+ wcss_wlan {
+ pins = "gpio79", "gpio80";
+ function = "wcss_wlan";
+ };
+
+ config {
+ pins = "gpio76", "gpio77",
+ "gpio78", "gpio79",
+ "gpio80";
+ drive-strength = <6>; /* 6 MA */
+ bias-pull-up; /* PULL UP */
+ };
+ };
+
+ wcnss_sleep: wcnss_sleep {
+ wcss_wlan2 {
+ pins = "gpio76";
+ function = "wcss_wlan2";
+ };
+ wcss_wlan1 {
+ pins = "gpio77";
+ function = "wcss_wlan1";
+ };
+ wcss_wlan0 {
+ pins = "gpio78";
+ function = "wcss_wlan0";
+ };
+ wcss_wlan {
+ pins = "gpio79", "gpio80";
+ function = "wcss_wlan";
+ };
+
+ config {
+ pins = "gpio76", "gpio77",
+ "gpio78", "gpio79",
+ "gpio80";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down; /* PULL Down */
+ };
+ };
+ };
+
+ wcnss_pmux_gpio: wcnss_pmux_gpio {
+ wcnss_gpio_default: wcnss_gpio_default {
+ /* Active configuration of bus pins */
+ mux {
+ /* Uses general purpose pins */
+ pins = "gpio76", "gpio77",
+ "gpio78", "gpio79",
+ "gpio80";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio76", "gpio77",
+ "gpio78", "gpio79",
+ "gpio80";
+ drive-strength = <6>; /* 6 MA */
+ bias-pull-up; /* PULL UP */
+ };
+ };
+ };
+
+ pmx_mdss: pmx_mdss {
+ mdss_dsi_active: mdss_dsi_active {
+ mux {
+ pins = "gpio60", "gpio98";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio60", "gpio98";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable = <0>; /* no pull */
+ output-high;
+ };
+ };
+ mdss_dsi_suspend: mdss_dsi_suspend {
+ mux {
+ pins = "gpio60", "gpio98";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio60", "gpio98";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* pull down */
+ };
+ };
+ };
+
+ pmx_mdss_te {
+ mdss_te_active: mdss_te_active {
+ mux {
+ pins = "gpio24";
+ function = "mdp_vsync";
+ };
+
+ config {
+ pins = "gpio24";
+ drive-strength = <2>; /* 8 mA */
+ bias-pull-down; /* pull down*/
+ };
+ };
+ mdss_te_suspend: mdss_te_suspend {
+ mux {
+ pins = "gpio24";
+ function = "mdp_vsync";
+ };
+
+ config {
+ pins = "gpio24";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* pull down */
+ };
+ };
+ };
+
+ pmx_qdsd_clk {
+ qdsd_clk_sdcard: clk_sdcard {
+ config {
+ pins = "qdsd_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <16>; /* 16 MA */
+ };
+ };
+ qdsd_clk_trace: clk_trace {
+ config {
+ pins = "qdsd_clk";
+ bias-pull-down; /* pull down */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_clk_swdtrc: clk_swdtrc {
+ config {
+ pins = "qdsd_clk";
+ bias-pull-down; /* pull down */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_clk_spmi: clk_spmi {
+ config {
+ pins = "qdsd_clk";
+ bias-pull-down; /* pull down */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ pmx_qdsd_cmd {
+ qdsd_cmd_sdcard: cmd_sdcard {
+ config {
+ pins = "qdsd_cmd";
+ bias-pull-down; /* pull down */
+ drive-strength = <8>; /* 8 MA */
+ };
+ };
+ qdsd_cmd_trace: cmd_trace {
+ config {
+ pins = "qdsd_cmd";
+ bias-pull-down; /* pull down */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_cmd_swduart: cmd_uart {
+ config {
+ pins = "qdsd_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_cmd_swdtrc: cmd_swdtrc {
+ config {
+ pins = "qdsd_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_cmd_jtag: cmd_jtag {
+ config {
+ pins = "qdsd_cmd";
+ bias-disable; /* NO pull */
+ drive-strength = <8>; /* 8 MA */
+ };
+ };
+ qdsd_cmd_spmi: cmd_spmi {
+ config {
+ pins = "qdsd_cmd";
+ bias-pull-down; /* pull down */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+ };
+
+ pmx_qdsd_data0 {
+ qdsd_data0_sdcard: data0_sdcard {
+ config {
+ pins = "qdsd_data0";
+ bias-pull-down; /* pull down */
+ drive-strength = <8>; /* 8 MA */
+ };
+ };
+ qdsd_data0_trace: data0_trace {
+ config {
+ pins = "qdsd_data0";
+ bias-pull-down; /* pull down */
+ drive-strength = <8>; /* 8 MA */
+ };
+ };
+ qdsd_data0_swduart: data0_uart {
+ config {
+ pins = "qdsd_data0";
+ bias-pull-down; /* pull down */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_data0_swdtrc: data0_swdtrc {
+ config {
+ pins = "qdsd_data0";
+ bias-pull-down; /* pull down */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_data0_jtag: data0_jtag {
+ config {
+ pins = "qdsd_data0";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_data0_spmi: data0_spmi {
+ config {
+ pins = "qdsd_data0";
+ bias-pull-down; /* pull down */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ pmx_qdsd_data1 {
+ qdsd_data1_sdcard: data1_sdcard {
+ config {
+ pins = "qdsd_data1";
+ bias-pull-down; /* pull down */
+ drive-strength = <8>; /* 8 MA */
+ };
+ };
+ qdsd_data1_trace: data1_trace {
+ config {
+ pins = "qdsd_data1";
+ bias-pull-down; /* pull down */
+ drive-strength = <8>; /* 8 MA */
+ };
+ };
+ qdsd_data1_swduart: data1_uart {
+ config {
+ pins = "qdsd_data1";
+ bias-pull-down; /* pull down */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_data1_swdtrc: data1_swdtrc {
+ config {
+ pins = "qdsd_data1";
+ bias-pull-down; /* pull down */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_data1_jtag: data1_jtag {
+ config {
+ pins = "qdsd_data1";
+ bias-pull-down; /* pull down */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ pmx_qdsd_data2 {
+ qdsd_data2_sdcard: data2_sdcard {
+ config {
+ pins = "qdsd_data2";
+ bias-pull-down; /* pull down */
+ drive-strength = <8>; /* 8 MA */
+ };
+ };
+ qdsd_data2_trace: data2_trace {
+ config {
+ pins = "qdsd_data2";
+ bias-pull-down; /* pull down */
+ drive-strength = <8>; /* 8 MA */
+ };
+ };
+ qdsd_data2_swduart: data2_uart {
+ config {
+ pins = "qdsd_data2";
+ bias-pull-down; /* pull down */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_data2_swdtrc: data2_swdtrc {
+ config {
+ pins = "qdsd_data2";
+ bias-pull-down; /* pull down */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_data2_jtag: data2_jtag {
+ config {
+ pins = "qdsd_data2";
+ bias-pull-up; /* pull up */
+ drive-strength = <8>; /* 8 MA */
+ };
+ };
+ };
+
+ pmx_qdsd_data3 {
+ qdsd_data3_sdcard: data3_sdcard {
+ config {
+ pins = "qdsd_data3";
+ bias-pull-down; /* pull down */
+ drive-strength = <8>; /* 8 MA */
+ };
+ };
+ qdsd_data3_trace: data3_trace {
+ config {
+ pins = "qdsd_data3";
+ bias-pull-down; /* pull down */
+ drive-strength = <8>; /* 8 MA */
+ };
+ };
+ qdsd_data3_swduart: data3_uart {
+ config {
+ pins = "qdsd_data3";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_data3_swdtrc: data3_swdtrc {
+ config {
+ pins = "qdsd_data3";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_data3_jtag: data3_jtag {
+ config {
+ pins = "qdsd_data3";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ qdsd_data3_spmi: data3_spmi {
+ config {
+ pins = "qdsd_data3";
+ bias-pull-down; /* pull down */
+ drive-strength = <8>; /* 8 MA */
+ };
+ };
+ };
+
+ pmx_sdc1_rclk {
+ sdc1_rclk_on: sdc1_rclk_on {
+ config {
+ pins = "sdc1_rclk";
+ bias-pull-down; /* pull down */
+ };
+ };
+
+ sdc1_rclk_off: sdc1_rclk_off {
+ config {
+ pins = "sdc1_rclk";
+ bias-pull-down; /* pull down */
+ };
+ };
+ };
+
+ pmx_sdc1_clk {
+ sdc1_clk_on: sdc1_clk_on {
+ config {
+ pins = "sdc1_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <16>; /* 16 MA */
+ };
+ };
+
+ sdc1_clk_off: sdc1_clk_off {
+ config {
+ pins = "sdc1_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ pmx_sdc1_cmd {
+ sdc1_cmd_on: sdc1_cmd_on {
+ config {
+ pins = "sdc1_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc1_cmd_off: sdc1_cmd_off {
+ config {
+ pins = "sdc1_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ pmx_sdc1_data {
+ sdc1_data_on: sdc1_data_on {
+ config {
+ pins = "sdc1_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc1_data_off: sdc1_data_off {
+ config {
+ pins = "sdc1_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ sdhc2_cd_pin {
+ sdc2_cd_on: cd_on {
+ mux {
+ pins = "gpio67";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio67";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ sdc2_cd_off: cd_off {
+ mux {
+ pins = "gpio67";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio67";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ pmx_sdc2_clk {
+ sdc2_clk_on: sdc2_clk_on {
+ config {
+ pins = "sdc2_clk";
+ drive-strength = <16>; /* 16 MA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ sdc2_clk_off: sdc2_clk_off {
+ config {
+ pins = "sdc2_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ pmx_sdc2_cmd {
+ sdc2_cmd_on: sdc2_cmd_on {
+ config {
+ pins = "sdc2_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc2_cmd_off: sdc2_cmd_off {
+ config {
+ pins = "sdc2_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ pmx_sdc2_data {
+ sdc2_data_on: sdc2_data_on {
+ config {
+ pins = "sdc2_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc2_data_off: sdc2_data_off {
+ config {
+ pins = "sdc2_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ };
+
+ sdc2_wlan_gpio {
+ sdc2_wlan_gpio_active: sdc2_wlan_gpio_active {
+ config {
+ pins = "gpio99";
+ output-high;
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+ };
+ sdc2_wlan_gpio_sleep: sdc2_wlan_gpio_sleep {
+ config {
+ pins = "gpio99";
+ output-low;
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ wcd9xxx_intr {
+ wcd_intr_default: wcd_intr_default{
+ mux {
+ pins = "gpio73";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio73";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* pull down */
+ input-enable;
+ };
+ };
+ };
+
+ pri_mi2s_mclk_b_lines {
+ pri_mi2s_mclk_b_default: pri_mi2s_mclk_default {
+ mux {
+ pins = "gpio69";
+ function = "pri_mi2s_mclk_b";
+ };
+ config {
+ pins = "gpio69";
+ drive-strength = <8>;
+ bias-disable;
+ input-enable;
+ };
+ };
+ };
+
+ sec_mi2s_mclk_a_lines {
+ sec_mi2s_mclk_a_active: sec_mi2s_mclk_a_active {
+ mux {
+ pins = "gpio25";
+ function = "sec_mi2s_mclk_a";
+ };
+
+ config {
+ pins = "gpio25";
+ drive-strength = <8>; /* 8 MA */
+ output-high;
+ bias-disable;
+ };
+ };
+
+ sec_mi2s_mclk_a_sleep: sec_mi2s_mclk_a_sleep {
+ mux {
+ pins = "gpio25";
+ function = "sec_mi2s_mclk_a";
+ };
+
+ config {
+ pins = "gpio25";
+ drive-strength = <2>; /* 2 MA */
+ output-low;
+ bias-pull-down;
+ };
+ };
+ };
+
+ cdc_reset_ctrl {
+ cdc_reset_sleep: cdc_reset_sleep {
+ mux {
+ pins = "gpio68";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio68";
+ drive-strength = <16>;
+ bias-disable;
+ output-low;
+ };
+ };
+ cdc_reset_active:cdc_reset_active {
+ mux {
+ pins = "gpio68";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio68";
+ drive-strength = <16>;
+ bias-pull-down;
+ output-high;
+ };
+ };
+ };
+
+ cdc-pdm-2-lines {
+ cdc_pdm_lines_2_act: pdm_lines_2_on {
+ mux {
+ pins = "gpio70", "gpio71", "gpio72";
+ function = "cdc_pdm0";
+ };
+
+ config {
+ pins = "gpio70", "gpio71", "gpio72";
+ drive-strength = <8>;
+ };
+ };
+
+ cdc_pdm_lines_2_sus: pdm_lines_2_off {
+ mux {
+ pins = "gpio70", "gpio71", "gpio72";
+ function = "cdc_pdm0";
+ };
+
+ config {
+ pins = "gpio70", "gpio71", "gpio72";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ cdc-pdm-lines {
+ cdc_pdm_lines_act: pdm_lines_on {
+ mux {
+ pins = "gpio69", "gpio73", "gpio74";
+ function = "cdc_pdm0";
+ };
+
+ config {
+ pins = "gpio69", "gpio73", "gpio74";
+ drive-strength = <8>;
+ };
+ };
+ cdc_pdm_lines_sus: pdm_lines_off {
+ mux {
+ pins = "gpio69", "gpio73", "gpio74";
+ function = "cdc_pdm0";
+ };
+
+ config {
+ pins = "gpio69", "gpio73", "gpio74";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ cross-conn-det {
+ cross_conn_det_act: lines_on {
+ mux {
+ pins = "gpio63";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio63";
+ drive-strength = <8>;
+ output-low;
+ bias-pull-down;
+ };
+ };
+
+ cross_conn_det_sus: lines_off {
+ mux {
+ pins = "gpio63";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio63";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+ };
+
+ /* WSA VI sense */
+ wsa-vi {
+ wsa_vi_on: wsa_vi_on {
+ mux {
+ pins = "gpio94", "gpio95";
+ function = "wsa_io";
+ };
+
+ config {
+ pins = "gpio94", "gpio95";
+ drive-strength = <8>; /* 8 MA */
+ bias-disable; /* NO pull */
+ };
+ };
+
+ wsa_vi_off: wsa_vi_off {
+ mux {
+ pins = "gpio94", "gpio95";
+ function = "wsa_io";
+ };
+
+ config {
+ pins = "gpio94", "gpio95";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down;
+ };
+ };
+ };
+
+ /* WSA Reset */
+ wsa_reset {
+ wsa_reset_on: wsa_reset_on {
+ mux {
+ pins = "gpio96";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio96";
+ drive-strength = <2>; /* 2 MA */
+ output-high;
+ };
+ };
+
+ wsa_reset_off: wsa_reset_off {
+ mux {
+ pins = "gpio96";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio96";
+ drive-strength = <2>; /* 2 MA */
+ output-low;
+ };
+ };
+ };
+
+ /* WSA CLK */
+ wsa_clk {
+ wsa_clk_on: wsa_clk_on {
+ mux {
+ pins = "gpio25";
+ function = "pri_mi2s_mclk_a";
+ };
+
+ config {
+ pins = "gpio25";
+ drive-strength = <8>; /* 8 MA */
+ output-high;
+ };
+ };
+
+ wsa_clk_off: wsa_clk_off {
+ mux {
+ pins = "gpio25";
+ function = "pri_mi2s_mclk_a";
+ };
+
+ config {
+ pins = "gpio25";
+ drive-strength = <2>; /* 2 MA */
+ output-low;
+ bias-pull-down;
+ };
+ };
+ };
+
+ pri-tlmm-lines {
+ pri_tlmm_lines_act: pri_tlmm_lines_act {
+ mux {
+ pins = "gpio85", "gpio88";
+ function = "pri_mi2s";
+ };
+
+ config {
+ pins = "gpio85", "gpio88";
+ drive-strength = <8>;
+ };
+ };
+
+ pri_tlmm_lines_sus: pri_tlmm_lines_sus {
+ mux {
+ pins = "gpio85", "gpio88";
+ function = "pri_mi2s";
+ };
+
+ config {
+ pins = "gpio85", "gpio88";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+ };
+
+ pri-tlmm-ws-lines {
+ pri_tlmm_ws_act: pri_tlmm_ws_act {
+ mux {
+ pins = "gpio87";
+ function = "pri_mi2s_ws";
+ };
+
+ config {
+ pins = "gpio87";
+ drive-strength = <16>;
+ bias-disable;
+ output-high;
+ };
+ };
+
+ pri_tlmm_ws_sus: pri_tlmm_ws_sus {
+ mux {
+ pins = "gpio87";
+ function = "pri_mi2s_ws";
+ };
+
+ config {
+ pins = "gpio87";
+ drive-strength = <2>;
+ bias-pull-down;
+ input-enable;
+ };
+ };
+ };
+
+ spi3 {
+ spi3_default: spi3_default {
+ /* active state */
+ mux {
+ /* MOSI, MISO, CLK */
+ pins = "gpio8", "gpio9", "gpio11";
+ function = "blsp_spi3";
+ };
+
+ config {
+ pins = "gpio8", "gpio9", "gpio11";
+ drive-strength = <12>; /* 12 MA */
+ bias-disable = <0>; /* No PULL */
+ };
+ };
+
+ spi3_sleep: spi3_sleep {
+ /* suspended state */
+ mux {
+ /* MOSI, MISO, CLK */
+ pins = "gpio8", "gpio9", "gpio11";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio8", "gpio9", "gpio11";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down; /* PULL Down */
+ };
+ };
+
+ spi3_cs0_active: cs0_active {
+ /* CS */
+ mux {
+ pins = "gpio10";
+ function = "blsp_spi3";
+ };
+
+ config {
+ pins = "gpio10";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+
+ spi3_cs0_sleep: cs0_sleep {
+ /* CS */
+ mux {
+ pins = "gpio10";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio10";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+ };
+
+ spi6 {
+ spi6_default: spi6_default {
+ /* active state */
+ mux {
+ /* MOSI, MISO, CLK */
+ pins = "gpio20", "gpio21", "gpio23";
+ function = "blsp_spi6";
+ };
+
+ config {
+ pins = "gpio20", "gpio21", "gpio23";
+ drive-strength = <16>; /* 16 MA */
+ bias-disable = <0>; /* No PULL */
+ };
+ };
+
+ spi6_sleep: spi6_sleep {
+ /* suspended state */
+ mux {
+ /* MOSI, MISO, CLK */
+ pins = "gpio20", "gpio21", "gpio23";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio20", "gpio21", "gpio23";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down; /* PULL Down */
+ };
+ };
+
+ spi6_cs0_active: cs0_active {
+ /* CS */
+ mux {
+ pins = "gpio47";
+ function = "blsp6_spi";
+ };
+
+ config {
+ pins = "gpio47";
+ drive-strength = <16>;
+ bias-disable = <0>;
+ };
+ };
+
+ spi6_cs0_sleep: cs0_sleep {
+ /* CS */
+ mux {
+ pins = "gpio47";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio47";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+
+ spi6_cs1_active: cs1_active {
+ /* CS */
+ mux {
+ pins = "gpio22";
+ function = "blsp_spi6";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <16>;
+ bias-disable = <0>;
+ };
+ };
+
+ spi6_cs1_sleep: cs1_sleep {
+ /* CS */
+ mux {
+ pins = "gpio22";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+ };
+
+ i2c_2 {
+ i2c_2_active: i2c_2_active {
+ /* active state */
+ mux {
+ pins = "gpio6", "gpio7";
+ function = "blsp_i2c2";
+ };
+
+ config {
+ pins = "gpio6", "gpio7";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_2_sleep: i2c_2_sleep {
+ /* suspended state */
+ mux {
+ pins = "gpio6", "gpio7";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio6", "gpio7";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ i2c_3 {
+ i2c_3_active: i2c_3_active {
+ /* active state */
+ mux {
+ pins = "gpio10", "gpio11";
+ function = "blsp_i2c3";
+ };
+
+ config {
+ pins = "gpio10", "gpio11";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_3_sleep: i2c_3_sleep {
+ /* suspended state */
+ mux {
+ pins = "gpio10", "gpio11";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio10", "gpio11";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* IO Expander SX150xq */
+ i2c_4 {
+ i2c_4_active: i2c_4_active {
+ /* active state */
+ mux {
+ pins = "gpio14", "gpio15";
+ function = "blsp_i2c4";
+ };
+
+ config {
+ pins = "gpio14", "gpio15";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_4_sleep: i2c_4_sleep {
+ /* suspended state */
+ mux {
+ pins = "gpio14", "gpio15";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio14", "gpio15";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ i2c_5 {
+ i2c_5_active: i2c_5_active {
+ /* active state */
+ mux {
+ pins = "gpio18", "gpio19";
+ function = "blsp_i2c5";
+ };
+
+ config {
+ pins = "gpio18", "gpio19";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_5_sleep: i2c_5_sleep {
+ /* suspended state */
+ mux {
+ pins = "gpio18", "gpio19";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio18", "gpio19";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ i2c_6 {
+ i2c_6_active: i2c_6_active {
+ /* active state */
+ mux {
+ pins = "gpio22", "gpio23";
+ function = "blsp_i2c6";
+ };
+
+ config {
+ pins = "gpio22", "gpio23";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_6_sleep: i2c_6_sleep {
+ /* suspended state */
+ mux {
+ pins = "gpio22", "gpio23";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio22", "gpio23";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ pmx_rd_nfc_int {
+ /*qcom,pins = <&gp 17>;*/
+ pins = "gpio17";
+ qcom,pin-func = <0>;
+ qcom,num-grp-pins = <1>;
+ label = "pmx_nfc_int";
+
+ nfc_int_active: active {
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+
+ nfc_int_suspend: suspend {
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+ };
+
+ pmx_nfc_reset {
+ /*qcom,pins = <&gp 16>;*/
+ pins = "gpio16";
+ qcom,pin-func = <0>;
+ qcom,num-grp-pins = <1>;
+ label = "pmx_nfc_disable";
+
+ nfc_disable_active: active {
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+
+ nfc_disable_suspend: suspend {
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ tlmm_gpio_key {
+ gpio_key_active: gpio_key_active {
+ mux {
+ pins = "gpio91", "gpio127", "gpio128";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ gpio_key_suspend: gpio_key_suspend {
+ mux {
+ pins = "gpio91", "gpio127", "gpio128";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ tlmm_pmi_flash_led {
+ rear_flash_led_enable: rear_flash_led_enable {
+ mux {
+ pins = "gpio33";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio33";
+ drive-strength = <16>;
+ output-high;
+ };
+ };
+
+ rear_flash_led_disable: rear_flash_led_disable {
+ mux {
+ pins = "gpio33";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio33";
+ drive-strength = <2>;
+ output-low;
+ };
+ };
+
+ front_flash_led_enable: front_flash_led_enable {
+ mux {
+ pins = "gpio50";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio50";
+ drive-strength = <16>;
+ output-high;
+ };
+ };
+
+ front_flash_led_disable: front_flash_led_disable {
+ mux {
+ pins = "gpio50";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio50";
+ drive-strength = <2>;
+ output-low;
+ };
+ };
+ };
+
+ usbc_int_default: usbc_int_default {
+ mux {
+ pins = "gpio97", "gpio131";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio97", "gpio131";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ pri_mi2s_sck {
+ pri_mi2s_sck_sleep: pri_mi2s_sck_sleep {
+ mux {
+ pins = "gpio85";
+ function = "pri_mi2s";
+ };
+
+ config {
+ pins = "gpio85";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ pri_mi2s_sck_active: pri_mi2s_sck_active {
+ mux {
+ pins = "gpio85";
+ function = "pri_mi2s";
+ };
+
+ config {
+ pins = "gpio85";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable; /* NO PULL */
+ output-high;
+ };
+ };
+ };
+
+ pri_mi2s_sd0 {
+ pri_mi2s_sd0_sleep: pri_mi2s_sd0_sleep {
+ mux {
+ pins = "gpio88";
+ function = "pri_mi2s";
+ };
+
+ config {
+ pins = "gpio88";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+
+ pri_mi2s_sd0_active: pri_mi2s_sd0_active {
+ mux {
+ pins = "gpio88";
+ function = "pri_mi2s";
+ };
+
+ config {
+ pins = "gpio88";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ pri_mi2s_sd1 {
+ pri_mi2s_sd1_sleep: pri_mi2s_sd1_sleep {
+ mux {
+ pins = "gpio86";
+ function = "pri_mi2s";
+ };
+
+ config {
+ pins = "gpio86";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+ pri_mi2s_sd1_active: pri_mi2s_sd1_active {
+ mux {
+ pins = "gpio86";
+ function = "pri_mi2s";
+ };
+
+ config {
+ pins = "gpio86";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable; /* NO PULL */
+ output-high;
+ };
+ };
+ };
+ sec_mi2s_ws {
+ sec_mi2s_ws_sleep: sec_mi2s_ws_sleep {
+ mux {
+ pins = "gpio95";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio95";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ sec_mi2s_ws_active: sec_mi2s_ws_active {
+ mux {
+ pins = "gpio95";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio95";
+ drive-strength = <16>;
+ bias-disable;
+ output-high;
+ };
+ };
+ };
+ sec_mi2s_sck {
+ sec_mi2s_sck_sleep: sec_mi2s_sck_sleep {
+ mux {
+ pins = "gpio94";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio94";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ sec_mi2s_sck_active: sec_mi2s_sck_active {
+ mux {
+ pins = "gpio94";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio94";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable; /* NO PULL */
+ output-high;
+ };
+ };
+ };
+
+ sec_mi2s_sd0 {
+ sec_mi2s_sd0_sleep: sec_mi2s_sd0_sleep {
+ mux {
+ pins = "gpio12";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio12";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+ sec_mi2s_sd0_active: sec_mi2s_sd0_active {
+ mux {
+ pins = "gpio12";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio12";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable; /* NO PULL */
+ output-high;
+ };
+ };
+ };
+
+ sec_mi2s_sd1 {
+ sec_mi2s_sd1_sleep: sec_mi2s_sd1_sleep {
+ mux {
+ pins = "gpio13";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio13";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ input-enable;
+ };
+ };
+ sec_mi2s_sd1_active: sec_mi2s_sd1_active {
+ mux {
+ pins = "gpio13";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio13";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ usb_mode_select: usb_mode_select {
+ mux {
+ pins = "gpio130";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio130";
+ drive-strength = <2>;
+ bias-disable;
+ input-enable;
+ };
+ };
+
+ usb2533_hub_reset: usb2533_hub_reset {
+ mux {
+ pins = "gpio100";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio100";
+ drive-strength = <2>;
+ output-low;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi
new file mode 100644
index 0000000..6200b4e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/msm/pm.h>
+
+&soc {
+ qcom,spm@b012000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xb012000 0x1000>;
+ qcom,name = "perf-l2";
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x14>;
+ qcom,saw2-spm-dly= <0x3C11840A>;
+ qcom,saw2-spm-ctl = <0xe>;
+ qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
+ qcom,vctl-timeout-us = <500>;
+ qcom,vctl-port = <0x0>;
+ };
+
+ qcom,lpm-levels {
+ compatible = "qcom,lpm-levels";
+ qcom,use-psci;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,pm-cluster@0{
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ label = "perf";
+ qcom,spm-device-names = "l2";
+ qcom,default-level=<0>;
+ qcom,psci-mode-shift = <4>;
+ qcom,psci-mode-mask = <0xf>;
+
+ qcom,pm-cluster-level@0{
+ reg = <0>;
+ label = "perf-l2-wfi";
+ qcom,psci-mode = <1>;
+ qcom,latency-us = <180>;
+ qcom,ss-power = <429>;
+ qcom,energy-overhead = <162991>;
+ qcom,time-overhead = <305>;
+ };
+
+ qcom,pm-cluster-level@1{
+ reg = <1>;
+ label = "perf-l2-gdhs";
+ qcom,psci-mode = <4>;
+ qcom,latency-us = <280>;
+ qcom,ss-power = <421>;
+ qcom,energy-overhead = <257510>;
+ qcom,time-overhead = <520>;
+ qcom,min-child-idx = <1>;
+ qcom,reset-level = <LPM_RESET_LVL_GDHS>;
+ };
+
+ qcom,pm-cluster-level@2{
+ reg = <2>;
+ label = "perf-l2-retention";
+ qcom,psci-mode = <2>;
+ qcom,latency-us = <650>;
+ qcom,ss-power = <350>;
+ qcom,energy-overhead = <651061>;
+ qcom,time-overhead = <1350>;
+ qcom,min-child-idx = <1>;
+ qcom,reset-level = <LPM_RESET_LVL_RET>;
+ };
+
+ qcom,pm-cluster-level@3{
+ reg = <3>;
+ label = "perf-l2-pc";
+ qcom,psci-mode = <5>;
+ qcom,latency-us = <11200>;
+ qcom,ss-power = <320>;
+ qcom,energy-overhead = <917561>;
+ qcom,time-overhead = <1700>;
+ qcom,min-child-idx = <1>;
+ qcom,is-reset;
+ qcom,notify-rpm;
+ qcom,reset-level = <LPM_RESET_LVL_PC>;
+ };
+
+ qcom,pm-cpu {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ qcom,psci-mode-shift = <0>;
+ qcom,psci-mode-mask = <0xf>;
+
+ qcom,pm-cpu-level@0 {
+ reg = <0>;
+ qcom,psci-cpu-mode = <0>;
+ label = "wfi";
+ qcom,latency-us = <12>;
+ qcom,ss-power = <463>;
+ qcom,energy-overhead = <23520>;
+ qcom,time-overhead = <25>;
+ };
+
+ qcom,pm-cpu-level@1 {
+ reg = <1>;
+ qcom,psci-cpu-mode = <3>;
+ label = "pc";
+ qcom,latency-us = <180>;
+ qcom,ss-power = <429>;
+ qcom,energy-overhead = <162991>;
+ qcom,time-overhead = <305>;
+ qcom,use-broadcast-timer;
+ qcom,is-reset;
+ qcom,reset-level = <LPM_RESET_LVL_PC>;
+ };
+ };
+ };
+ };
+
+ qcom,cpu-sleep-status {
+ compatible = "qcom,cpu-sleep-status";
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts
new file mode 100644
index 0000000..3fe60a3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015-2016, 2018, 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 "msm8917.dtsi"
+#include "msm8917-pmi8950-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 MTP";
+ compatible = "qcom,msm8917-mtp", "qcom,msm8917", "qcom,mtp";
+ qcom,board-id= <8 0>;
+ qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dtsi
new file mode 100644
index 0000000..a194cea
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dtsi
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015-2018, 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 "pmi8950.dtsi"
+#include "msm8917-mtp.dtsi"
+
+&soc {
+ led_flash0: qcom,camera-flash {
+ cell-index = <0>;
+ compatible = "qcom,camera-flash";
+ qcom,flash-type = <1>;
+ qcom,flash-source = <&pmi8950_flash0 &pmi8950_flash1>;
+ qcom,torch-source = <&pmi8950_torch0 &pmi8950_torch1>;
+ qcom,switch-source = <&pmi8950_switch>;
+ };
+
+ bluetooth: bt_qca6174 {
+ compatible = "qca,qca6174";
+ qca,bt-reset-gpio = <&tlmm 129 0>; /* BT_EN */
+ };
+};
+
+&vendor{
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "batterydata-itech-3000mah.dtsi"
+ #include "batterydata-ascent-3450mAh.dtsi"
+ };
+};
+
+&pm8937_gpios {
+ gpio@c400 {
+ qcom,mode = <0>;
+ qcom,output-type = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <0>;
+ qcom,master-en = <1>;
+ status = "okay";
+ };
+};
+
+&qpnp_fg {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+ qcom,battery-data = <&mtp_batterydata>;
+ qcom,chg-led-sw-controls;
+ qcom,chg-led-support;
+ /delete-property/ dpdm-supply;
+};
+
+&usb_otg {
+ extcon = <&qpnp_smbcharger>;
+};
+
+&labibb {
+ status = "ok";
+ qpnp,qpnp-labibb-mode = "lcd";
+};
+
+&ibb_regulator {
+ qcom,qpnp-ibb-discharge-resistor = <32>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8917-regulator.dtsi
new file mode 100644
index 0000000..7fb3707
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-regulator.dtsi
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2015-2018, 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 "msm8937-regulator.dtsi"
+
+&soc {
+ /* delete the CPR and MEM ACC nodes of msm8937 */
+ /delete-node/ regulator@b018000;
+ /delete-node/ regulator@01946004;
+
+ mem_acc_vreg_corner: regulator@01946004 {
+ compatible = "qcom,mem-acc-regulator";
+ reg = <0xa4000 0x1000>;
+ reg-names = "efuse_addr";
+ regulator-name = "mem_acc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <3>;
+
+ qcom,acc-reg-addr-list =
+ <0x01942138 0x01942130 0x01942120 0x01942124>;
+
+ qcom,acc-init-reg-config = <1 0xff>, <2 0x5555>;
+
+ qcom,num-acc-corners = <3>;
+ qcom,boot-acc-corner = <2>;
+ qcom,corner1-reg-config =
+ /* SVS+ => SVS+ */
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* SVS+ => NOM */
+ < 3 0x1041041>, < 4 0x1041>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* SVS+ => TURBO/NOM+ */
+ < 3 0x1041041>, < 4 0x1041>, < 3 0x0>,
+ < 4 0x0>;
+
+ qcom,corner2-reg-config =
+ /* NOM => SVS+ */
+ < 3 0x30c30c3>, < 4 0x30c3>,
+ /* NOM => NOM */
+ <(-1) (-1)>, <(-1) (-1)>,
+ /* NOM => TURBO/NOM+ */
+ < 3 0x0>, < 4 0x0>;
+
+ qcom,corner3-reg-config =
+ /* TURBO/NOM+ => SVS+ */
+ < 3 0x1041041>, < 4 0x1041>, < 3 0x30c30c3>,
+ < 4 0x30c3>,
+ /* TURBO/NOM+ => NOM */
+ < 3 0x1041041>, < 4 0x1041>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* TURBO/NOM+ => TURBO/NOM+ */
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>;
+
+ qcom,override-acc-fuse-sel = <71 17 3 0>;
+ qcom,override-fuse-version-map = <1>,
+ <2>,
+ <3>,
+ <4>;
+ qcom,override-corner1-addr-val-map =
+ /* 1st fuse version tuple matched */
+ /* SVS+ => SVS+ */
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* SVS+ => NOM */
+ < 3 0x1041041>, < 4 0x1041>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* SVS+ => TURBO/NOM+ */
+ < 3 0x1041041>, < 4 0x1041>, < 3 0x1>,
+ < 4 0x0>,
+
+ /* 2nd fuse version tuple matched */
+ /* SVS+ => SVS+ */
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* SVS+ => NOM */
+ < 3 0x1041041>, < 4 0x1041>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* SVS+ => TURBO/NOM+ */
+ < 3 0x1041041>, < 4 0x1041>, < 3 0x3>,
+ < 4 0x0>,
+
+ /* 3rd fuse version tuple matched */
+ /* SVS+ => SVS+ */
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* SVS+ => NOM */
+ < 3 0x1041043>, < 4 0x1041>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* SVS+ => TURBO/NOM+ */
+ < 3 0x1041041>, < 4 0x1041>, < 3 0x0>,
+ < 4 0x0>,
+
+ /* 4th fuse version tuple matched */
+ /* SVS+ => SVS+ */
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* SVS+ => NOM */
+ < 3 0x1041043>, < 4 0x1041>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* SVS+ => TURBO/NOM+ */
+ < 3 0x1041041>, < 4 0x1041>, < 3 0x1>,
+ < 4 0x0>;
+
+ qcom,override-corner2-addr-val-map =
+ /* 1st fuse version tuple matched */
+ /* NOM => SVS+ */
+ < 3 0x30c30c3>, < 4 0x30c3>,
+ /* NOM => NOM */
+ <(-1) (-1)>, <(-1) (-1)>,
+ /* NOM => TURBO/NOM+ */
+ < 3 0x1>, < 4 0x0>,
+
+ /* 2nd fuse version tuple matched */
+ /* NOM => SVS+ */
+ < 3 0x30c30c3>, < 4 0x30c3>,
+ /* NOM => NOM */
+ <(-1) (-1)>, <(-1) (-1)>,
+ /* NOM => TURBO/NOM+ */
+ < 3 0x3>, < 4 0x0>,
+
+ /* 3rd fuse version tuple matched */
+ /* NOM => SVS+ */
+ < 3 0x30c30c3>, < 4 0x30c3>,
+ /* NOM => NOM */
+ <(-1) (-1)>, <(-1) (-1)>,
+ /* NOM => TURBO/NOM+ */
+ < 3 0x0>, < 4 0x0>,
+
+ /* 4th fuse version tuple matched */
+ /* NOM => SVS+ */
+ < 3 0x30c30c3>, < 4 0x30c3>,
+ /* NOM => NOM */
+ <(-1) (-1)>, <(-1) (-1)>,
+ /* NOM => TURBO/NOM+ */
+ < 3 0x1>, < 4 0x0>;
+
+ qcom,override-corner3-addr-val-map =
+ /* 1st fuse version tuple matched */
+ /* TURBO/NOM+ => SVS+ */
+ < 3 0x1041041>, < 4 0x1041>, < 3 0x30c30c3>,
+ < 4 0x30c3>,
+ /* TURBO/NOM+ => NOM */
+ < 3 0x1041041>, < 4 0x1041>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* TURBO/NOM+ => TURBO/NOM+ */
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>,
+
+ /* 2nd fuse version tuple matched */
+ /* TURBO/NOM+ => SVS+ */
+ < 3 0x1041041>, < 4 0x1041>, < 3 0x30c30c3>,
+ < 4 0x30c3>,
+ /* TURBO/NOM+ => NOM */
+ < 3 0x1041041>, < 4 0x1041>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* TURBO/NOM+ => TURBO/NOM+ */
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>,
+
+ /* 3rd fuse version tuple matched */
+ /* TURBO/NOM+ => SVS+ */
+ < 3 0x1041041>, < 4 0x1041>, < 3 0x30c30c3>,
+ < 4 0x30c3>,
+ /* TURBO/NOM+ => NOM */
+ < 3 0x1041043>, < 4 0x1041>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* TURBO/NOM+ => TURBO/NOM+ */
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>,
+
+ /* 4th fuse version tuple matched */
+ /* TURBO/NOM+ => SVS+ */
+ < 3 0x1041041>, < 4 0x1041>, < 3 0x30c30c3>,
+ < 4 0x30c3>,
+ /* TURBO/NOM+ => NOM */
+ < 3 0x1041043>, < 4 0x1041>, <(-1) (-1)>,
+ <(-1) (-1)>,
+ /* TURBO/NOM+ => TURBO/NOM+ */
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>;
+ };
+
+ apc_vreg_corner: regulator@b018000 {
+ compatible = "qcom,cpr-regulator";
+ reg = <0xb018000 0x1000>, <0xb011064 4>, <0xa4000 0x1000>;
+ reg-names = "rbcpr", "rbcpr_clk", "efuse_addr";
+ interrupts = <0 15 0>;
+ regulator-name = "apc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <5>;
+
+ qcom,cpr-fuse-corners = <3>;
+ qcom,cpr-voltage-ceiling = <1155000 1225000 1350000>;
+ qcom,cpr-voltage-floor = <1050000 1050000 1090000>;
+ vdd-apc-supply = <&pm8937_s5>;
+
+ mem-acc-supply = <&mem_acc_vreg_corner>;
+
+ qcom,cpr-ref-clk = <19200>;
+ qcom,cpr-timer-delay = <5000>;
+ qcom,cpr-timer-cons-up = <0>;
+ qcom,cpr-timer-cons-down = <2>;
+ qcom,cpr-irq-line = <0>;
+ qcom,cpr-step-quotient = <16>;
+ qcom,cpr-up-threshold = <2>;
+ qcom,cpr-down-threshold = <4>;
+ qcom,cpr-idle-clocks = <15>;
+ qcom,cpr-gcnt-time = <1>;
+ qcom,vdd-apc-step-up-limit = <1>;
+ qcom,vdd-apc-step-down-limit = <1>;
+ qcom,cpr-apc-volt-step = <5000>;
+
+ qcom,cpr-fuse-row = <67 0>;
+ qcom,cpr-fuse-target-quot = <42 24 6>;
+ qcom,cpr-fuse-ro-sel = <60 57 54>;
+ qcom,cpr-init-voltage-ref = <1155000 1225000 1350000>;
+ qcom,cpr-fuse-init-voltage =
+ <67 36 6 0>,
+ <67 18 6 0>,
+ <67 0 6 0>;
+ qcom,cpr-fuse-quot-offset =
+ <71 26 6 0>,
+ <71 20 6 0>,
+ <70 54 7 0>;
+ qcom,cpr-fuse-quot-offset-scale = <5 5 5>;
+ qcom,cpr-init-voltage-step = <10000>;
+ qcom,cpr-corner-map = <1 2 3 3 3>;
+ qcom,cpr-corner-frequency-map =
+ <1 960000000>,
+ <2 1094400000>,
+ <3 1248000000>,
+ <4 1401000000>,
+ <5 1497600000>;
+ qcom,speed-bin-fuse-sel = <37 34 3 0>;
+ qcom,cpr-speed-bin-max-corners =
+ <0 (-1) 1 2 4>,
+ <1 (-1) 1 2 5>;
+ qcom,cpr-quot-adjust-scaling-factor-max = <0 1400 1400>;
+ qcom,cpr-voltage-scaling-factor-max = <0 2000 2000>;
+ qcom,cpr-scaled-init-voltage-as-ceiling;
+ qcom,cpr-fuse-revision = <69 39 3 0>;
+ qcom,pvs-version-fuse-sel = <37 40 3 0>; /* foundry */
+ qcom,cpr-fuse-version-map =
+ < 1 0 3 (-1) (-1) (-1)>,
+ < 1 5 3 (-1) (-1) (-1)>,
+ <(-1) 0 1 (-1) (-1) (-1)>,
+ <(-1) 0 2 (-1) (-1) (-1)>,
+ <(-1) 5 1 (-1) (-1) (-1)>,
+ <(-1) 5 2 (-1) (-1) (-1)>,
+ <(-1) (-1) (-1) (-1) (-1) (-1)>;
+ qcom,cpr-quotient-adjustment =
+ <50 40 50>,
+ <0 0 40>,
+ <50 40 100>,
+ <50 40 50>,
+ <0 0 100>,
+ <0 0 50>,
+ <0 0 0>;
+ qcom,cpr-init-voltage-adjustment =
+ <30000 5000 10000>,
+ <0 0 0>,
+ <30000 5000 35000>,
+ <30000 5000 10000>,
+ <0 0 20000>,
+ <0 0 0>,
+ <0 0 0>;
+ qcom,cpr-enable;
+ };
+
+ eldo2_pm8937: eldo2 {
+ compatible = "regulator-fixed";
+ regulator-name = "eldo2_pm8937";
+ startup-delay-us = <0>;
+ enable-active-high;
+ gpio = <&pm8937_gpios 7 0>;
+ regulator-always-on;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-smp2p.dtsi b/arch/arm64/boot/dts/qcom/msm8917-smp2p.dtsi
new file mode 100644
index 0000000..061d985
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-smp2p.dtsi
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&soc {
+ qcom,smp2p-modem@b011008 {
+ compatible = "qcom,smp2p";
+ reg = <0xb011008 0x4>;
+ qcom,remote-pid = <1>;
+ qcom,irq-bitmask = <0x4000>;
+ interrupts = <GIC_SPI 27 IRQ_TYPE_EDGE_RISING>;
+ };
+
+ qcom,smp2p-wcnss@b011008 {
+ compatible = "qcom,smp2p";
+ reg = <0xb011008 0x4>;
+ qcom,remote-pid = <4>;
+ qcom,irq-bitmask = <0x40000>;
+ interrupts = <GIC_SPI 143 IRQ_TYPE_EDGE_RISING>;
+ };
+
+ qcom,smp2p-adsp@b011008 {
+ compatible = "qcom,smp2p";
+ reg = <0xb011008 0x4>;
+ qcom,remote-pid = <2>;
+ qcom,irq-bitmask = <0x400>;
+ interrupts = <GIC_SPI 291 IRQ_TYPE_EDGE_RISING>;
+ };
+
+ smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <15>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_15_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+ gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <15>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_15_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+ gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+ gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+ gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+ gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+ gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+ gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+ gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+ };
+
+ /* ssr - inbound entry from mss. */
+ smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to mss */
+ smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - inbound entry from lpass. */
+ smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to lpass */
+ smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - inbound entry from wcnss. */
+ smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to wcnss */
+ smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917.dtsi b/arch/arm64/boot/dts/qcom/msm8917.dtsi
new file mode 100644
index 0000000..6f0da53
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917.dtsi
@@ -0,0 +1,1289 @@
+/*
+ * Copyright (c) 2015-2018, 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 "skeleton64.dtsi"
+#include <dt-bindings/clock/msm-clocks-8952.h>
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8917";
+ compatible = "qcom,msm8917";
+ qcom,msm-id = <303 0x0>, <308 0x0>, <309 0x0>;
+ interrupt-parent = <&intc>;
+
+ chosen {
+ bootargs = "sched_enable_hmp=1";
+ };
+
+ aliases {
+ /* smdtty devices */
+ smd1 = &smdtty_apps_fm;
+ smd2 = &smdtty_apps_riva_bt_acl;
+ smd3 = &smdtty_apps_riva_bt_cmd;
+ smd4 = &smdtty_mbalbridge;
+ smd5 = &smdtty_apps_riva_ant_cmd;
+ smd6 = &smdtty_apps_riva_ant_data;
+ smd7 = &smdtty_data1;
+ smd8 = &smdtty_data4;
+ smd11 = &smdtty_data11;
+ smd21 = &smdtty_data21;
+ smd36 = &smdtty_loopback;
+ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
+ sdhc2 = &sdhc_2; /* SDC2 for SD card */
+ spi3 = &spi_3;
+ spi6 = &spi_6;
+ i2c2 = &i2c_2;
+ i2c5 = &i2c_5;
+ i2c3 = &i2c_3;
+ i2c4 = &i2c_4;
+ };
+
+ firmware: firmware {
+ android {
+ compatible = "android,firmware";
+ fstab {
+ compatible = "android,fstab";
+ vendor {
+ compatible = "android,vendor";
+ dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor";
+ type = "ext4";
+ mnt_flags = "ro,barrier=1,discard";
+ fsmgr_flags = "wait";
+ status = "ok";
+ };
+ system {
+ compatible = "android,system";
+ dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system";
+ type = "ext4";
+ mnt_flags = "ro,barrier=1,discard";
+ fsmgr_flags = "wait";
+ status = "ok";
+ };
+ };
+ };
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ other_ext_mem: other_ext_region@0 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0x0 0x85b00000 0x0 0xd00000>;
+ };
+
+ modem_mem: modem_region@0 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0x0 0x86800000 0x0 0x5000000>;
+ };
+
+ adsp_fw_mem: adsp_fw_region@0 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0x0 0x8b800000 0x0 0x1100000>;
+ };
+
+ wcnss_fw_mem: wcnss_fw_region@0 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0x0 0x8c900000 0x0 0x700000>;
+ };
+
+ venus_mem: venus_region@0 {
+ compatible = "shared-dma-pool";
+ reusable;
+ alloc-ranges = <0x0 0x80000000 0x0 0x10000000>;
+ alignment = <0 0x400000>;
+ size = <0 0x0800000>;
+ };
+
+ secure_mem: secure_region@0 {
+ compatible = "shared-dma-pool";
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0x7000000>;
+ status = "disabled";
+ };
+
+ qseecom_mem: qseecom_region@0 {
+ compatible = "shared-dma-pool";
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0x1000000>;
+ };
+
+ qseecom_ta_mem: qseecom_ta_region {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0 0x00000000 0 0xffffffff>;
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0x400000>;
+ };
+
+ adsp_mem: adsp_region@0 {
+ compatible = "shared-dma-pool";
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0x400000>;
+ };
+
+ cont_splash_mem: splash_region@83000000 {
+ reg = <0x0 0x90000000 0x0 0x1400000>;
+ };
+ };
+
+ soc: soc { };
+ vendor: vendor {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0xffffffff>;
+ compatible = "simple-bus";
+ };
+};
+
+#include "msm8917-pinctrl.dtsi"
+#include "msm8917-cpu.dtsi"
+#include "msm8917-pm.dtsi"
+#include "msm8917-ion.dtsi"
+#include "msm8917-smp2p.dtsi"
+#include "msm8917-bus.dtsi"
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0xffffffff>;
+ compatible = "simple-bus";
+
+ intc: interrupt-controller@b000000 {
+ compatible = "qcom,msm-qgic2";
+ interrupt-controller;
+ interrupt-parent = <&intc>;
+ #interrupt-cells = <3>;
+ reg = <0x0b000000 0x1000>,
+ <0x0b002000 0x1000>;
+ };
+
+ wakegic: wake-gic {
+ compatible = "qcom,mpm-gic", "qcom,mpm-gic-msm8937";
+ interrupts = <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>;
+ reg = <0x601d0 0x1000>,
+ <0xb011008 0x4>; /* MSM_APCS_GCC_BASE 4K */
+ reg-names = "vmpm", "ipc";
+ qcom,num-mpm-irqs = <96>;
+ interrupt-controller;
+ interrupt-parent = <&intc>;
+ #interrupt-cells = <3>;
+ };
+
+ wakegpio: wake-gpio {
+ compatible = "qcom,mpm-gpio", "qcom,mpm-gpio-msm8937";
+ interrupt-controller;
+ interrupt-parent = <&intc>;
+ #interrupt-cells = <2>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <1 2 0xff08>,
+ <1 3 0xff08>,
+ <1 4 0xff08>,
+ <1 1 0xff08>;
+ clock-frequency = <19200000>;
+ };
+
+ qcom,sps {
+ compatible = "qcom,msm_sps_4k";
+ qcom,pipe-attr-ee;
+ };
+
+ timer@b120000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ compatible = "arm,armv7-timer-mem";
+ reg = <0xb120000 0x1000>;
+ clock-frequency = <19200000>;
+
+ frame@b121000 {
+ frame-number = <0>;
+ interrupts = <0 8 0x4>,
+ <0 7 0x4>;
+ reg = <0xb121000 0x1000>,
+ <0xb122000 0x1000>;
+ };
+
+ frame@b123000 {
+ frame-number = <1>;
+ interrupts = <0 9 0x4>;
+ reg = <0xb123000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@b124000 {
+ frame-number = <2>;
+ interrupts = <0 10 0x4>;
+ reg = <0xb124000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@b125000 {
+ frame-number = <3>;
+ interrupts = <0 11 0x4>;
+ reg = <0xb125000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@b126000 {
+ frame-number = <4>;
+ interrupts = <0 12 0x4>;
+ reg = <0xb126000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@b127000 {
+ frame-number = <5>;
+ interrupts = <0 13 0x4>;
+ reg = <0xb127000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@b128000 {
+ frame-number = <6>;
+ interrupts = <0 14 0x4>;
+ reg = <0xb128000 0x1000>;
+ status = "disabled";
+ };
+ };
+
+ qcom,rmtfs_sharedmem@00000000 {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x00000000 0x00180000>;
+ reg-names = "rmtfs";
+ qcom,client-id = <0x00000001>;
+ };
+
+ restart@4ab000 {
+ compatible = "qcom,pshold";
+ reg = <0x4ab000 0x4>,
+ <0x193d100 0x4>;
+ reg-names = "pshold-base", "tcsr-boot-misc-detect";
+ };
+
+ qcom,mpm2-sleep-counter@4a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0x4a3000 0x1000>;
+ clock-frequency = <32768>;
+ };
+
+ cpu-pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <1 7 0xff00>;
+ };
+
+ slim_msm: slim@c140000{
+ cell-index = <1>;
+ compatible = "qcom,slim-ngd";
+ reg = <0xc140000 0x2c000>,
+ <0xc104000 0x2a000>;
+ reg-names = "slimbus_physical", "slimbus_bam_physical";
+ interrupts = <0 163 0>, <0 180 0>;
+ interrupt-names = "slimbus_irq", "slimbus_bam_irq";
+ qcom,apps-ch-pipes = <0x600000>;
+ qcom,ea-pc = <0x230>;
+ status = "disabled";
+ };
+
+
+ blsp1_uart2: serial@78b0000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x78b0000 0x200>;
+ interrupts = <0 108 0>;
+ clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ clock-names = "core", "iface";
+ status = "disabled";
+ };
+
+ blsp1_uart1: uart@78af000 { /* BLSP1 UART1 */
+ compatible = "qcom,msm-hsuart-v14";
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x78af000 0x200>,
+ <0x7884000 0x1f000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupt-parent = <&blsp1_uart1>;
+ interrupts = <0 1 2>;
+ interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+ interrupt-map = <0 &intc 0 107 0
+ 1 &intc 0 238 0
+ 2 &tlmm 1 0>;
+ interrupt-map-mask = <0xffffffff>;
+
+ qcom,inject-rx-on-wakeup;
+ qcom,rx-char-to-inject = <0xFD>;
+
+ qcom,bam-tx-ep-pipe-index = <0>;
+ qcom,bam-rx-ep-pipe-index = <1>;
+ qcom,master-id = <86>;
+ clock-names = "core_clk", "iface_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_uart1_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ pinctrl-names = "sleep", "default";
+ pinctrl-0 = <&blsp1_uart1_sleep>;
+ pinctrl-1 = <&blsp1_uart1_active>;
+
+ qcom,msm-bus,name = "blsp1_uart1";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <86 512 0 0>,
+ <86 512 500 800>;
+ status = "disabled";
+ };
+
+ dma_blsp1: qcom,sps-dma@7884000 { /* BLSP1 */
+ #dma-cells = <4>;
+ compatible = "qcom,sps-dma";
+ reg = <0x7884000 0x1f000>;
+ interrupts = <0 238 0>;
+ qcom,summing-threshold = <10>;
+ };
+
+ dma_blsp2: qcom,sps-dma@7ac4000 { /* BLSP2 */
+ #dma-cells = <4>;
+ compatible = "qcom,sps-dma";
+ reg = <0x7ac4000 0x1f000>;
+ interrupts = <0 239 0>;
+ qcom,summing-threshold = <10>;
+ };
+
+
+ /* IO Expander SX150xq */
+ /* BLSP1 QUP4 */
+ i2c_4: i2c@78b8000 {
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b8000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 98 0>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup4_i2c_apps_clk>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_4_active>;
+ pinctrl-1 = <&i2c_4_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ qcom,master-id = <86>;
+ dmas = <&dma_blsp1 10 64 0x20000020 0x20>,
+ <&dma_blsp1 11 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ rpm_bus: qcom,rpm-smd {
+ compatible = "qcom,rpm-smd";
+ rpm-channel-name = "rpm_requests";
+ rpm-channel-type = <15>; /* SMD_APPS_RPM */
+ };
+
+ clock_gcc: qcom,gcc@1800000 {
+ compatible = "qcom,gcc-8917";
+ reg = <0x1800000 0x80000>,
+ <0xb016000 0x00040>,
+ <0x00a6018 0x00004>;
+ reg-names = "cc_base", "apcs_c1_base", "efuse";
+ vdd_dig-supply = <&pm8937_s2_level>;
+ vdd_hf_dig-supply = <&pm8937_s2_level_ao>;
+ vdd_hf_pll-supply = <&pm8937_l7_ao>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ clock_debug: qcom,cc-debug@1874000 {
+ compatible = "qcom,cc-debug-8917";
+ reg = <0x1874000 0x4>,
+ <0xb01101c 0x8>;
+ reg-names = "cc_base", "meas";
+ #clock-cells = <1>;
+ };
+
+ clock_cpu: qcom,cpu-clock-8939@b111050 {
+ compatible = "qcom,cpu-clock-8917";
+ reg = <0xb011050 0x8>,
+ <0x00a412c 0x8>;
+ reg-names = "apcs-c1-rcg-base", "efuse";
+ qcom,num-cluster;
+ vdd-c1-supply = <&apc_vreg_corner>;
+ clocks = <&clock_gcc clk_gpll0_ao_clk_src>,
+ <&clock_gcc clk_a53ss_c1_pll>;
+ clock-names = "clk-c1-4", "clk-c1-5";
+ qcom,speed0-bin-v0-c1 =
+ < 0 0>,
+ < 960000000 1>,
+ < 1094400000 2>,
+ < 1248000000 3>,
+ < 1401000000 4>;
+
+ qcom,speed1-bin-v0-c1 =
+ < 0 0>,
+ < 960000000 1>,
+ < 1094400000 2>,
+ < 1248000000 3>,
+ < 1401000000 4>,
+ < 1497600000 5>;
+
+ #clock-cells = <1>;
+ };
+
+ i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b6000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 96 0>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup2_i2c_apps_clk>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_2_active>;
+ pinctrl-1 = <&i2c_2_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ qcom,master-id = <86>;
+ dmas = <&dma_blsp1 6 64 0x20000020 0x20>,
+ <&dma_blsp1 7 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c_3: i2c@78b7000 { /* BLSP1 QUP3 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b7000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 97 0>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>;
+
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_3_active>;
+ pinctrl-1 = <&i2c_3_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ qcom,master-id = <86>;
+ dmas = <&dma_blsp1 8 64 0x20000020 0x20>,
+ <&dma_blsp1 9 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c_5: i2c@7af5000 { /* BLSP2 QUP1 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x7af5000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 299 0>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp2_qup1_i2c_apps_clk>;
+
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_5_active>;
+ pinctrl-1 = <&i2c_5_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ qcom,master-id = <84>;
+ dmas = <&dma_blsp2 4 64 0x20000020 0x20>,
+ <&dma_blsp2 5 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ spi_3: spi@78b7000 { /* BLSP1 QUP3 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0x78b7000 0x600>,
+ <0x7884000 0x1f000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 97 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi3_default &spi3_cs0_active>;
+ pinctrl-1 = <&spi3_sleep &spi3_cs0_sleep>;
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup3_spi_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,use-pinctrl;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <8>;
+ qcom,bam-producer-pipe-index = <9>;
+ qcom,master-id = <86>;
+ status = "disabled";
+ };
+
+ usb_otg: usb@78db000 {
+ compatible = "qcom,hsusb-otg";
+ reg = <0x78db000 0x400>, <0x6c000 0x200>;
+ reg-names = "core", "phy_csr";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ interrupts = <0 134 0>,<0 140 0>;
+ interrupt-names = "core_irq", "async_irq";
+
+ hsusb_vdd_dig-supply = <&pm8937_l2>;
+ HSUSB_1p8-supply = <&pm8937_l7>;
+ HSUSB_3p3-supply = <&pm8937_l13>;
+ qcom,vdd-voltage-level = <0 1200000 1200000>;
+ vbus_otg-supply = <&smbcharger_charger_otg>;
+
+ qcom,hsusb-otg-phy-type = <3>; /* SNPS Femto PHY */
+ qcom,hsusb-otg-mode = <3>; /* OTG mode */
+ qcom,hsusb-otg-otg-control = <2>; /* PMIC */
+ qcom,dp-manual-pullup;
+ qcom,phy-dvdd-always-on;
+ qcom,boost-sysclk-with-streaming;
+ qcom,axi-prefetch-enable;
+ qcom,enable-sdp-typec-current-limit;
+ qcom,hsusb-otg-delay-lpm;
+
+ qcom,msm-bus,name = "usb2";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <87 512 0 0>,
+ <87 512 80000 0>,
+ <87 512 6000 6000>;
+ clocks = <&clock_gcc clk_gcc_usb_hs_ahb_clk>,
+ <&clock_gcc clk_gcc_usb_hs_system_clk>,
+ <&clock_gcc clk_gcc_usb2a_phy_sleep_clk>,
+ <&clock_gcc clk_bimc_usb_a_clk>,
+ <&clock_gcc clk_snoc_usb_a_clk>,
+ <&clock_gcc clk_pnoc_usb_a_clk>,
+ <&clock_gcc clk_gcc_qusb2_phy_clk>,
+ <&clock_gcc clk_gcc_usb2_hs_phy_only_clk>,
+ <&clock_gcc clk_gcc_usb_hs_phy_cfg_ahb_clk>,
+ <&clock_gcc clk_xo_otg_clk>;
+ clock-names = "iface_clk", "core_clk", "sleep_clk",
+ "bimc_clk", "snoc_clk", "pcnoc_clk",
+ "phy_reset_clk", "phy_por_clk", "phy_csr_clk",
+ "xo";
+ qcom,bus-clk-rate = <595200000 200000000 100000000>;
+ qcom,max-nominal-sysclk-rate = <133330000>;
+
+ resets = <&clock_gcc GCC_USB_HS_BCR>,
+ <&clock_gcc GCC_QUSB2_PHY_BCR>,
+ <&clock_gcc GCC_USB2_HS_PHY_ONLY_BCR>;
+ reset-names = "core_reset", "phy_reset", "phy_por_reset";
+
+ qcom,usbbam@78c4000 {
+ compatible = "qcom,usb-bam-msm";
+ reg = <0x78c4000 0x17000>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 135 0>;
+
+ qcom,bam-type = <1>;
+ qcom,usb-bam-num-pipes = <4>;
+ qcom,usb-bam-fifo-baseaddr = <0x08605000>;
+ qcom,ignore-core-reset-ack;
+ qcom,disable-clk-gating;
+ qcom,usb-bam-max-mbps-highspeed = <400>;
+ qcom,reset-bam-on-disconnect;
+
+ qcom,pipe0 {
+ label = "hsusb-qdss-in-0";
+ qcom,usb-bam-mem-type = <2>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <0>;
+ qcom,peer-bam-physical-address = <0x6044000>;
+ qcom,src-bam-pipe-index = <0>;
+ qcom,dst-bam-pipe-index = <0>;
+ qcom,data-fifo-offset = <0x0>;
+ qcom,data-fifo-size = <0xe00>;
+ qcom,descriptor-fifo-offset = <0xe00>;
+ qcom,descriptor-fifo-size = <0x200>;
+ };
+ };
+ };
+
+ cpubw: qcom,cpubw {
+ compatible = "qcom,devbw";
+ governor = "cpufreq";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 769 /* 100.8 MHz */ >,
+ < 1611 /* 211.2 MHz */ >,
+ < 2270 /* 297.6 MHz */ >, /*SVS */
+ < 2929 /* 384 MHz */ >,
+ < 4248 /* 556.8 MHz */ >, /*SVS+*/
+ < 4541 /* 595.2 MHz */ >, /*NOM*/
+ < 5126 /* 672 MHz */ >, /*NOM+*/
+ < 5645 /* 740 MHz */ >; /*TURBO*/
+ };
+
+ mincpubw: qcom,mincpubw {
+ compatible = "qcom,devbw";
+ governor = "cpufreq";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 769 /* 100.8 MHz */ >,
+ < 1611 /* 211.2 MHz */ >,
+ < 2270 /* 297.6 MHz */ >,
+ < 2929 /* 384 MHz */ >,
+ < 4248 /* 556.8 MHz */ >,
+ < 4541 /* 595.2 MHz */ >,
+ < 5126 /* 672 MHz */ >,
+ < 5645 /* 740 MHz */ >;
+ };
+
+ qcom,cpu-bwmon {
+ compatible = "qcom,bimc-bwmon2";
+ reg = <0x408000 0x300>, <0x401000 0x200>;
+ reg-names = "base", "global_base";
+ interrupts = <0 183 4>;
+ qcom,mport = <0>;
+ qcom,target-dev = <&cpubw>;
+ };
+
+ qcom,wdt@b017000 {
+ compatible = "qcom,msm-watchdog";
+ reg = <0xb017000 0x1000>;
+ reg-names = "wdt-base";
+ interrupts = <0 3 0>, <0 4 0>;
+ qcom,bark-time = <11000>;
+ qcom,pet-time = <10000>;
+ qcom,ipi-ping;
+ qcom,wakeup-enable;
+ };
+
+ spmi_bus: qcom,spmi@200f000 {
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0x200f000 0x1000>,
+ <0x2400000 0x800000>,
+ <0x2c00000 0x800000>,
+ <0x3800000 0x200000>,
+ <0x200a000 0x2100>;
+ reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+ interrupt-names = "periph_irq";
+ interrupts = <GIC_SPI 190 IRQ_TYPE_NONE>;
+ qcom,ee = <0>;
+ qcom,channel = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-controller;
+ #interrupt-cells = <4>;
+ cell-index = <0>;
+ };
+
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,rtb-size = <0x100000>; /* 1M EBI1 buffer */
+ };
+
+ qcom,msm-imem@8600000 {
+ compatible = "qcom,msm-imem";
+ reg = <0x08600000 0x1000>; /* Address and size of IMEM */
+ ranges = <0x0 0x08600000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ mem_dump_table@10 {
+ compatible = "qcom,msm-imem-mem_dump_table";
+ reg = <0x10 8>;
+ };
+
+ dload_type@18 {
+ compatible = "qcom,msm-imem-dload-type";
+ reg = <0x18 4>;
+ };
+
+ restart_reason@65c {
+ compatible = "qcom,msm-imem-restart_reason";
+ reg = <0x65c 4>;
+ };
+
+ boot_stats@6b0 {
+ compatible = "qcom,msm-imem-boot_stats";
+ reg = <0x6b0 32>;
+ };
+
+ pil@94c {
+ compatible = "qcom,msm-imem-pil";
+ reg = <0x94c 200>;
+ };
+
+ };
+
+ qcom,ipc-spinlock@1905000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0x1905000 0x8000>;
+ qcom,num-locks = <8>;
+ };
+
+ qcom,smem@86300000 {
+ compatible = "qcom,smem";
+ reg = <0x86300000 0x100000>,
+ <0xb011008 0x4>,
+ <0x60000 0x8000>,
+ <0x193d000 0x8>;
+ reg-names = "smem", "irq-reg-base", "aux-mem1",
+ "smem_targ_info_reg";
+ qcom,mpu-enabled;
+
+ qcom,smd-modem {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <0>;
+ qcom,smd-irq-offset = <0x0>;
+ qcom,smd-irq-bitmask = <0x1000>;
+ interrupts = <0 25 1>;
+ label = "modem";
+ qcom,not-loadable;
+ };
+
+ qcom,smsm-modem {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <0>;
+ qcom,smsm-irq-offset = <0x0>;
+ qcom,smsm-irq-bitmask = <0x2000>;
+ interrupts = <0 26 1>;
+ };
+
+ qcom,smd-wcnss {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <6>;
+ qcom,smd-irq-offset = <0x0>;
+ qcom,smd-irq-bitmask = <0x20000>;
+ interrupts = <0 142 1>;
+ label = "wcnss";
+ };
+
+ qcom,smsm-wcnss {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <6>;
+ qcom,smsm-irq-offset = <0x0>;
+ qcom,smsm-irq-bitmask = <0x80000>;
+ interrupts = <0 144 1>;
+ };
+
+ qcom,smd-adsp {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <1>;
+ qcom,smd-irq-offset = <0x0>;
+ qcom,smd-irq-bitmask = <0x100>;
+ interrupts = <0 289 1>;
+ label = "adsp";
+ };
+
+ qcom,smsm-adsp {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <1>;
+ qcom,smsm-irq-offset = <0x0>;
+ qcom,smsm-irq-bitmask = <0x200>;
+ interrupts = <0 290 1>;
+ };
+
+ qcom,smd-rpm {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <15>;
+ qcom,smd-irq-offset = <0x0>;
+ qcom,smd-irq-bitmask = <0x1>;
+ interrupts = <0 168 1>;
+ label = "rpm";
+ qcom,irq-no-suspend;
+ qcom,not-loadable;
+ };
+ };
+
+ qcom,smdtty {
+ compatible = "qcom,smdtty";
+
+ smdtty_apps_fm: qcom,smdtty-apps-fm {
+ qcom,smdtty-remote = "wcnss";
+ qcom,smdtty-port-name = "APPS_FM";
+ };
+
+ smdtty_apps_riva_bt_acl: smdtty-apps-riva-bt-acl {
+ qcom,smdtty-remote = "wcnss";
+ qcom,smdtty-port-name = "APPS_RIVA_BT_ACL";
+ };
+
+ smdtty_apps_riva_bt_cmd: qcom,smdtty-apps-riva-bt-cmd {
+ qcom,smdtty-remote = "wcnss";
+ qcom,smdtty-port-name = "APPS_RIVA_BT_CMD";
+ };
+
+ smdtty_mbalbridge: qcom,smdtty-mbalbridge {
+ qcom,smdtty-remote = "modem";
+ qcom,smdtty-port-name = "MBALBRIDGE";
+ };
+
+ smdtty_apps_riva_ant_cmd: smdtty-apps-riva-ant-cmd {
+ qcom,smdtty-remote = "wcnss";
+ qcom,smdtty-port-name = "APPS_RIVA_ANT_CMD";
+ };
+
+ smdtty_apps_riva_ant_data: smdtty-apps-riva-ant-data {
+ qcom,smdtty-remote = "wcnss";
+ qcom,smdtty-port-name = "APPS_RIVA_ANT_DATA";
+ };
+
+ smdtty_data1: qcom,smdtty-data1 {
+ qcom,smdtty-remote = "modem";
+ qcom,smdtty-port-name = "DATA1";
+ };
+
+ smdtty_data4: qcom,smdtty-data4 {
+ qcom,smdtty-remote = "modem";
+ qcom,smdtty-port-name = "DATA4";
+ };
+
+ smdtty_data11: qcom,smdtty-data11 {
+ qcom,smdtty-remote = "modem";
+ qcom,smdtty-port-name = "DATA11";
+ };
+
+ smdtty_data21: qcom,smdtty-data21 {
+ qcom,smdtty-remote = "modem";
+ qcom,smdtty-port-name = "DATA21";
+ };
+
+ smdtty_loopback: smdtty-loopback {
+ qcom,smdtty-remote = "modem";
+ qcom,smdtty-port-name = "LOOPBACK";
+ qcom,smdtty-dev-name = "LOOPBACK_TTY";
+ };
+ };
+
+ qcom,smdpkt {
+ compatible = "qcom,smdpkt";
+
+ qcom,smdpkt-data5-cntl {
+ qcom,smdpkt-remote = "modem";
+ qcom,smdpkt-port-name = "DATA5_CNTL";
+ qcom,smdpkt-dev-name = "smdcntl0";
+ };
+
+ qcom,smdpkt-data22 {
+ qcom,smdpkt-remote = "modem";
+ qcom,smdpkt-port-name = "DATA22";
+ qcom,smdpkt-dev-name = "smd22";
+ };
+
+ qcom,smdpkt-data40-cntl {
+ qcom,smdpkt-remote = "modem";
+ qcom,smdpkt-port-name = "DATA40_CNTL";
+ qcom,smdpkt-dev-name = "smdcntl8";
+ };
+
+ qcom,smdpkt-apr-apps2 {
+ qcom,smdpkt-remote = "adsp";
+ qcom,smdpkt-port-name = "apr_apps2";
+ qcom,smdpkt-dev-name = "apr_apps2";
+ };
+
+ qcom,smdpkt-loopback {
+ qcom,smdpkt-remote = "modem";
+ qcom,smdpkt-port-name = "LOOPBACK";
+ qcom,smdpkt-dev-name = "smd_pkt_loopback";
+ };
+ };
+
+ qcom_tzlog: tz-log@8600720 {
+ compatible = "qcom,tz-log";
+ reg = <0x08600720 0x2000>;
+ };
+
+ qcom,ipc_router {
+ compatible = "qcom,ipc_router";
+ qcom,node-id = <1>;
+ };
+
+ qcom,ipc_router_modem_xprt {
+ compatible = "qcom,ipc_router_smd_xprt";
+ qcom,ch-name = "IPCRTR";
+ qcom,xprt-remote = "modem";
+ qcom,xprt-linkid = <1>;
+ qcom,xprt-version = <1>;
+ qcom,fragmented-data;
+ qcom,disable-pil-loading;
+ };
+
+ qcom,ipc_router_q6_xprt {
+ compatible = "qcom,ipc_router_smd_xprt";
+ qcom,ch-name = "IPCRTR";
+ qcom,xprt-remote = "adsp";
+ qcom,xprt-linkid = <1>;
+ qcom,xprt-version = <1>;
+ qcom,fragmented-data;
+ };
+
+ qcom,ipc_router_wcnss_xprt {
+ compatible = "qcom,ipc_router_smd_xprt";
+ qcom,ch-name = "IPCRTR";
+ qcom,xprt-remote = "wcnss";
+ qcom,xprt-linkid = <1>;
+ qcom,xprt-version = <1>;
+ qcom,fragmented-data;
+ };
+
+ bam_dmux: qcom,bam_dmux@4044000 {
+ compatible = "qcom,bam_dmux";
+ reg = <0x4044000 0x19000>;
+ interrupts = <GIC_SPI 162 IRQ_TYPE_EDGE_RISING>;
+ qcom,rx-ring-size = <32>;
+ qcom,max-rx-mtu = <4096>;
+ qcom,fast-shutdown;
+ qcom,no-cpu-affinity;
+ };
+
+ sdcc1_ice: sdcc1ice@7803000 {
+ compatible = "qcom,ice";
+ reg = <0x7803000 0x8000>;
+ interrupt-names = "sdcc_ice_nonsec_level_irq",
+ "sdcc_ice_sec_level_irq";
+ interrupts = <0 312 0>, <0 313 0>;
+ qcom,enable-ice-clk;
+ clock-names = "ice_core_clk_src", "ice_core_clk",
+ "bus_clk", "iface_clk";
+ clocks = <&clock_gcc clk_sdcc1_ice_core_clk_src>,
+ <&clock_gcc clk_gcc_sdcc1_ice_core_clk>,
+ <&clock_gcc clk_gcc_sdcc1_apps_clk>,
+ <&clock_gcc clk_gcc_sdcc1_ahb_clk>;
+ qcom,op-freq-hz = <200000000>, <0>, <0>, <0>;
+ qcom,msm-bus,name = "sdcc_ice_noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <78 512 0 0>, /* No vote */
+ <78 512 1000 0>; /* Max. bandwidth */
+ qcom,bus-vector-names = "MIN", "MAX";
+ qcom,instance-type = "sdcc";
+ };
+
+ sdhc_1: sdhci@7824900 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0x7824900 0x500>, <0x7824000 0x800>, <0x7824e00 0x200>;
+ reg-names = "hc_mem", "core_mem", "cmdq_mem";
+
+ interrupts = <0 123 0>, <0 138 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ sdhc-msm-crypto = <&sdcc1_ice>;
+ qcom,bus-width = <8>;
+ qcom,large-address-bus;
+
+ qcom,devfreq,freq-table = <50000000 200000000>;
+
+ qcom,pm-qos-irq-type = "affine_irq";
+ qcom,pm-qos-irq-latency = <13 651>;
+
+ qcom,pm-qos-cpu-groups = <0x0f>;
+ qcom,pm-qos-cmdq-latency-us = <13 651>;
+
+ qcom,pm-qos-legacy-latency-us = <13 651>;
+
+ qcom,msm-bus,name = "sdhc1";
+ qcom,msm-bus,num-cases = <9>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
+ <78 512 1046 3200>, /* 400 KB/s*/
+ <78 512 52286 160000>, /* 20 MB/s */
+ <78 512 65360 200000>, /* 25 MB/s */
+ <78 512 130718 400000>, /* 50 MB/s */
+ <78 512 130718 400000>, /* 100 MB/s */
+ <78 512 261438 800000>, /* 200 MB/s */
+ <78 512 261438 800000>, /* 400 MB/s */
+ <78 512 1338562 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000
+ 50000000 100000000 200000000 400000000 4294967295>;
+
+ clocks = <&clock_gcc clk_gcc_sdcc1_ahb_clk>,
+ <&clock_gcc clk_gcc_sdcc1_apps_clk>,
+ <&clock_gcc clk_gcc_sdcc1_ice_core_clk>;
+ clock-names = "iface_clk", "core_clk", "ice_core_clk";
+ qcom,ice-clk-rates = <200000000 100000000>;
+
+ qcom,scaling-lower-bus-speed-mode = "DDR52";
+ status = "disabled";
+ };
+
+ sdhc_2: sdhci@7864900 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0x7864900 0x500>, <0x7864000 0x800>;
+ reg-names = "hc_mem", "core_mem";
+
+ interrupts = <0 125 0>, <0 221 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ qcom,bus-width = <4>;
+ qcom,large-address-bus;
+
+ qcom,pm-qos-irq-type = "affine_irq";
+ qcom,pm-qos-irq-latency = <13 651>;
+
+ qcom,pm-qos-cpu-groups = <0x0f>;
+ qcom,pm-qos-legacy-latency-us = <13 651>;
+
+ qcom,msm-bus,name = "sdhc2";
+ qcom,msm-bus,num-cases = <8>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
+ <81 512 1046 3200>, /* 400 KB/s*/
+ <81 512 52286 160000>, /* 20 MB/s */
+ <81 512 65360 200000>, /* 25 MB/s */
+ <81 512 130718 400000>, /* 50 MB/s */
+ <81 512 261438 800000>, /* 100 MB/s */
+ <81 512 261438 800000>, /* 200 MB/s */
+ <81 512 1338562 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+ 100000000 200000000 4294967295>;
+
+ qcom,devfreq,freq-table = <50000000 200000000>;
+ clocks = <&clock_gcc clk_gcc_sdcc2_ahb_clk>,
+ <&clock_gcc clk_gcc_sdcc2_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+
+ status = "disabled";
+ };
+
+ qcom_seecom: qseecom@85b00000 {
+ compatible = "qcom,qseecom";
+ reg = <0x85b00000 0x800000>;
+ reg-names = "secapp-region";
+ qcom,hlos-num-ce-hw-instances = <1>;
+ qcom,hlos-ce-hw-instance = <0>;
+ qcom,qsee-ce-hw-instance = <0>;
+ qcom,disk-encrypt-pipe-pair = <2>;
+ qcom,support-fde;
+ qcom,msm-bus,name = "qseecom-noc";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,support-bus-scaling;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 0 0>,
+ <55 512 120000 1200000>,
+ <55 512 393600 3936000>;
+ clocks = <&clock_gcc clk_crypto_clk_src>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ qcom,ce-opp-freq = <100000000>;
+ };
+
+ qcom_rng: qrng@e3000 {
+ compatible = "qcom,msm-rng";
+ reg = <0xe3000 0x1000>;
+ qcom,msm-rng-iface-clk;
+ qcom,no-qrng-config;
+ qcom,msm-bus,name = "msm-rng-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <1 618 0 0>, /* No vote */
+ <1 618 0 800>; /* 100 MB/s */
+ clocks = <&clock_gcc clk_gcc_prng_ahb_clk>;
+ clock-names = "iface_clk";
+ };
+
+ qcom_crypto: qcrypto@720000 {
+ compatible = "qcom,qcrypto";
+ reg = <0x720000 0x20000>,
+ <0x704000 0x20000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 207 0>;
+ qcom,bam-pipe-pair = <2>;
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ qcom,ce-hw-shared;
+ qcom,clk-mgmt-sus-res;
+ qcom,msm-bus,name = "qcrypto-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 393600 393600>;
+ clocks = <&clock_gcc clk_crypto_clk_src>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ qcom,use-sw-aes-cbc-ecb-ctr-algo;
+ qcom,use-sw-aes-xts-algo;
+ qcom,use-sw-aes-ccm-algo;
+ qcom,use-sw-ahash-algo;
+ qcom,use-sw-hmac-algo;
+ qcom,use-sw-aead-algo;
+ qcom,ce-opp-freq = <100000000>;
+ };
+
+ qcom_cedev: qcedev@720000 {
+ compatible = "qcom,qcedev";
+ reg = <0x720000 0x20000>,
+ <0x704000 0x20000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 207 0>;
+ qcom,bam-pipe-pair = <1>;
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ qcom,ce-hw-shared;
+ qcom,msm-bus,name = "qcedev-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 393600 393600>;
+ clocks = <&clock_gcc clk_crypto_clk_src>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ qcom,ce-opp-freq = <100000000>;
+ };
+
+ qcom,adsprpc-mem {
+ compatible = "qcom,msm-adsprpc-mem-region";
+ memory-region = <&adsp_mem>;
+ };
+
+ spi_6: spi@7af6000 { /* BLSP2 QUP2 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0x7af6000 0x600>,
+ <0x7ac4000 0x1d000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 300 0>, <0 239 0>;
+ spi-max-frequency = <50000000>;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi6_default &spi6_cs0_active>;
+ pinctrl-1 = <&spi6_sleep &spi6_cs0_sleep>;
+ clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp2_qup2_spi_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,use-pinctrl;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <6>;
+ qcom,bam-producer-pipe-index = <7>;
+ qcom,master-id = <84>;
+ status = "disabled";
+ };
+
+};
+
+#include "pm8937-rpm-regulator.dtsi"
+#include "msm8917-regulator.dtsi"
+#include "pm8937.dtsi"
+#include "msm-gdsc-8916.dtsi"
+
+&gdsc_venus {
+ clock-names = "bus_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_venus0_axi_clk>,
+ <&clock_gcc clk_gcc_venus0_vcodec0_clk>;
+ status = "okay";
+};
+
+&gdsc_venus_core0 {
+ qcom,support-hw-trigger;
+ clock-names ="core0_clk";
+ clocks = <&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>;
+ status = "okay";
+};
+
+&gdsc_mdss {
+ clock-names = "core_clk", "bus_clk";
+ clocks = <&clock_gcc clk_gcc_mdss_mdp_clk>,
+ <&clock_gcc clk_gcc_mdss_axi_clk>;
+ status = "okay";
+};
+
+&gdsc_jpeg {
+ clock-names = "core_clk", "bus_clk";
+ clocks = <&clock_gcc clk_gcc_camss_jpeg0_clk>,
+ <&clock_gcc clk_gcc_camss_jpeg_axi_clk>;
+ status = "okay";
+};
+
+&gdsc_vfe {
+ clock-names = "core_clk", "bus_clk", "micro_clk",
+ "csi_clk";
+ clocks = <&clock_gcc clk_gcc_camss_vfe0_clk>,
+ <&clock_gcc clk_gcc_camss_vfe_axi_clk>,
+ <&clock_gcc clk_gcc_camss_micro_ahb_clk>,
+ <&clock_gcc clk_gcc_camss_csi_vfe0_clk>;
+ status = "okay";
+};
+
+&gdsc_vfe1 {
+ clock-names = "core_clk", "bus_clk", "micro_clk",
+ "csi_clk";
+ clocks = <&clock_gcc clk_gcc_camss_vfe1_clk>,
+ <&clock_gcc clk_gcc_camss_vfe1_axi_clk>,
+ <&clock_gcc clk_gcc_camss_micro_ahb_clk>,
+ <&clock_gcc clk_gcc_camss_csi_vfe1_clk>;
+ status = "okay";
+};
+
+&gdsc_cpp {
+ clock-names = "core_clk", "bus_clk";
+ clocks = <&clock_gcc clk_gcc_camss_cpp_clk>,
+ <&clock_gcc clk_gcc_camss_cpp_axi_clk>;
+ status = "okay";
+};
+
+&gdsc_oxili_gx {
+ clock-names = "core_root_clk", "gfx_clk";
+ clocks =<&clock_gcc clk_gfx3d_clk_src>,
+ <&clock_gcc clk_gcc_oxili_gfx3d_clk>;
+ qcom,enable-root-clk;
+ qcom,clk-dis-wait-val = <0x5>;
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi b/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi
new file mode 100644
index 0000000..2e4d38e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2018, 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 "msm-audio-lpass.dtsi"
+#include "msm8953-wsa881x.dtsi"
+
+&msm_audio_ion {
+ iommus = <&apps_iommu 0x2001 0x0>;
+ qcom,smmu-sid-mask = /bits/ 64 <0xf>;
+};
+
+&soc {
+ qcom,msm-audio-apr {
+ compatible = "qcom,msm-audio-apr";
+ msm_audio_apr_dummy {
+ compatible = "qcom,msm-audio-apr-dummy";
+ };
+ };
+
+ qcom,avtimer@c0a300c {
+ compatible = "qcom,avtimer";
+ reg = <0x0c0a300c 0x4>,
+ <0x0c0a3010 0x4>;
+ reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+ qcom,clk-div = <27>;
+ };
+
+ int_codec: sound {
+ status = "okay";
+ compatible = "qcom,msm8952-audio-codec";
+ qcom,model = "msm8952-snd-card-mtp";
+ reg = <0xc051000 0x4>,
+ <0xc051004 0x4>,
+ <0xc055000 0x4>,
+ <0xc052000 0x4>;
+ reg-names = "csr_gp_io_mux_mic_ctl",
+ "csr_gp_io_mux_spkr_ctl",
+ "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+ "csr_gp_io_mux_quin_ctl";
+
+ qcom,msm-ext-pa = "primary";
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,msm-hs-micbias-type = "external";
+ qcom,msm-micbias1-ext-cap;
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "SPK_RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "RX_I2S_CLK", "MCLK",
+ "TX_I2S_CLK", "MCLK",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS External2", "Headset Mic",
+ "MIC BIAS External", "Secondary Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS External2",
+ "AMIC3", "MIC BIAS External",
+ "ADC1_IN", "ADC1_OUT",
+ "ADC2_IN", "ADC2_OUT",
+ "ADC3_IN", "ADC3_OUT",
+ "PDM_IN_RX1", "PDM_OUT_RX1",
+ "PDM_IN_RX2", "PDM_OUT_RX2",
+ "PDM_IN_RX3", "PDM_OUT_RX3",
+ "WSA_SPK OUT", "VDD_WSA_SWITCH",
+ "SpkrMono WSA_IN", "WSA_SPK OUT";
+
+ qcom,cdc-us-euro-gpios = <&tlmm 63 0>;
+ qcom,cdc-us-eu-gpios = <&cdc_us_euro_sw>;
+ qcom,pri-mi2s-gpios = <&cdc_pri_mi2s_gpios>;
+ qcom,quin-mi2s-gpios = <&cdc_quin_mi2s_gpios>;
+
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&pcm_noirq>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-pcm-dsp-noirq";
+ asoc-cpu = <&dai_pri_auxpcm>,
+ <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_mi2s4>, <&dai_mi2s5>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>,
+ <&bt_sco_rx>, <&bt_sco_tx>,
+ <&int_fm_rx>, <&int_fm_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>,
+ <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>,
+ <&incall_music_rx>, <&incall_music_2_rx>;
+
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.4", "msm-dai-q6-mi2s.6",
+ "msm-dai-q6-dev.16384", "msmdai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+ "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770";
+
+ asoc-codec = <&stub_codec>, <&msm_digital_codec>,
+ <&pmic_analog_codec>;
+ asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec",
+ "analog-codec";
+ asoc-wsa-codec-names = "wsa881x-i2c-codec.2-000f";
+ asoc-wsa-codec-prefixes = "SpkrMono";
+ msm-vdd-wsa-switch-supply = <&pm8937_l5>;
+ qcom,msm-vdd-wsa-switch-voltage = <1800000>;
+ qcom,msm-vdd-wsa-switch-current = <10000>;
+ };
+
+ cdc_us_euro_sw: msm_cdc_pinctrl_us_euro_sw {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cross_conn_det_act>;
+ pinctrl-1 = <&cross_conn_det_sus>;
+ };
+
+ cdc_pri_mi2s_gpios: msm_cdc_pinctrl_pri {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act>;
+ pinctrl-1 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus>;
+ };
+
+ cdc_quin_mi2s_gpios: msm_cdc_pinctrl_quin {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&pri_tlmm_lines_act &pri_tlmm_ws_act>;
+ pinctrl-1 = <&pri_tlmm_lines_sus &pri_tlmm_ws_sus>;
+ };
+
+
+ i2c@78b6000 {
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wsa881x_i2c_f: wsa881x-i2c-codec@f {
+ status = "okay";
+ compatible = "qcom,wsa881x-i2c-codec";
+ reg = <0x0f>;
+ qcom,wsa-analog-vi-gpio = <&wsa881x_analog_vi_gpio>;
+ qcom,wsa-analog-clk-gpio = <&wsa881x_analog_clk_gpio>;
+ qcom,wsa-analog-reset-gpio =
+ <&wsa881x_analog_reset_gpio>;
+ };
+ wsa881x_i2c_45: wsa881x-i2c-codec@45 {
+ status = "okay";
+ compatible = "qcom,wsa881x-i2c-codec";
+ reg = <0x45>;
+ };
+ };
+
+ wsa881x_analog_vi_gpio: wsa881x_analog_vi_pctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&wsa_vi_on>;
+ pinctrl-1 = <&wsa_vi_off>;
+ };
+ wsa881x_analog_clk_gpio: wsa881x_analog_clk_pctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&wsa_clk_on>;
+ pinctrl-1 = <&wsa_clk_off>;
+ };
+ wsa881x_analog_reset_gpio: wsa881x_analog_reset_pctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&wsa_reset_on>;
+ pinctrl-1 = <&wsa_reset_off>;
+ };
+
+ ext_codec: sound-9335 {
+ status = "disabled";
+ compatible = "qcom,msm8952-audio-slim-codec";
+ qcom,model = "msm8952-tasha-snd-card";
+
+ reg = <0xc051000 0x4>,
+ <0xc051004 0x4>,
+ <0xc055000 0x4>,
+ <0xc052000 0x4>;
+ reg-names = "csr_gp_io_mux_mic_ctl",
+ "csr_gp_io_mux_spkr_ctl",
+ "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+ "csr_gp_io_mux_quin_ctl";
+
+ qcom,audio-routing =
+ "AIF4 VI", "MCLK",
+ "AIF4 VI", "MICBIAS_REGULATOR",
+ "RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
+ "AIF4 MAD", "MICBIAS_REGULATOR",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC3", "MIC BIAS2",
+ "MIC BIAS2", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2",
+ "MIC BIAS2", "ANCLeft Headset Mic",
+ "AMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Handset Mic",
+ "AMIC6", "MIC BIAS4",
+ "MIC BIAS4", "Analog Mic6",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "DMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic5",
+ "MIC BIAS1", "MICBIAS_REGULATOR",
+ "MIC BIAS2", "MICBIAS_REGULATOR",
+ "MIC BIAS3", "MICBIAS_REGULATOR",
+ "MIC BIAS4", "MICBIAS_REGULATOR",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+
+ qcom,tasha-mclk-clk-freq = <9600000>;
+
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing";
+
+ asoc-cpu = <&dai_pri_auxpcm>,
+ <&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s5>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>,
+ <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>,
+ <&incall_music_rx>, <&incall_music_2_rx>,
+ <&sb_5_rx>, <&bt_sco_rx>, <&bt_sco_tx>,
+ <&int_fm_rx>, <&int_fm_tx>, <&sb_6_rx>;
+
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.5", "msm-dai-q6-dev.16384",
+ "msm-dai-q6-dev.16385", "msm-dai-q6-dev.16386",
+ "msm-dai-q6-dev.16387", "msm-dai-q6-dev.16388",
+ "msm-dai-q6-dev.16389", "msm-dai-q6-dev.16390",
+ "msm-dai-q6-dev.16391", "msm-dai-q6-dev.16392",
+ "msm-dai-q6-dev.16393", "msm-dai-q6-dev.16395",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+ "msm-dai-q6-dev.16394", "msm-dai-q6-dev.12288",
+ "msm-dai-q6-dev.12289", "msm-dai-q6-dev.12292",
+ "msm-dai-q6-dev.12293", "msm-dai-q6-dev.16396";
+
+ asoc-codec = <&stub_codec>, <&hdmi_dba>;
+ asoc-codec-names = "msm-stub-codec.1", "msm-hdmi-dba-codec-rx";
+ qcom,cdc-us-euro-gpios = <&tlmm 63 0>;
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
+ <&wsa881x_213>, <&wsa881x_214>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ };
+
+ wcd9xxx_intc: wcd9xxx-irq {
+ status = "disabled";
+ interrupt-parent = <&tlmm>;
+ interrupts = <73 0>;
+ qcom,gpio-connect = <&tlmm 73 0>;
+ };
+
+ clock_audio: audio_ext_clk {
+ status = "disabled";
+ compatible = "qcom,audio-ref-clk";
+ clock-names = "osr_clk";
+ qcom,node_has_rpm_clock;
+ #clock-cells = <1>;
+ qcom,audio-ref-clk-gpio = <&pm8937_gpios 1 0>;
+ qcom,lpass-mclk-id = "pri_mclk";
+ clocks = <&clock_gcc clk_div_clk2>;
+ pinctrl-0 = <&cdc_mclk2_sleep>;
+ pinctrl-1 = <&cdc_mclk2_active>;
+ };
+
+ wcd_rst_gpio: wcd_gpio_ctrl {
+ status = "disabled";
+ qcom,cdc-rst-n-gpio = <&tlmm 68 0>;
+ };
+};
+
+&slim_msm {
+ status = "disabled";
+ wcd9335: tasha_codec {
+ status = "disabled";
+ compatible = "qcom,tasha-slim-pgd";
+ clock-names = "wcd_clk", "wcd_native_clk";
+ clocks = <&clock_audio clk_audio_pmi_clk>,
+ <&clock_audio clk_audio_ap_clk2>;
+
+ qcom,cdc-reset-gpio = <&tlmm 68 0>;
+
+ cdc-vdd-buck-supply = <&eldo2_pm8937>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ cdc-buck-sido-supply = <&eldo2_pm8937>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <250000>;
+
+ cdc-vdd-tx-h-supply = <&pm8937_l5>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&pm8937_l5>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vdd-px-supply = <&pm8937_l5>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8937_l13>;
+ qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+ qcom,cdc-vdd-mic-bias-current = <15000>;
+ };
+};
+
+&pm8937_gpios {
+ gpio@c000 {
+ status = "ok";
+ qcom,mode = <1>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ qcom,out-strength = <2>;
+ };
+};
+
+&pm8937_1 {
+ pmic_analog_codec: analog-codec@f000 {
+ status = "okay";
+ compatible = "qcom,pmic-analog-codec";
+ reg = <0xf000 0x200>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x1 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x2 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x3 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x4 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x5 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x6 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x7 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x0 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x1 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x2 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x3 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x4 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x5 IRQ_TYPE_NONE>;
+ interrupt-names = "spk_cnp_int",
+ "spk_clip_int",
+ "spk_ocp_int",
+ "ins_rem_det1",
+ "but_rel_det",
+ "but_press_det",
+ "ins_rem_det",
+ "mbhc_int",
+ "ear_ocp_int",
+ "hphr_ocp_int",
+ "hphl_ocp_det",
+ "ear_cnp_int",
+ "hphr_cnp_int",
+ "hphl_cnp_int";
+
+ cdc-vdda-cp-supply = <&pm8937_s4>;
+ qcom,cdc-vdda-cp-voltage = <2050000 2050000>;
+ qcom,cdc-vdda-cp-current = <210000>;
+
+ cdc-vdd-io-supply = <&pm8937_l5>;
+ qcom,cdc-vdd-io-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-io-current = <5000>;
+
+ cdc-vdd-pa-supply = <&pm8937_s4>;
+ qcom,cdc-vdd-pa-voltage = <1900000 2050000>;
+ qcom,cdc-vdd-pa-current = <260000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8937_l13>;
+ qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+ qcom,cdc-vdd-mic-bias-current = <5000>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+
+ qcom,cdc-static-supplies = "cdc-vdd-io",
+ "cdc-vdd-pa",
+ "cdc-vdda-cp";
+
+ qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+
+ msm_digital_codec: msm-dig-codec {
+ compatible = "qcom,msm-digital-codec";
+ reg = <0xc0f0000 0x0>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-bus.dtsi b/arch/arm64/boot/dts/qcom/msm8937-bus.dtsi
new file mode 100644
index 0000000..89bfc73
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-bus.dtsi
@@ -0,0 +1,986 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/msm/msm-bus-ids.h>
+
+&soc {
+ /*Version = 11 */
+ ad_hoc_bus: ad-hoc-bus@580000 {
+ compatible = "qcom,msm-bus-device";
+ reg = <0x580000 0x16080>,
+ <0x580000 0x16080>,
+ <0x400000 0x5A000>,
+ <0x500000 0x13080>;
+ reg-names = "snoc-base", "snoc-mm-base",
+ "bimc-base", "pcnoc-base";
+
+ /*Buses*/
+ fab_bimc: fab-bimc {
+ cell-id = <MSM_BUS_FAB_BIMC>;
+ label = "fab-bimc";
+ qcom,fab-dev;
+ qcom,base-name = "bimc-base";
+ qcom,bus-type = <2>;
+ qcom,util-fact = <154>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_gcc clk_bimc_msmbus_clk>,
+ <&clock_gcc clk_bimc_msmbus_a_clk>;
+ };
+
+ fab_pcnoc: fab-pcnoc {
+ cell-id = <MSM_BUS_FAB_PERIPH_NOC>;
+ label = "fab-pcnoc";
+ qcom,fab-dev;
+ qcom,base-name = "pcnoc-base";
+ qcom,base-offset = <0x7000>;
+ qcom,qos-off = <0x1000>;
+ qcom,bus-type = <1>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_gcc clk_pnoc_msmbus_clk>,
+ <&clock_gcc clk_pnoc_msmbus_a_clk>;
+ };
+
+ fab_snoc: fab-snoc {
+ cell-id = <MSM_BUS_FAB_SYS_NOC>;
+ label = "fab-snoc";
+ qcom,fab-dev;
+ qcom,base-name = "snoc-base";
+ qcom,base-offset = <0x7000>;
+ qcom,qos-off = <0x1000>;
+ qcom,bus-type = <1>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_gcc clk_snoc_msmbus_clk>,
+ <&clock_gcc clk_snoc_msmbus_a_clk>;
+ };
+
+ fab_snoc_mm: fab-snoc-mm {
+ cell-id = <MSM_BUS_FAB_MMSS_NOC>;
+ label = "fab-snoc-mm";
+ qcom,fab-dev;
+ qcom,base-name = "snoc-mm-base";
+ qcom,base-offset = <0x7000>;
+ qcom,qos-off = <0x1000>;
+ qcom,bus-type = <1>;
+ qcom,util-fact = <154>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&clock_gcc clk_sysmmnoc_msmbus_clk>,
+ <&clock_gcc clk_sysmmnoc_msmbus_a_clk>;
+ };
+
+ /*BIMC Masters*/
+ mas_apps_proc: mas-apps-proc {
+ cell-id = <MSM_BUS_MASTER_AMPSS_M0>;
+ label = "mas-apps-proc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <0>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+ qcom,prio-lvl = <0>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_APPSS_PROC>;
+ };
+
+ mas_oxili: mas-oxili {
+ cell-id = <MSM_BUS_MASTER_GRAPHICS_3D>;
+ label = "mas-oxili";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <2>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+ qcom,prio-lvl = <0>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_GFX3D>;
+ };
+
+ mas_snoc_bimc_0: mas-snoc-bimc-0 {
+ cell-id = <MSM_BUS_SNOC_BIMC_0_MAS>;
+ label = "mas-snoc-bimc-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <3>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC_0>;
+ };
+
+ mas_snoc_bimc_2: mas-snoc-bimc-2 {
+ cell-id = <MSM_BUS_SNOC_BIMC_2_MAS>;
+ label = "mas-snoc-bimc-2";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <4>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC_2>;
+ };
+
+ mas_snoc_bimc_1: mas-snoc-bimc-1 {
+ cell-id = <MSM_BUS_SNOC_BIMC_1_MAS>;
+ label = "mas-snoc-bimc-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <5>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_ebi>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC_1>;
+ };
+
+ mas_tcu_0: mas-tcu-0 {
+ cell-id = <MSM_BUS_MASTER_TCU_0>;
+ label = "mas-tcu-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <6>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+ qcom,prio-lvl = <2>;
+ qcom,prio-rd = <2>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_TCU_0>;
+ };
+
+ /*PCNOC Masters*/
+ mas_spdm: mas-spdm {
+ cell-id = <MSM_BUS_MASTER_SPDM>;
+ label = "mas-spdm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,connections = <&pcnoc_m_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SPDM>;
+ };
+
+ mas_blsp_1: mas-blsp-1 {
+ cell-id = <MSM_BUS_MASTER_BLSP_1>;
+ label = "mas-blsp-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_m_1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_BLSP_1>;
+ };
+
+ mas_blsp_2: mas-blsp-2 {
+ cell-id = <MSM_BUS_MASTER_BLSP_2>;
+ label = "mas-blsp-2";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_m_1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_BLSP_2>;
+ };
+
+ mas_usb_hs1: mas-usb-hs1 {
+ cell-id = <MSM_BUS_MASTER_USB_HS>;
+ label = "mas-usb-hs1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <12>;
+ qcom,qos-mode = "fixed";
+ qcom,prio1 = <1>;
+ qcom,prio0 = <1>;
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_USB_HS1>;
+ };
+
+ mas_xi_usb_hs1: mas-xi-usb-hs1 {
+ cell-id = <MSM_BUS_MASTER_XM_USB_HS1>;
+ label = "mas-xi-usb-hs1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <11>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_XI_USB_HS1>;
+ };
+
+ mas_crypto: mas-crypto {
+ cell-id = <MSM_BUS_MASTER_CRYPTO_CORE0>;
+ label = "mas-crypto";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <0>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,prio1 = <1>;
+ qcom,prio0 = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_CRYPTO>;
+ };
+
+ mas_sdcc_1: mas-sdcc-1 {
+ cell-id = <MSM_BUS_MASTER_SDCC_1>;
+ label = "mas-sdcc-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <7>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SDCC_1>;
+ };
+
+ mas_sdcc_2: mas-sdcc-2 {
+ cell-id = <MSM_BUS_MASTER_SDCC_2>;
+ label = "mas-sdcc-2";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <8>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SDCC_2>;
+ };
+
+ mas_snoc_pcnoc: mas-snoc-pcnoc {
+ cell-id = <MSM_BUS_SNOC_PNOC_MAS>;
+ label = "mas-snoc-pcnoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <9>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_s_7
+ &pcnoc_int_2 &pcnoc_int_3>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_PCNOC>;
+ };
+
+ /*SNOC Masters*/
+ mas_qdss_bam: mas-qdss-bam {
+ cell-id = <MSM_BUS_MASTER_QDSS_BAM>;
+ label = "mas-qdss-bam";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <11>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&qdss_int>;
+ qcom,prio1 = <1>;
+ qcom,prio0 = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_QDSS_BAM>;
+ };
+
+ mas_bimc_snoc: mas-bimc-snoc {
+ cell-id = <MSM_BUS_BIMC_SNOC_MAS>;
+ label = "mas-bimc-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&snoc_int_0
+ &snoc_int_1 &snoc_int_2>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_BIMC_SNOC>;
+ };
+
+ mas_jpeg: mas-jpeg {
+ cell-id = <MSM_BUS_MASTER_JPEG>;
+ label = "mas-jpeg";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <6>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_snoc_bimc_2>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_JPEG>;
+ };
+
+ mas_mdp: mas-mdp {
+ cell-id = <MSM_BUS_MASTER_MDP_PORT0>;
+ label = "mas-mdp";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <7>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_snoc_bimc_0>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_MDP>;
+ };
+
+ mas_pcnoc_snoc: mas-pcnoc-snoc {
+ cell-id = <MSM_BUS_PNOC_SNOC_MAS>;
+ label = "mas-pcnoc-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <5>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&snoc_int_0
+ &snoc_int_1 &slv_snoc_bimc_1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PNOC_SNOC>;
+ qcom,blacklist = <&slv_snoc_pcnoc>;
+ };
+
+ mas_venus: mas-venus {
+ cell-id = <MSM_BUS_MASTER_VIDEO_P0>;
+ label = "mas-venus";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <8>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_snoc_bimc_2>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_VIDEO>;
+ };
+
+ mas_vfe0: mas-vfe0 {
+ cell-id = <MSM_BUS_MASTER_VFE>;
+ label = "mas-vfe0";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <9>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_snoc_bimc_0>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_VFE>;
+ };
+
+ mas_vfe1: mas-vfe1 {
+ cell-id = <MSM_BUS_MASTER_VFE1>;
+ label = "mas-vfe1";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <13>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_snoc_bimc_0>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_VFE1>;
+ };
+
+ mas_cpp: mas-cpp {
+ cell-id = <MSM_BUS_MASTER_CPP>;
+ label = "mas-cpp";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <12>;
+ qcom,qos-mode = "bypass";
+ qcom,connections = <&slv_snoc_bimc_2>;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,mas-rpm-id = <ICBID_MASTER_CPP>;
+ };
+
+ mas_qdss_etr: mas-qdss-etr {
+ cell-id = <MSM_BUS_MASTER_QDSS_ETR>;
+ label = "mas-qdss-etr";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <10>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&qdss_int>;
+ qcom,prio1 = <1>;
+ qcom,prio0 = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_QDSS_ETR>;
+ };
+
+ /*Internal nodes*/
+ pcnoc_m_0: pcnoc-m-0 {
+ cell-id = <MSM_BUS_PNOC_M_0>;
+ label = "pcnoc-m-0";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,qport = <5>;
+ qcom,qos-mode = "fixed";
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,prio1 = <1>;
+ qcom,prio0 = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_M_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_M_0>;
+ };
+
+ pcnoc_m_1: pcnoc-m-1 {
+ cell-id = <MSM_BUS_PNOC_M_1>;
+ label = "pcnoc-m-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_int_0>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_M_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_M_1>;
+ };
+
+ pcnoc_int_0: pcnoc-int-0 {
+ cell-id = <MSM_BUS_PNOC_INT_0>;
+ label = "pcnoc-int-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_pcnoc_snoc
+ &pcnoc_s_7 &pcnoc_int_3 &pcnoc_int_2>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_0>;
+ };
+
+ pcnoc_int_1: pcnoc-int-1 {
+ cell-id = <MSM_BUS_PNOC_INT_1>;
+ label = "pcnoc-int-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_pcnoc_snoc
+ &pcnoc_s_7 &pcnoc_int_3 &pcnoc_int_2>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_1>;
+ };
+
+ pcnoc_int_2: pcnoc-int-2 {
+ cell-id = <MSM_BUS_PNOC_INT_2>;
+ label = "pcnoc-int-2";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&pcnoc_s_2
+ &pcnoc_s_3 &pcnoc_s_6 &pcnoc_s_8>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_2>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_2>;
+ };
+
+ pcnoc_int_3: pcnoc-int-3 {
+ cell-id = <MSM_BUS_PNOC_INT_3>;
+ label = "pcnoc-int-3";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = < &pcnoc_s_1 &pcnoc_s_0 &pcnoc_s_4
+ &slv_gpu_cfg &slv_tcu >;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_3>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_3>;
+ };
+
+ pcnoc_s_0: pcnoc-s-0 {
+ cell-id = <MSM_BUS_PNOC_SLV_0>;
+ label = "pcnoc-s-0";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_spdm &slv_pdm &slv_prng
+ &slv_sdcc_2>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_0>;
+ };
+
+ pcnoc_s_1: pcnoc-s-1 {
+ cell-id = <MSM_BUS_PNOC_SLV_1>;
+ label = "pcnoc-s-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_tcsr>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_1>;
+ };
+
+ pcnoc_s_2: pcnoc-s-2 {
+ cell-id = <MSM_BUS_PNOC_SLV_2>;
+ label = "pcnoc-s-2";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_snoc_cfg>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_2>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_2>;
+ };
+
+ pcnoc_s_3: pcnoc-s-3 {
+ cell-id = <MSM_BUS_PNOC_SLV_3>;
+ label = "pcnoc-s-3";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_message_ram>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_3>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_3>;
+ };
+
+ pcnoc_s_4: pcnoc-s-4 {
+ cell-id = <MSM_BUS_PNOC_SLV_4>;
+ label = "pcnoc-s-4";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,connections = <&slv_camera_ss_cfg
+ &slv_disp_ss_cfg &slv_venus_cfg>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_4>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_4>;
+ };
+
+ pcnoc_s_6: pcnoc-s-6 {
+ cell-id = <MSM_BUS_PNOC_SLV_6>;
+ label = "pcnoc-s-6";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_tlmm &slv_blsp_1 &slv_blsp_2>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_6>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_6>;
+ };
+
+ pcnoc_s_7: pcnoc-s-7 {
+ cell-id = <MSM_BUS_PNOC_SLV_7>;
+ label = "pcnoc-s-7";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = < &slv_sdcc_1 &slv_pmic_arb>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_7>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_7>;
+ };
+
+ pcnoc_s_8: pcnoc-s-8 {
+ cell-id = <MSM_BUS_PNOC_SLV_8>;
+ label = "pcnoc-s-8";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_usb_hs &slv_crypto_0_cfg>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_8>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_8>;
+ };
+
+ qdss_int: qdss-int {
+ cell-id = <MSM_BUS_SNOC_QDSS_INT>;
+ label = "qdss-int";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,connections = <&snoc_int_1 &slv_snoc_bimc_1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_QDSS_INT>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_QDSS_INT>;
+ };
+
+ snoc_int_0: snoc-int-0 {
+ cell-id = <MSM_BUS_SNOC_INT_0>;
+ label = "snoc-int-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,connections = <&slv_lpass
+ &slv_wcss &slv_kpss_ahb>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_0>;
+ };
+
+ snoc_int_1: snoc-int-1 {
+ cell-id = <MSM_BUS_SNOC_INT_1>;
+ label = "snoc-int-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qdss_stm
+ &slv_imem &slv_snoc_pcnoc>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_1>;
+ };
+
+ snoc_int_2: snoc-int-2 {
+ cell-id = <MSM_BUS_SNOC_INT_2>;
+ label = "snoc-int-2";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,connections = <&slv_cats_0 &slv_cats_1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_2>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_2>;
+ };
+ /*Slaves*/
+
+ slv_ebi:slv-ebi {
+ cell-id = <MSM_BUS_SLAVE_EBI_CH0>;
+ label = "slv-ebi";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_EBI1>;
+ };
+
+ slv_bimc_snoc:slv-bimc-snoc {
+ cell-id = <MSM_BUS_BIMC_SNOC_SLV>;
+ label = "slv-bimc-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_bimc>;
+ qcom,connections = <&mas_bimc_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_BIMC_SNOC>;
+ };
+
+ slv_sdcc_2:slv-sdcc-2 {
+ cell-id = <MSM_BUS_SLAVE_SDCC_2>;
+ label = "slv-sdcc-2";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SDCC_2>;
+ };
+
+ slv_spdm:slv-spdm {
+ cell-id = <MSM_BUS_SLAVE_SPDM_WRAPPER>;
+ label = "slv-spdm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SPDM_WRAPPER>;
+ };
+
+ slv_pdm:slv-pdm {
+ cell-id = <MSM_BUS_SLAVE_PDM>;
+ label = "slv-pdm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PDM>;
+ };
+
+ slv_prng:slv-prng {
+ cell-id = <MSM_BUS_SLAVE_PRNG>;
+ label = "slv-prng";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PRNG>;
+ };
+
+ slv_tcsr:slv-tcsr {
+ cell-id = <MSM_BUS_SLAVE_TCSR>;
+ label = "slv-tcsr";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_TCSR>;
+ };
+
+ slv_snoc_cfg:slv-snoc-cfg {
+ cell-id = <MSM_BUS_SLAVE_SNOC_CFG>;
+ label = "slv-snoc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_CFG>;
+ };
+
+ slv_message_ram:slv-message-ram {
+ cell-id = <MSM_BUS_SLAVE_MESSAGE_RAM>;
+ label = "slv-message-ram";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_MESSAGE_RAM>;
+ };
+
+ slv_camera_ss_cfg:slv-camera-ss-cfg {
+ cell-id = <MSM_BUS_SLAVE_CAMERA_CFG>;
+ label = "slv-camera-ss-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CAMERA_CFG>;
+ };
+
+ slv_disp_ss_cfg:slv-disp-ss-cfg {
+ cell-id = <MSM_BUS_SLAVE_DISPLAY_CFG>;
+ label = "slv-disp-ss-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_DISPLAY_CFG>;
+ };
+
+ slv_venus_cfg:slv-venus-cfg {
+ cell-id = <MSM_BUS_SLAVE_VENUS_CFG>;
+ label = "slv-venus-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_VENUS_CFG>;
+ };
+
+ slv_gpu_cfg:slv-gpu-cfg {
+ cell-id = <MSM_BUS_SLAVE_GRAPHICS_3D_CFG>;
+ label = "slv-gpu-cfg";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_GFX3D_CFG>;
+ };
+
+ slv_tlmm:slv-tlmm {
+ cell-id = <MSM_BUS_SLAVE_TLMM>;
+ label = "slv-tlmm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_TLMM>;
+ };
+
+ slv_blsp_1:slv-blsp-1 {
+ cell-id = <MSM_BUS_SLAVE_BLSP_1>;
+ label = "slv-blsp-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_BLSP_1>;
+ };
+
+ slv_blsp_2:slv-blsp-2 {
+ cell-id = <MSM_BUS_SLAVE_BLSP_2>;
+ label = "slv-blsp-2";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_BLSP_2>;
+ };
+
+ slv_pmic_arb:slv-pmic-arb {
+ cell-id = <MSM_BUS_SLAVE_PMIC_ARB>;
+ label = "slv-pmic-arb";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PMIC_ARB>;
+ };
+
+ slv_sdcc_1:slv-sdcc-1 {
+ cell-id = <MSM_BUS_SLAVE_SDCC_1>;
+ label = "slv-sdcc-1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SDCC_1>;
+ };
+
+ slv_crypto_0_cfg:slv-crypto-0-cfg {
+ cell-id = <MSM_BUS_SLAVE_CRYPTO_0_CFG>;
+ label = "slv-crypto-0-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CRYPTO_0_CFG>;
+ };
+
+ slv_usb_hs:slv-usb-hs {
+ cell-id = <MSM_BUS_SLAVE_USB_HS>;
+ label = "slv-usb-hs";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_USB_HS>;
+ };
+
+ slv_tcu:slv-tcu {
+ cell-id = <MSM_BUS_SLAVE_TCU>;
+ label = "slv-tcu";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_TCU>;
+ };
+
+ slv_pcnoc_snoc:slv-pcnoc-snoc {
+ cell-id = <MSM_BUS_PNOC_SNOC_SLV>;
+ label = "slv-pcnoc-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_pcnoc>;
+ qcom,connections = <&mas_pcnoc_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_SNOC>;
+ };
+
+ slv_kpss_ahb:slv-kpss-ahb {
+ cell-id = <MSM_BUS_SLAVE_APPSS>;
+ label = "slv-kpss-ahb";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_APPSS>;
+ };
+
+ slv_wcss:slv-wcss {
+ cell-id = <MSM_BUS_SLAVE_WCSS>;
+ label = "slv-wcss";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_WCSS>;
+ };
+
+ slv_snoc_bimc_0:slv-snoc-bimc-0 {
+ cell-id = <MSM_BUS_SNOC_BIMC_0_SLV>;
+ label = "slv-snoc-bimc-0";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,connections = <&mas_snoc_bimc_0>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC_0>;
+ };
+
+ slv_snoc_bimc_1:slv-snoc-bimc-1 {
+ cell-id = <MSM_BUS_SNOC_BIMC_1_SLV>;
+ label = "slv-snoc-bimc-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,connections = <&mas_snoc_bimc_1>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC_1>;
+ };
+
+ slv_snoc_bimc_2:slv-snoc-bimc-2 {
+ cell-id = <MSM_BUS_SNOC_BIMC_2_SLV>;
+ label = "slv-snoc-bimc-2";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,connections = <&mas_snoc_bimc_2>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC_2>;
+ };
+
+ slv_imem:slv-imem {
+ cell-id = <MSM_BUS_SLAVE_OCIMEM>;
+ label = "slv-imem";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_IMEM>;
+ };
+
+ slv_snoc_pcnoc:slv-snoc-pcnoc {
+ cell-id = <MSM_BUS_SNOC_PNOC_SLV>;
+ label = "slv-snoc-pcnoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,connections = <&mas_snoc_pcnoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_PCNOC>;
+ };
+
+ slv_qdss_stm:slv-qdss-stm {
+ cell-id = <MSM_BUS_SLAVE_QDSS_STM>;
+ label = "slv-qdss-stm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_QDSS_STM>;
+ };
+
+ slv_cats_0:slv-cats-0 {
+ cell-id = <MSM_BUS_SLAVE_CATS_128>;
+ label = "slv-cats-0";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc_mm>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CATS_0>;
+ };
+
+ slv_cats_1:slv-cats-1 {
+ cell-id = <MSM_BUS_SLAVE_OCMEM_64>;
+ label = "slv-cats-1";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_CATS_1>;
+ };
+
+ slv_lpass:slv-lpass {
+ cell-id = <MSM_BUS_SLAVE_LPASS>;
+ label = "slv-lpass";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,ap-owned;
+ qcom,bus-dev = <&fab_snoc>;
+ qcom,slv-rpm-id = <ICBID_SLAVE_LPASS>;
+ };
+ };
+
+ devfreq_spdm_cpu {
+ compatible = "qcom,devfreq_spdm";
+ qcom,msm-bus,name = "devfreq_spdm";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <1 512 0 0>,
+ <1 512 0 0>;
+ qcom,msm-bus,active-only;
+ qcom,spdm-client = <0>;
+
+ clock-names = "cci_clk";
+ clocks = <&clock_cpu clk_cci_clk>;
+
+ qcom,bw-upstep = <400>;
+ qcom,bw-dwnstep = <3640>;
+ qcom,max-vote = <3640>;
+ qcom,up-step-multp = <1>;
+ qcom,spdm-interval = <50>;
+
+ qcom,ports = <11>;
+ qcom,alpha-up = <8>;
+ qcom,alpha-down = <15>;
+ qcom,bucket-size = <8>;
+
+ /*max pl1 freq, max pl2 freq*/
+ qcom,pl-freqs = <520000 720000>;
+
+ /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+ qcom,reject-rate = <5000 5000 5000 5000 5000 5000>;
+ /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+ qcom,response-time-us = <5000 5000 5000 5000 5000 5000>;
+ /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+ qcom,cci-response-time-us = <5000 5000 5000 5000 5000 5000>;
+ qcom,max-cci-freq = <500000>;
+ };
+
+ devfreq_spdm_gov {
+ compatible = "qcom,gov_spdm_hyp";
+ interrupt-names = "spdm-irq";
+ interrupts = <0 192 0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi
new file mode 100644
index 0000000..0a8c0bf
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi
@@ -0,0 +1,1201 @@
+/*
+ * Copyright (c) 2015-2018, 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 an
+ * 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.
+ */
+
+&soc {
+ tmc_etr: tmc@6028000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b961>;
+
+ reg = <0x6028000 0x1000>,
+ <0x6044000 0x15000>;
+ reg-names = "tmc-base", "bam-base";
+
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
+
+ arm,buffer-size = <0x100000>;
+ arm,sg-enable;
+
+ coresight-name = "coresight-tmc-etr";
+ coresight-ctis = <&cti0 &cti8>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ tmc_etr_in_replicator: endpoint {
+ slave-mode;
+ remote-endpoint = <&replicator_out_tmc_etr>;
+ };
+ };
+ };
+
+ tmc_etf: tmc@6027000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b961>;
+
+ reg = <0x6027000 0x1000>;
+ reg-names = "tmc-base";
+
+ coresight-name = "coresight-tmc-etf";
+
+ arm,default-sink;
+ coresight-ctis = <&cti0 &cti8>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ tmc_etf_out_replicator:endpoint {
+ remote-endpoint =
+ <&replicator_in_tmc_etf>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ tmc_etf_in_funnel_in0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_in0_out_tmc_etf>;
+ };
+ };
+ };
+ };
+
+ replicator: replicator@6026000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b909>;
+
+ reg = <0x6026000 0x1000>;
+ reg-names = "replicator-base";
+
+ coresight-name = "coresight-replicator";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ replicator_out_tmc_etr: endpoint {
+ remote-endpoint =
+ <&tmc_etr_in_replicator>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ replicator_in_tmc_etf: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tmc_etf_out_replicator>;
+ };
+ };
+ };
+ };
+
+ funnel_in0: funnel@6021000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6021000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-in0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ funnel_in0_out_tmc_etf: endpoint {
+ remote-endpoint =
+ <&tmc_etf_in_funnel_in0>;
+ };
+ };
+
+ port@1 {
+ reg = <7>;
+ funnel_in0_in_stm: endpoint {
+ slave-mode;
+ remote-endpoint = <&stm_out_funnel_in0>;
+ };
+ };
+
+ port@2 {
+ reg = <6>;
+ funnel_in0_in_tpda: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpda_out_funnel_in0>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+ funnel_in0_in_funnel_center: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_center_out_funnel_in0>;
+ };
+ };
+
+ port@4 {
+ reg = <4>;
+ funnel_in0_in_funnel_right: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_right_out_funnel_in0>;
+ };
+ };
+
+ port@5 {
+ reg = <5>;
+ funnel_in0_in_funnel_mm: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_mm_out_funnel_in0>;
+ };
+ };
+ };
+ };
+
+ funnel_center: funnel@6100000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6100000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-center";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ funnel_center_out_funnel_in0: endpoint {
+ remote-endpoint =
+ <&funnel_in0_in_funnel_center>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ funnel_center_in_rpm_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&rpm_etm0_out_funnel_center>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ funnel_center_in_dbgui: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&dbgui_out_funnel_center>;
+ };
+ };
+ };
+ };
+
+ funnel_right: funnel@6120000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6120000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-right";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ funnel_right_out_funnel_in0: endpoint {
+ remote-endpoint =
+ <&funnel_in0_in_funnel_right>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ funnel_right_in_modem_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&modem_etm0_out_funnel_right>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ funnel_right_in_funnel_apss: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_apss_out_funnel_right>;
+ };
+ };
+ };
+ };
+
+ funnel_mm: funnel@6130000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6130000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-mm";
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ funnel_mm_out_funnel_in0: endpoint {
+ remote-endpoint =
+ <&funnel_in0_in_funnel_mm>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ funnel_mm_in_wcn_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&wcn_etm0_out_funnel_mm>;
+ };
+ };
+
+ port@2 {
+ reg = <4>;
+ funnel_mm_in_funnel_cam: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_cam_out_funnel_mm>;
+ };
+ };
+
+ port@3 {
+ reg = <5>;
+ funnel_mm_in_audio_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&audio_etm0_out_funnel_mm>;
+ };
+ };
+
+ port@4 {
+ reg = <6>;
+ funnel_mm_in_gfx: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&gfx_out_funnel_mm>;
+ };
+ };
+ };
+ };
+
+ funnel_cam: funnel@6132000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6132000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-cam";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ funnel_cam_out_funnel_mm: endpoint {
+ remote-endpoint = <&funnel_mm_in_funnel_cam>;
+ };
+ };
+ };
+
+ funnel_apss: funnel@61a1000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x61a1000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-apss";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ funnel_apss_out_funnel_right: endpoint {
+ remote-endpoint =
+ <&funnel_right_in_funnel_apss>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ funnel_apss0_in_etm4: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm4_out_funnel_apss0>;
+ };
+ };
+
+ port@2 {
+ reg = <1>;
+ funnel_apss0_in_etm5: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm5_out_funnel_apss0>;
+ };
+ };
+
+ port@3 {
+ reg = <2>;
+ funnel_apss0_in_etm6: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm6_out_funnel_apss0>;
+ };
+ };
+
+ port@4 {
+ reg = <3>;
+ funnel_apss0_in_etm7: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm7_out_funnel_apss0>;
+ };
+ };
+
+ port@5 {
+ reg = <4>;
+ funnel_apss0_in_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm0_out_funnel_apss0>;
+ };
+ };
+
+ port@6 {
+ reg = <5>;
+ funnel_apss0_in_etm1: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm1_out_funnel_apss0>;
+ };
+ };
+
+ port@7 {
+ reg = <6>;
+ funnel_apss0_in_etm2: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm2_out_funnel_apss0>;
+ };
+ };
+
+ port@8 {
+ reg = <7>;
+ funnel_apss0_in_etm3: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm3_out_funnel_apss0>;
+ };
+ };
+ };
+ };
+
+ etm4: etm@619c000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x000bb95d>;
+
+ reg = <0x619c000 0x1000>;
+ cpu = <&CPU4>;
+ coresight-name = "coresight-etm4";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ etm4_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm4>;
+ };
+ };
+ };
+
+ etm5: etm@619d000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x000bb95d>;
+
+ reg = <0x619d000 0x1000>;
+ cpu = <&CPU5>;
+ coresight-name = "coresight-etm5";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ etm5_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm5>;
+ };
+ };
+ };
+
+ etm6: etm@619e000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x000bb95d>;
+
+ reg = <0x619e000 0x1000>;
+ cpu = <&CPU6>;
+ coresight-name = "coresight-etm6";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ etm6_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm6>;
+ };
+ };
+ };
+
+ etm7: etm@619f000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x000bb95d>;
+
+ reg = <0x619f000 0x1000>;
+ cpu = <&CPU7>;
+ coresight-name = "coresight-etm7";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ etm7_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm7>;
+ };
+ };
+ };
+
+ etm0: etm@61bc000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x000bb95d>;
+
+ reg = <0x61bc000 0x1000>;
+ cpu = <&CPU0>;
+ coresight-name = "coresight-etm0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ etm0_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm0>;
+ };
+ };
+ };
+
+ etm1: etm@61bd000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x000bb95d>;
+
+ reg = <0x61bd000 0x1000>;
+ cpu = <&CPU1>;
+ coresight-name = "coresight-etm1";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ etm1_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm1>;
+ };
+ };
+ };
+
+ etm2: etm@61be000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x000bb95d>;
+
+ reg = <0x61be000 0x1000>;
+ cpu = <&CPU2>;
+ coresight-name = "coresight-etm2";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ etm2_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm2>;
+ };
+ };
+ };
+
+ etm3: etm@61bf000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x000bb95d>;
+
+ reg = <0x61bf000 0x1000>;
+ coresight-name = "coresight-etm3";
+ cpu = <&CPU3>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ etm3_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm3>;
+ };
+ };
+ };
+
+ stm: stm@6002000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b962>;
+
+ reg = <0x6002000 0x1000>,
+ <0x9280000 0x180000>;
+ reg-names = "stm-base", "stm-stimulus-base";
+
+ coresight-name = "coresight-stm";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ stm_out_funnel_in0: endpoint {
+ remote-endpoint = <&funnel_in0_in_stm>;
+ };
+ };
+ };
+
+ cti0: cti@6010000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6010000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti1: cti@6011000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6011000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti1";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti2: cti@6012000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6012000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti2";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti3: cti@6013000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6013000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti3";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti4: cti@6014000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6014000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti4";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti5: cti@6015000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6015000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti5";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti6: cti@6016000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6016000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti6";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti7: cti@6017000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6017000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti7";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti8: cti@6018000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6018000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti8";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti9: cti@6019000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6019000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti9";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti10: cti@601a000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x601a000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti10";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti11: cti@601b000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x601b000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti11";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti12: cti@601c000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x601c000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti12";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti13: cti@601d000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x601d000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti13";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti14: cti@601e000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x601e000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti14";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti15: cti@601f000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x601f000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti15";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu0: cti@6198000{
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6198000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-cpu0";
+ cpu = <&CPU0>;
+ qcom,cti-save;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu1: cti@6199000{
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6199000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-cpu1";
+ cpu = <&CPU1>;
+ qcom,cti-save;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu2: cti@619a000{
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x619a000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-cpu2";
+ cpu = <&CPU2>;
+ qcom,cti-save;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu3: cti@619b000{
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x619b000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-cpu3";
+ cpu = <&CPU3>;
+ qcom,cti-save;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu4: cti@61b8000{
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x61b8000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-cpu4";
+ cpu = <&CPU4>;
+ qcom,cti-save;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu5: cti@61b9000{
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x61b9000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-cpu5";
+ cpu = <&CPU5>;
+ qcom,cti-save;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu6: cti@61ba000{
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x61ba000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-cpu6";
+ cpu = <&CPU6>;
+ qcom,cti-save;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu7: cti@61bb000{
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x61bb000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-cpu7";
+ cpu = <&CPU7>;
+ qcom,cti-save;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_modem_cpu0: cti@6128000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6128000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-modem-cpu0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_modem_cpu1: cti@6124000{
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6124000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-modem-cpu1";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ /* Venus CTI */
+ cti_video_cpu0: cti@6134000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6134000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-video-cpu0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ /* Pronto CTI */
+ cti_wcn_cpu0: cti@6139000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6139000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-wcn-cpu0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ /* LPASS CTI */
+ cti_audio_cpu0: cti@613c000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x613c000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-audio-cpu0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_rpm_cpu0: cti@610c000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x610c000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-rpm-cpu0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ /* Pronto ETM */
+ wcn_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+ coresight-name = "coresight-wcn-etm0";
+ qcom,inst-id = <3>;
+
+ port {
+ wcn_etm0_out_funnel_mm: endpoint {
+ remote-endpoint = <&funnel_mm_in_wcn_etm0>;
+ };
+ };
+ };
+
+ rpm_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+ coresight-name = "coresight-rpm-etm0";
+ qcom,inst-id = <4>;
+
+ port {
+ rpm_etm0_out_funnel_center: endpoint {
+ remote-endpoint = <&funnel_center_in_rpm_etm0>;
+ };
+ };
+ };
+
+ /* LPASS ETM */
+ audio_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+ coresight-name = "coresight-audio-etm0";
+ qcom,inst-id = <5>;
+
+ port {
+ audio_etm0_out_funnel_mm: endpoint {
+ remote-endpoint = <&funnel_mm_in_audio_etm0>;
+ };
+ };
+ };
+
+ /* MSS_SCL */
+ modem_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+ coresight-name = "coresight-modem-etm0";
+ qcom,inst-id = <11>;
+
+ port {
+ modem_etm0_out_funnel_right: endpoint {
+ remote-endpoint = <&funnel_right_in_modem_etm0>;
+ };
+ };
+ };
+
+
+ csr: csr@6001000 {
+ compatible = "qcom,coresight-csr";
+ reg = <0x6001000 0x1000>;
+ reg-names = "csr-base";
+ coresight-name = "coresight-csr";
+
+ qcom,blk-size = <1>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ dbgui: dbgui@6108000 {
+ compatible = "qcom,coresight-dbgui";
+ reg = <0x6108000 0x1000>;
+ reg-names = "dbgui-base";
+ coresight-name = "coresight-dbgui";
+
+ qcom,dbgui-addr-offset = <0x30>;
+ qcom,dbgui-data-offset = <0x130>;
+ qcom,dbgui-size = <64>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ dbgui_out_funnel_center: endpoint {
+ remote-endpoint = <&funnel_center_in_dbgui>;
+ };
+ };
+ };
+
+ tpda: tpda@6003000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b969>;
+
+ reg = <0x6003000 0x1000>;
+ reg-names = "tpda-base";
+ coresight-name = "coresight-tpda";
+
+ qcom,tpda-atid = <64>;
+ qcom,cmb-elem-size = <0 32>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ tpda_out_funnel_in0: endpoint {
+ remote-endpoint = <&funnel_in0_in_tpda>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ tpda_in_tpdm_dcc: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpdm_dcc_out_tpda>;
+ };
+ };
+ };
+ };
+
+ tpdm_dcc: tpdm@6110000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
+
+ reg = <0x6110000 0x1000>;
+ reg-names = "tpdm-base";
+ coresight-name = "coresight-tpdm-dcc";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ tpdm_dcc_out_tpda: endpoint {
+ remote-endpoint = <&tpda_in_tpdm_dcc>;
+ };
+ };
+ };
+
+ hwevent: hwevent@6101000 {
+ compatible = "qcom,coresight-hwevent";
+
+ reg = <0x6101000 0x148>,
+ <0x6101fb0 0x4>,
+ <0x6121000 0x148>,
+ <0x6121fb0 0x4>,
+ <0x6131000 0x148>,
+ <0x6131fb0 0x4>,
+ <0x7105010 0x4>,
+ <0x7885010 0x4>;
+
+ reg-names = "center-wrapper-mux", "center-wrapper-lockaccess",
+ "right-wrapper-mux", "right-wrapper-lockaccess",
+ "mm-wrapper-mux", "mm-wrapper-lockaccess",
+ "usbbam-mux", "blsp-mux";
+
+ coresight-name = "coresight-hwevent";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-cpu.dtsi b/arch/arm64/boot/dts/qcom/msm8937-cpu.dtsi
index 84f73a4..f72fda9 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-cpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-cpu.dtsi
@@ -57,7 +57,10 @@
compatible = "arm,cortex-a53";
reg = <0x100>;
enable-method = "psci";
+ efficiency = <1126>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
L2_1: l2-cache {
compatible = "arm,arch-cache";
cache-level = <2>;
@@ -79,7 +82,10 @@
compatible = "arm,cortex-a53";
reg = <0x101>;
enable-method = "psci";
+ efficiency = <1126>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
L1_I_101: l1-icache {
compatible = "arm,arch-cache";
qcom,dump-size = <0x8800>;
@@ -95,7 +101,10 @@
compatible = "arm,cortex-a53";
reg = <0x102>;
enable-method = "psci";
+ efficiency = <1126>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
L1_I_102: l1-icache {
compatible = "arm,arch-cache";
qcom,dump-size = <0x8800>;
@@ -111,7 +120,10 @@
compatible = "arm,cortex-a53";
reg = <0x103>;
enable-method = "psci";
+ efficiency = <1126>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
L1_I_103: l1-icache {
compatible = "arm,arch-cache";
qcom,dump-size = <0x8800>;
@@ -127,7 +139,10 @@
compatible = "arm,cortex-a53";
reg = <0x0>;
enable-method = "psci";
+ efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_0>;
next-level-cache = <&L2_0>;
+ #cooling-cells = <2>;
L2_0: l2-cache {
compatible = "arm,arch-cache";
cache-level = <2>;
@@ -148,7 +163,10 @@
compatible = "arm,cortex-a53";
reg = <0x1>;
enable-method = "psci";
+ efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_0>;
next-level-cache = <&L2_0>;
+ #cooling-cells = <2>;
L1_I_1: l1-icache {
compatible = "arm,arch-cache";
qcom,dump-size = <0x8800>;
@@ -164,7 +182,10 @@
compatible = "arm,cortex-a53";
reg = <0x2>;
enable-method = "psci";
+ efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_0>;
next-level-cache = <&L2_0>;
+ #cooling-cells = <2>;
L1_I_2: l1-icache {
compatible = "arm,arch-cache";
qcom,dump-size = <0x8800>;
@@ -180,7 +201,10 @@
compatible = "arm,cortex-a53";
reg = <0x3>;
enable-method = "psci";
+ efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_0>;
next-level-cache = <&L2_0>;
+ #cooling-cells = <2>;
L1_I_3: l1-icache {
compatible = "arm,arch-cache";
qcom,dump-size = <0x8800>;
@@ -191,4 +215,57 @@
};
};
};
+
+ energy_costs: energy-costs {
+ compatible = "sched-energy";
+
+ CPU_COST_0: core-cost0 {
+ busy-cost-data = <
+ 700000 623
+ 1000000 917
+ 1100000 1106
+ 1250000 1432
+ 1400000 1740
+ >;
+ idle-cost-data = <
+ 100 80 60 40
+ >;
+ };
+ CPU_COST_1: core-cost1 {
+ busy-cost-data = <
+ 500000 70
+ 800000 114
+ 900000 141
+ 1000000 178
+ 1100000 213
+ >;
+ idle-cost-data = <
+ 40 20 10 8
+ >;
+ };
+ CLUSTER_COST_0: cluster-cost0 {
+ busy-cost-data = <
+ 500000 19
+ 800000 29
+ 900000 36
+ 1000000 46
+ 1100000 55
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ CLUSTER_COST_1: cluster-cost1 {
+ busy-cost-data = <
+ 700000 85
+ 1000000 126
+ 1100000 152
+ 1250000 197
+ 1400000 239
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-gpu.dtsi b/arch/arm64/boot/dts/qcom/msm8937-gpu.dtsi
new file mode 100644
index 0000000..eff49a4
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-gpu.dtsi
@@ -0,0 +1,246 @@
+/* Copyright (c) 2018, 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.
+ */
+
+&soc {
+ msm_bus: qcom,kgsl-busmon {
+ label = "kgsl-busmon";
+ compatible = "qcom,kgsl-busmon";
+ };
+
+ gpubw: qcom,gpubw {
+ compatible = "qcom,devbw";
+ governor = "bw_vbif";
+ qcom,src-dst-ports = <26 512>;
+ /*
+ * active-only flag is used while registering the bus
+ * governor.It helps release the bus vote when the CPU
+ * subsystem is inactiv3
+ */
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 0 >, /* off */
+ < 769 >, /* 1. DDR:100.80 MHz BIMC: 50.40 MHz */
+ < 1611 >, /* 2. DDR:211.20 MHz BIMC: 105.60 MHz */
+ < 2124 >, /* 3. DDR:278.40 MHz BIMC: 139.20 MHz */
+ < 2929 >, /* 4. DDR:384.00 MHz BIMC: 192.00 MHz */
+ < 4101 >, /* 5. DDR:537.60 MHz BIMC: 268.80 MHz */
+ < 4248 >, /* 6. DDR:556.80 MHz BIMC: 278.40 MHz */
+ < 5346 >, /* 7. DDR:662.40 MHz BIMC: 331.20 MHz */
+ < 5712 >, /* 8. DDR:748.80 MHz BIMC: 374.40 MHz */
+ < 6152 >, /* 9. DDR:806.40 MHz BIMC: 403.20 MHz */
+ < 7031 >; /* 10. DDR:921.60 MHz BIMC: 460.80 MHz */
+ };
+
+ msm_gpu: qcom,kgsl-3d0@1c00000 {
+ label = "kgsl-3d0";
+ compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+ status = "ok";
+ reg = <0x1c00000 0x40000
+ 0xa0000 0x6fff>;
+ reg-names = "kgsl_3d0_reg_memory", "qfprom_memory";
+ interrupts = <0 33 0>;
+ interrupt-names = "kgsl_3d0_irq";
+ qcom,id = <0>;
+ qcom,chipid = <0x05000500>;
+
+ qcom,initial-pwrlevel = <2>;
+
+ qcom,idle-timeout = <80>; //msecs
+ qcom,strtstp-sleepwake;
+
+ qcom,highest-bank-bit = <14>;
+
+ qcom,snapshot-size = <1048576>; //bytes
+
+ clocks = <&clock_gcc clk_gcc_oxili_gfx3d_clk>,
+ <&clock_gcc clk_gcc_oxili_ahb_clk>,
+ <&clock_gcc clk_gcc_bimc_gfx_clk>,
+ <&clock_gcc clk_gcc_bimc_gpu_clk>,
+ <&clock_gcc clk_gcc_oxili_timer_clk>,
+ <&clock_gcc clk_gcc_oxili_aon_clk>;
+
+ clock-names = "core_clk", "iface_clk",
+ "mem_iface_clk", "alt_mem_iface_clk",
+ "rbbmtimer_clk", "alwayson_clk";
+
+
+ /* Bus Scale Settings */
+ qcom,gpubw-dev = <&gpubw>;
+ qcom,bus-control;
+ qcom,bus-width = <16>;
+ qcom,msm-bus,name = "grp3d";
+ qcom,msm-bus,num-cases = <11>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <26 512 0 0>, /* off */
+ <26 512 0 806400>, /* 1. 100.80 MHz */
+ <26 512 0 1689600>, /* 2. 211.20 MHz */
+ <26 512 0 2227200>, /* 3. 278.40 MHz */
+ <26 512 0 3072000>, /* 4. 384.00 MHz */
+ <26 512 0 4300800>, /* 5. 537.60 MHz */
+ <26 512 0 4454400>, /* 6. 556.80 MHz */
+ <26 512 0 5299200>, /* 7. 662.40 MHz */
+ <26 512 0 5990400>, /* 8. 748.80 MHz */
+ <26 512 0 6451200>, /* 9. 806.40 MHz */
+ <26 512 0 7372800>; /* 10. 921.60 MHz */
+
+ /* GDSC regulator names */
+ regulator-names = "vddcx", "vdd";
+ /* GDSC oxili regulators */
+ vddcx-supply = <&gdsc_oxili_cx>;
+ vdd-supply = <&gdsc_oxili_gx>;
+
+ /* CPU latency parameter */
+ qcom,pm-qos-active-latency = <360>;
+ qcom,pm-qos-wakeup-latency = <360>;
+
+ /* Quirks */
+ qcom,gpu-quirk-two-pass-use-wfi;
+ qcom,gpu-quirk-dp2clockgating-disable;
+ qcom,gpu-quirk-lmloadkill-disable;
+
+ /* Enable context aware freq. scaling */
+ qcom,enable-ca-jump;
+
+ /* Context aware jump busy penalty in us */
+ qcom,ca-busy-penalty = <12000>;
+
+ /* Context aware jump target power level */
+ qcom,ca-target-pwrlevel = <1>;
+
+ /* Enable gpu cooling device */
+ #cooling-cells = <2>;
+
+ /* GPU Mempools */
+ qcom,gpu-mempools {
+ #address-cells= <1>;
+ #size-cells = <0>;
+ compatible = "qcom,gpu-mempools";
+
+ qcom,mempool-max-pages = <32768>;
+
+ /* 4K Page Pool configuration */
+ qcom,gpu-mempool@0 {
+ reg = <0>;
+ qcom,mempool-page-size = <4096>;
+ };
+ /* 64K Page Pool configuration */
+ qcom,gpu-mempool@1 {
+ reg = <1>;
+ qcom,mempool-page-size = <65536>;
+ };
+ };
+
+ qcom,gpu-coresights {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "qcom,gpu-coresight";
+
+ /* Trace bus */
+ qcom,gpu-coresight@0 {
+ reg = <0>;
+ coresight-name = "coresight-gfx";
+ coresight-atid = <67>;
+ port {
+ gfx_out_funnel_mm: endpoint {
+ remote-endpoint =
+ <&funnel_mm_in_gfx>;
+ };
+ };
+ };
+ };
+
+ /* Power levels */
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ /* TURBO */
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <450000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <9>;
+ qcom,bus-max = <9>;
+ };
+
+ /* NOM+ */
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <400000000>;
+ qcom,bus-freq = <7>;
+ qcom,bus-min = <6>;
+ qcom,bus-max = <9>;
+ };
+
+ /* NOM */
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <375000000>;
+ qcom,bus-freq = <6>;
+ qcom,bus-min = <5>;
+ qcom,bus-max = <8>;
+ };
+
+ /* SVS+ */
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <300000000>;
+ qcom,bus-freq = <5>;
+ qcom,bus-min = <4>;
+ qcom,bus-max = <7>;
+ };
+
+ /* SVS */
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
+ qcom,gpu-freq = <216000000>;
+ qcom,bus-freq = <3>;
+ qcom,bus-min = <1>;
+ qcom,bus-max = <4>;
+ };
+
+ /* XO */
+ qcom,gpu-pwrlevel@5 {
+ reg = <5>;
+ qcom,gpu-freq = <19200000>;
+ qcom,bus-freq = <0>;
+ qcom,bus-min = <0>;
+ qcom,bus-max = <0>;
+ };
+ };
+ };
+
+ kgsl_msm_iommu: qcom,kgsl-iommu@1c40000 {
+ compatible = "qcom,kgsl-smmu-v2";
+
+ reg = <0x1c40000 0x10000>;
+ qcom,protect = <0x40000 0x10000>;
+ qcom,micro-mmu-control = <0x6000>;
+
+ clocks = <&clock_gcc clk_gcc_oxili_ahb_clk>,
+ <&clock_gcc clk_gcc_bimc_gfx_clk>;
+
+ clock-names = "gpu_ahb_clk", "gcc_bimc_gfx_clk";
+
+ qcom,secure_align_mask = <0xfff>;
+ qcom,retention;
+ gfx3d_user: gfx3d_user {
+ compatible = "qcom,smmu-kgsl-cb";
+ label = "gfx3d_user";
+ iommus = <&kgsl_smmu 0>;
+ qcom,gpu-offset = <0x48000>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-cdp.dts b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-cdp.dts
new file mode 100644
index 0000000..4045e9c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-cdp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, 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 "msm8937-interposer-sdm439.dtsi"
+#include "sdm439-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8937 Interposer SDM439 CDP";
+ compatible = "qcom,msm8937-cdp", "qcom,msm8937", "qcom,cdp";
+ qcom,board-id = <1 2>;
+ qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-mtp.dts b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-mtp.dts
new file mode 100644
index 0000000..b34974c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-mtp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, 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 "msm8937-interposer-sdm439.dtsi"
+#include "sdm439-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8937 Interposer SDM439 MTP";
+ compatible = "qcom,msm8937-mtp", "qcom,msm8937", "qcom,mtp";
+ qcom,board-id = <8 1>;
+ qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-qrd.dts b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-qrd.dts
new file mode 100644
index 0000000..2bad28b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-qrd.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, 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 "msm8937-interposer-sdm439.dtsi"
+#include "sdm439-qrd.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8937 Interposer SDM439 QRD";
+ compatible = "qcom,msm8937-qrd", "qcom,msm8937", "qcom,qrd";
+ qcom,board-id = <0xb 2>;
+ qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439.dtsi b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439.dtsi
new file mode 100644
index 0000000..477802a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439.dtsi
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2018, 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 "msm8937.dtsi"
+#include "sdm439-pm8953.dtsi"
+#include "sdm439-audio.dtsi"
+#include "sdm439-pmi632.dtsi"
+
+&pm8953_s5 {
+ regulator-min-microvolt = <1155000>;
+ regulator-max-microvolt = <1350000>;
+};
+
+&pm8953_s5_limit {
+ regulator-min-microvolt = <1155000>;
+ regulator-max-microvolt = <1350000>;
+};
+
+&soc {
+ qcom,csid@1b30000 {
+ /delete-property/ qcom,mipi-csi-vdd-supply;
+ };
+ qcom,csid@1b30400 {
+ /delete-property/ qcom,mipi-csi-vdd-supply;
+ };
+ qcom,csid@1b30800 {
+ /delete-property/ qcom,mipi-csi-vdd-supply;
+ };
+
+ mem_acc_vreg_corner: regulator@01946004 {
+ compatible = "qcom,mem-acc-regulator";
+ regulator-name = "mem_acc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <3>;
+
+ qcom,acc-reg-addr-list =
+ <0x01942138 0x01942130 0x01942120
+ 0x01942124 0x01946000 0x01946004>;
+
+ qcom,acc-init-reg-config = <1 0xff>, <2 0x5555>, <6 0x55>;
+
+ qcom,num-acc-corners = <3>;
+ qcom,boot-acc-corner = <2>;
+ qcom,corner1-reg-config =
+ /* SVS+ => SVS+ */
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ /* SVS+ => NOM */
+ < 3 0x1041041>, < 4 0x1041>, < 5 0x2020202>,
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ /* SVS+ => TURBO/NOM+ */
+ < 3 0x1041041>, < 4 0x1041>, < 5 0x2020202>,
+ < 3 0x0>, < 4 0x0>, < 5 0x0>;
+
+ qcom,corner2-reg-config =
+ /* NOM => SVS+ */
+ < 3 0x30c30c3>, < 4 0x30c3>, < 5 0x6060606>,
+ /* NOM => NOM */
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ /* NOM => TURBO/NOM+ */
+ < 3 0x0>, < 4 0x0>, < 5 0x0>;
+
+ qcom,corner3-reg-config =
+ /* TURBO/NOM+ => SVS+ */
+ < 3 0x1041041>, < 4 0x1041>, < 5 0x2020202>,
+ < 3 0x30c30c3>, < 4 0x30c3>, < 5 0x6060606>,
+ /* TURBO/NOM+ => NOM */
+ < 3 0x1041041>, < 4 0x1041>, < 5 0x2020202>,
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ /* TURBO/NOM+ => TURBO/NOM+ */
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>;
+ };
+
+ apc_vreg_corner: regulator@b018000 {
+ compatible = "qcom,cpr-regulator";
+ reg = <0xb018000 0x1000>, <0xb011064 4>, <0xa4000 0x1000>;
+ reg-names = "rbcpr", "rbcpr_clk", "efuse_addr";
+ interrupts = <0 15 0>;
+ regulator-name = "apc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+
+ qcom,cpr-fuse-corners = <3>;
+ qcom,cpr-voltage-ceiling = <1155000 1225000 1350000>;
+ qcom,cpr-voltage-floor = <1050000 1050000 1090000>;
+ vdd-apc-supply = <&pm8953_s5>;
+
+ mem-acc-supply = <&mem_acc_vreg_corner>;
+
+ qcom,cpr-ref-clk = <19200>;
+ qcom,cpr-timer-delay = <5000>;
+ qcom,cpr-timer-cons-up = <0>;
+ qcom,cpr-timer-cons-down = <2>;
+ qcom,cpr-irq-line = <0>;
+ qcom,cpr-step-quotient = <10>;
+ qcom,cpr-up-threshold = <2>;
+ qcom,cpr-down-threshold = <4>;
+ qcom,cpr-idle-clocks = <15>;
+ qcom,cpr-gcnt-time = <1>;
+ qcom,vdd-apc-step-up-limit = <1>;
+ qcom,vdd-apc-step-down-limit = <1>;
+ qcom,cpr-apc-volt-step = <5000>;
+
+ qcom,cpr-fuse-row = <67 0>;
+ qcom,cpr-fuse-target-quot = <42 24 6>;
+ qcom,cpr-fuse-ro-sel = <60 57 54>;
+ qcom,cpr-init-voltage-ref = <1155000 1225000 1350000>;
+ qcom,cpr-fuse-init-voltage =
+ <67 36 6 0>,
+ <67 18 6 0>,
+ <67 0 6 0>;
+ qcom,cpr-fuse-quot-offset =
+ <71 26 6 0>,
+ <71 20 6 0>,
+ <70 54 7 0>;
+ qcom,cpr-fuse-quot-offset-scale = <5 5 5>;
+ qcom,cpr-init-voltage-step = <10000>;
+ qcom,cpr-corner-map = <1 2 3 3 3 3 3>;
+ qcom,cpr-corner-frequency-map =
+ <1 960000000>,
+ <2 1094400000>,
+ <3 1209600000>,
+ <4 1248000000>,
+ <5 1344000000>,
+ <6 1401000000>,
+ <7 1497600000>;
+ qcom,speed-bin-fuse-sel = <37 34 3 0>;
+ qcom,cpr-speed-bin-max-corners =
+ <0 0 1 2 6>,
+ <1 0 1 2 7>,
+ <2 0 1 2 3>;
+ qcom,cpr-fuse-revision = <69 39 3 0>;
+ qcom,cpr-quot-adjust-scaling-factor-max = <0 1400 1400>;
+ qcom,cpr-voltage-scaling-factor-max = <0 2000 2000>;
+ qcom,cpr-scaled-init-voltage-as-ceiling;
+ qcom,cpr-fuse-version-map =
+ <0 (-1) 1 (-1) (-1) (-1)>,
+ <(-1) (-1) 2 (-1) (-1) (-1)>,
+ <(-1) (-1) 3 (-1) (-1) (-1)>,
+ <(-1) (-1) (-1) (-1) (-1) (-1)>;
+ qcom,cpr-quotient-adjustment =
+ <(-20) (-40) (-20)>,
+ <0 (-40) (20)>,
+ <0 0 (20)>,
+ <0 0 0>;
+ qcom,cpr-init-voltage-adjustment =
+ <0 0 0>,
+ <(10000) (15000) (20000)>,
+ <0 0 0>,
+ <0 0 0>;
+ qcom,cpr-enable;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8937-ion.dtsi
index 823d99d..96e7166 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-ion.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-ion.dtsi
@@ -33,5 +33,11 @@
memory-region = <&qseecom_mem>;
qcom,ion-heap-type = "DMA";
};
+
+ qcom,ion-heap@19 { /* QSEECOM TA HEAP */
+ reg = <19>;
+ memory-region = <&qseecom_ta_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi
index 7fdcb2d..ab2a365 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -16,14 +16,8 @@
#include "dsi-panel-truly-1080p-cmd.dtsi"
#include "dsi-panel-r69006-1080p-cmd.dtsi"
#include "dsi-panel-r69006-1080p-video.dtsi"
-#include "dsi-panel-hx8394f-720p-video.dtsi"
#include "dsi-adv7533-1080p.dtsi"
#include "dsi-adv7533-720p.dtsi"
-#include "dsi-panel-truly-720p-video.dtsi"
-#include "dsi-panel-truly-wuxga-video.dtsi"
-#include "dsi-panel-truly-720p-cmd.dtsi"
-#include "dsi-panel-lead-fl10802-fwvga-video.dtsi"
-#include "dsi-panel-icn9706-720-1440p-video.dtsi"
&soc {
dsi_panel_pwr_supply: dsi_panel_pwr_supply {
@@ -48,5 +42,23 @@
qcom,supply-disable-load = <100>;
};
+ qcom,panel-supply-entry@2 {
+ reg = <2>;
+ qcom,supply-name = "lab";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@3 {
+ reg = <3>;
+ qcom,supply-name = "ibb";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-post-on-sleep = <10>;
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-mdss.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mdss.dtsi
index 07ff464..2c86c8f 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-mdss.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-mdss.dtsi
@@ -185,11 +185,11 @@
smmu_mdp_unsec: qcom,smmu_mdp_unsec_cb {
compatible = "qcom,smmu_mdp_unsec";
- iommus = <&apps_iommu 0xC00 0>; /* For NS ctx bank */
+ iommus = <&apps_iommu 0x2800 0>; /* For NS ctx bank */
};
smmu_mdp_sec: qcom,smmu_mdp_sec_cb {
compatible = "qcom,smmu_mdp_sec";
- iommus = <&apps_iommu 0xC01 0>; /* For SEC Ctx Bank */
+ iommus = <&apps_iommu 0x2801 0>; /* For SEC Ctx Bank */
};
mdss_fb0: qcom,mdss_fb_primary {
diff --git a/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi
index 4cd3568..01192af 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi
@@ -11,6 +11,144 @@
* GNU General Public License for more details.
*/
+#include "msm8937-pinctrl.dtsi"
&blsp1_uart2 {
status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_console_active>;
+};
+
+&sdhc_1 {
+ /* device core power supply */
+ vdd-supply = <&pm8937_l8>;
+ qcom,vdd-voltage-level = <2900000 2900000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8937_l5>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+ 384000000>;
+ qcom,nonremovable;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+ status = "ok";
+};
+
+&sdhc_2 {
+ /* device core power supply */
+ vdd-supply = <&pm8937_l11>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 800000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8937_l12>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+ cd-gpios = <&tlmm 67 0x1>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+ 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
+
+#include "msm8937-mdss-panels.dtsi"
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_truly_1080_vid>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+ qcom,platform-te-gpio = <&tlmm 24 0>;
+ qcom,platform-reset-gpio = <&tlmm 61 0>;
+ qcom,platform-bklight-en-gpio = <&tlmm 59 0>;
+};
+
+&mdss_dsi1 {
+ status = "disabled";
+ qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+ qcom,pluggable;
+ qcom,platform-te-gpio = <&tlmm 24 0>;
+ qcom,platform-reset-gpio = <&tlmm 61 0>;
+ qcom,platform-bklight-en-gpio = <&tlmm 59 0>;
+};
+
+&dsi_truly_1080_vid {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_truly_1080_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,ulps-enabled;
+ qcom,partial-update-enabled;
+ qcom,panel-roi-alignment = <2 2 4 2 1080 2>;
+};
+
+&soc {
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio_key_active>;
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&tlmm 128 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&tlmm 127 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&tlmm 91 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi
index 17ee465..1b273ef 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi
@@ -19,6 +19,7 @@
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
+ interrupt-parent = <&wakegpio>;
#interrupt-cells = <2>;
pmx-uartconsole {
@@ -369,6 +370,31 @@
};
};
+ cdc_mclk2_pin {
+ cdc_mclk2_sleep: cdc_mclk2_sleep {
+ mux {
+ pins = "gpio66";
+ function = "pri_mi2s";
+ };
+ config {
+ pins = "gpio66";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ cdc_mclk2_active: cdc_mclk2_active {
+ mux {
+ pins = "gpio66";
+ function = "pri_mi2s";
+ };
+ config {
+ pins = "gpio66";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
blsp2_uart1_active: blsp2_uart1_active {
mux {
pins = "gpio16", "gpio17", "gpio18", "gpio19";
diff --git a/arch/arm64/boot/dts/qcom/msm8937-pm.dtsi b/arch/arm64/boot/dts/qcom/msm8937-pm.dtsi
new file mode 100644
index 0000000..463ba63
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-pm.dtsi
@@ -0,0 +1,268 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/msm/pm.h>
+
+&soc {
+ qcom,spm@b1d2000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xb1d2000 0x1000>;
+ qcom,name = "system-cci";
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x14>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0xe>;
+ qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3
+ &CPU4 &CPU5 &CPU6 &CPU7>;
+ qcom,vctl-timeout-us = <500>;
+ qcom,vctl-port = <0x0>;
+ qcom,phase-port = <0x1>;
+ qcom,pfm-port = <0x2>;
+ };
+
+ qcom,lpm-levels {
+ compatible = "qcom,lpm-levels";
+ qcom,use-psci;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,pm-cluster@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ label = "system";
+ qcom,psci-mode-shift = <8>;
+ qcom,psci-mode-mask = <0xf>;
+
+ qcom,pm-cluster-level@0{
+ reg = <0>;
+ label = "system-active";
+ qcom,psci-mode = <0>;
+ qcom,latency-us = <415>;
+ qcom,ss-power = <405>;
+ qcom,energy-overhead = <558549>;
+ qcom,time-overhead = <980>;
+ };
+
+ qcom,pm-cluster-level@1{
+ reg = <1>;
+ label = "system-wfi";
+ qcom,psci-mode = <1>;
+ qcom,latency-us = <475>;
+ qcom,ss-power = <346>;
+ qcom,energy-overhead = <718929>;
+ qcom,time-overhead = <1050>;
+ qcom,min-child-idx = <1>;
+ };
+
+ qcom,pm-cluster-level@2{
+ reg = <2>;
+ label = "system-ret";
+ qcom,psci-mode = <2>;
+ qcom,latency-us = <900>;
+ qcom,ss-power = <320>;
+ qcom,energy-overhead = <918687>;
+ qcom,time-overhead = <1250>;
+ qcom,min-child-idx = <1>;
+ qcom,reset-level = <LPM_RESET_LVL_RET>;
+ };
+
+ qcom,pm-cluster-level@3{
+ reg = <3>;
+ label = "system-pc";
+ qcom,psci-mode = <3>;
+ qcom,latency-us = <10782>;
+ qcom,ss-power = <306>;
+ qcom,energy-overhead = <1060040>;
+ qcom,time-overhead = <1426>;
+ qcom,min-child-idx = <2>;
+ qcom,notify-rpm;
+ qcom,is-reset;
+ qcom,reset-level = <LPM_RESET_LVL_PC>;
+ };
+
+ qcom,pm-cluster@0{
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ label = "perf";
+ qcom,psci-mode-shift = <4>;
+ qcom,psci-mode-mask = <0xf>;
+
+ qcom,pm-cluster-level@0{
+ reg = <0>;
+ label = "perf-l2-wfi";
+ qcom,psci-mode = <1>;
+ qcom,latency-us = <210>;
+ qcom,ss-power = <472>;
+ qcom,energy-overhead = <233383>;
+ qcom,time-overhead = <326>;
+ };
+
+ qcom,pm-cluster-level@1{
+ reg = <1>;
+ label = "perf-l2-gdhs";
+ qcom,psci-mode = <4>;
+ qcom,latency-us = <267>;
+ qcom,ss-power = <435>;
+ qcom,energy-overhead = <388012>;
+ qcom,time-overhead = <627>;
+ qcom,min-child-idx = <1>;
+ qcom,reset-level = <LPM_RESET_LVL_GDHS>;
+ };
+
+ qcom,pm-cluster-level@2{
+ reg = <2>;
+ label = "perf-l2-pc";
+ qcom,psci-mode = <5>;
+ qcom,latency-us = <305>;
+ qcom,ss-power = <405>;
+ qcom,energy-overhead = <564794>;
+ qcom,time-overhead = <879>;
+ qcom,min-child-idx = <1>;
+ qcom,is-reset;
+ qcom,reset-level = <LPM_RESET_LVL_PC>;
+ };
+
+ qcom,pm-cpu {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ qcom,psci-mode-shift = <0>;
+ qcom,psci-mode-mask = <0xf>;
+ qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>;
+
+ qcom,pm-cpu-level@0 {
+ reg = <0>;
+ qcom,psci-cpu-mode = <0>;
+ label = "wfi";
+ qcom,latency-us = <1>;
+ qcom,ss-power = <530>;
+ qcom,energy-overhead = <62806>;
+ qcom,time-overhead = <67>;
+ };
+
+ qcom,pm-cpu-level@1 {
+ reg = <1>;
+ qcom,psci-cpu-mode = <3>;
+ label = "pc";
+ qcom,latency-us = <190>;
+ qcom,ss-power = <472>;
+ qcom,energy-overhead = <233383>;
+ qcom,time-overhead = <326>;
+ qcom,use-broadcast-timer;
+ qcom,is-reset;
+ qcom,reset-level =
+ <LPM_RESET_LVL_PC>;
+ };
+ };
+ };
+
+ qcom,pm-cluster@1{
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ label = "pwr";
+ qcom,psci-mode-shift = <4>;
+ qcom,psci-mode-mask = <0xf>;
+
+ qcom,pm-cluster-level@0{
+ reg = <0>;
+ label = "pwr-l2-wfi";
+ qcom,psci-mode = <1>;
+ qcom,latency-us = <221>;
+ qcom,ss-power = <460>;
+ qcom,energy-overhead = <219499>;
+ qcom,time-overhead = <400>;
+ };
+
+ qcom,pm-cluster-level@1{
+ reg = <1>;
+ label = "pwr-l2-gdhs";
+ qcom,psci-mode = <4>;
+ qcom,latency-us = <337>;
+ qcom,ss-power = <433>;
+ qcom,energy-overhead = <372429>;
+ qcom,time-overhead = <717>;
+ qcom,min-child-idx = <1>;
+ qcom,reset-level =
+ <LPM_RESET_LVL_GDHS>;
+ };
+
+ qcom,pm-cluster-level@2{
+ reg = <2>;
+ label = "pwr-l2-pc";
+ qcom,psci-mode = <5>;
+ qcom,latency-us = <415>;
+ qcom,ss-power = <405>;
+ qcom,energy-overhead = <558549>;
+ qcom,time-overhead = <980>;
+ qcom,min-child-idx = <1>;
+ qcom,is-reset;
+ qcom,reset-level =
+ <LPM_RESET_LVL_PC>;
+ };
+
+ qcom,pm-cpu {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ qcom,psci-mode-shift = <0>;
+ qcom,psci-mode-mask = <0xf>;
+ qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>;
+
+ qcom,pm-cpu-level@0 {
+ reg = <0>;
+ qcom,psci-cpu-mode = <0>;
+ label = "wfi";
+ qcom,latency-us = <1>;
+ qcom,ss-power = <540>;
+ qcom,energy-overhead = <93024>;
+ qcom,time-overhead = <57>;
+ };
+
+ qcom,pm-cpu-level@1 {
+ reg = <1>;
+ qcom,psci-cpu-mode = <3>;
+ label = "pc";
+ qcom,latency-us = <221>;
+ qcom,ss-power = <460>;
+ qcom,energy-overhead = <219499>;
+ qcom,time-overhead = <400>;
+ qcom,use-broadcast-timer;
+ qcom,is-reset;
+ qcom,reset-level =
+ <LPM_RESET_LVL_PC>;
+ };
+ };
+ };
+ };
+ };
+
+ qcom,rpm-stats@200000 {
+ compatible = "qcom,rpm-stats";
+ reg = <0x200000 0x1000>,
+ <0x290014 0x4>,
+ <0x29001c 0x4>;
+ reg-names = "phys_addr_base", "offset_addr",
+ "heap_phys_addrbase";
+ qcom,sleep-stats-version = <2>;
+ };
+
+ qcom,rpm-master-stats@60150 {
+ compatible = "qcom,rpm-master-stats";
+ reg = <0x60150 0x5000>;
+ qcom,masters = "APSS", "MPSS", "PRONTO", "TZ", "LPASS";
+ qcom,master-stats-version = <2>;
+ qcom,master-offset = <4096>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
index 3da16e4..1afa230 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
@@ -14,17 +14,6 @@
#include "pmi8950.dtsi"
#include "msm8937-mtp.dtsi"
-&soc {
- led_flash0: qcom,camera-flash {
- cell-index = <0>;
- compatible = "qcom,camera-flash";
- qcom,flash-type = <1>;
- qcom,flash-source = <&pmi8950_flash0 &pmi8950_flash1>;
- qcom,torch-source = <&pmi8950_torch0 &pmi8950_torch1>;
- qcom,switch-source = <&pmi8950_switch>;
- };
-};
-
&vendor {
mtp_batterydata: qcom,battery-data {
qcom,batt-id-range-pct = <15>;
@@ -44,6 +33,10 @@
/delete-property/ dpdm-supply;
};
+&usb_otg {
+ extcon = <&qpnp_smbcharger>;
+};
+
&labibb {
status = "ok";
qpnp,qpnp-labibb-mode = "lcd";
@@ -52,3 +45,13 @@
&ibb_regulator {
qcom,qpnp-ibb-discharge-resistor = <32>;
};
+
+&mdss_dsi0 {
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+};
+
+&mdss_dsi1 {
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi
index 57272a4..44bdfc9 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -58,6 +58,14 @@
<RPM_SMD_REGULATOR_LEVEL_BINNING>;
qcom,use-voltage-level;
};
+
+ pm8937_cx_cdev: regulator-cx-cdev {
+ compatible = "qcom,regulator-cooling-device";
+ regulator-cdev-supply = <&pm8937_s2_floor_level>;
+ regulator-levels = <RPM_SMD_REGULATOR_LEVEL_NOM
+ RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ #cooling-cells = <2>;
+ };
};
rpm-regulator-smpa3 {
diff --git a/arch/arm64/boot/dts/qcom/msm8937-thermal.dtsi b/arch/arm64/boot/dts/qcom/msm8937-thermal.dtsi
new file mode 100644
index 0000000..0148253
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-thermal.dtsi
@@ -0,0 +1,742 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/thermal/thermal.h>
+
+&soc {
+ qmi-tmd-devices {
+ compatible = "qcom,qmi_cooling_devices";
+
+ modem {
+ qcom,instance-id = <0x0>;
+
+ modem_pa: modem_pa {
+ qcom,qmi-dev-name = "pa";
+ #cooling-cells = <2>;
+ };
+
+ modem_proc: modem_proc {
+ qcom,qmi-dev-name = "modem";
+ #cooling-cells = <2>;
+ };
+
+ modem_current: modem_current {
+ qcom,qmi-dev-name = "modem_current";
+ #cooling-cells = <2>;
+ };
+
+ modem_vdd: modem_vdd {
+ qcom,qmi-dev-name = "cpuv_restriction_cold";
+ #cooling-cells = <2>;
+ };
+ };
+ };
+};
+
+&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";
+ };
+ };
+ };
+
+ mdm-core-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";
+ };
+ };
+ };
+
+ lpass-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";
+ };
+ };
+ };
+
+ camera-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";
+ };
+ };
+ };
+
+ cpuss1-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";
+ };
+ };
+ };
+
+ apc1-cpu0-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";
+ };
+ };
+ };
+
+ apc1-cpu1-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";
+ };
+ };
+ };
+
+ apc1-cpu2-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";
+ };
+ };
+ };
+
+ apc1-cpu3-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";
+ };
+ };
+ };
+
+ cpuss0-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";
+ };
+ };
+ };
+
+ gpu-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";
+ };
+ };
+ };
+
+ gpu-step {
+ polling-delay-passive = <250>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 10>;
+ thermal-governor = "step_wise";
+ trips {
+ gpu_step_trip: gpu-step-trip {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ gpu_cdev0 {
+ trip = <&gpu_step_trip>;
+ cooling-device =
+ <&msm_gpu THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+
+ hexa-cpu-max-step {
+ polling-delay-passive = <50>;
+ polling-delay = <100>;
+ thermal-governor = "step_wise";
+ trips {
+ cpu_trip:cpu-trip {
+ temperature = <85000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_cdev {
+ trip = <&cpu_trip>;
+ cooling-device =
+ <&CPU0 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu1_cdev {
+ trip = <&cpu_trip>;
+ cooling-device =
+ <&CPU1 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu2_cdev {
+ trip = <&cpu_trip>;
+ cooling-device =
+ <&CPU2 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu3_cdev {
+ trip = <&cpu_trip>;
+ cooling-device =
+ <&CPU3 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu4_cdev {
+ trip = <&cpu_trip>;
+ cooling-device =
+ <&CPU4 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu5_cdev {
+ trip = <&cpu_trip>;
+ cooling-device =
+ <&CPU5 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu6_cdev {
+ trip = <&cpu_trip>;
+ cooling-device =
+ <&CPU6 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu7_cdev {
+ trip = <&cpu_trip>;
+ cooling-device =
+ <&CPU7 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ };
+ };
+
+ apc1-cpu0-step {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 5>;
+ thermal-governor = "step_wise";
+ trips {
+ apc1_cpu0_trip: apc1-cpu0-trip {
+ temperature = <105000>;
+ hysteresis = <15000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_cdev {
+ trip = <&apc1_cpu0_trip>;
+ cooling-device =
+ <&CPU0 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ apc1-cpu1-step {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 6>;
+ thermal-governor = "step_wise";
+ trips {
+ apc1_cpu1_trip: apc1-cpu1-trip {
+ temperature = <105000>;
+ hysteresis = <15000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu1_cdev {
+ trip = <&apc1_cpu1_trip>;
+ cooling-device =
+ <&CPU1 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ apc1-cpu2-step {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 7>;
+ thermal-governor = "step_wise";
+ trips {
+ apc1_cpu2_trip: apc1-cpu2-trip {
+ temperature = <105000>;
+ hysteresis = <15000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu2_cdev {
+ trip = <&apc1_cpu2_trip>;
+ cooling-device =
+ <&CPU2 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ apc1-cpu3-step {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 8>;
+ thermal-governor = "step_wise";
+ trips {
+ apc1_cpu3_trip: apc1-cpu3-trip {
+ temperature = <105000>;
+ hysteresis = <15000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu3_cdev {
+ trip = <&apc1_cpu3_trip>;
+ cooling-device =
+ <&CPU3 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ cpuss0-step {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 9>;
+ thermal-governor = "step_wise";
+ trips {
+ cpuss0_step_trip: cpuss0-step-trip {
+ temperature = <105000>;
+ hysteresis = <15000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu4_cdev {
+ trip = <&cpuss0_step_trip>;
+ cooling-device =
+ <&CPU4 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ cpu5_cdev {
+ trip = <&cpuss0_step_trip>;
+ cooling-device =
+ <&CPU5 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ cpu6_cdev {
+ trip = <&cpuss0_step_trip>;
+ cooling-device =
+ <&CPU6 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ cpu7_cdev {
+ trip = <&cpuss0_step_trip>;
+ cooling-device =
+ <&CPU7 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ aoss0-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 0>;
+ tracks-low;
+ trips {
+ aoss0_trip: aoss-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ cx_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&pm8937_cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ mdm-core-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 1>;
+ tracks-low;
+ trips {
+ mdm_core_trip: mdm-core-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&mdm_core_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ cx_vdd_cdev {
+ trip = <&mdm_core_trip>;
+ cooling-device = <&pm8937_cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&mdm_core_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ lpass-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 2>;
+ tracks-low;
+ trips {
+ qdsp_trip: qdsp-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&qdsp_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ cx_vdd_cdev {
+ trip = <&qdsp_trip>;
+ cooling-device = <&pm8937_cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&qdsp_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ camera-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 3>;
+ tracks-low;
+ trips {
+ camera_trip: camera-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ cx_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&pm8937_cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ cpuss1-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 4>;
+ tracks-low;
+ trips {
+ cpuss1_trip: cpuss1-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpuss1_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpuss1_trip>;
+ cooling-device = <&pm8937_cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpuss1_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ apc1-cpu0-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 5>;
+ tracks-low;
+ trips {
+ cpu0_trip: apc1-cpu0-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&pm8937_cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ apc1-cpu1-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 6>;
+ tracks-low;
+ trips {
+ cpu1_trip: apc1-cpu1-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&pm8937_cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ apc1-cpu2-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 7>;
+ tracks-low;
+ trips {
+ cpu2_trip: apc1-cpu2-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&pm8937_cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ apc1-cpu3-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 8>;
+ tracks-low;
+ trips {
+ cpu3_trip: apc1-cpu3-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&pm8937_cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ cpuss0-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 9>;
+ tracks-low;
+ trips {
+ cpuss0_lowf_trip: cpuss0-lowf-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpuss0_lowf_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpuss0_lowf_trip>;
+ cooling-device = <&pm8937_cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpuss0_lowf_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ gpu-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 10>;
+ tracks-low;
+ trips {
+ gpu_lowf_trip: gpu-lowf-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&gpu_lowf_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ cx_vdd_cdev {
+ trip = <&gpu_lowf_trip>;
+ cooling-device = <&pm8937_cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&gpu_lowf_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-vidc.dtsi b/arch/arm64/boot/dts/qcom/msm8937-vidc.dtsi
new file mode 100644
index 0000000..c4d5b90
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-vidc.dtsi
@@ -0,0 +1,168 @@
+/* Copyright (c) 2015-2018, 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.
+ */
+
+&soc {
+ qcom,vidc@1d00000 {
+ compatible = "qcom,msm-vidc";
+ reg = <0x01d00000 0xff000>;
+ interrupts = <0 44 0>;
+ qcom,hfi-version = "3xx";
+ venus-supply = <&gdsc_venus>;
+ venus-core0-supply = <&gdsc_venus_core0>;
+ clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>,
+ <&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>,
+ <&clock_gcc clk_gcc_venus0_ahb_clk>,
+ <&clock_gcc clk_gcc_venus0_axi_clk>;
+ clock-names = "core_clk", "core0_clk", "iface_clk", "bus_clk";
+ qcom,clock-configs = <0x1 0x0 0x0 0x0>;
+ qcom,sw-power-collapse;
+ qcom,slave-side-cp;
+ qcom,dcvs-tbl =
+ <108000 108000 244800 0x00000004>, /* Encoder */
+ <108000 108000 244800 0x0f00000c>; /* Decoder */
+ qcom,dcvs-limit =
+ <8160 30>, /* Encoder */
+ <8160 30>; /* Decoder */
+ qcom,hfi = "venus";
+ qcom,reg-presets = <0xe0020 0x05555556>,
+ <0xe0024 0x05555556>,
+ <0x80124 0x00000003>;
+ qcom,qdss-presets = <0x826000 0x1000>,
+ <0x827000 0x1000>,
+ <0x822000 0x1000>,
+ <0x803000 0x1000>,
+ <0x9180000 0x1000>,
+ <0x9181000 0x1000>;
+ qcom,max-hw-load = <352800>; /* 1080p@30 + 720p@30 */
+ qcom,firmware-name = "venus";
+ qcom,allowed-clock-rates = <360000000 320000000
+ 308570000 240000000 166150000>;
+ qcom,clock-freq-tbl {
+ qcom,profile-enc {
+ qcom,codec-mask = <0x55555555>;
+ qcom,cycles-per-mb = <2316>;
+ qcom,low-power-mode-factor = <32768>;
+ };
+ qcom,profile-dec {
+ qcom,codec-mask = <0xf3ffffff>;
+ qcom,cycles-per-mb = <788>;
+ };
+ qcom,profile-hevcdec {
+ qcom,codec-mask = <0x0c000000>;
+ qcom,cycles-per-mb = <1015>;
+ };
+ };
+
+ /* MMUs */
+ non_secure_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_ns";
+ iommus = <&apps_iommu 0x800 0x00>,
+ <&apps_iommu 0x807 0x00>,
+ <&apps_iommu 0x808 0x27>,
+ <&apps_iommu 0x811 0x20>;
+ buffer-types = <0xfff>;
+ virtual-addr-pool = <0x5dc00000 0x7f000000
+ 0xdcc00000 0x1000000>;
+ };
+
+ secure_bitstream_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_bitstream";
+ iommus = <&apps_iommu 0x90c 0x20>;
+ buffer-types = <0x241>;
+ virtual-addr-pool = <0x4b000000 0x12c00000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_pixel";
+ iommus = <&apps_iommu 0x940 0x00>,
+ <&apps_iommu 0x907 0x08>,
+ <&apps_iommu 0x908 0x20>,
+ <&apps_iommu 0x90d 0x20>;
+ buffer-types = <0x106>;
+ virtual-addr-pool = <0x25800000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_non_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_non_pixel";
+ iommus = <&apps_iommu 0x900 0x00>,
+ <&apps_iommu 0x90a 0x04>,
+ <&apps_iommu 0x909 0x22>;
+ buffer-types = <0x480>;
+ virtual-addr-pool = <0x1000000 0x24800000>;
+ qcom,secure-context-bank;
+ };
+
+ /* Buses */
+ venus_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "venus-ddr-gov";
+ qcom,bus-range-kbps = <1000 917000>;
+ };
+
+ arm9_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-arm9-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1 1>;
+ };
+ };
+
+ venus-ddr-gov {
+ compatible = "qcom,msm-vidc,governor,table";
+ name = "venus-ddr-gov";
+ status = "ok";
+ qcom,bus-freq-table {
+ qcom,profile-enc {
+ qcom,codec-mask = <0x55555555>;
+ qcom,load-busfreq-tbl =
+ <244800 841000>, /* 1080p30E */
+ <216000 740000>, /* 720p60E */
+ <194400 680000>, /* FWVGA120E */
+ <144000 496000>, /* VGA120E */
+ <108000 370000>, /* 720p30E */
+ <97200 340000>, /* FWVGA60E */
+ <48600 170000>, /* FWVGA30E */
+ <72000 248000>, /* VGA60E */
+ <36000 124000>, /* VGA30E */
+ <18000 70000>, /* QVGA60E */
+ <9000 35000>, /* QVGA30E */
+ <0 0>;
+ };
+ qcom,profile-dec {
+ qcom,codec-mask = <0xffffffff>;
+ qcom,load-busfreq-tbl =
+ <244800 605000>, /* 1080p30D */
+ <216000 540000>, /* 720p60D */
+ <194400 484000>, /* FWVGA120D */
+ <144000 360000>, /* VGA120D */
+ <108000 270000>, /* 720p30D */
+ <97200 242000>, /* FWVGA60D */
+ <48600 121000>, /* FWVGA30D */
+ <72000 180000>, /* VGA60D */
+ <36000 90000>, /* VGA30D */
+ <18000 45000>, /* HVGA30D */
+ <0 0>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi
index 14a1e9a..09890bb 100644
--- a/arch/arm64/boot/dts/qcom/msm8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi
@@ -21,10 +21,36 @@
model = "Qualcomm Technologies, Inc. MSM8937";
compatible = "qcom,msm8937";
qcom,msm-id = <294 0x0>;
- interrupt-parent = <&intc>;
+ interrupt-parent = <&wakegic>;
chosen {
- bootargs = "sched_enable_hmp=1";
+ bootargs = "sched_enable_hmp=1 kpti=0";
+ };
+
+ firmware: firmware {
+ android {
+ compatible = "android,firmware";
+ fstab {
+ compatible = "android,fstab";
+ vendor {
+ compatible = "android,vendor";
+ dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor";
+ type = "ext4";
+ mnt_flags = "ro,barrier=1,discard";
+ fsmgr_flags = "wait";
+ status = "ok";
+ };
+ system {
+ compatible = "android,system";
+ dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system";
+ type = "ext4";
+ mnt_flags = "ro,barrier=1,discard";
+ fsmgr_flags = "wait";
+ status = "ok";
+ };
+
+ };
+ };
};
reserved-memory {
@@ -79,6 +105,14 @@
size = <0 0x1000000>;
};
+ qseecom_ta_mem: qseecom_ta_region {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0 0x00000000 0 0xffffffff>;
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0x1000000>;
+ };
+
adsp_mem: adsp_region@0 {
compatible = "shared-dma-pool";
reusable;
@@ -105,6 +139,12 @@
smd11 = &smdtty_data11;
smd21 = &smdtty_data21;
smd36 = &smdtty_loopback;
+ i2c2 = &i2c_2;
+ i2c5 = &i2c_5;
+ spi3 = &spi_3;
+ i2c3 = &i2c_3;
+ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
+ sdhc2 = &sdhc_2; /* SDC2 for SD card */
};
soc: soc { };
@@ -122,7 +162,14 @@
#include "msm8937-pinctrl.dtsi"
#include "msm8937-cpu.dtsi"
#include "msm8937-ion.dtsi"
+#include "msm-arm-smmu-8937.dtsi"
#include "msm8937-smp2p.dtsi"
+#include "msm8937-bus.dtsi"
+#include "msm8937-vidc.dtsi"
+#include "msm8937-pm.dtsi"
+#include "msm8937-gpu.dtsi"
+#include "msm8937-mdss.dtsi"
+#include "msm8937-mdss-pll.dtsi"
&soc {
#address-cells = <1>;
@@ -133,11 +180,31 @@
intc: interrupt-controller@b000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
+ interrupt-parent = <&intc>;
#interrupt-cells = <3>;
reg = <0x0b000000 0x1000>,
<0x0b002000 0x1000>;
};
+ wakegic: wake-gic {
+ compatible = "qcom,mpm-gic-msm8937", "qcom,mpm-gic";
+ interrupts = <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>;
+ reg = <0x601d0 0x1000>,
+ <0xb011008 0x4>; /* MSM_APCS_GCC_BASE 4K */
+ reg-names = "vmpm", "ipc";
+ qcom,num-mpm-irqs = <96>;
+ interrupt-controller;
+ interrupt-parent = <&intc>;
+ #interrupt-cells = <3>;
+ };
+
+ wakegpio: wake-gpio {
+ compatible = "qcom,mpm-gpio-msm8937", "qcom,mpm-gpio";
+ interrupt-controller;
+ interrupt-parent = <&intc>;
+ #interrupt-cells = <2>;
+ };
+
timer {
compatible = "arm,armv8-timer";
interrupts = <1 2 0xff08>,
@@ -236,161 +303,7 @@
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";
- };
- };
- };
-
- mdm-core-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";
- };
- };
- };
-
- mdss-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";
- };
- };
- };
-
- camera-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";
- };
- };
- };
-
- cpuss-0-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";
- };
- };
- };
-
- apc1_cpu1-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";
- };
- };
- };
-
- apc1_cpu2-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";
- };
- };
- };
-
- apc1_cpu3-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";
- };
- };
- };
-
- apc1_cpu4-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";
- };
- };
- };
-
- apc0_cpu0-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";
- };
- };
- };
-
- gpu0-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";
- };
- };
- };
- };
+ thermal_zones: thermal-zones {};
tsens0: tsens@4a8000 {
compatible = "qcom,msm8937-tsens";
@@ -421,6 +334,9 @@
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0x78b0000 0x200>;
interrupts = <0 108 0>;
+ clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ clock-names = "core", "iface";
status = "disabled";
};
@@ -474,6 +390,17 @@
#clock-cells = <1>;
};
+ clock_gcc_mdss: qcom,gcc-mdss@1800000 {
+ compatible = "qcom,gcc-mdss-8937";
+ clocks = <&mdss_dsi0_pll clk_dsi_pll0_pixel_clk_src>,
+ <&mdss_dsi0_pll clk_dsi_pll0_byte_clk_src>,
+ <&mdss_dsi1_pll clk_dsi_pll1_pixel_clk_src>,
+ <&mdss_dsi1_pll clk_dsi_pll1_byte_clk_src>;
+ clock-names = "pclk0_src", "byte0_src", "pclk1_src",
+ "byte1_src";
+ #clock-cells = <1>;
+ };
+
clock_cpu: qcom,cpu-clock-8939@b111050 {
compatible = "qcom,cpu-clock-8939";
reg = <0xb011050 0x8>,
@@ -555,6 +482,154 @@
#clock-cells = <1>;
};
+ i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b6000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 96 0>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup2_i2c_apps_clk>;
+
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_2_active>;
+ pinctrl-1 = <&i2c_2_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ qcom,master-id = <86>;
+ dmas = <&dma_blsp1 6 64 0x20000020 0x20>,
+ <&dma_blsp1 7 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c_3: i2c@78b7000 { /* BLSP1 QUP3 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b7000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 97 0>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>;
+
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_3_active>;
+ pinctrl-1 = <&i2c_3_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ qcom,master-id = <86>;
+ dmas = <&dma_blsp1 8 64 0x20000020 0x20>,
+ <&dma_blsp1 9 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c_5: i2c@7af5000 { /* BLSP2 QUP1 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x7af5000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 299 0>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp2_qup1_i2c_apps_clk>;
+
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_5_active>;
+ pinctrl-1 = <&i2c_5_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ qcom,master-id = <84>;
+ dmas = <&dma_blsp2 4 64 0x20000020 0x20>,
+ <&dma_blsp2 5 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ spi_3: spi@78b7000 { /* BLSP1 QUP3 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0x78b7000 0x600>,
+ <0x7884000 0x1f000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 97 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi3_default &spi3_cs0_active>;
+ pinctrl-1 = <&spi3_sleep &spi3_cs0_sleep>;
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup3_spi_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,use-pinctrl;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <8>;
+ qcom,bam-producer-pipe-index = <9>;
+ qcom,master-id = <86>;
+ status = "disabled";
+ };
+
+ msm_cpufreq: qcom,msm-cpufreq {
+ compatible = "qcom,msm-cpufreq";
+ clock-names = "l2_clk", "cpu0_clk", "cpu1_clk", "cpu2_clk",
+ "cpu3_clk", "cpu4_clk", "cpu5_clk",
+ "cpu6_clk", "cpu7_clk";
+ clocks = <&clock_cpu clk_cci_clk>,
+ <&clock_cpu clk_a53_bc_clk>,
+ <&clock_cpu clk_a53_bc_clk>,
+ <&clock_cpu clk_a53_bc_clk>,
+ <&clock_cpu clk_a53_bc_clk>,
+ <&clock_cpu clk_a53_lc_clk>,
+ <&clock_cpu clk_a53_lc_clk>,
+ <&clock_cpu clk_a53_lc_clk>,
+ <&clock_cpu clk_a53_lc_clk>;
+
+ qcom,governor-per-policy;
+
+ qcom,cpufreq-table-0 =
+ < 960000 >,
+ < 1094400 >,
+ < 1209600 >,
+ < 1248000 >,
+ < 1344000 >,
+ < 1401000 >,
+ < 1497600 >;
+
+ qcom,cpufreq-table-4 =
+ < 768000 >,
+ < 902400 >,
+ < 998400 >,
+ < 1094400 >,
+ < 1209600 >;
+ };
+
+ cci_cache: qcom,cci {
+ compatible = "devfreq-simple-dev";
+ clock-names = "devfreq_clk";
+ clocks = <&clock_cpu clk_cci_clk>;
+ governor = "cpufreq";
+ freq-tbl-khz =
+ < 400000 >,
+ < 533333 >;
+ };
+
cpubw: qcom,cpubw {
compatible = "qcom,devbw";
governor = "cpufreq";
@@ -600,6 +675,84 @@
< 7031 /* 921.6 MHz */ >; /* TURBO */
};
+ devfreq-cpufreq {
+ cpubw-cpufreq {
+ target-dev = <&cpubw>;
+ cpu-to-dev-map-0 =
+ < 998400 2929 >, /* SVS */
+ < 1094400 5053 >, /* NOM */
+ < 1248000 5712 >, /* NOM+ */
+ < 1344000 7031 >,
+ < 1497600 7031 >; /* TURBO */
+ cpu-to-dev-map-4 =
+ < 806400 2929 >, /* SVS */
+ < 902400 5053 >, /* NOM */
+ < 998400 6152 >, /* NOM+ */
+ < 1209600 7031 >; /* TURBO */
+ };
+
+ cci-cpufreq {
+ target-dev = <&cci_cache>;
+ cpu-to-dev-map-0 =
+ < 998400 400000 >, /* SVS */
+ < 1094400 400000 >, /* NOM */
+ < 1248000 533333 >, /* NOM+ */
+ < 1344000 533333 >,
+ < 1497600 533333 >; /* TURBO */
+ cpu-to-dev-map-4 =
+ < 806400 400000 >, /* SVS */
+ < 902400 400000 >, /* NOM */
+ < 998400 533333 >, /* NOM+ */
+ < 1209600 533333 >; /* TURBO */
+ };
+
+ mincpubw-cpufreq {
+ target-dev = <&mincpubw>;
+ cpu-to-dev-map-0 =
+ < 1094400 2929 >,
+ < 1497600 4248 >;
+ cpu-to-dev-map-4 =
+ < 998400 2929 >,
+ < 1209600 4248 >;
+ };
+ };
+
+ blsp2_uart1: uart@7aef000 {
+ compatible = "qcom,msm-hsuart-v14";
+ reg = <0x7aef000 0x200>,
+ <0x7ac4000 0x1f000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+ #address-cells = <0>;
+ interrupt-parent = <&blsp2_uart1>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 306 0
+ 1 &intc 0 239 0
+ 2 &tlmm 17 0>;
+
+ qcom,inject-rx-on-wakeup;
+ qcom,rx-char-to-inject = <0xfd>;
+
+ qcom,bam-tx-ep-pipe-index = <0>;
+ qcom,bam-rx-ep-pipe-index = <1>;
+ qcom,master-id = <84>;
+ clock-names = "core_clk", "iface_clk";
+ clocks = <&clock_gcc clk_gcc_blsp2_uart1_apps_clk>,
+ <&clock_gcc clk_gcc_blsp2_ahb_clk>;
+ pinctrl-names = "sleep", "default";
+ pinctrl-0 = <&blsp2_uart1_sleep>;
+ pinctrl-1 = <&blsp2_uart1_active>;
+ qcom,msm-bus,name = "blsp2_uart1";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <84 512 0 0>,
+ <84 512 500 800>;
+ status = "disabled";
+ };
+
qcom,ipc-spinlock@1905000 {
compatible = "qcom,ipc-spinlock-sfpb";
reg = <0x1905000 0x8000>;
@@ -686,6 +839,92 @@
rpm-channel-type = <15>; /* SMD_APPS_RPM */
};
+ usb_otg: usb@78db000 {
+ compatible = "qcom,hsusb-otg";
+ reg = <0x78db000 0x400>, <0x6c000 0x200>;
+ reg-names = "core", "phy_csr";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ interrupts = <0 134 0>,<0 140 0>;
+ interrupt-names = "core_irq", "async_irq";
+
+ hsusb_vdd_dig-supply = <&pm8937_l2>;
+ HSUSB_1p8-supply = <&pm8937_l7>;
+ HSUSB_3p3-supply = <&pm8937_l13>;
+ qcom,vdd-voltage-level = <0 1200000 1200000>;
+ vbus_otg-supply = <&smbcharger_charger_otg>;
+
+ qcom,hsusb-otg-phy-type = <3>; /* SNPS Femto PHY */
+ qcom,hsusb-otg-mode = <3>; /* OTG mode */
+ qcom,hsusb-otg-otg-control = <2>; /* PMIC */
+ qcom,dp-manual-pullup;
+ qcom,phy-dvdd-always-on;
+ qcom,boost-sysclk-with-streaming;
+ qcom,axi-prefetch-enable;
+ qcom,hsusb-otg-delay-lpm;
+
+ qcom,msm-bus,name = "usb2";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <87 512 0 0>,
+ <87 512 80000 0>,
+ <87 512 6000 6000>;
+ clocks = <&clock_gcc clk_gcc_usb_hs_ahb_clk>,
+ <&clock_gcc clk_gcc_usb_hs_system_clk>,
+ <&clock_gcc clk_gcc_usb2a_phy_sleep_clk>,
+ <&clock_gcc clk_bimc_usb_a_clk>,
+ <&clock_gcc clk_snoc_usb_a_clk>,
+ <&clock_gcc clk_pnoc_usb_a_clk>,
+ <&clock_gcc clk_gcc_qusb2_phy_clk>,
+ <&clock_gcc clk_gcc_usb2_hs_phy_only_clk>,
+ <&clock_gcc clk_gcc_usb_hs_phy_cfg_ahb_clk>,
+ <&clock_gcc clk_xo_otg_clk>;
+ clock-names = "iface_clk", "core_clk", "sleep_clk",
+ "bimc_clk", "snoc_clk", "pcnoc_clk",
+ "phy_reset_clk", "phy_por_clk", "phy_csr_clk",
+ "xo";
+ qcom,bus-clk-rate = <748800000 200000000 100000000>;
+ qcom,max-nominal-sysclk-rate = <133330000>;
+
+ resets = <&clock_gcc GCC_USB_HS_BCR>,
+ <&clock_gcc GCC_QUSB2_PHY_BCR>,
+ <&clock_gcc GCC_USB2_HS_PHY_ONLY_BCR>;
+ reset-names = "core_reset", "phy_reset", "phy_por_reset";
+
+ qcom,usbbam@78c4000 {
+ compatible = "qcom,usb-bam-msm";
+ reg = <0x78c4000 0x17000>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 135 0>;
+
+ qcom,bam-type = <1>;
+ qcom,usb-bam-num-pipes = <4>;
+ qcom,usb-bam-fifo-baseaddr = <0x08605000>;
+ qcom,ignore-core-reset-ack;
+ qcom,disable-clk-gating;
+ qcom,usb-bam-max-mbps-highspeed = <400>;
+ qcom,reset-bam-on-disconnect;
+
+ qcom,pipe0 {
+ label = "hsusb-qdss-in-0";
+ qcom,usb-bam-mem-type = <2>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <0>;
+ qcom,peer-bam-physical-address = <0x6044000>;
+ qcom,src-bam-pipe-index = <0>;
+ qcom,dst-bam-pipe-index = <0>;
+ qcom,data-fifo-offset = <0x0>;
+ qcom,data-fifo-size = <0xe00>;
+ qcom,descriptor-fifo-offset = <0xe00>;
+ qcom,descriptor-fifo-size = <0x200>;
+ };
+ };
+ };
+
qcom,wdt@b017000 {
compatible = "qcom,msm-watchdog";
reg = <0xb017000 0x1000>;
@@ -871,6 +1110,12 @@
qcom,smdpkt-dev-name = "smdcntl8";
};
+ qcom,smdpkt-data2 {
+ qcom,smdpkt-remote = "modem";
+ qcom,smdpkt-port-name = "DATA2";
+ qcom,smdpkt-dev-name = "at_mdm0";
+ };
+
qcom,smdpkt-apr-apps2 {
qcom,smdpkt-remote = "adsp";
qcom,smdpkt-port-name = "apr_apps2";
@@ -926,13 +1171,504 @@
compatible = "qcom,msm-adsprpc-mem-region";
memory-region = <&adsp_mem>;
};
+ qcom,msm_fastrpc {
+ compatible = "qcom,msm-fastrpc-legacy-compute";
+ qcom,msm_fastrpc_compute_cb {
+ compatible = "qcom,msm-fastrpc-legacy-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&apps_iommu 0x2008 0x7>;
+ sids = <0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf>;
+ };
+ };
+
+ sdcc1_ice: sdcc1ice@7803000 {
+ compatible = "qcom,ice";
+ reg = <0x7803000 0x8000>;
+ interrupt-names = "sdcc_ice_nonsec_level_irq",
+ "sdcc_ice_sec_level_irq";
+ interrupts = <0 312 0>, <0 313 0>;
+ qcom,enable-ice-clk;
+ clock-names = "ice_core_clk_src", "ice_core_clk",
+ "bus_clk", "iface_clk";
+ clocks = <&clock_gcc clk_sdcc1_ice_core_clk_src>,
+ <&clock_gcc clk_gcc_sdcc1_ice_core_clk>,
+ <&clock_gcc clk_gcc_sdcc1_apps_clk>,
+ <&clock_gcc clk_gcc_sdcc1_ahb_clk>;
+ qcom,op-freq-hz = <200000000>, <0>, <0>, <0>;
+ qcom,msm-bus,name = "sdcc_ice_noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <78 512 0 0>, /* No vote */
+ <78 512 1000 0>; /* Max. bandwidth */
+ qcom,bus-vector-names = "MIN", "MAX";
+ qcom,instance-type = "sdcc";
+ };
+
+ sdhc_1: sdhci@7824900 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0x7824900 0x500>, <0x7824000 0x800>, <0x7824e00 0x200>;
+ reg-names = "hc_mem", "core_mem", "cmdq_mem";
+
+ interrupts = <0 123 0>, <0 138 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ sdhc-msm-crypto = <&sdcc1_ice>;
+ qcom,bus-width = <8>;
+ qcom,large-address-bus;
+
+ qcom,devfreq,freq-table = <50000000 200000000>;
+
+ qcom,pm-qos-irq-type = "affine_irq";
+ qcom,pm-qos-irq-latency = <2 200>;
+
+ qcom,pm-qos-cpu-groups = <0x0f 0xf0>;
+ qcom,pm-qos-cmdq-latency-us = <2 200>, <2 200>;
+
+ qcom,pm-qos-legacy-latency-us = <2 200>, <2 200>;
+
+ qcom,msm-bus,name = "sdhc1";
+ qcom,msm-bus,num-cases = <9>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
+ <78 512 1046 3200>, /* 400 KB/s*/
+ <78 512 52286 160000>, /* 20 MB/s */
+ <78 512 65360 200000>, /* 25 MB/s */
+ <78 512 130718 400000>, /* 50 MB/s */
+ <78 512 130718 400000>, /* 100 MB/s */
+ <78 512 261438 800000>, /* 200 MB/s */
+ <78 512 261438 800000>, /* 400 MB/s */
+ <78 512 1338562 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000
+ 50000000 100000000 200000000 400000000 4294967295>;
+
+ clocks = <&clock_gcc clk_gcc_sdcc1_ahb_clk>,
+ <&clock_gcc clk_gcc_sdcc1_apps_clk>,
+ <&clock_gcc clk_gcc_sdcc1_ice_core_clk>;
+ clock-names = "iface_clk", "core_clk", "ice_core_clk";
+ qcom,ice-clk-rates = <200000000 100000000>;
+
+ qcom,scaling-lower-bus-speed-mode = "DDR52";
+ status = "disabled";
+ };
+
+ sdhc_2: sdhci@7864900 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0x7864900 0x500>, <0x7864000 0x800>;
+ reg-names = "hc_mem", "core_mem";
+
+ interrupts = <0 125 0>, <0 221 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ qcom,bus-width = <4>;
+ qcom,large-address-bus;
+
+ qcom,pm-qos-irq-type = "affine_irq";
+ qcom,pm-qos-irq-latency = <2 200>;
+
+ qcom,pm-qos-cpu-groups = <0x0f 0xf0>;
+ qcom,pm-qos-legacy-latency-us = <2 200>, <2 200>;
+
+ qcom,msm-bus,name = "sdhc2";
+ qcom,msm-bus,num-cases = <8>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
+ <81 512 1046 3200>, /* 400 KB/s*/
+ <81 512 52286 160000>, /* 20 MB/s */
+ <81 512 65360 200000>, /* 25 MB/s */
+ <81 512 130718 400000>, /* 50 MB/s */
+ <81 512 261438 800000>, /* 100 MB/s */
+ <81 512 261438 800000>, /* 200 MB/s */
+ <81 512 1338562 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+ 100000000 200000000 4294967295>;
+
+ qcom,devfreq,freq-table = <50000000 200000000>;
+ clocks = <&clock_gcc clk_gcc_sdcc2_ahb_clk>,
+ <&clock_gcc clk_gcc_sdcc2_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+
+ status = "disabled";
+ };
+
+ qcom_seecom: qseecom@85b00000 {
+ compatible = "qcom,qseecom";
+ reg = <0x85b00000 0x800000>;
+ reg-names = "secapp-region";
+ qcom,hlos-num-ce-hw-instances = <1>;
+ qcom,hlos-ce-hw-instance = <0>;
+ qcom,qsee-ce-hw-instance = <0>;
+ qcom,disk-encrypt-pipe-pair = <2>;
+ qcom,support-fde;
+ qcom,msm-bus,name = "qseecom-noc";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,support-bus-scaling;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 0 0>,
+ <55 512 120000 1200000>,
+ <55 512 393600 3936000>;
+ clocks = <&clock_gcc clk_crypto_clk_src>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ qcom,ce-opp-freq = <100000000>;
+ };
+
+ qcom_rng: qrng@e3000 {
+ compatible = "qcom,msm-rng";
+ reg = <0xe3000 0x1000>;
+ qcom,msm-rng-iface-clk;
+ qcom,no-qrng-config;
+ qcom,msm-bus,name = "msm-rng-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <1 618 0 0>, /* No vote */
+ <1 618 0 800>; /* 100 MB/s */
+ clocks = <&clock_gcc clk_gcc_prng_ahb_clk>;
+ clock-names = "iface_clk";
+ };
+
+ qcom_crypto: qcrypto@720000 {
+ compatible = "qcom,qcrypto";
+ reg = <0x720000 0x20000>,
+ <0x704000 0x20000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 207 0>;
+ qcom,bam-pipe-pair = <2>;
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ qcom,ce-hw-shared;
+ qcom,clk-mgmt-sus-res;
+ qcom,msm-bus,name = "qcrypto-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 393600 393600>;
+ clocks = <&clock_gcc clk_crypto_clk_src>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ qcom,use-sw-aes-cbc-ecb-ctr-algo;
+ qcom,use-sw-aes-xts-algo;
+ qcom,use-sw-aes-ccm-algo;
+ qcom,use-sw-ahash-algo;
+ qcom,use-sw-hmac-algo;
+ qcom,use-sw-aead-algo;
+ qcom,ce-opp-freq = <100000000>;
+ };
+
+ qcom_cedev: qcedev@720000 {
+ compatible = "qcom,qcedev";
+ reg = <0x720000 0x20000>,
+ <0x704000 0x20000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 207 0>;
+ qcom,bam-pipe-pair = <1>;
+ qcom,ce-hw-instance = <0>;
+ qcom,ce-device = <0>;
+ qcom,ce-hw-shared;
+ qcom,msm-bus,name = "qcedev-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 393600 393600>;
+ clocks = <&clock_gcc clk_crypto_clk_src>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ qcom,ce-opp-freq = <100000000>;
+ };
+
+ pil_mss: qcom,mss@4080000 {
+ compatible = "qcom,pil-q6v55-mss";
+ reg = <0x04080000 0x100>,
+ <0x0194f000 0x010>,
+ <0x01950000 0x008>,
+ <0x01951000 0x008>,
+ <0x04020000 0x040>,
+ <0x01871000 0x004>;
+ reg-names = "qdsp6_base", "halt_q6", "halt_modem", "halt_nc",
+ "rmb_base", "restart_reg";
+
+ interrupts = <GIC_SPI 24 IRQ_TYPE_EDGE_RISING>;
+ vdd_mss-supply = <&pm8937_s1>;
+ vdd_cx-supply = <&pm8937_s2_level>;
+ vdd_cx-voltage = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ vdd_mx-supply = <&pm8937_l3_level_ao>;
+ vdd_mx-uV = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ vdd_pll-supply = <&pm8937_l7>;
+ qcom,vdd_pll = <1800000>;
+ vdd_mss-uV = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+
+ clocks = <&clock_gcc clk_xo_pil_mss_clk>,
+ <&clock_gcc clk_gcc_mss_cfg_ahb_clk>,
+ <&clock_gcc clk_gcc_mss_q6_bimc_axi_clk>,
+ <&clock_gcc clk_gcc_boot_rom_ahb_clk>;
+ clock-names = "xo", "iface_clk", "bus_clk", "mem_clk";
+ qcom,proxy-clock-names = "xo";
+ qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk";
+
+ qcom,pas-id = <5>;
+ qcom,pil-mss-memsetup;
+ qcom,firmware-name = "modem";
+ qcom,pil-self-auth;
+ qcom,override-acc-1 = <0x80800000>;
+ qcom,sysmon-id = <0>;
+ qcom,ssctl-instance-id = <0x12>;
+ qcom,qdsp6v56-1-8-inrush-current;
+ qcom,reset-clk;
+
+ /* 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>;
+
+ memory-region = <&modem_mem>;
+ };
+
+ qcom,lpass@c200000 {
+ compatible = "qcom,pil-tz-generic";
+ reg = <0xc200000 0x00100>;
+ interrupts = <GIC_SPI 293 IRQ_TYPE_EDGE_RISING>;
+
+ vdd_cx-supply = <&pm8937_s2_level>;
+ qcom,proxy-reg-names = "vdd_cx";
+ qcom,vdd_cx-uV-uA = <RPM_SMD_REGULATOR_LEVEL_TURBO 100000>;
+
+ clocks = <&clock_gcc clk_xo_pil_lpass_clk>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>,
+ <&clock_gcc clk_crypto_clk_src>;
+ clock-names = "xo", "scm_core_clk", "scm_iface_clk",
+ "scm_bus_clk", "scm_core_clk_src";
+ qcom,proxy-clock-names = "xo", "scm_core_clk", "scm_iface_clk",
+ "scm_bus_clk", "scm_core_clk_src";
+ qcom,scm_core_clk_src-freq = <80000000>;
+
+ qcom,mas-crypto = <&mas_crypto>;
+ qcom,pas-id = <1>;
+ qcom,proxy-timeout-ms = <10000>;
+ qcom,smem-id = <423>;
+ qcom,sysmon-id = <1>;
+ qcom,ssctl-instance-id = <0x14>;
+ qcom,firmware-name = "adsp";
+
+ /* GPIO inputs from lpass */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_2_in 3 0>;
+
+ /* GPIO output to lpass */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
+
+ memory-region = <&adsp_fw_mem>;
+ };
+
+ qcom,pronto@a21b000 {
+ compatible = "qcom,pil-tz-generic";
+ reg = <0x0a21b000 0x3000>;
+ interrupts = <GIC_SPI 149 IRQ_TYPE_EDGE_RISING>;
+
+ vdd_pronto_pll-supply = <&pm8937_l7>;
+ proxy-reg-names = "vdd_pronto_pll";
+ vdd_pronto_pll-uV-uA = <1800000 18000>;
+ clocks = <&clock_gcc clk_xo_pil_pronto_clk>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>,
+ <&clock_gcc clk_crypto_clk_src>;
+
+ clock-names = "xo", "scm_core_clk", "scm_iface_clk",
+ "scm_bus_clk", "scm_core_clk_src";
+ qcom,proxy-clock-names = "xo", "scm_core_clk", "scm_iface_clk",
+ "scm_bus_clk", "scm_core_clk_src";
+ qcom,scm_core_clk_src = <80000000>;
+
+ qcom,mas-crypto = <&mas_crypto>;
+ qcom,pas-id = <6>;
+ qcom,proxy-timeout-ms = <10000>;
+ qcom,smem-id = <422>;
+ qcom,sysmon-id = <6>;
+ qcom,ssctl-instance-id = <0x13>;
+ qcom,firmware-name = "wcnss";
+
+ /* GPIO inputs from wcnss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_4_in 3 0>;
+
+ /* GPIO output to wcnss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
+ memory-region = <&wcnss_fw_mem>;
+ };
+
+ qcom,venus@1de0000 {
+ compatible = "qcom,pil-tz-generic";
+ reg = <0x1de0000 0x4000>;
+
+ vdd-supply = <&gdsc_venus>;
+ qcom,proxy-reg-names = "vdd";
+
+ clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>,
+ <&clock_gcc clk_gcc_venus0_ahb_clk>,
+ <&clock_gcc clk_gcc_venus0_axi_clk>,
+ <&clock_gcc clk_gcc_crypto_clk>,
+ <&clock_gcc clk_gcc_crypto_ahb_clk>,
+ <&clock_gcc clk_gcc_crypto_axi_clk>,
+ <&clock_gcc clk_crypto_clk_src>;
+
+ clock-names = "core_clk", "iface_clk", "bus_clk",
+ "scm_core_clk", "scm_iface_clk",
+ "scm_bus_clk", "scm_core_clk_src";
+
+ qcom,proxy-clock-names = "core_clk", "iface_clk",
+ "bus_clk", "scm_core_clk",
+ "scm_iface_clk", "scm_bus_clk",
+ "scm_core_clk_src";
+ qcom,scm_core_clk_src-freq = <80000000>;
+
+ qcom,msm-bus,name = "pil-venus";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <63 512 0 0>,
+ <63 512 0 304000>;
+
+ qcom,mas-crypto = <&mas_crypto>;
+ qcom,pas-id = <9>;
+ qcom,proxy-timeout-ms = <100>;
+ qcom,firmware-name = "venus";
+ memory-region = <&venus_mem>;
+ };
+
+ qcom,wcnss-wlan@0a000000 {
+ compatible = "qcom,wcnss_wlan";
+ reg = <0x0a000000 0x280000>,
+ <0xb011008 0x04>,
+ <0x0a21b000 0x3000>,
+ <0x03204000 0x00000100>,
+ <0x03200800 0x00000200>,
+ <0x0a100400 0x00000200>,
+ <0x0a205050 0x00000200>,
+ <0x0a219000 0x00000020>,
+ <0x0a080488 0x00000008>,
+ <0x0a080fb0 0x00000008>,
+ <0x0a08040c 0x00000008>,
+ <0x0a0120a8 0x00000008>,
+ <0x0a012448 0x00000008>,
+ <0x0a080c00 0x00000001>;
+
+ reg-names = "wcnss_mmio", "wcnss_fiq",
+ "pronto_phy_base", "riva_phy_base",
+ "riva_ccu_base", "pronto_a2xb_base",
+ "pronto_ccpu_base", "pronto_saw2_base",
+ "wlan_tx_phy_aborts","wlan_brdg_err_source",
+ "wlan_tx_status", "alarms_txctl",
+ "alarms_tactl", "pronto_mcu_base";
+
+ interrupts = <0 145 0 0 146 0>;
+ interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+ qcom,pronto-vddmx-supply = <&pm8937_l3_level_ao>;
+ qcom,pronto-vddcx-supply = <&pm8937_s2_level>;
+ qcom,pronto-vddpx-supply = <&pm8937_l5>;
+ qcom,iris-vddxo-supply = <&pm8937_l7>;
+ qcom,iris-vddrfa-supply = <&pm8937_l19>;
+ qcom,iris-vddpa-supply = <&pm8937_l9>;
+ qcom,iris-vdddig-supply = <&pm8937_l5>;
+
+ qcom,iris-vddxo-voltage-level = <1800000 0 1800000>;
+ qcom,iris-vddrfa-voltage-level = <1300000 0 1300000>;
+ qcom,iris-vddpa-voltage-level = <3300000 0 3300000>;
+ qcom,iris-vdddig-voltage-level = <1800000 0 1800000>;
+
+ qcom,vddmx-voltage-level = <RPM_SMD_REGULATOR_LEVEL_TURBO
+ RPM_SMD_REGULATOR_LEVEL_NONE
+ RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,vddcx-voltage-level = <RPM_SMD_REGULATOR_LEVEL_NOM
+ RPM_SMD_REGULATOR_LEVEL_NONE
+ RPM_SMD_REGULATOR_LEVEL_BINNING>;
+ qcom,vddpx-voltage-level = <1800000 0 1800000>;
+
+ qcom,iris-vddxo-current = <10000>;
+ qcom,iris-vddrfa-current = <100000>;
+ qcom,iris-vddpa-current = <515000>;
+ qcom,iris-vdddig-current = <10000>;
+
+ qcom,pronto-vddmx-current = <0>;
+ qcom,pronto-vddcx-current = <0>;
+ qcom,pronto-vddpx-current = <0>;
+
+ pinctrl-names = "wcnss_default", "wcnss_sleep",
+ "wcnss_gpio_default";
+ pinctrl-0 = <&wcnss_default>;
+ pinctrl-1 = <&wcnss_sleep>;
+ pinctrl-2 = <&wcnss_gpio_default>;
+
+ gpios = <&tlmm 76 0>, <&tlmm 77 0>, <&tlmm 78 0>,
+ <&tlmm 79 0>, <&tlmm 80 0>;
+
+ clocks = <&clock_gcc clk_xo_wlan_clk>,
+ <&clock_gcc clk_rf_clk2>,
+ <&clock_debug clk_gcc_debug_mux_8937>,
+ <&clock_gcc clk_wcnss_m_clk>,
+ <&clock_gcc clk_snoc_wcnss_a_clk>;
+
+ clock-names = "xo", "rf_clk", "measure", "wcnss_debug",
+ "snoc_wcnss";
+
+ qcom,snoc-wcnss-clock-freq = <200000000>;
+
+ qcom,has-autodetect-xo;
+ qcom,is-pronto-v3;
+ qcom,has-pronto-hw;
+ qcom,has-vsys-adc-channel;
+ qcom,wcnss-adc_tm = <&pm8937_adc_tm>;
+ };
+
+ bam_dmux: qcom,bam_dmux@4044000 {
+ compatible = "qcom,bam_dmux";
+ reg = <0x4044000 0x19000>;
+ interrupts = <0 162 1>;
+ qcom,rx-ring-size = <32>;
+ qcom,max-rx-mtu = <4096>;
+ qcom,fast-shutdown;
+ qcom,no-cpu-affinity;
+ };
+
+ ssc_sensors: qcom,msm-ssc-sensors {
+ compatible = "qcom,msm-ssc-sensors";
+ status = "ok";
+ };
};
#include "pm8937-rpm-regulator.dtsi"
#include "msm8937-regulator.dtsi"
#include "pm8937.dtsi"
+#include "msm8937-audio.dtsi"
#include "msm-gdsc-8916.dtsi"
+#include "msm8937-coresight.dtsi"
+#include "msm8937-thermal.dtsi"
&gdsc_venus {
clock-names = "bus_clk", "core_clk";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-audio-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-audio-cdp.dtsi
new file mode 100644
index 0000000..493e002
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-audio-cdp.dtsi
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015-2016, 2018, 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.
+ */
+
+&int_codec {
+ status = "okay";
+ qcom,msm-hs-micbias-type = "external";
+};
+
+&msm_digital_codec {
+ status = "okay";
+};
+
+&pmic_analog_codec {
+ status = "okay";
+};
+
+&wsa881x_i2c_f {
+ status = "okay";
+};
+
+&wsa881x_i2c_45 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-audio.dtsi b/arch/arm64/boot/dts/qcom/msm8953-audio.dtsi
new file mode 100644
index 0000000..fc10b4d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-audio.dtsi
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 2015-2016, 2018, 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 "msm-audio-lpass.dtsi"
+#include "msm8953-wsa881x.dtsi"
+
+&msm_audio_ion {
+ iommus = <&apps_iommu 0x2401 0x0>;
+ qcom,smmu-sid-mask = /bits/ 64 <0xf>;
+};
+
+&soc {
+ qcom,msm-audio-apr {
+ compatible = "qcom,msm-audio-apr";
+ msm_audio_apr_dummy {
+ compatible = "qcom,msm-audio-apr-dummy";
+ };
+ };
+
+ qcom,avtimer@c0a300c {
+ compatible = "qcom,avtimer";
+ reg = <0x0c0a300c 0x4>,
+ <0x0c0a3010 0x4>;
+ reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+ qcom,clk-div = <27>;
+ };
+
+ int_codec: sound {
+ status = "okay";
+ compatible = "qcom,msm8952-audio-codec";
+ qcom,model = "msm8953-snd-card-mtp";
+ reg = <0xc051000 0x4>,
+ <0xc051004 0x4>,
+ <0xc055000 0x4>,
+ <0xc052000 0x4>;
+ reg-names = "csr_gp_io_mux_mic_ctl",
+ "csr_gp_io_mux_spkr_ctl",
+ "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+ "csr_gp_io_mux_quin_ctl";
+
+ qcom,msm-ext-pa = "primary";
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,msm-hs-micbias-type = "internal";
+ qcom,msm-micbias1-ext-cap;
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "SPK_RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "RX_I2S_CLK", "MCLK",
+ "TX_I2S_CLK", "MCLK",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS External2", "Headset Mic",
+ "MIC BIAS External", "Secondary Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS External2",
+ "AMIC3", "MIC BIAS External",
+ "ADC1_IN", "ADC1_OUT",
+ "ADC2_IN", "ADC2_OUT",
+ "ADC3_IN", "ADC3_OUT",
+ "PDM_IN_RX1", "PDM_OUT_RX1",
+ "PDM_IN_RX2", "PDM_OUT_RX2",
+ "PDM_IN_RX3", "PDM_OUT_RX3",
+ "WSA_SPK OUT", "VDD_WSA_SWITCH",
+ "SpkrMono WSA_IN", "WSA_SPK OUT";
+
+ qcom,cdc-us-euro-gpios = <&tlmm 63 0>;
+ qcom,cdc-us-eu-gpios = <&cdc_us_euro_sw>;
+ qcom,cdc-comp-gpios = <&cdc_comp_gpios>;
+ qcom,pri-mi2s-gpios = <&cdc_pri_mi2s_gpios>;
+ qcom,quin-mi2s-gpios = <&cdc_quin_mi2s_gpios>;
+
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&pcm_noirq>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-pcm-dsp-noirq";
+ asoc-cpu = <&dai_pri_auxpcm>,
+ <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_mi2s4>, <&dai_mi2s5>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>,
+ <&bt_sco_rx>, <&bt_sco_tx>,
+ <&int_fm_rx>, <&int_fm_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>,
+ <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>,
+ <&incall_music_rx>, <&incall_music_2_rx>;
+
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.4", "msm-dai-q6-mi2s.6",
+ "msm-dai-q6-dev.16384", "msmdai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+ "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770";
+
+ asoc-codec = <&stub_codec>, <&msm_digital_codec>,
+ <&pmic_analog_codec>;
+ asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec",
+ "analog-codec";
+ asoc-wsa-codec-names = "wsa881x-i2c-codec.2-000f";
+ asoc-wsa-codec-prefixes = "SpkrMono";
+ msm-vdd-wsa-switch-supply = <&pm8953_l5>;
+ qcom,msm-vdd-wsa-switch-voltage = <1800000>;
+ qcom,msm-vdd-wsa-switch-current = <10000>;
+ };
+
+ cdc_us_euro_sw: msm_cdc_pinctrl_us_euro_sw {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cross_conn_det_act>;
+ pinctrl-1 = <&cross_conn_det_sus>;
+ };
+
+ cdc_comp_gpios: cdc_comp_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_pdm_comp_lines_act>;
+ pinctrl-1 = <&cdc_pdm_comp_lines_sus>;
+ };
+
+ cdc_pri_mi2s_gpios: msm_cdc_pinctrl_pri {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act>;
+ pinctrl-1 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus>;
+ };
+
+ cdc_quin_mi2s_gpios: msm_cdc_pinctrl_quin {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&pri_tlmm_lines_act &pri_tlmm_ws_act>;
+ pinctrl-1 = <&pri_tlmm_lines_sus &pri_tlmm_ws_sus>;
+ };
+
+
+ i2c@78b6000 {
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wsa881x_i2c_f: wsa881x-i2c-codec@f {
+ status = "okay";
+ compatible = "qcom,wsa881x-i2c-codec";
+ reg = <0x0f>;
+ qcom,wsa-analog-vi-gpio = <&wsa881x_analog_vi_gpio>;
+ qcom,wsa-analog-clk-gpio = <&wsa881x_analog_clk_gpio>;
+ qcom,wsa-analog-reset-gpio =
+ <&wsa881x_analog_reset_gpio>;
+ };
+ wsa881x_i2c_45: wsa881x-i2c-codec@45 {
+ status = "okay";
+ compatible = "qcom,wsa881x-i2c-codec";
+ reg = <0x45>;
+ };
+ };
+
+ wsa881x_analog_vi_gpio: wsa881x_analog_vi_pctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&wsa_vi_on>;
+ pinctrl-1 = <&wsa_vi_off>;
+ };
+ wsa881x_analog_clk_gpio: wsa881x_analog_clk_pctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&wsa_clk_on>;
+ pinctrl-1 = <&wsa_clk_off>;
+ };
+ wsa881x_analog_reset_gpio: wsa881x_analog_reset_pctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&wsa_reset_on>;
+ pinctrl-1 = <&wsa_reset_off>;
+ };
+
+ ext_codec: sound-9335 {
+ status = "disabled";
+ compatible = "qcom,msm8952-audio-slim-codec";
+ qcom,model = "msm8953-tasha-snd-card";
+
+ reg = <0xc051000 0x4>,
+ <0xc051004 0x4>,
+ <0xc055000 0x4>,
+ <0xc052000 0x4>;
+ reg-names = "csr_gp_io_mux_mic_ctl",
+ "csr_gp_io_mux_spkr_ctl",
+ "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+ "csr_gp_io_mux_quin_ctl";
+
+ qcom,audio-routing =
+ "AIF4 VI", "MCLK",
+ "AIF4 VI", "MICBIAS_REGULATOR",
+ "RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
+ "AIF4 MAD", "MICBIAS_REGULATOR",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC3", "MIC BIAS2",
+ "MIC BIAS2", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2",
+ "MIC BIAS2", "ANCLeft Headset Mic",
+ "AMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Handset Mic",
+ "AMIC6", "MIC BIAS4",
+ "MIC BIAS4", "Analog Mic6",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "DMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic5",
+ "MIC BIAS1", "MICBIAS_REGULATOR",
+ "MIC BIAS2", "MICBIAS_REGULATOR",
+ "MIC BIAS3", "MICBIAS_REGULATOR",
+ "MIC BIAS4", "MICBIAS_REGULATOR",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+
+ qcom,tasha-mclk-clk-freq = <9600000>;
+ qcom,cdc-us-euro-gpios = <&tlmm 63 0>;
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,cdc-us-eu-gpios = <&cdc_us_euro_sw>;
+ qcom,quin-mi2s-gpios = <&cdc_quin_mi2s_gpios>;
+
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
+ <&pcm_noirq>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-compr-dsp", "msm-pcm-dsp-noirq";
+
+ asoc-cpu = <&dai_pri_auxpcm>,
+ <&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s5>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>,
+ <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>,
+ <&incall_music_rx>, <&incall_music_2_rx>,
+ <&sb_5_rx>, <&bt_sco_rx>, <&bt_sco_tx>,
+ <&int_fm_rx>, <&int_fm_tx>, <&sb_6_rx>;
+
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.5", "msm-dai-q6-dev.16384",
+ "msm-dai-q6-dev.16385", "msm-dai-q6-dev.16386",
+ "msm-dai-q6-dev.16387", "msm-dai-q6-dev.16388",
+ "msm-dai-q6-dev.16389", "msm-dai-q6-dev.16390",
+ "msm-dai-q6-dev.16391", "msm-dai-q6-dev.16392",
+ "msm-dai-q6-dev.16393", "msm-dai-q6-dev.16395",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+ "msm-dai-q6-dev.16394", "msm-dai-q6-dev.12288",
+ "msm-dai-q6-dev.12289", "msm-dai-q6-dev.12292",
+ "msm-dai-q6-dev.12293", "msm-dai-q6-dev.16396";
+
+ asoc-codec = <&stub_codec>, <&hdmi_dba>;
+ asoc-codec-names = "msm-stub-codec.1", "msm-hdmi-dba-codec-rx";
+
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
+ <&wsa881x_213>, <&wsa881x_214>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ };
+
+ cpe: qcom,msm-cpe-lsm {
+ compatible = "qcom,msm-cpe-lsm";
+ };
+
+ wcd9xxx_intc: wcd9xxx-irq {
+ status = "disabled";
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tlmm>;
+ qcom,gpio-connect = <&tlmm 73 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wcd_intr_default>;
+ };
+
+ clock_audio: audio_ext_clk {
+ status = "disabled";
+ compatible = "qcom,audio-ref-clk";
+ clock-names = "osr_clk";
+ qcom,node_has_rpm_clock;
+ #clock-cells = <1>;
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&tasha_mclk_default>;
+ pinctrl-1 = <&tasha_mclk_default>;
+ qcom,audio-ref-clk-gpio = <&pm8953_gpios 1 0>;
+ clocks = <&clock_gcc clk_div_clk2>;
+ };
+
+ wcd_rst_gpio: msm_cdc_pinctrl@67 {
+ status = "disabled";
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_reset_active>;
+ pinctrl-1 = <&cdc_reset_sleep>;
+ };
+};
+
+&slim_msm {
+ status = "disabled";
+
+ dai_slim: msm_dai_slim {
+ status = "disabled";
+ compatible = "qcom,msm-dai-slim";
+ elemental-addr = [ff ff ff fe 17 02];
+ };
+
+ wcd9335: tasha_codec {
+ status = "disabled";
+ compatible = "qcom,tasha-slim-pgd";
+ elemental-addr = [00 01 A0 01 17 02];
+
+ qcom,cdc-slim-ifd = "tasha-slim-ifd";
+ qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 01 17 02];
+
+ interrupt-parent = <&wcd9xxx_intc>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29 30>;
+
+ qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>;
+
+ clock-names = "wcd_clk", "wcd_native_clk";
+ clocks = <&clock_audio clk_audio_pmi_clk>,
+ <&clock_audio clk_audio_ap_clk2>;
+
+ qcom,cdc-static-supplies =
+ "cdc-vdd-buck",
+ "cdc-buck-sido",
+ "cdc-vdd-tx-h",
+ "cdc-vdd-rx-h",
+ "cdc-vdd-px";
+
+ qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+ qcom,cdc-micbias1-mv = <1800>;
+ qcom,cdc-micbias2-mv = <1800>;
+ qcom,cdc-micbias3-mv = <1800>;
+ qcom,cdc-micbias4-mv = <1800>;
+
+ qcom,cdc-dmic-sample-rate = <2400000>;
+ qcom,cdc-mclk-clk-rate = <9600000>;
+
+ cdc-vdd-buck-supply = <&eldo2_8953>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ cdc-buck-sido-supply = <&eldo2_8953>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <150000>;
+
+ cdc-vdd-tx-h-supply = <&eldo2_8953>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&eldo2_8953>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vdd-px-supply = <&eldo2_8953>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8953_l13>;
+ qcom,cdc-vdd-mic-bias-voltage = <3125000 3125000>;
+ qcom,cdc-vdd-mic-bias-current = <15000>;
+ };
+};
+&pm8953_gpios {
+ gpio@c000 {
+ status = "ok";
+ qcom,mode = <1>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ qcom,out-strength = <2>;
+ };
+
+ tasha_mclk {
+ tasha_mclk_default: tasha_mclk_default{
+ pins = "gpio1";
+ function = "func1";
+ qcom,drive-strength = <2>;
+ power-source = <0>;
+ bias-disable;
+ output-low;
+ };
+ };
+};
+
+&pm8953_1 {
+ pmic_analog_codec: analog-codec@f000 {
+ status = "okay";
+ compatible = "qcom,pmic-analog-codec";
+ reg = <0xf000 0x200>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x1 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x2 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x3 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x4 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x5 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x6 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x7 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x0 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x1 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x2 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x3 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x4 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x5 IRQ_TYPE_NONE>;
+ interrupt-names = "spk_cnp_int",
+ "spk_clip_int",
+ "spk_ocp_int",
+ "ins_rem_det1",
+ "but_rel_det",
+ "but_press_det",
+ "ins_rem_det",
+ "mbhc_int",
+ "ear_ocp_int",
+ "hphr_ocp_int",
+ "hphl_ocp_det",
+ "ear_cnp_int",
+ "hphr_cnp_int",
+ "hphl_cnp_int";
+
+ cdc-vdda-cp-supply = <&pm8953_s4>;
+ qcom,cdc-vdda-cp-voltage = <1900000 2050000>;
+ qcom,cdc-vdda-cp-current = <500000>;
+
+ cdc-vdd-io-supply = <&pm8953_l5>;
+ qcom,cdc-vdd-io-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-io-current = <5000>;
+
+ cdc-vdd-pa-supply = <&pm8953_s4>;
+ qcom,cdc-vdd-pa-voltage = <1900000 2050000>;
+ qcom,cdc-vdd-pa-current = <260000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8953_l13>;
+ qcom,cdc-vdd-mic-bias-voltage = <3125000 3125000>;
+ qcom,cdc-vdd-mic-bias-current = <5000>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+
+ qcom,cdc-static-supplies = "cdc-vdd-io",
+ "cdc-vdd-pa",
+ "cdc-vdda-cp";
+
+ qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+
+ msm_digital_codec: msm-dig-codec {
+ compatible = "qcom,msm-digital-codec";
+ reg = <0xc0f0000 0x0>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-cdp.dtsi
new file mode 100644
index 0000000..a46bce3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-cdp.dtsi
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&cci {
+ actuator0: qcom,actuator@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vaf";
+ qcom,cam-vreg-min-voltage = <2850000>;
+ qcom,cam-vreg-max-voltage = <2850000>;
+ qcom,cam-vreg-op-mode = <80000>;
+ };
+
+ actuator1: qcom,actuator@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <1>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vaf";
+ qcom,cam-vreg-min-voltage = <2850000>;
+ qcom,cam-vreg-max-voltage = <2850000>;
+ qcom,cam-vreg-op-mode = <80000>;
+ };
+
+ eeprom0: qcom,eeprom@0 {
+ cell-index = <0>;
+ compatible = "qcom,eeprom";
+ qcom,cci-master = <0>;
+ reg = <0x0>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vdig-supply = <&pm8953_l2>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+ qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-op-mode = <0 105000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_default
+ &cam_sensor_rear_default
+ &cam_sensor_rear_vana>;
+ pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+ &cam_sensor_rear_vana_sleep>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 134 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VANA";
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk0_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ eeprom1: qcom,eeprom@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ qcom,eeprom-name = "sunny_8865";
+ compatible = "qcom,eeprom";
+ qcom,slave-addr = <0x6c>;
+ qcom,cci-master = <0>;
+ qcom,num-blocks = <8>;
+
+ qcom,page0 = <1 0x0100 2 0x01 1 1>;
+ qcom,poll0 = <0 0x0 2 0x0 1 0>;
+ qcom,mem0 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page1 = <1 0x5002 2 0x00 1 0>;
+ qcom,poll1 = <0 0x0 2 0x0 1 0>;
+ qcom,mem1 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page2 = <1 0x3d84 2 0xc0 1 0>;
+ qcom,poll2 = <0 0x0 2 0x0 1 0>;
+ qcom,mem2 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page3 = <1 0x3d88 2 0x70 1 0>;
+ qcom,poll3 = <0 0x0 2 0x0 1 0>;
+ qcom,mem3 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page4 = <1 0x3d89 2 0x10 1 0>;
+ qcom,poll4 = <0 0x0 2 0x0 1 0>;
+ qcom,mem4 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page5 = <1 0x3d8a 2 0x70 1 0>;
+ qcom,poll5 = <0 0x0 2 0x0 1 0>;
+ qcom,mem5 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page6 = <1 0x3d8b 2 0xf4 1 0>;
+ qcom,poll6 = <0 0x0 2 0x0 1 0>;
+ qcom,mem6 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page7 = <1 0x3d81 2 0x01 1 10>;
+ qcom,poll7 = <0 0x0 2 0x0 1 1>;
+ qcom,mem7 = <1536 0x7010 2 0 1 0>;
+
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_default
+ &cam_sensor_front1_default>;
+ pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front1_sleep>;
+ gpios = <&tlmm 27 0>,
+ <&tlmm 129 0>,
+ <&tlmm 130 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
+ qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg",
+ "sensor_vreg",
+ "sensor_gpio", "sensor_gpio" , "sensor_clk";
+ qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio",
+ "sensor_gpio_reset", "sensor_gpio_standby",
+ "sensor_cam_mclk";
+ qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+ qcom,cam-power-seq-delay = <1 1 1 30 30 5>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk1_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk1_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ eeprom2: qcom,eeprom@2 {
+ cell-index = <2>;
+ compatible = "qcom,eeprom";
+ qcom,cci-master = <1>;
+ reg = <0x2>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_default
+ &cam_sensor_front_default>;
+ pinctrl-1 = <&cam_sensor_mclk2_sleep
+ &cam_sensor_front_sleep>;
+ gpios = <&tlmm 28 0>,
+ <&tlmm 131 0>,
+ <&tlmm 132 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_STANDBY1";
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk2_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ qcom,camera@0 {
+ cell-index = <0>;
+ compatible = "qcom,camera";
+ reg = <0x0>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <270>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,eeprom-src = <&eeprom0>;
+ qcom,actuator-src = <&actuator0>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vdig-supply = <&pm8953_l2>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+ qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-op-mode = <0 105000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_default
+ &cam_sensor_rear_default
+ &cam_sensor_rear_vana>;
+ pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+ &cam_sensor_rear_vana_sleep>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 134 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VANA";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk0_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@1 {
+ cell-index = <1>;
+ compatible = "qcom,camera";
+ reg = <0x1>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <90>;
+ qcom,eeprom-src = <&eeprom2>;
+ qcom,actuator-src = <&actuator1>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_default
+ &cam_sensor_front_default>;
+ pinctrl-1 = <&cam_sensor_mclk2_sleep
+ &cam_sensor_front_sleep>;
+ gpios = <&tlmm 28 0>,
+ <&tlmm 131 0>,
+ <&tlmm 132 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_STANDBY1";
+ qcom,sensor-position = <0x100>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk2_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@2 {
+ cell-index = <2>;
+ compatible = "qcom,camera";
+ reg = <0x02>;
+ qcom,csiphy-sd-index = <2>;
+ qcom,csid-sd-index = <2>;
+ qcom,mount-angle = <90>;
+ qcom,eeprom-src = <&eeprom1>;
+ qcom,actuator-src = <&actuator1>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1175000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1175000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_default
+ &cam_sensor_front1_default>;
+ pinctrl-1 = <&cam_sensor_mclk1_sleep
+ &cam_sensor_front1_sleep>;
+ gpios = <&tlmm 27 0>,
+ <&tlmm 129 0>,
+ <&tlmm 130 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk1_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk1_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-mtp.dtsi
new file mode 100644
index 0000000..a7688f0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-mtp.dtsi
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&cci {
+ actuator0: qcom,actuator@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vaf";
+ qcom,cam-vreg-min-voltage = <2850000>;
+ qcom,cam-vreg-max-voltage = <2850000>;
+ qcom,cam-vreg-op-mode = <80000>;
+ };
+
+ actuator1: qcom,actuator@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <1>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vaf";
+ qcom,cam-vreg-min-voltage = <2850000>;
+ qcom,cam-vreg-max-voltage = <2850000>;
+ qcom,cam-vreg-op-mode = <80000>;
+ };
+
+ eeprom0: qcom,eeprom@0 {
+ cell-index = <0>;
+ compatible = "qcom,eeprom";
+ qcom,cci-master = <0>;
+ reg = <0x0>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vdig-supply = <&pm8953_l2>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+ qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-op-mode = <0 105000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_default
+ &cam_sensor_rear_default
+ &cam_sensor_rear_vana>;
+ pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+ &cam_sensor_rear_vana_sleep>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 134 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VANA";
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk0_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ eeprom1: qcom,eeprom@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ qcom,eeprom-name = "sunny_8865";
+ compatible = "qcom,eeprom";
+ qcom,slave-addr = <0x6c>;
+ qcom,cci-master = <0>;
+ qcom,num-blocks = <8>;
+
+ qcom,page0 = <1 0x0100 2 0x01 1 1>;
+ qcom,poll0 = <0 0x0 2 0x0 1 0>;
+ qcom,mem0 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page1 = <1 0x5002 2 0x00 1 0>;
+ qcom,poll1 = <0 0x0 2 0x0 1 0>;
+ qcom,mem1 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page2 = <1 0x3d84 2 0xc0 1 0>;
+ qcom,poll2 = <0 0x0 2 0x0 1 0>;
+ qcom,mem2 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page3 = <1 0x3d88 2 0x70 1 0>;
+ qcom,poll3 = <0 0x0 2 0x0 1 0>;
+ qcom,mem3 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page4 = <1 0x3d89 2 0x10 1 0>;
+ qcom,poll4 = <0 0x0 2 0x0 1 0>;
+ qcom,mem4 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page5 = <1 0x3d8a 2 0x70 1 0>;
+ qcom,poll5 = <0 0x0 2 0x0 1 0>;
+ qcom,mem5 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page6 = <1 0x3d8b 2 0xf4 1 0>;
+ qcom,poll6 = <0 0x0 2 0x0 1 0>;
+ qcom,mem6 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page7 = <1 0x3d81 2 0x01 1 10>;
+ qcom,poll7 = <0 0x0 2 0x0 1 1>;
+ qcom,mem7 = <1536 0x7010 2 0 1 0>;
+
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_default
+ &cam_sensor_front1_default>;
+ pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front1_sleep>;
+ gpios = <&tlmm 27 0>,
+ <&tlmm 129 0>,
+ <&tlmm 130 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
+ qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg",
+ "sensor_vreg",
+ "sensor_gpio", "sensor_gpio" , "sensor_clk";
+ qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio",
+ "sensor_gpio_reset", "sensor_gpio_standby",
+ "sensor_cam_mclk";
+ qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+ qcom,cam-power-seq-delay = <1 1 1 30 30 5>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk1_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk1_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ eeprom2: qcom,eeprom@2 {
+ cell-index = <2>;
+ compatible = "qcom,eeprom";
+ qcom,cci-master = <1>;
+ reg = <0x2>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_default
+ &cam_sensor_front_default>;
+ pinctrl-1 = <&cam_sensor_mclk2_sleep
+ &cam_sensor_front_sleep>;
+ gpios = <&tlmm 28 0>,
+ <&tlmm 131 0>,
+ <&tlmm 132 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_STANDBY1";
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk2_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ qcom,camera@0 {
+ cell-index = <0>;
+ compatible = "qcom,camera";
+ reg = <0x0>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <270>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,eeprom-src = <&eeprom0>;
+ qcom,actuator-src = <&actuator0>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vdig-supply = <&pm8953_l2>;
+ cam_vaf-supply = <&pm8953_l17>;
+ cam_vana-supply = <&pm8953_l22>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf",
+ "cam_vana";
+ qcom,cam-vreg-min-voltage = <0 1100000 2850000 2800000>;
+ qcom,cam-vreg-max-voltage = <0 1100000 2850000 2800000>;
+ qcom,cam-vreg-op-mode = <0 105000 100000 80000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_default
+ &cam_sensor_rear_default
+ &cam_sensor_rear_vana>;
+ pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+ &cam_sensor_rear_vana_sleep>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 134 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VANA";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk0_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@1 {
+ cell-index = <1>;
+ compatible = "qcom,camera";
+ reg = <0x1>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <90>;
+ qcom,eeprom-src = <&eeprom2>;
+ qcom,actuator-src = <&actuator1>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_default
+ &cam_sensor_front_default>;
+ pinctrl-1 = <&cam_sensor_mclk2_sleep
+ &cam_sensor_front_sleep>;
+ gpios = <&tlmm 28 0>,
+ <&tlmm 131 0>,
+ <&tlmm 132 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_STANDBY1";
+ qcom,sensor-position = <0x100>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk2_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@2 {
+ cell-index = <2>;
+ compatible = "qcom,camera";
+ reg = <0x02>;
+ qcom,csiphy-sd-index = <2>;
+ qcom,csid-sd-index = <2>;
+ qcom,mount-angle = <90>;
+ qcom,eeprom-src = <&eeprom1>;
+ qcom,actuator-src = <&actuator1>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1175000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1175000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_default
+ &cam_sensor_front1_default>;
+ pinctrl-1 = <&cam_sensor_mclk1_sleep
+ &cam_sensor_front1_sleep>;
+ gpios = <&tlmm 27 0>,
+ <&tlmm 129 0>,
+ <&tlmm 130 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk1_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk1_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-qrd.dtsi
new file mode 100644
index 0000000..8098efb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-qrd.dtsi
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&cci {
+ actuator0: qcom,actuator@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vaf";
+ qcom,cam-vreg-min-voltage = <2850000>;
+ qcom,cam-vreg-max-voltage = <2850000>;
+ qcom,cam-vreg-op-mode = <80000>;
+ };
+
+ eeprom0: qcom,eeprom@0 {
+ cell-index = <0>;
+ compatible = "qcom,eeprom";
+ qcom,cci-master = <0>;
+ reg = <0x0>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+ qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-op-mode = <0 105000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_default
+ &cam_sensor_rear_default
+ &cam_sensor_rear_vana>;
+ pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+ &cam_sensor_rear_vana_sleep>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 134 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VANA";
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk0_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ eeprom2: qcom,eeprom@2 {
+ cell-index = <2>;
+ reg = <0x2>;
+ compatible = "qcom,eeprom";
+ qcom,cci-master = <1>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_default
+ &cam_sensor_front1_default>;
+ pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front1_sleep>;
+ gpios = <&tlmm 27 0>,
+ <&tlmm 129 0>,
+ <&tlmm 130 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
+ qcom,sensor-mode = <0>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk1_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk1_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ qcom,camera@0 {
+ cell-index = <0>;
+ compatible = "qcom,camera";
+ reg = <0x0>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <90>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,eeprom-src = <&eeprom0>;
+ qcom,actuator-src = <&actuator0>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vaf-supply = <&pm8953_l17>;
+ cam_vana-supply = <&pm8953_l22>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf",
+ "cam_vana";
+ qcom,cam-vreg-min-voltage = <0 1100000 2850000 2800000>;
+ qcom,cam-vreg-max-voltage = <0 1100000 2850000 2800000>;
+ qcom,cam-vreg-op-mode = <0 105000 100000 80000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_default
+ &cam_sensor_rear_default
+ &cam_sensor_rear_vana>;
+ pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+ &cam_sensor_rear_vana_sleep>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 134 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VANA";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk0_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@1 {
+ cell-index = <1>;
+ compatible = "qcom,camera";
+ reg = <0x1>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <90>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_default
+ &cam_sensor_front_default>;
+ pinctrl-1 = <&cam_sensor_mclk2_sleep
+ &cam_sensor_front_sleep>;
+ gpios = <&tlmm 28 0>,
+ <&tlmm 131 0>,
+ <&tlmm 132 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_STANDBY1";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "disabled";
+ clocks = <&clock_gcc clk_mclk2_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@2 {
+ cell-index = <2>;
+ compatible = "qcom,camera";
+ reg = <0x02>;
+ qcom,csiphy-sd-index = <2>;
+ qcom,csid-sd-index = <2>;
+ qcom,mount-angle = <270>;
+ qcom,eeprom-src = <&eeprom2>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_default
+ &cam_sensor_front1_default>;
+ pinctrl-1 = <&cam_sensor_mclk1_sleep
+ &cam_sensor_front1_sleep>;
+ gpios = <&tlmm 27 0>,
+ <&tlmm 129 0>,
+ <&tlmm 130 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk1_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk1_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-camera.dtsi b/arch/arm64/boot/dts/qcom/msm8953-camera.dtsi
index 39d67ab..2685f5a 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-camera.dtsi
@@ -332,32 +332,31 @@
compatible = "qcom,vfe";
num_child = <2>;
};
-/*
- * qcom,cam_smmu {
- * status = "ok";
- * compatible = "qcom,msm-cam-smmu";
- * msm_cam_smmu_cb1: msm_cam_smmu_cb1 {
- * compatible = "qcom,qsmmu-cam-cb";
- * iommus = <&apps_iommu 0x400>,
- * <&apps_iommu 0x2800>;
- * label = "vfe";
- * qcom,scratch-buf-support;
- * };
- *
- *
- * msm_cam_smmu_cb3: msm_cam_smmu_cb3 {
- * compatible = "qcom,qsmmu-cam-cb";
- * iommus = <&apps_iommu 0x1c00>;
- * label = "cpp";
- * };
- *
- * msm_cam_smmu_cb4: msm_cam_smmu_cb4 {
- * compatible = "qcom,qsmmu-cam-cb";
- * iommus = <&apps_iommu 0x1800>;
- * label = "jpeg_enc0";
- * };
- * };
- */
+
+ qcom,cam_smmu {
+ status = "ok";
+ compatible = "qcom,msm-cam-smmu";
+ msm_cam_smmu_cb1: msm_cam_smmu_cb1 {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_iommu 0x400 0x00>,
+ <&apps_iommu 0x2800 0x00>;
+ label = "vfe";
+ qcom,scratch-buf-support;
+ };
+
+ msm_cam_smmu_cb3: msm_cam_smmu_cb3 {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_iommu 0x1c00 0x00>;
+ label = "cpp";
+ };
+
+ msm_cam_smmu_cb4: msm_cam_smmu_cb4 {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_iommu 0x1800 0x00>;
+ label = "jpeg_enc0";
+ };
+ };
+
qcom,jpeg@1b1c000 {
status = "ok";
cell-index = <0>;
@@ -422,6 +421,8 @@
qcom,clock-rates = <0 180000000 0 0 180000000 0 0>;
qcom,min-clock-rate = <100000000>;
qcom,bus-master = <1>;
+ resets = <&clock_gcc GCC_CAMSS_MICRO_BCR>;
+ reset-names = "micro_iface_reset";
qcom,msm-bus,name = "msm_camera_cpp";
qcom,msm-bus,num-cases = <2>;
qcom,msm-bus,num-paths = <1>;
@@ -429,6 +430,7 @@
<106 512 0 0>,
<106 512 0 0>;
qcom,msm-bus-vector-dyn-vote;
+ qcom,micro-reset;
qcom,cpp-fw-payload-info {
qcom,stripe-base = <156>;
qcom,plane-base = <141>;
diff --git a/arch/arm64/boot/dts/qcom/msm8953-cdp.dts b/arch/arm64/boot/dts/qcom/msm8953-cdp.dts
index 34c5f8f..6105b52 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-cdp.dts
@@ -17,6 +17,7 @@
#include "pmi8950.dtsi"
#include "msm8953-cdp.dtsi"
#include "msm8953-pmi8950.dtsi"
+#include "msm8953-camera-sensor-cdp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 CDP";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi
index 8a0f492..5680409 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi
@@ -11,6 +11,10 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/msm-clocks-8953.h>
+#include "msm8953-audio-cdp.dtsi"
+
&blsp1_uart0 {
status = "ok";
pinctrl-names = "default";
@@ -148,6 +152,12 @@
qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
};
+&dsi_hx8399c_truly_vid {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
&dsi_truly_1080_cmd {
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
qcom,ulps-enabled;
@@ -155,3 +165,78 @@
qcom,panel-roi-alignment = <2 2 4 2 1080 2>;
};
+&soc {
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio_key_active>;
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&tlmm 87 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&tlmm 86 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&tlmm 85 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
+ };
+
+ home {
+ label = "home";
+ gpios = <&tlmm 88 0x1>;
+ linux,input-type = <1>;
+ linux,code = <102>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
+ };
+ };
+};
+
+&tlmm {
+ tlmm_gpio_key {
+ gpio_key_active: gpio_key_active {
+ mux {
+ pins = "gpio85", "gpio86", "gpio87", "gpio88";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio85", "gpio86", "gpio87", "gpio88";
+ };
+ };
+
+ gpio_key_suspend: gpio_key_suspend {
+ mux {
+ pins = "gpio85", "gpio86", "gpio87", "gpio88";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio85", "gpio86", "gpio87", "gpio88";
+ };
+ };
+ };
+};
+
diff --git a/arch/arm64/boot/dts/qcom/msm8953-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8953-coresight.dtsi
index 55914d0..aa00147 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-coresight.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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 an
@@ -330,6 +330,15 @@
<&audio_etm0_out_funnel_mm>;
};
};
+
+ port@4 {
+ reg = <6>;
+ funnel_mm_in_gfx: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&gfx_out_funnel_mm>;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts
index b80583e..ee22633 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts
@@ -17,6 +17,7 @@
#include "pmi8950.dtsi"
#include "msm8953-mtp.dtsi"
#include "msm8953-pmi8950.dtsi"
+#include "msm8953-camera-sensor-mtp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 Ext Codec MTP";
@@ -25,3 +26,75 @@
qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
};
+&int_codec {
+ status = "disabled";
+};
+
+&pmic_analog_codec {
+ status = "disabled";
+};
+
+&wsa881x_i2c_f {
+ status = "disabled";
+};
+
+&wsa881x_i2c_45 {
+ status = "disabled";
+};
+
+&cdc_pri_mi2s_gpios {
+ status = "disabled";
+};
+
+&wsa881x_analog_vi_gpio {
+ status = "disabled";
+};
+
+&wsa881x_analog_clk_gpio {
+ status = "disabled";
+};
+
+&wsa881x_analog_reset_gpio {
+ status = "disabled";
+};
+
+&cdc_comp_gpios {
+ status = "disabled";
+};
+
+&slim_msm {
+ status = "okay";
+};
+
+&dai_slim {
+ status = "okay";
+};
+
+&wcd9xxx_intc {
+ status = "okay";
+};
+
+&clock_audio {
+ status = "okay";
+};
+
+&wcd9335 {
+ status = "okay";
+};
+
+&cdc_us_euro_sw {
+ status = "okay";
+};
+
+&cdc_quin_mi2s_gpios {
+ status = "okay";
+};
+
+&wcd_rst_gpio {
+ status = "okay";
+};
+
+&ext_codec {
+ qcom,model = "msm8953-tasha-snd-card";
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi b/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi
index 5cf6eb2..f82b68d 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi
@@ -124,14 +124,6 @@
qcom,gpu-quirk-dp2clockgating-disable;
qcom,gpu-quirk-lmloadkill-disable;
- /* Trace bus */
- coresight-id = <67>;
- coresight-name = "coresight-gfx";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_mm>;
- coresight-child-ports = <6>;
-
/* Enable context aware freq. scaling */
qcom,enable-ca-jump;
@@ -164,6 +156,25 @@
};
};
+ qcom,gpu-coresights {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "qcom,gpu-coresight";
+
+ /* Trace bus */
+ qcom,gpu-coresight@0 {
+ reg = <0>;
+ coresight-name = "coresight-gfx";
+ coresight-atid = <67>;
+ port {
+ gfx_out_funnel_mm: endpoint {
+ remote-endpoint =
+ <&funnel_mm_in_gfx>;
+ };
+ };
+ };
+ };
+
/* Power levels */
qcom,gpu-pwrlevels {
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ipc.dtsi b/arch/arm64/boot/dts/qcom/msm8953-ipc.dtsi
index 26f4338..b62d12d 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-ipc.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-ipc.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -11,6 +11,8 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/gpio/gpio.h>
+
&blsp1_uart0 {
status = "ok";
pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
index 28a6b74..c6bc2b9 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
@@ -47,6 +47,23 @@
qcom,supply-enable-load = <100000>;
qcom,supply-disable-load = <100>;
};
+ qcom,panel-supply-entry@2 {
+ reg = <2>;
+ qcom,supply-name = "lab";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+ qcom,panel-supply-entry@3 {
+ reg = <3>;
+ qcom,supply-name = "ibb";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-post-on-sleep = <10>;
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
index 97c6db3..82f6315 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
@@ -17,6 +17,7 @@
#include "pmi8950.dtsi"
#include "msm8953-mtp.dtsi"
#include "msm8953-pmi8950.dtsi"
+#include "msm8953-camera-sensor-mtp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 MTP";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi
index 8a0f492..93565cf 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi
@@ -11,6 +11,9 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/msm-clocks-8953.h>
+
&blsp1_uart0 {
status = "ok";
pinctrl-names = "default";
@@ -148,6 +151,12 @@
qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
};
+&dsi_hx8399c_truly_vid {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
&dsi_truly_1080_cmd {
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
qcom,ulps-enabled;
@@ -155,3 +164,47 @@
qcom,panel-roi-alignment = <2 2 4 2 1080 2>;
};
+&soc {
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio_key_active>;
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&tlmm 87 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&tlmm 86 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&tlmm 85 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
+ };
+ };
+};
+
+&thermal_zones {
+ case-therm-step {
+ status = "disabled";
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
index 171b7c4..6503b33 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
@@ -20,6 +20,7 @@
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
+ interrupt-parent = <&wakegpio>;
#interrupt-cells = <2>;
pmx-uartconsole {
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pm.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pm.dtsi
index da4f4df..b40b668 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pm.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -144,6 +144,7 @@
#size-cells = <0>;
qcom,psci-mode-shift = <0>;
qcom,psci-mode-mask = <0xf>;
+ qcom,use-prediction;
qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>;
qcom,pm-cpu-level@0 {
@@ -235,6 +236,7 @@
#size-cells = <0>;
qcom,psci-mode-shift = <0>;
qcom,psci-mode-mask = <0xf>;
+ qcom,use-prediction;
qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>;
qcom,pm-cpu-level@0 {
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi632-cdp-s2.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi632-cdp-s2.dts
index 78ff97f..4639f02 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi632-cdp-s2.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi632-cdp-s2.dts
@@ -16,6 +16,7 @@
#include "msm8953.dtsi"
#include "sdm450-pmi632-cdp-s2.dtsi"
#include "sdm450-pmi632.dtsi"
+#include "sdm632-camera-sensor-cdp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. msm8953 + PMI632 CDP S2";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
index d81a0a5..e8bdb7a 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
@@ -11,17 +11,6 @@
* GNU General Public License for more details.
*/
-&soc {
- led_flash0: qcom,camera-flash {
- cell-index = <0>;
- compatible = "qcom,camera-flash";
- qcom,flash-type = <1>;
- qcom,flash-source = <&pmi8950_flash0 &pmi8950_flash1>;
- qcom,torch-source = <&pmi8950_torch0 &pmi8950_torch1>;
- qcom,switch-source = <&pmi8950_switch>;
- };
-};
-
&labibb {
status = "ok";
qpnp,qpnp-labibb-mode = "lcd";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi
index 2f9e20e..253e87e 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi
@@ -11,35 +11,12 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/msm-clocks-8953.h>
&soc {
i2c@78b7000 { /* BLSP1 QUP3 */
- status = "okay";
- synaptics@4b {
- compatible = "synaptics,dsx-i2c";
- reg = <0x4b>;
- interrupt-parent = <&tlmm>;
- interrupts = <65 0x2008>;
- vdd_ana-supply = <&vdd_vreg>;
- vcc_i2c-supply = <&pm8953_l6>;
- synaptics,pwr-reg-name = "vdd_ana";
- synaptics,bus-reg-name = "vcc_i2c";
- synaptics,irq-gpio = <&tlmm 65 0x2008>;
- synaptics,irq-on-state = <0>;
- synaptics,irq-flags = <0x2008>;
- synaptics,power-delay-ms = <200>;
- synaptics,reset-delay-ms = <200>;
- synaptics,max-y-for-2d = <1919>;
- synaptics,cap-button-codes = <139 158 172>;
- synaptics,vir-button-codes = <139 180 2000 320 160
- 158 540 2000 320 160
- 172 900 2000 320 160>;
- synaptics,resume-in-workqueue;
- /* Underlying clocks used by secure touch */
- clock-names = "iface_clk", "core_clk";
- clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
- <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>;
- };
+ /delete-node/ synaptics@4b;
};
vdd_vreg: vdd_vreg {
@@ -48,6 +25,22 @@
regulator-name = "vdd_vreg";
};
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio_key_active>;
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&tlmm 85 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
+ };
+ };
};
&blsp1_uart0 {
diff --git a/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi b/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi
index d5a6f52..54634ce 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi
@@ -253,6 +253,21 @@
};
};
+ case-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8953_vadc 0x13>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
gpu1-step {
polling-delay-passive = <250>;
polling-delay = <0>;
@@ -1087,4 +1102,101 @@
};
};
};
+
+ pa-therm0 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8953_adc_tm 0x36>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ };
+
+ case-therm-step {
+ polling-delay-passive = <2000>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8953_vadc 0x13>;
+ thermal-governor = "step_wise";
+
+ trips {
+ cpus_trip: cpus-trip {
+ temperature = <43000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ modem_trip0: modem-trip0 {
+ temperature = <45000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ modem_trip1: modem-trip1 {
+ temperature = <48000>;
+ hysteresis = <3000>;
+ type = "passive";
+ };
+ modem_trip2: modem-trip2 {
+ temperature = <54000>;
+ hysteresis = <4000>;
+ type = "passive";
+ };
+ };
+
+ cooling-maps {
+ skin_cpu0 {
+ trip = <&cpus_trip>;
+ /* throttle from fmax to 1689600KHz */
+ cooling-device = <&CPU0 THERMAL_NO_LIMIT 3>;
+ };
+ skin_cpu1 {
+ trip = <&cpus_trip>;
+ cooling-device = <&CPU1 THERMAL_NO_LIMIT 3>;
+ };
+ skin_cpu2 {
+ trip = <&cpus_trip>;
+ cooling-device = <&CPU2 THERMAL_NO_LIMIT 3>;
+ };
+ skin_cpu3 {
+ trip = <&cpus_trip>;
+ cooling-device = <&CPU3 THERMAL_NO_LIMIT 3>;
+ };
+ skin_cpu4 {
+ trip = <&cpus_trip>;
+ cooling-device = <&CPU4 THERMAL_NO_LIMIT 3>;
+ };
+ skin_cpu5 {
+ trip = <&cpus_trip>;
+ cooling-device = <&CPU5 THERMAL_NO_LIMIT 3>;
+ };
+ skin_cpu6 {
+ trip = <&cpus_trip>;
+ cooling-device = <&CPU6 THERMAL_NO_LIMIT 3>;
+ };
+ skin_cpu7 {
+ trip = <&cpus_trip>;
+ cooling-device = <&CPU7 THERMAL_NO_LIMIT 3>;
+ };
+ modem_lvl1 {
+ trip = <&modem_trip1>;
+ cooling-device = <&modem_pa 2 2>;
+ };
+ modem_lvl2 {
+ trip = <&modem_trip2>;
+ cooling-device = <&modem_pa 3 3>;
+ };
+ modem_proc_lvl1 {
+ trip = <&modem_trip0>;
+ cooling-device = <&modem_proc 1 1>;
+ };
+ modem_proc_lvl2 {
+ trip = <&modem_trip2>;
+ cooling-device = <&modem_proc 3 3>;
+ };
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-wsa881x.dtsi b/arch/arm64/boot/dts/qcom/msm8953-wsa881x.dtsi
new file mode 100644
index 0000000..86f5323
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-wsa881x.dtsi
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015-2016, 2018, 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.
+ */
+
+&slim_msm {
+ tasha_codec {
+ swr_master {
+ compatible = "qcom,swr-wcd";
+ qcom,swr-num-dev = <2>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ wsa881x_211: wsa881x@20170211 {
+ compatible = "qcom,wsa881x";
+ reg = <0x00 0x20170211>;
+ qcom,spkr-sd-n-gpio = <&tlmm 96 0>;
+ };
+
+ wsa881x_212: wsa881x@20170212 {
+ compatible = "qcom,wsa881x";
+ reg = <0x00 0x20170212>;
+ qcom,spkr-sd-n-gpio = <&tlmm 96 0>;
+ };
+
+ wsa881x_213: wsa881x@21170213 {
+ compatible = "qcom,wsa881x";
+ reg = <0x00 0x21170213>;
+ qcom,spkr-sd-n-gpio = <&tlmm 96 0>;
+ };
+
+ wsa881x_214: wsa881x@21170214 {
+ compatible = "qcom,wsa881x";
+ reg = <0x00 0x21170214>;
+ qcom,spkr-sd-n-gpio = <&tlmm 96 0>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index aa96539..978d432 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -26,7 +26,7 @@
interrupt-parent = <&wakegic>;
chosen {
- bootargs = "sched_enable_hmp=1 sched_enable_power_aware=1";
+ bootargs = "kpti=0";
};
firmware: firmware {
@@ -103,7 +103,7 @@
compatible = "shared-dma-pool";
reusable;
alignment = <0 0x400000>;
- size = <0 0x0400000>;
+ size = <0 0x1000000>;
};
qseecom_ta_mem: qseecom_ta_region {
@@ -111,7 +111,7 @@
alloc-ranges = <0 0x00000000 0 0xffffffff>;
reusable;
alignment = <0 0x400000>;
- size = <0 0x1000000>;
+ size = <0 0x400000>;
};
adsp_mem: adsp_region@0 {
@@ -138,6 +138,12 @@
alignment = <0 0x400000>;
size = <0 0x800000>;
};
+
+ dump_mem: mem_dump_region {
+ compatible = "shared-dma-pool";
+ reusable;
+ size = <0 0x2400000>;
+ };
};
aliases {
@@ -214,20 +220,23 @@
<0x0b002000 0x1000>;
};
- mpm: mpm@601d4 {
- compatible = "qcom,mpm";
+ wakegic: wake-gic@601d4 {
+ compatible = "qcom,mpm-gic-msm8953", "qcom,mpm-gic";
interrupts = <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>;
reg = <0x601d4 0x1000>,
<0xb011008 0x4>; /* MSM_APCS_GCC_BASE 4K */
reg-names = "vmpm", "ipc";
qcom,num-mpm-irqs = <96>;
+ interrupt-controller;
+ interrupt-parent = <&intc>;
+ #interrupt-cells = <3>;
+ };
- wakegic: wake-gic {
- compatible = "qcom,mpm-gic", "qcom,mpm-gic-msm8953";
- interrupt-controller;
- interrupt-parent = <&intc>;
- #interrupt-cells = <3>;
- };
+ wakegpio: wake-gpio {
+ compatible = "qcom,mpm-gpio-msm8953", "qcom,mpm-gpio";
+ interrupt-controller;
+ interrupt-parent = <&intc>;
+ #interrupt-cells = <2>;
};
qcom,msm-gladiator@b1c0000 {
@@ -336,6 +345,52 @@
thermal_zones: thermal-zones {};
+ mem_dump {
+ compatible = "qcom,mem-dump";
+ memory-region = <&dump_mem>;
+
+ rpmh_dump {
+ qcom,dump-size = <0x2000000>;
+ qcom,dump-id = <0xec>;
+ };
+
+ fcm_dump {
+ qcom,dump-size = <0x8400>;
+ qcom,dump-id = <0xee>;
+ };
+
+ rpm_sw_dump {
+ qcom,dump-size = <0x28000>;
+ qcom,dump-id = <0xea>;
+ };
+
+ pmic_dump {
+ qcom,dump-size = <0x10000>;
+ qcom,dump-id = <0xe4>;
+ };
+
+ tmc_etf_dump {
+ qcom,dump-size = <0x10000>;
+ qcom,dump-id = <0xf0>;
+ };
+
+ tmc_etr_reg_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0x100>;
+ };
+
+ tmc_etf_reg_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0x101>;
+ };
+
+ misc_data_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0xe8>;
+ };
+
+ };
+
tsens0: tsens@4a8000 {
compatible = "qcom,msm8953-tsens";
reg = <0x4a8000 0x1000>,
@@ -720,6 +775,7 @@
vdd_gfx-supply = <&gfx_vreg_corner>;
clocks = <&clock_gcc clk_xo_clk_src>;
clock-names = "xo";
+ qcom,gcc_oxili_gfx3d_clk-opp-handle = <&msm_gpu>;
qcom,gfxfreq-corner =
< 0 0 >,
< 133330000 1 >, /* Min SVS */
@@ -1107,6 +1163,12 @@
qcom,smdpkt-dev-name = "smdcntl8";
};
+ qcom,smdpkt-data2 {
+ qcom,smdpkt-remote = "modem";
+ qcom,smdpkt-port-name = "DATA2";
+ qcom,smdpkt-dev-name = "at_mdm0";
+ };
+
qcom,smdpkt-apr-apps2 {
qcom,smdpkt-remote = "adsp";
qcom,smdpkt-port-name = "apr_apps2";
@@ -1137,12 +1199,22 @@
qcom,wakeup-enable;
};
- qcom,chd {
+ qcom,chd_silver {
compatible = "qcom,core-hang-detect";
+ label = "silver";
qcom,threshold-arr = <0xb1880b0 0xb1980b0 0xb1a80b0
- 0xb1b80b0 0xb0880b0 0xb0980b0 0xb0a80b0 0xb0b80b0>;
+ 0xb1b80b0>;
qcom,config-arr = <0xb1880b8 0xb1980b8 0xb1a80b8
- 0xb1b80b8 0xb0880b8 0xb0980b8 0xb0a80b8 0xb0b80b8>;
+ 0xb1b80b8>;
+ };
+
+ qcom,chd_gold {
+ compatible = "qcom,core-hang-detect";
+ label = "gold";
+ qcom,threshold-arr = <0xb0880b0 0xb0980b0 0xb0a80b0
+ 0xb0b80b0>;
+ qcom,config-arr = <0xb0880b8 0xb0980b8 0xb0a80b8
+ 0xb0b80b8>;
};
qcom,msm-rtb {
@@ -1391,8 +1463,8 @@
interrupts = <GIC_SPI 190 IRQ_TYPE_NONE>;
qcom,ee = <0>;
qcom,channel = <0>;
- #address-cells = <2>;
- #size-cells = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
interrupt-controller;
#interrupt-cells = <4>;
cell-index = <0>;
@@ -1450,8 +1522,8 @@
usb-phy = <&qusb_phy>, <&ssphy>;
tx-fifo-resize;
snps,usb3-u1u2-disable;
- snps,nominal-elastic-buffer;
snps,is-utmi-l1-suspend;
+ snps,usb2-l1-disable;
snps,hird-threshold = /bits/ 8 <0x0>;
};
@@ -1721,6 +1793,15 @@
qcom,qdsp6v56-1-10;
qcom,reset-clk;
+ /* 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>;
memory-region = <&modem_mem>;
};
@@ -1753,6 +1834,15 @@
qcom,ssctl-instance-id = <0x14>;
qcom,firmware-name = "adsp";
+ /* GPIO inputs from lpass */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_2_in 3 0>;
+
+ /* GPIO output to lpass */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
+
memory-region = <&adsp_fw_mem>;
};
@@ -1785,6 +1875,14 @@
qcom,ssctl-instance-id = <0x13>;
qcom,firmware-name = "wcnss";
+ /* GPIO inputs from wcnss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_4_in 3 0>;
+
+ /* GPIO output to wcnss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
memory-region = <&wcnss_fw_mem>;
};
@@ -1921,6 +2019,7 @@
#include "msm-gdsc-8916.dtsi"
#include "msm8953-thermal.dtsi"
#include "msm8953-camera.dtsi"
+#include "msm8953-audio.dtsi"
&gdsc_venus {
clock-names = "bus_clk", "core_clk";
diff --git a/arch/arm64/boot/dts/qcom/pm660-rpm-regulator.dtsi b/arch/arm64/boot/dts/qcom/pm660-rpm-regulator.dtsi
new file mode 100644
index 0000000..ff91250
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm660-rpm-regulator.dtsi
@@ -0,0 +1,381 @@
+/* Copyright (c) 2016-2018, 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.
+ */
+
+&rpm_bus {
+ rpm-regulator-smpa2 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s2 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_s2";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa3 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s3 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_s3";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa4 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s4 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_s4";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa5 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <5>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s5 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_s5";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa6 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <6>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s6 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_s6";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l1 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l2 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l2";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l3 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l3";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <5>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l5 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l5";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <6>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l6 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l6";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <7>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l7 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l7";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <8>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l8 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l8";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <9>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l9 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l9";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <10>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l10 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l10";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <11>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l11 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l11";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <12>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l12 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l12";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <13>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l13 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l13";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa14 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <14>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l14 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l14";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa15 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <15>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l15 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l15";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa16 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <16>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l16 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l16";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <17>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l17 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l17";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa18 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <18>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l18 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l18";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa19 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <19>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l19 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm660_l19";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
index 7724714..fa10500 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -507,20 +507,6 @@
type = "passive";
};
};
- cooling-maps {
- vbat_map6 {
- trip = <&pm660_vbat_adc>;
- cooling-device =
- <&CPU6 THERMAL_MAX_LIMIT
- THERMAL_MAX_LIMIT>;
- };
- vbat_map7 {
- trip = <&pm660_vbat_adc>;
- cooling-device =
- <&CPU7 THERMAL_MAX_LIMIT
- THERMAL_MAX_LIMIT>;
- };
- };
};
vbat_low {
@@ -569,20 +555,6 @@
type = "passive";
};
};
- cooling-maps {
- soc_map6 {
- trip = <&pm660_low_soc>;
- cooling-device =
- <&CPU6 THERMAL_MAX_LIMIT
- THERMAL_MAX_LIMIT>;
- };
- soc_map7 {
- trip = <&pm660_low_soc>;
- cooling-device =
- <&CPU7 THERMAL_MAX_LIMIT
- THERMAL_MAX_LIMIT>;
- };
- };
};
pm660_temp_alarm: pm660_tz {
@@ -608,97 +580,5 @@
type = "critical";
};
};
- cooling-maps {
- trip0_cpu0 {
- trip = <&pm660_trip0>;
- cooling-device =
- <&CPU0 (THERMAL_MAX_LIMIT-1)
- (THERMAL_MAX_LIMIT-1)>;
- };
- trip0_cpu1 {
- trip = <&pm660_trip0>;
- cooling-device =
- <&CPU1 (THERMAL_MAX_LIMIT-1)
- (THERMAL_MAX_LIMIT-1)>;
- };
- trip0_cpu2 {
- trip = <&pm660_trip0>;
- cooling-device =
- <&CPU2 (THERMAL_MAX_LIMIT-1)
- (THERMAL_MAX_LIMIT-1)>;
- };
- trip0_cpu3 {
- trip = <&pm660_trip0>;
- cooling-device =
- <&CPU3 (THERMAL_MAX_LIMIT-1)
- (THERMAL_MAX_LIMIT-1)>;
- };
- trip0_cpu4 {
- trip = <&pm660_trip0>;
- cooling-device =
- <&CPU4 (THERMAL_MAX_LIMIT-1)
- (THERMAL_MAX_LIMIT-1)>;
- };
- trip0_cpu5 {
- trip = <&pm660_trip0>;
- cooling-device =
- <&CPU5 (THERMAL_MAX_LIMIT-1)
- (THERMAL_MAX_LIMIT-1)>;
- };
- trip0_cpu6 {
- trip = <&pm660_trip0>;
- cooling-device =
- <&CPU6 (THERMAL_MAX_LIMIT-1)
- (THERMAL_MAX_LIMIT-1)>;
- };
- trip0_cpu7 {
- trip = <&pm660_trip0>;
- cooling-device =
- <&CPU7 (THERMAL_MAX_LIMIT-1)
- (THERMAL_MAX_LIMIT-1)>;
- };
- trip1_cpu1 {
- trip = <&pm660_trip1>;
- cooling-device =
- <&CPU1 THERMAL_MAX_LIMIT
- THERMAL_MAX_LIMIT>;
- };
- trip1_cpu2 {
- trip = <&pm660_trip1>;
- cooling-device =
- <&CPU2 THERMAL_MAX_LIMIT
- THERMAL_MAX_LIMIT>;
- };
- trip1_cpu3 {
- trip = <&pm660_trip1>;
- cooling-device =
- <&CPU3 THERMAL_MAX_LIMIT
- THERMAL_MAX_LIMIT>;
- };
- trip1_cpu4 {
- trip = <&pm660_trip1>;
- cooling-device =
- <&CPU4 THERMAL_MAX_LIMIT
- THERMAL_MAX_LIMIT>;
- };
- trip1_cpu5 {
- trip = <&pm660_trip1>;
- cooling-device =
- <&CPU5 THERMAL_MAX_LIMIT
- THERMAL_MAX_LIMIT>;
- };
- trip1_cpu6 {
- trip = <&pm660_trip1>;
- cooling-device =
- <&CPU6 THERMAL_MAX_LIMIT
- THERMAL_MAX_LIMIT>;
- };
- trip1_cpu7 {
- trip = <&pm660_trip1>;
- cooling-device =
- <&CPU7 THERMAL_MAX_LIMIT
- THERMAL_MAX_LIMIT>;
- };
- };
};
};
diff --git a/arch/arm64/boot/dts/qcom/pm8004-rpm-regulator.dtsi b/arch/arm64/boot/dts/qcom/pm8004-rpm-regulator.dtsi
new file mode 100644
index 0000000..87c43e0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm8004-rpm-regulator.dtsi
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+&rpm_bus {
+ rpm-regulator-ldoc1 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoc";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l1 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8004_l1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8909-rpm-regulator.dtsi b/arch/arm64/boot/dts/qcom/pm8909-rpm-regulator.dtsi
new file mode 100644
index 0000000..6da90de
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm8909-rpm-regulator.dtsi
@@ -0,0 +1,317 @@
+/* Copyright (c) 2016, 2018 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.
+ */
+
+&rpm_bus {
+ rpm-regulator-smpa1 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s1 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_s1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa2 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s2 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_s2";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l1 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l2 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l2";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l3 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l3";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa4 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l4 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l4";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <5>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l5 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l5";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <6>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l6 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l6";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <7>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l7 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l7";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <8>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l8 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l8";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <9>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l9 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l9";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <10>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l10 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l10";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <11>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l11 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l11";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <12>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l12 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l12";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <13>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ status = "disabled";
+
+ regulator-l13 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l13";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa14 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <14>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ status = "disabled";
+
+ regulator-l14 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l14";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa15 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <15>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ status = "disabled";
+
+ regulator-l15 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l15";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <17>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l17 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l17";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa18 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <18>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l18 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8909_l18";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8937.dtsi b/arch/arm64/boot/dts/qcom/pm8937.dtsi
index 6a61445..cd1bddb 100644
--- a/arch/arm64/boot/dts/qcom/pm8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8937.dtsi
@@ -57,6 +57,7 @@
qcom,channel-num = <8>;
qcom,threshold-set = <0>;
qcom,temp_alarm-vadc = <&pm8937_vadc>;
+ #thermal-sensor-cells = <0>;
};
pm8937_coincell: qcom,coincell@2800 {
@@ -92,6 +93,24 @@
"pm8937_mpp3", "pm8937_mpp4";
gpio-controller;
#gpio-cells = <2>;
+
+ case_therm {
+ cas_therm_default: cas_therm_default {
+ pins = "mpp4";
+ function = "analog";
+ input-enable;
+ qcom,amux-route = <3>;
+ };
+ };
+
+ pa_therm1 {
+ pa_therm1_default: pa_therm1_default {
+ pins = "mpp2";
+ function = "analog";
+ input-enable;
+ qcom,amux-route = <1>;
+ };
+ };
};
pm8937_gpios: gpios {
@@ -120,6 +139,9 @@
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
qcom,vadc-poll-eoc;
+ #thermal-sensor-cells = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pa_therm1_default &cas_therm_default>;
chan@5 {
label = "vcoin";
@@ -307,3 +329,105 @@
};
};
};
+
+&thermal_zones {
+ pa-therm1-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8937_vadc 0x11>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ xo-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8937_vadc 0x32>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ xo-therm-buf-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8937_vadc 0x3c>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ case-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8937_vadc 0x13>;
+ 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 = <&pm8937_adc_tm 0x36>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ pm8937_tz {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&pm8937_temp_alarm>;
+
+ trips {
+ pm8937_trip0: pm8937-trip0 {
+ temperature = <105000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm8937_trip1: pm8937-trip1 {
+ temperature = <125000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm8937_trip2: pm8937-trip2 {
+ temperature = <145000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8953.dtsi b/arch/arm64/boot/dts/qcom/pm8953.dtsi
index b26f993..c496257 100644
--- a/arch/arm64/boot/dts/qcom/pm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8953.dtsi
@@ -35,6 +35,7 @@
"resin-bark", "kpdpwr-resin-bark";
qcom,pon-dbc-delay = <15625>;
qcom,system-reset;
+ qcom,store-hard-reset-reason;
qcom,pon_1 {
qcom,pon-type = <0>;
@@ -78,6 +79,24 @@
gpio-controller;
#gpio-cells = <2>;
+
+ case_therm {
+ cas_therm_default: cas_therm_default {
+ pins = "mpp4";
+ function = "analog";
+ input-enable;
+ qcom,amux-route = <3>;
+ };
+ };
+
+ pa_therm1 {
+ pa_therm1_default: pa_therm1_default {
+ pins = "mpp2";
+ function = "analog";
+ input-enable;
+ qcom,amux-route = <1>;
+ };
+ };
};
pm8953_gpios: gpios {
@@ -87,15 +106,16 @@
interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>,
<0x0 0xc1 0 IRQ_TYPE_NONE>,
<0x0 0xc3 0 IRQ_TYPE_NONE>,
+ <0x0 0xc4 0 IRQ_TYPE_NONE>,
<0x0 0xc6 0 IRQ_TYPE_NONE>,
<0x0 0xc7 0 IRQ_TYPE_NONE>;
interrupt-names = "pm8953_gpio1", "pm8953_gpio2",
- "pm8953_gpio4", "pm8953_gpio7",
- "pm8953_gpio8";
+ "pm8953_gpio4", "pm8953_gpio5",
+ "pm8953_gpio7", "pm8953_gpio8";
gpio-controller;
#gpio-cells = <2>;
- qcom,gpios-disallowed = <3 5 6>;
+ qcom,gpios-disallowed = <3 6>;
};
pm8953_vadc: vadc@3100 {
@@ -109,6 +129,8 @@
qcom,adc-vdd-reference = <1800>;
qcom,vadc-poll-eoc;
#thermal-sensor-cells = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pa_therm1_default &cas_therm_default>;
chan@5 {
label = "vcoin";
@@ -231,6 +253,7 @@
qcom,scale-function = <2>;
qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
};
};
@@ -248,6 +271,20 @@
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
qcom,adc_tm-vadc = <&pm8953_vadc>;
+ #thermal-sensor-cells = <1>;
+
+ chan@36 {
+ label = "pa_therm0";
+ reg = <0x36>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,decimation = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x48>;
+ qcom,fast-avg-setup = <0>;
+ qcom,thermal-node;
+ };
};
pm8953_rtc: qcom,pm8953_rtc {
@@ -295,13 +332,11 @@
#address-cells = <1>;
#size-cells = <1>;
- pm8953_pwm: pwm@bc00 {
+ pm8953_pwm: qcom,pwms@bc00 {
status = "disabled";
- compatible = "qcom,qpnp-pwm";
+ compatible = "qcom,pwm-lpg";
reg = <0xbc00 0x100>;
- reg-names = "qpnp-lpg-channel-base";
- qcom,channel-id = <0>;
- qcom,supported-sizes = <6>, <9>;
+ reg-names = "lpg-base";
#pwm-cells = <2>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi
index d5a3c35..bdd69e2 100644
--- a/arch/arm64/boot/dts/qcom/pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi
@@ -18,8 +18,8 @@
qcom,pmi632@2 {
compatible = "qcom,spmi-pmic";
reg = <0x2 SPMI_USID>;
- #address-cells = <2>;
- #size-cells = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
pmi632_revid: qcom,revid@100 {
compatible = "qcom,qpnp-revid";
@@ -37,10 +37,12 @@
reg = <0x3100 0x100>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "eoc-int-en-set";
qcom,adc-vdd-reference = <1875>;
qcom,adc-full-scale-code = <0x70e4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&quiet_therm_default &smb_therm_default>;
chan@0 {
label = "ref_gnd";
@@ -186,6 +188,41 @@
qcom,cal-val = <0>;
};
+ chan@52 {
+ label = "typec_therm";
+ reg = <0x52>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@53 {
+ label = "quiet_therm";
+ reg = <0x53>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
+
+ chan@54 {
+ label = "smb_therm";
+ reg = <0x54>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,cal-val = <0>;
+ };
};
pmi632_tz: qcom,temp-alarm@2400 {
@@ -213,15 +250,36 @@
gpio-controller;
#gpio-cells = <2>;
qcom,gpios-disallowed = <1>;
+
+ quiet_therm {
+ quiet_therm_default: quiet_therm_default {
+ pins = "gpio3";
+ bias-high-impedance;
+ };
+ };
+
+ smb_therm {
+ smb_therm_default: smb_therm_default {
+ pins = "gpio4";
+ bias-high-impedance;
+ };
+ };
+
};
pmi632_charger: qcom,qpnp-smb5 {
compatible = "qcom,qpnp-smb5";
#address-cells = <1>;
#size-cells = <1>;
+ #cooling-cells = <2>;
qcom,pmic-revid = <&pmi632_revid>;
dpdm-supply = <&qusb_phy>;
+ qcom,auto-recharge-soc = <98>;
+
+ qcom,thermal-mitigation
+ = <3000000 2500000 2000000 1500000
+ 1000000 500000>;
qcom,chgr@1000 {
reg = <0x1000 0x100>;
@@ -232,8 +290,8 @@
<0x2 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
<0x2 0x10 0x4 IRQ_TYPE_EDGE_RISING>,
<0x2 0x10 0x5 IRQ_TYPE_EDGE_RISING>,
- <0x2 0x10 0x6 IRQ_TYPE_LEVEL_HIGH>,
- <0x2 0x10 0x7 IRQ_TYPE_LEVEL_HIGH>;
+ <0x2 0x10 0x6 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x10 0x7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "chgr-error",
"chg-state-change",
@@ -251,7 +309,7 @@
<0x2 0x11 0x0 IRQ_TYPE_EDGE_RISING>,
<0x2 0x11 0x1 IRQ_TYPE_EDGE_RISING>,
<0x2 0x11 0x2 IRQ_TYPE_EDGE_RISING>,
- <0x2 0x11 0x3 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x11 0x3 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x11 0x4 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x11 0x5 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x11 0x6 IRQ_TYPE_EDGE_RISING>,
@@ -277,7 +335,7 @@
<0x2 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x12 0x5 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x12 0x6 IRQ_TYPE_EDGE_BOTH>,
- <0x2 0x12 0x7 IRQ_TYPE_LEVEL_HIGH>;
+ <0x2 0x12 0x7 IRQ_TYPE_EDGE_BOTH>;
interrupt-names = "bat-temp",
"all-chnl-conv-done",
@@ -296,8 +354,8 @@
<0x2 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
- <0x2 0x13 0x4 IRQ_TYPE_LEVEL_HIGH>,
- <0x2 0x13 0x5 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x13 0x5 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
<0x2 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
@@ -315,12 +373,12 @@
reg = <0x1500 0x100>;
interrupts =
<0x2 0x15 0x0 IRQ_TYPE_EDGE_BOTH>,
- <0x2 0x15 0x1 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x15 0x1 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x15 0x2 IRQ_TYPE_EDGE_RISING>,
- <0x2 0x15 0x3 IRQ_TYPE_LEVEL_HIGH>,
- <0x2 0x15 0x4 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x15 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x15 0x4 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x15 0x5 IRQ_TYPE_EDGE_RISING>,
- <0x2 0x15 0x6 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x15 0x6 IRQ_TYPE_EDGE_RISING>,
<0x2 0x15 0x7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "typec-or-rid-detect-change",
@@ -338,11 +396,11 @@
interrupts =
<0x2 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
<0x2 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
- <0x2 0x16 0x2 IRQ_TYPE_LEVEL_HIGH>,
- <0x2 0x16 0x3 IRQ_TYPE_LEVEL_HIGH>,
- <0x2 0x16 0x4 IRQ_TYPE_LEVEL_HIGH>,
+ <0x2 0x16 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x16 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x16 0x4 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x16 0x5 IRQ_TYPE_EDGE_RISING>,
- <0x2 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+ <0x2 0x16 0x6 IRQ_TYPE_EDGE_RISING>,
<0x2 0x16 0x7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "wdog-snarl",
@@ -355,6 +413,20 @@
"temp-change-smb";
};
+ qcom,schgm-flash@a600 {
+ reg = <0xa600 0x100>;
+ interrupts =
+ <0x2 0xa6 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0xa6 0x5 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0xa6 0x6 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0xa6 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+ interrupt-names = "flash-state-change",
+ "ilim1-s1",
+ "ilim2-s2",
+ "vreg-ok";
+ };
+
smb5_vbus: qcom,smb5-vbus {
regulator-name = "smb5-vbus";
};
@@ -365,11 +437,12 @@
#address-cells = <1>;
#size-cells = <1>;
- qcom,vbatt-empty-mv = <3200>;
+ qcom,vbatt-empty-mv = <3300>;
qcom,vbatt-low-mv = <3500>;
qcom,vbatt-cutoff-mv = <3400>;
qcom,qg-iterm-ma = <100>;
-
+ qcom,hold-soc-while-full;
+ qcom,linearize-soc;
qcom,qg-vadc = <&pmi632_vadc>;
qcom,pmic-revid = <&pmi632_revid>;
@@ -393,13 +466,34 @@
reg = <0xb100 0x100>;
};
};
+
+ bcl_sensor: bcl@3d00 {
+ compatible = "qcom,bcl-v5";
+ reg = <0x3d00 0x100>;
+ interrupts = <0x2 0x3d 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x3d 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x3d 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x3d 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x3d 0x2 IRQ_TYPE_NONE>;
+ interrupt-names = "bcl-ibat-lvl0",
+ "bcl-ibat-lvl1",
+ "bcl-vbat-lvl0",
+ "bcl-vbat-lvl1",
+ "bcl-vbat-lvl2";
+ #thermal-sensor-cells = <1>;
+ };
+
+ bcl_soc: bcl-soc {
+ compatible = "qcom,msm-bcl-soc";
+ #thermal-sensor-cells = <0>;
+ };
};
pmi632_3: qcom,pmi632@3 {
compatible ="qcom,spmi-pmic";
reg = <0x3 SPMI_USID>;
- #address-cells = <2>;
- #size-cells = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
pmi632_vib: qcom,vibrator@5700 {
compatible = "qcom,qpnp-vibrator-ldo";
@@ -408,54 +502,34 @@
qcom,vib-overdrive-volt-uv = <3544000>;
};
- pmi632_pwm_1: pwm@b300 {
- compatible = "qcom,qpnp-pwm";
- reg = <0xb300 0x100>;
- reg-names = "qpnp-lpg-channel-base";
- qcom,channel-id = <1>;
- qcom,supported-sizes = <6>, <9>;
+ pmi632_pwm: qcom,pwms@b300 {
+ compatible = "qcom,pwm-lpg";
+ reg = <0xb300 0x500>;
+ reg-names = "lpg-base";
#pwm-cells = <2>;
- status = "disabled";
};
- pmi632_pwm_2: pwm@b400 {
- compatible = "qcom,qpnp-pwm";
- reg = <0xb400 0x100>;
- reg-names = "qpnp-lpg-channel-base";
- qcom,channel-id = <2>;
- qcom,supported-sizes = <6>, <9>;
- #pwm-cells = <2>;
- status = "disabled";
- };
-
- pmi632_pwm_3: pwm@b500 {
- compatible = "qcom,qpnp-pwm";
- reg = <0xb500 0x100>;
- reg-names = "qpnp-lpg-channel-base";
- qcom,channel-id = <3>;
- qcom,supported-sizes = <6>, <9>;
- #pwm-cells = <2>;
- status = "disabled";
- };
-
- pmi632_pwm_4: pwm@b600 {
- compatible = "qcom,qpnp-pwm";
- reg = <0xb600 0x100>;
- reg-names = "qpnp-lpg-channel-base";
- qcom,channel-id = <4>;
- qcom,supported-sizes = <6>, <9>;
- #pwm-cells = <2>;
- status = "disabled";
- };
-
- pmi632_pwm_5: pwm@b700 {
- compatible = "qcom,qpnp-pwm";
- reg = <0xb700 0x100>;
- reg-names = "qpnp-lpg-channel-base";
- qcom,channel-id = <5>;
- qcom,supported-sizes = <6>, <9>;
- #pwm-cells = <2>;
- status = "disabled";
+ pmi632_rgb: qcom,leds@d000 {
+ compatible = "qcom,tri-led";
+ reg = <0xd000 0x100>;
+ red {
+ label = "red";
+ pwms = <&pmi632_pwm 0 1000000>;
+ led-sources = <0>;
+ linux,default-trigger = "timer";
+ };
+ green {
+ label = "green";
+ pwms = <&pmi632_pwm 1 1000000>;
+ led-sources = <1>;
+ linux,default-trigger = "timer";
+ };
+ blue {
+ label = "blue";
+ pwms = <&pmi632_pwm 2 1000000>;
+ led-sources = <2>;
+ linux,default-trigger = "timer";
+ };
};
pmi632_lcdb: qpnp-lcdb@ec00 {
@@ -482,5 +556,222 @@
regulator-max-microvolt = <6000000>;
};
};
+
+ flash_led: qcom,leds@d300 {
+ compatible = "qcom,qpnp-flash-led-v2";
+ status = "okay";
+ reg = <0xd300 0x100>;
+ label = "flash";
+ interrupts = <0x3 0xd3 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x3 0xd3 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x3 0xd3 0x4 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "led-fault-irq",
+ "all-ramp-down-done-irq",
+ "all-ramp-up-done-irq";
+ qcom,short-circuit-det;
+ qcom,open-circuit-det;
+ qcom,vph-droop-det;
+ qcom,thermal-derate-en;
+ qcom,thermal-derate-current = <200 500 1000>;
+ qcom,isc-delay = <192>;
+ qcom,pmic-revid = <&pmi632_revid>;
+
+ pmi632_flash0: qcom,flash_0 {
+ label = "flash";
+ qcom,led-name = "led:flash_0";
+ qcom,max-current = <1500>;
+ qcom,default-led-trigger = "flash0_trigger";
+ qcom,id = <0>;
+ qcom,current-ma = <1000>;
+ qcom,duration-ms = <1280>;
+ qcom,ires-ua = <12500>;
+ qcom,hdrm-voltage-mv = <400>;
+ qcom,hdrm-vol-hi-lo-win-mv = <100>;
+ };
+
+ pmi632_flash1: qcom,flash_1 {
+ label = "flash";
+ qcom,led-name = "led:flash_1";
+ qcom,max-current = <1500>;
+ qcom,default-led-trigger = "flash1_trigger";
+ qcom,id = <1>;
+ qcom,current-ma = <1000>;
+ qcom,duration-ms = <1280>;
+ qcom,ires-ua = <12500>;
+ qcom,hdrm-voltage-mv = <400>;
+ qcom,hdrm-vol-hi-lo-win-mv = <100>;
+ };
+
+ pmi632_torch0: qcom,torch_0 {
+ label = "torch";
+ qcom,led-name = "led:torch_0";
+ qcom,max-current = <500>;
+ qcom,default-led-trigger = "torch0_trigger";
+ qcom,id = <0>;
+ qcom,current-ma = <300>;
+ qcom,ires-ua = <12500>;
+ qcom,hdrm-voltage-mv = <400>;
+ qcom,hdrm-vol-hi-lo-win-mv = <100>;
+ };
+
+ pmi632_torch1: qcom,torch_1 {
+ label = "torch";
+ qcom,led-name = "led:torch_1";
+ qcom,max-current = <500>;
+ qcom,default-led-trigger = "torch1_trigger";
+ qcom,id = <1>;
+ qcom,current-ma = <300>;
+ qcom,ires-ua = <12500>;
+ qcom,hdrm-voltage-mv = <400>;
+ qcom,hdrm-vol-hi-lo-win-mv = <100>;
+ };
+
+ pmi632_switch0: qcom,led_switch_0 {
+ label = "switch";
+ qcom,led-name = "led:switch_0";
+ qcom,led-mask = <3>;
+ qcom,default-led-trigger = "switch0_trigger";
+ };
+
+ pmi632_switch1: qcom,led_switch_1 {
+ label = "switch";
+ qcom,led-name = "led:switch_1";
+ qcom,led-mask = <2>;
+ qcom,default-led-trigger = "switch1_trigger";
+ };
+
+ };
+
+ };
+};
+&soc {
+ led_flash0: qcom,camera-flash {
+ cell-index = <0>;
+ compatible = "qcom,camera-flash";
+ qcom,flash-type = <1>;
+ qcom,flash-source = <&pmi632_flash0 &pmi632_flash1>;
+ qcom,torch-source = <&pmi632_torch0 &pmi632_torch1>;
+ qcom,switch-source = <&pmi632_switch0>;
+ };
+};
+
+&thermal_zones {
+ pmi-ibat-lvl0 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&bcl_sensor 0>;
+
+ trips {
+ pmi632_ibat:ibat-lvl0 {
+ temperature = <3500>;
+ hysteresis = <200>;
+ type = "passive";
+ };
+ };
+ };
+
+ pmi-ibat-lvl1 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&bcl_sensor 1>;
+
+ trips {
+ ibat-lvl1 {
+ temperature = <4000>;
+ hysteresis = <200>;
+ type = "passive";
+ };
+ };
+ };
+
+ pmi-vbat-lvl0 {
+ polling-delay-passive = <100>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 2>;
+ tracks-low;
+
+ trips {
+ pmi632_vbat_lvl0: vbat-lvl0 {
+ temperature = <3000>;
+ hysteresis = <100>;
+ type = "passive";
+ };
+ };
+ };
+
+ pmi-vbat-lvl1 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 3>;
+ tracks-low;
+
+ trips {
+ vbat-lvl1 {
+ temperature = <2800>;
+ hysteresis = <100>;
+ type = "passive";
+ };
+ };
+ };
+
+ pmi-vbat-lvl2 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 4>;
+ tracks-low;
+
+ trips {
+ vbat-lvl1 {
+ temperature = <2600>;
+ hysteresis = <100>;
+ type = "passive";
+ };
+ };
+ };
+
+ soc {
+ polling-delay-passive = <100>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_soc>;
+ tracks-low;
+
+ trips {
+ pmi632_low_soc: low-soc {
+ temperature = <10>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ };
+
+ pmi632_tz {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&pmi632_tz>;
+
+ trips {
+ pmi632_tz_trip0: pmi632-trip0 {
+ temperature = <105000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pmi632_tz_trip1: pmi632-trip1 {
+ temperature = <125000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pmi632_tz_trip2: pmi632-trip2 {
+ temperature = <145000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/pmi8950.dtsi b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
index e3388c1..8797ea8 100644
--- a/arch/arm64/boot/dts/qcom/pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
@@ -18,8 +18,8 @@
qcom,pmi8950@2 {
compatible ="qcom,spmi-pmic";
reg = <0x2 SPMI_USID>;
- #address-cells = <2>;
- #size-cells = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
pmi8950_revid: qcom,revid@100 {
compatible = "qcom,qpnp-revid";
@@ -50,6 +50,7 @@
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
qcom,vadc-poll-eoc;
+ #thermal-sensor-cells = <1>;
chan@0 {
label = "usbin";
@@ -609,3 +610,31 @@
};
};
};
+
+&thermal_zones {
+ chg-temp-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pmi8950_vadc 0xd>;
+ thermal-governor = "user_space";
+
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+};
+
+&soc {
+ led_flash0: qcom,camera-flash {
+ cell-index = <0>;
+ compatible = "qcom,camera-flash";
+ qcom,flash-type = <1>;
+ qcom,flash-source = <&pmi8950_flash0 &pmi8950_flash1>;
+ qcom,torch-source = <&pmi8950_torch0 &pmi8950_torch1>;
+ qcom,switch-source = <&pmi8950_switch>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi b/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
index bad4fd7..5d7d0b8 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
@@ -131,6 +131,20 @@
};
};
+/delete-node/ &mtp_batterydata;
+
+&vendor {
+ qcs_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "fg-gen3-batterydata-vrcamera-1300mah.dtsi"
+ };
+};
+
+&pm660_fg {
+ qcom,fg-force-load-profile;
+ qcom,battery-data = <&qcs_batterydata>;
+};
+
&int_codec {
qcom,model = "sdm670-360cam-snd-card";
qcom,audio-routing =
@@ -301,7 +315,7 @@
label = "cam_snapshot";
gpios = <&tlmm 91 GPIO_ACTIVE_LOW>;
linux,input-type = <1>;
- linux,code = <766>;
+ linux,code = <767>;
gpio-key,wakeup;
debounce-interval = <15>;
linux,can-disable;
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
index 02b6821..f592c0e 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
@@ -41,3 +41,46 @@
status = "ok";
};
+
+&tlmm {
+ sdc2_cd_on: cd_on {
+ mux {
+ pins = "gpio116";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio116";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ sdc2_cd_off: cd_off {
+ mux {
+ pins = "gpio116";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio116";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+};
+
+&sdhc_2 {
+ /* VDD external regulator is enabled/disabled by pm660_l18 regulator */
+ vdd-io-supply = <&pm660_l18>;
+ qcom,vdd-io-voltage-level = <1800000 2960000>;
+ qcom,vdd-io-current-level = <0 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
+
+ cd-gpios = <&tlmm 116 0x1>;
+
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi
index 2db6129..2af6610 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi
@@ -19,6 +19,10 @@
model = "Qualcomm Technologies, Inc. QCS605 SoC";
compatible = "qcom,qcs605";
+ chosen {
+ bootargs = "core_ctl_disable_cpumask=0-3";
+ };
+
cpus {
/delete-node/ cpu@200;
/delete-node/ cpu@300;
@@ -91,6 +95,13 @@
};
};
};
+
+ qcom,chd_silver {
+ compatible = "qcom,core-hang-detect";
+ label = "silver";
+ qcom,threshold-arr = <0x17e00058 0x17e10058>;
+ qcom,config-arr = <0x17e00060 0x17e10060>;
+ };
};
&pm660_temp_alarm {
@@ -108,7 +119,7 @@
&thermal_zones {
- xo-therm-cpu-step {
+ xo-therm-step {
cooling-maps {
/delete-node/ skin_cpu2;
/delete-node/ skin_cpu3;
@@ -132,53 +143,70 @@
&soc {
qcom,turing@8300000 {
/delete-property/ vdd_cx-supply;
+ vdd_cx-supply = <&pm8005_s1_level>;
};
qcom,lpass@62400000 {
/delete-property/ vdd_cx-supply;
+ vdd_cx-supply = <&pm8005_s1_level>;
};
};
&clock_cpucc {
/delete-property/ vdd_l3_mx_ao-supply;
/delete-property/ vdd_pwrcl_mx_ao-supply;
+ vdd_l3_mx_ao-supply = <&pm660_s2_level_ao>;
+ vdd_pwrcl_mx_ao-supply = <&pm660_s2_level_ao>;
};
&clock_gcc {
/delete-property/ vdd_cx-supply;
/delete-property/ vdd_cx_ao-supply;
+ vdd_cx-supply = <&pm8005_s1_level>;
+ vdd_cx_ao-supply = <&pm8005_s1_level_ao>;
};
&clock_videocc {
/delete-property/ vdd_cx-supply;
+ vdd_cx-supply = <&pm8005_s1_level>;
};
&clock_camcc {
/delete-property/ vdd_mx-supply;
/delete-property/ vdd_cx-supply;
+ vdd_cx-supply = <&pm8005_s1_level>;
+ vdd_mx-supply = <&pm660_s2_level>;
};
&clock_dispcc {
/delete-property/ vdd_cx-supply;
+ vdd_cx-supply = <&pm8005_s1_level>;
};
&clock_gpucc {
/delete-property/ vdd_mx-supply;
/delete-property/ vdd_cx-supply;
+ vdd_cx-supply = <&pm8005_s1_level>;
+ vdd_mx-supply = <&pm660_s2_level>;
};
&pil_modem {
/delete-property/ vdd_mx-supply;
/delete-property/ vdd_cx-supply;
/delete-property/ vdd_mss-supply;
+ vdd_cx-supply = <&pm8005_s1_level>;
+ vdd_mx-supply = <&pm660_s2_level>;
+ vdd_mss-supply = <&pm8005_s1_level>;
};
&clock_gfx {
/delete-property/ vdd_gfx-supply;
+ vdd_gfx-supply = <&pm8005_s2>;
};
&gpu_gx_gdsc {
/delete-property/ parent-supply;
+ parent-supply = <&pm8005_s2>;
};
&mdss_dsi_phy0 {
diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi
index 23da195..5adbbb8 100644
--- a/arch/arm64/boot/dts/qcom/qcs605.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi
@@ -83,3 +83,7 @@
};
};
};
+
+&msm_gpu {
+ /delete-node/qcom,gpu-mempools;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda632.dtsi b/arch/arm64/boot/dts/qcom/sda632.dtsi
index 8a71b19..0248630 100644
--- a/arch/arm64/boot/dts/qcom/sda632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sda632.dtsi
@@ -22,3 +22,12 @@
status = "disabled";
};
+&soc {
+ qcom,rmnet-ipa {
+ status = "disabled";
+ };
+};
+
+&ipa_hw {
+ status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-svr.dtsi b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
index fa82be2..51dbe74 100644
--- a/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
+++ b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
@@ -324,6 +324,10 @@
};
};
+&adsp_mem {
+ size = <0 0xc800000>;
+};
+
&qupv3_se9_2uart {
status = "ok";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-cdp.dts b/arch/arm64/boot/dts/qcom/sdm429-cdp.dts
new file mode 100644
index 0000000..f3312bd
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-cdp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, 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 "sdm429.dtsi"
+#include "sdm429-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM429 CDP";
+ compatible = "qcom,sdm429-cdp", "qcom,sdm429", "qcom,cdp";
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-cdp.dtsi
new file mode 100644
index 0000000..4ba4c00
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-cdp.dtsi
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018, 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 "sdm439-cdp.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi b/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi
new file mode 100644
index 0000000..d2a8f3e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+/ {
+ /delete-node/ cpus;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu-map {
+
+ cluster0 {
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&CPU0>;
+ };
+ core1 {
+ cpu = <&CPU1>;
+ };
+ core2 {
+ cpu = <&CPU2>;
+ };
+ core3 {
+ cpu = <&CPU3>;
+ };
+ };
+ };
+
+ CPU0: cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x100>;
+ enable-method = "psci";
+ cpu-release-addr = <0x0 0x90000000>;
+ next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
+ L2_1: l2-cache {
+ compatible = "arm,arch-cache";
+ cache-level = <2>;
+ /* A53 L2 dump not supported */
+ qcom,dump-size = <0x0>;
+ };
+ L1_I_100: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x8800>;
+ };
+ L1_D_100: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9000>;
+ };
+ };
+
+ CPU1: cpu@101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x101>;
+ enable-method = "psci";
+ cpu-release-addr = <0x0 0x90000000>;
+ next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
+ L1_I_101: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x8800>;
+ };
+ L1_D_101: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9000>;
+ };
+ };
+
+ CPU2: cpu@102 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x102>;
+ enable-method = "psci";
+ cpu-release-addr = <0x0 0x90000000>;
+ next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
+ L1_I_102: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x8800>;
+ };
+ L1_D_102: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9000>;
+ };
+ };
+
+ CPU3: cpu@103 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x103>;
+ enable-method = "psci";
+ cpu-release-addr = <0x0 0x90000000>;
+ next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
+ L1_I_103: l1-icache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x8800>;
+ };
+ L1_D_103: l1-dcache {
+ compatible = "arm,arch-cache";
+ qcom,dump-size = <0x9000>;
+ };
+ };
+
+ };
+
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-mtp.dts b/arch/arm64/boot/dts/qcom/sdm429-mtp.dts
new file mode 100644
index 0000000..a809be7
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-mtp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, 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 "sdm429.dtsi"
+#include "sdm429-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM429 MTP";
+ compatible = "qcom,sdm429-mtp", "qcom,sdm429", "qcom,mtp";
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-mtp.dtsi
new file mode 100644
index 0000000..839fa56
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-mtp.dtsi
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018, 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 "sdm439-mtp.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd.dts b/arch/arm64/boot/dts/qcom/sdm429-qrd.dts
new file mode 100644
index 0000000..d97cf54
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-qrd.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, 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 "sdm429.dtsi"
+#include "sdm429-qrd.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM429 QRD";
+ compatible = "qcom,sdm429-qrd", "qcom,sdm429", "qcom,qrd";
+ qcom,board-id = <0xb 0>;
+ qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi
new file mode 100644
index 0000000..7116662
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018, 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 "sdm439-qrd.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi
new file mode 100644
index 0000000..f31eb6e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018, 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 "sdm439.dtsi"
+#include "sdm429-cpu.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM429";
+ compatible = "qcom,sdm429";
+ qcom,msm-id = <354 0x0>;
+};
+
+&soc {
+ /delete-node/ qcom,spm@b1d2000;
+ /delete-node/ qcom,lpm-levels;
+ /delete-node/ etm@619c000;
+ /delete-node/ etm@619d000;
+ /delete-node/ etm@619e000;
+ /delete-node/ etm@619f000;
+ /delete-node/ cti@61b8000;
+ /delete-node/ cti@61b9000;
+ /delete-node/ cti@61ba000;
+ /delete-node/ cti@61bb000;
+};
+
+&funnel_apss {
+ ports {
+ /delete-node/ port@1;
+ /delete-node/ port@2;
+ /delete-node/ port@3;
+ /delete-node/ port@4;
+ };
+};
+
+&thermal_zones {
+ hexa-cpu-max-step {
+ cooling-maps {
+ /delete-node/ cpu4_cdev;
+ /delete-node/ cpu5_cdev;
+ /delete-node/ cpu6_cdev;
+ /delete-node/ cpu7_cdev;
+ };
+ };
+
+ /delete-node/ cpuss0-step;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi
new file mode 100644
index 0000000..fae43ba
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+&soc {
+ int_codec: sound {
+ qcom,msm-hs-micbias-type = "internal";
+
+ asoc-codec = <&stub_codec>, <&msm_digital_codec>,
+ <&pmic_analog_codec>;
+ asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec",
+ "analog-codec";
+ msm-vdd-wsa-switch-supply = <&pm8953_l5>;
+ qcom,msm-vdd-wsa-switch-voltage = <1800000>;
+ qcom,msm-vdd-wsa-switch-current = <10000>;
+ };
+};
+
+&pm8953_1 {
+ pmic_analog_codec: analog-codec@f000 {
+ status = "okay";
+ compatible = "qcom,pmic-analog-codec";
+ reg = <0xf000 0x200>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x1 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x2 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x3 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x4 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x5 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x6 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x7 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x0 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x1 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x2 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x3 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x4 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x5 IRQ_TYPE_NONE>;
+ interrupt-names = "spk_cnp_int",
+ "spk_clip_int",
+ "spk_ocp_int",
+ "ins_rem_det1",
+ "but_rel_det",
+ "but_press_det",
+ "ins_rem_det",
+ "mbhc_int",
+ "ear_ocp_int",
+ "hphr_ocp_int",
+ "hphl_ocp_det",
+ "ear_cnp_int",
+ "hphr_cnp_int",
+ "hphl_cnp_int";
+
+ cdc-vdda-cp-supply = <&pm8953_s4>;
+ qcom,cdc-vdda-cp-voltage = <1900000 2050000>;
+ qcom,cdc-vdda-cp-current = <500000>;
+
+ cdc-vdd-io-supply = <&pm8953_l5>;
+ qcom,cdc-vdd-io-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-io-current = <5000>;
+
+ cdc-vdd-pa-supply = <&pm8953_s4>;
+ qcom,cdc-vdd-pa-voltage = <1900000 2050000>;
+ qcom,cdc-vdd-pa-current = <260000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8953_l13>;
+ qcom,cdc-vdd-mic-bias-voltage = <3125000 3125000>;
+ qcom,cdc-vdd-mic-bias-current = <5000>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+
+ qcom,cdc-static-supplies = "cdc-vdd-io",
+ "cdc-vdd-pa",
+ "cdc-vdda-cp";
+
+ qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+
+ msm_digital_codec: msm-dig-codec {
+ compatible = "qcom,msm-digital-codec";
+ reg = <0xc0f0000 0x0>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp.dts b/arch/arm64/boot/dts/qcom/sdm439-cdp.dts
new file mode 100644
index 0000000..1306230
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-cdp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, 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 "sdm439.dtsi"
+#include "sdm439-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM439 CDP";
+ compatible = "qcom,sdm439-cdp", "qcom,sdm439", "qcom,cdp";
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi
new file mode 100644
index 0000000..5512297
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+&blsp1_uart2 {
+ status = "ok";
+};
+
+&sdhc_1 {
+ /* device core power supply */
+ vdd-supply = <&pm8953_l8>;
+ qcom,vdd-voltage-level = <2900000 2900000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8953_l5>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+ 384000000>;
+ qcom,nonremovable;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+ status = "ok";
+};
+
+&sdhc_2 {
+ /* device core power supply */
+ vdd-supply = <&pm8953_l11>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 800000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8953_l12>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+ cd-gpios = <&tlmm 67 0x1>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+ 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp.dts b/arch/arm64/boot/dts/qcom/sdm439-mtp.dts
new file mode 100644
index 0000000..9f221f0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-mtp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, 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 "sdm439.dtsi"
+#include "sdm439-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM439 MTP";
+ compatible = "qcom,sdm439-mtp", "qcom,sdm439", "qcom,mtp";
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi
new file mode 100644
index 0000000..5512297
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+&blsp1_uart2 {
+ status = "ok";
+};
+
+&sdhc_1 {
+ /* device core power supply */
+ vdd-supply = <&pm8953_l8>;
+ qcom,vdd-voltage-level = <2900000 2900000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8953_l5>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+ 384000000>;
+ qcom,nonremovable;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+ status = "ok";
+};
+
+&sdhc_2 {
+ /* device core power supply */
+ vdd-supply = <&pm8953_l11>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 800000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8953_l12>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+ cd-gpios = <&tlmm 67 0x1>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+ 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-pm8953.dtsi b/arch/arm64/boot/dts/qcom/sdm439-pm8953.dtsi
new file mode 100644
index 0000000..289d5bf
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-pm8953.dtsi
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+&rpm_bus {
+ /* Deleting all pm8937 regulators */
+ /delete-node/ rpm-regulator-smpa1;
+ /delete-node/ rpm-regulator-smpa2;
+ /delete-node/ rpm-regulator-smpa3;
+ /delete-node/ rpm-regulator-smpa4;
+ /delete-node/ rpm-regulator-ldoa2;
+ /delete-node/ rpm-regulator-ldoa3;
+ /delete-node/ rpm-regulator-ldoa5;
+ /delete-node/ rpm-regulator-ldoa6;
+ /delete-node/ rpm-regulator-ldoa7;
+ /delete-node/ rpm-regulator-ldoa8;
+ /delete-node/ rpm-regulator-ldoa9;
+ /delete-node/ rpm-regulator-ldoa10;
+ /delete-node/ rpm-regulator-ldoa11;
+ /delete-node/ rpm-regulator-ldoa12;
+ /delete-node/ rpm-regulator-ldoa13;
+ /delete-node/ rpm-regulator-ldoa14;
+ /delete-node/ rpm-regulator-ldoa15;
+ /delete-node/ rpm-regulator-ldoa16;
+ /delete-node/ rpm-regulator-ldoa17;
+ /delete-node/ rpm-regulator-ldoa19;
+ /delete-node/ rpm-regulator-ldoa22;
+ /delete-node/ rpm-regulator-ldoa23;
+};
+
+&spmi_bus {
+ /delete-node/ qcom,pm8937@0;
+ /delete-node/ qcom,pm8937@1;
+};
+
+&thermal_zones {
+ /delete-node/ pa-therm1-adc;
+ /delete-node/ xo-therm-adc;
+ /delete-node/ xo-therm-buf-adc;
+ /delete-node/ case-therm-adc;
+ /delete-node/ pa-therm0-adc;
+ /delete-node/ pm8937_tz;
+};
+
+&int_codec {
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ /delete-property/ msm-vdd-wsa-switch-supply;
+};
+
+&clock_audio {
+ /delete-property/ qcom,audio-ref-clk-gpio;
+};
+
+&wcd9335 {
+ /delete-property/ cdc-vdd-buck-supply;
+ /delete-property/ cdc-buck-sido-supply;
+ /delete-property/ cdc-vdd-tx-h-supply;
+ /delete-property/ cdc-vdd-rx-h-supply;
+ /delete-property/ cdc-vdd-px-supply;
+ /delete-property/ cdc-vdd-mic-bias-supply;
+};
+
+&soc {
+ /delete-node/ regulator@01946004;
+ /delete-node/ regulator@b018000;
+ /delete-node/ eldo2;
+ /delete-node/ adv_vreg;
+
+ qcom,gcc@1800000 {
+ /delete-property/ vdd_dig-supply;
+ /delete-property/ vdd_sr2_dig-supply;
+ /delete-property/ vdd_sr2_pll-supply;
+ /delete-property/ vdd_hf_dig-supply;
+ /delete-property/ vdd_hf_pll-supply;
+ };
+
+ qcom,cpu-clock-8939@b111050 {
+ /delete-property/ vdd-c0-supply;
+ /delete-property/ vdd-c1-supply;
+ /delete-property/ vdd-cci-supply;
+ };
+
+ qcom,lpass@c200000 {
+ /delete-property/ vdd_cx-supply;
+ };
+
+ qcom,pronto@a21b000 {
+ /delete-property/ vdd_pronto_pll-supply;
+ };
+
+ qcom,wcnss-wlan@0a000000 {
+ /delete-property/ qcom,pronto-vddmx-supply;
+ /delete-property/ qcom,pronto-vddcx-supply;
+ /delete-property/ qcom,pronto-vddpx-supply;
+ /delete-property/ qcom,iris-vddxo-supply;
+ /delete-property/ qcom,iris-vddrfa-supply;
+ /delete-property/ qcom,iris-vddpa-supply;
+ /delete-property/ qcom,iris-vdddig-supply;
+ /delete-property/ qcom,wcnss-adc_tm;
+ };
+};
+
+&pil_mss {
+ /delete-property/ vdd_mss-supply;
+ /delete-property/ vdd_cx-supply;
+ /delete-property/ vdd_cx-voltage;
+ /delete-property/ vdd_mx-supply;
+ /delete-property/ vdd_mx-uV;
+ /delete-property/ vdd_pll-supply;
+};
+
+&mdss_dsi {
+ /delete-property/ vdda-supply;
+ /delete-property/ vddio-supply;
+};
+
+&usb_otg {
+ hsusb_vdd_dig-supply = <&pm8953_l23>;
+ HSUSB_1p8-supply = <&pm8953_l7>;
+ HSUSB_3p3-supply = <&pm8953_l13>;
+ qcom,vdd-voltage-level = <0 800000 800000>;
+};
+
+&mdss_dsi0_pll {
+ /delete-property/ vddio-supply;
+};
+
+&mdss_dsi1_pll {
+ /delete-property/ vddio-supply;
+};
+
+&mdss_dsi0 {
+ /delete-property/ vdd-supply;
+ /delete-property/ vddio-supply;
+};
+
+&mdss_dsi1 {
+ /delete-property/ vdd-supply;
+ /delete-property/ vddio-supply;
+};
+
+&int_codec {
+ /delete-property/ asoc-codec;
+ /delete-property/ msm-vdd-wsa-switch-supply;
+};
+
+&clock_audio {
+ /delete-property/ qcom,audio-ref-clk-gpio;
+};
+
+&wcd9335 {
+ /delete-property/ cdc-vdd-buck-supply;
+ /delete-property/ cdc-buck-sido-supply;
+ /delete-property/ cdc-vdd-tx-h-supply;
+ /delete-property/ cdc-vdd-rx-h-supply;
+ /delete-property/ cdc-vdd-px-supply;
+ /delete-property/ cdc-vdd-mic-bias-supply;
+};
+
+#include "pm8953.dtsi"
+#include "pm8953-rpm-regulator.dtsi"
+#include "sdm439-regulator.dtsi"
+
+&thermal_zones {
+ aoss0-lowf {
+ cooling-maps {
+ cx_vdd_cdev {
+ cooling-device = <&pm8953_cx_cdev 0 0>;
+ };
+ };
+ };
+
+ mdm-core-lowf {
+ cooling-maps {
+ cx_vdd_cdev {
+ cooling-device = <&pm8953_cx_cdev 0 0>;
+ };
+ };
+ };
+ lpass-lowf {
+ cooling-maps {
+ cx_vdd_cdev {
+ cooling-device = <&pm8953_cx_cdev 0 0>;
+ };
+ };
+ };
+ camera-lowf {
+ cooling-maps {
+ cx_vdd_cdev {
+ cooling-device = <&pm8953_cx_cdev 0 0>;
+ };
+ };
+ };
+ cpuss1-lowf {
+ cooling-maps {
+ cx_vdd_cdev {
+ cooling-device = <&pm8953_cx_cdev 0 0>;
+ };
+ };
+ };
+ apc1-cpu0-lowf {
+ cooling-maps {
+ cx_vdd_cdev {
+ cooling-device = <&pm8953_cx_cdev 0 0>;
+ };
+ };
+ };
+ apc1-cpu1-lowf {
+ cooling-maps {
+ cx_vdd_cdev {
+ cooling-device = <&pm8953_cx_cdev 0 0>;
+ };
+ };
+ };
+ apc1-cpu2-lowf {
+ cooling-maps {
+ cx_vdd_cdev {
+ cooling-device = <&pm8953_cx_cdev 0 0>;
+ };
+ };
+ };
+ apc1-cpu3-lowf {
+ cooling-maps {
+ cx_vdd_cdev {
+ cooling-device = <&pm8953_cx_cdev 0 0>;
+ };
+ };
+ };
+ cpuss0-lowf {
+ cooling-maps {
+ cx_vdd_cdev {
+ cooling-device = <&pm8953_cx_cdev 0 0>;
+ };
+ };
+ };
+ gpu-lowf {
+ cooling-maps {
+ cx_vdd_cdev {
+ cooling-device = <&pm8953_cx_cdev 0 0>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi b/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi
new file mode 100644
index 0000000..5075862
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018, 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 "pmi632.dtsi"
+
+&pmi632_charger {
+ dpdm-supply = <&usb_otg>;
+};
+
+&usb_otg {
+ vbus_otg-supply = <&smb5_vbus>;
+ extcon = <&pmi632_charger>;
+};
+
+&pmi632_pon {
+ qcom,ps-hold-hard-reset-disable;
+ qcom,ps-hold-shutdown-disable;
+};
+
+/{
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "qg-batterydata-ascent-3450mah.dtsi"
+ #include "qg-batterydata-mlp356477-2800mah.dtsi"
+ };
+};
+
+&pmi632_qg {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&pm8953_typec {
+ status = "disabled";
+};
+
+&thermal_zones {
+ pmi-vbat-lvl0 {
+ cooling-maps {
+ vbat_map0 {
+ trip = <&pmi632_vbat_lvl0>;
+ cooling-device =
+ <&CPU0 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ vbat_map1 {
+ trip = <&pmi632_vbat_lvl0>;
+ cooling-device =
+ <&CPU1 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ vbat_map2 {
+ trip = <&pmi632_vbat_lvl0>;
+ cooling-device =
+ <&CPU2 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ vbat_map3 {
+ trip = <&pmi632_vbat_lvl0>;
+ cooling-device =
+ <&CPU3 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ soc {
+ cooling-maps {
+ soc_map0 {
+ trip = <&pmi632_low_soc>;
+ cooling-device =
+ <&CPU0 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ soc_map1 {
+ trip = <&pmi632_low_soc>;
+ cooling-device =
+ <&CPU1 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ soc_map2 {
+ trip = <&pmi632_low_soc>;
+ cooling-device =
+ <&CPU2 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ soc_map3 {
+ trip = <&pmi632_low_soc>;
+ cooling-device =
+ <&CPU3 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dts b/arch/arm64/boot/dts/qcom/sdm439-qrd.dts
new file mode 100644
index 0000000..7b93e0c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, 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 "sdm439.dtsi"
+#include "sdm439-qrd.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM439 QRD";
+ compatible = "qcom,sdm439-qrd", "qcom,sdm439", "qcom,qrd";
+ qcom,board-id = <0xb 0>;
+ qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi
new file mode 100644
index 0000000..5512297
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+&blsp1_uart2 {
+ status = "ok";
+};
+
+&sdhc_1 {
+ /* device core power supply */
+ vdd-supply = <&pm8953_l8>;
+ qcom,vdd-voltage-level = <2900000 2900000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8953_l5>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+ 384000000>;
+ qcom,nonremovable;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+ status = "ok";
+};
+
+&sdhc_2 {
+ /* device core power supply */
+ vdd-supply = <&pm8953_l11>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 800000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8953_l12>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+ cd-gpios = <&tlmm 67 0x1>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+ 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
new file mode 100644
index 0000000..f9bef43
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&rpm_bus {
+ /* PM8953 regulators */
+ rpm-regulator-smpa1 {
+ status = "okay";
+ pm8953_s1: regulator-s1 {
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-level;
+ status = "okay";
+ };
+ };
+
+ /* PM8953 S2 - VDD_CX supply */
+ rpm-regulator-smpa2 {
+ status = "okay";
+ pm8953_s2_level: regulator-s2-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s2_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-level;
+ };
+
+ pm8953_s2_floor_level: regulator-s2-floor-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s2_floor_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-floor-level;
+ qcom,always-send-voltage;
+ };
+
+ pm8953_s2_level_ao: regulator-s2-level-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s2_level_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-level;
+ };
+
+ pm8953_cx_cdev: regulator-cx-cdev {
+ compatible = "qcom,regulator-cooling-device";
+ regulator-cdev-supply = <&pm8953_s2_floor_level>;
+ regulator-levels = <RPM_SMD_REGULATOR_LEVEL_NOM
+ RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ #cooling-cells = <2>;
+ };
+ };
+
+ rpm-regulator-smpa3 {
+ status = "okay";
+ pm8953_s3: regulator-s3 {
+ regulator-min-microvolt = <1280000>;
+ regulator-max-microvolt = <1280000>;
+ qcom,init-voltage = <1280000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa4 {
+ status = "okay";
+ pm8953_s4: regulator-s4 {
+ regulator-min-microvolt = <2040000>;
+ regulator-max-microvolt = <2040000>;
+ qcom,init-voltage = <2040000>;
+ status = "okay";
+ };
+ };
+
+ /* VDD_MX supply */
+ rpm-regulator-smpa7 {
+ status = "okay";
+ pm8953_s7_level: regulator-s7-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s7_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,init-voltage-level =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ qcom,use-voltage-level;
+ qcom,always-send-voltage;
+ };
+
+ pm8953_s7_level_ao: regulator-s7-level-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s7_level_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-level;
+ qcom,always-send-voltage;
+ };
+
+ pm8953_s7_level_so: regulator-s7-level-so {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s7_level_so";
+ qcom,set = <2>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,init-voltage-level =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ qcom,use-voltage-level;
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ status = "okay";
+ pm8953_l1: regulator-l1 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ qcom,init-voltage = <1000000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ status = "okay";
+ pm8953_l2: regulator-l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1200000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ status = "okay";
+ pm8953_l3: regulator-l3 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1200000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa4 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "okay";
+ pm8953_l4: regulator-l4 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ regulator-name = "pm8953_l4";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ status = "okay";
+ pm8953_l5: regulator-l5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ status = "okay";
+ pm8953_l6: regulator-l6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ status = "okay";
+ pm8953_l7: regulator-l7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+
+ pm8953_l7_ao: regulator-l7-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l7_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ status = "okay";
+ pm8953_l8: regulator-l8 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ qcom,init-voltage = <2900000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ status = "okay";
+ pm8953_l9: regulator-l9 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <3300000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ status = "okay";
+ pm8953_l10: regulator-l10 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,init-voltage = <3000000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ status = "okay";
+ pm8953_l11: regulator-l11 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ status = "okay";
+ pm8953_l12: regulator-l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ status = "okay";
+ pm8953_l13: regulator-l13 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <3075000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa14 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <14>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ status = "okay";
+ pm8953_l14: regulator-l14 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ regulator-name = "pm8953_l14";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa15 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <15>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ status = "okay";
+ pm8953_l15: regulator-l15 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ regulator-name = "pm8953_l15";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa16 {
+ status = "okay";
+ pm8953_l16: regulator-l16 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ status = "okay";
+ pm8953_l17: regulator-l17 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,init-voltage = <2850000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa19 {
+ status = "okay";
+ pm8953_l19: regulator-l19 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
+ qcom,init-voltage = <1300000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa22 {
+ status = "okay";
+ pm8953_l22: regulator-l22 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ qcom,init-voltage = <2800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa23 {
+ status = "okay";
+ pm8953_l23: regulator-l23 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <800000>;
+ qcom,init-voltage = <800000>;
+ status = "okay";
+ };
+ };
+};
+
+&spmi_bus {
+ qcom,pm8953@1 {
+ /* PM8953 S5 + S6 = VDD_APC_supply */
+ pm8953_s5: spm-regulator@2000 {
+ compatible = "qcom,spm-regulator";
+ reg = <0x2000 0x100>;
+ regulator-name = "pm8953_s5";
+ regulator-min-microvolt = <490000>;
+ regulator-max-microvolt = <910000>;
+
+ pm8953_s5_limit: avs-limit-regulator {
+ regulator-name = "pm8953_s5_avs_limit";
+ regulator-min-microvolt = <490000>;
+ regulator-max-microvolt = <910000>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi
new file mode 100644
index 0000000..13bcf1b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018, 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 "msm8937.dtsi"
+#include "sdm439-pm8953.dtsi"
+#include "sdm439-pmi632.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM439";
+ compatible = "qcom,sdm439";
+ qcom,msm-id = <353 0x0>;
+};
+
+&soc {
+ qcom,csid@1b30000 {
+ /delete-property/ qcom,mipi-csi-vdd-supply;
+ };
+ qcom,csid@1b30400 {
+ /delete-property/ qcom,mipi-csi-vdd-supply;
+ };
+ qcom,csid@1b30800 {
+ /delete-property/ qcom,mipi-csi-vdd-supply;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-cdp.dts b/arch/arm64/boot/dts/qcom/sdm450-cdp.dts
index c55622a..0458650 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-cdp.dts
@@ -17,6 +17,7 @@
#include "pmi8950.dtsi"
#include "msm8953-cdp.dtsi"
#include "msm8953-pmi8950.dtsi"
+#include "msm8953-camera-sensor-cdp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
index 5744390..f097895 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
@@ -17,6 +17,7 @@
#include "pmi8950.dtsi"
#include "msm8953-mtp.dtsi"
#include "msm8953-pmi8950.dtsi"
+#include "msm8953-camera-sensor-mtp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dts
index 68f02a8..004186b6be 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dts
@@ -16,6 +16,7 @@
#include "sdm450.dtsi"
#include "sdm450-pmi632-cdp-s2.dtsi"
#include "sdm450-pmi632.dtsi"
+#include "sdm632-camera-sensor-cdp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM450 + PMI632 CDP S2";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dtsi
index 220ec20..d8a0e9d 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dtsi
@@ -13,3 +13,27 @@
#include "msm8953-cdp.dtsi"
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_hx8399c_truly_vid>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active &bklt_en_default>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+ qcom,platform-bklight-en-gpio = <&pm8953_gpios 4 0>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
+};
+
+&dsi_truly_1080_vid {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+ qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+ qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+ qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+};
+
+&dsi_hx8399c_truly_vid {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+ qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+ qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+ qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts
index b9aadc1..1a2309f 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts
@@ -16,6 +16,7 @@
#include "sdm450.dtsi"
#include "sdm450-pmi632-mtp-s3.dtsi"
#include "sdm450-pmi632.dtsi"
+#include "sdm632-camera-sensor-mtp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM450 + PMI632 MTP S3";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi
index adb7f47..129d507 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi
@@ -13,3 +13,28 @@
#include "msm8953-mtp.dtsi"
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_hx8399c_truly_vid>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active &bklt_en_default>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+ qcom,platform-bklight-en-gpio = <&pm8953_gpios 4 0>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
+
+};
+
+&dsi_truly_1080_vid {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+ qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+ qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+ qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+};
+
+&dsi_hx8399c_truly_vid {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+ qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+ qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+ qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
index c79f7a7..d29d6fa 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
@@ -43,5 +43,123 @@
&pmi632_qg {
qcom,battery-data = <&mtp_batterydata>;
- qcom,rbat-conn-mohm = <20>;
+};
+
+&pm8953_gpios {
+ bklt_en {
+ bklt_en_default: bklt_en_default {
+ pins = "gpio4";
+ function = "normal";
+ power-source = <0>;
+ output-high;
+ };
+ };
+};
+
+&pm8953_pwm {
+ status = "ok";
+};
+
+&thermal_zones {
+ pmi-vbat-lvl0 {
+ cooling-maps {
+ vbat_map4 {
+ trip = <&pmi632_vbat_lvl0>;
+ cooling-device =
+ <&CPU4 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ vbat_map5 {
+ trip = <&pmi632_vbat_lvl0>;
+ cooling-device =
+ <&CPU5 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ vbat_map6 {
+ trip = <&pmi632_vbat_lvl0>;
+ cooling-device =
+ <&CPU6 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ vbat_map7 {
+ trip = <&pmi632_vbat_lvl0>;
+ cooling-device =
+ <&CPU7 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ soc {
+ cooling-maps {
+ soc_map4 {
+ trip = <&pmi632_low_soc>;
+ cooling-device =
+ <&CPU4 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ soc_map5 {
+ trip = <&pmi632_low_soc>;
+ cooling-device =
+ <&CPU5 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ soc_map6 {
+ trip = <&pmi632_low_soc>;
+ cooling-device =
+ <&CPU6 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ soc_map7 {
+ trip = <&pmi632_low_soc>;
+ cooling-device =
+ <&CPU7 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ case-therm-step {
+ trips {
+ batt_trip1: batt-trip1 {
+ temperature = <38000>;
+ hysteresis = <3000>;
+ type = "passive";
+ };
+ batt_trip2: batt-trip2 {
+ temperature = <40000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ batt_trip3: batt-trip3 {
+ temperature = <43000>;
+ hysteresis = <3000>;
+ type = "passive";
+ };
+ batt_trip4: batt-trip4 {
+ temperature = <48000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+
+ cooling-maps {
+ battery_lvl1 {
+ trip = <&batt_trip1>;
+ cooling-device = <&pmi632_charger 2 2>;
+ };
+ battery_lvl2 {
+ trip = <&batt_trip2>;
+ cooling-device = <&pmi632_charger 3 3>;
+ };
+ battery_lvl3 {
+ trip = <&batt_trip3>;
+ cooling-device = <&pmi632_charger 4 4>;
+ };
+ battery_lvl4 {
+ trip = <&batt_trip4>;
+ cooling-device = <&pmi632_charger 5 5>;
+ };
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dts b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dts
index 977a978..1dc8874 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dts
@@ -16,6 +16,7 @@
#include "sdm450.dtsi"
#include "sdm450-qrd-sku4.dtsi"
#include "sdm450-pmi632.dtsi"
+#include "msm8953-camera-sensor-qrd.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM450 + PMI632 QRD SKU4";
@@ -24,3 +25,8 @@
qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
};
+&pmi632_vadc {
+ chan@4a {
+ qcom,scale-function = <22>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
index 9e2981a..4a63f9e 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
@@ -32,6 +32,24 @@
status = "disabled";
};
+&int_codec {
+ status = "okay";
+ qcom,model = "msm8953-sku4-snd-card";
+ qcom,msm-micbias1-ext-cap;
+ qcom,msm-micbias2-ext-cap;
+ qcom,msm-mbhc-hphl-swh = <1>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,msm-hs-micbias-type = "external";
+};
+
+&wsa881x_i2c_f {
+ status = "okay";
+};
+
+&wsa881x_i2c_45 {
+ status = "okay";
+};
+
&tlmm {
pmx_mdss {
mdss_dsi_active: mdss_dsi_active {
@@ -107,3 +125,27 @@
qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
};
+
+&soc {
+ gpio_keys {
+ compatible = "gpio-keys";
+ label = "gpio-keys";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&gpio_key_active>;
+ pinctrl-1 = <&gpio_key_suspend>;
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&tlmm 85 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+ };
+};
+
+&sdhc_2 {
+ cd-gpios = <&tlmm 133 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-rcm.dts b/arch/arm64/boot/dts/qcom/sdm450-rcm.dts
index 1b7831b..68a7ca2 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-rcm.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-rcm.dts
@@ -17,6 +17,7 @@
#include "pmi8950.dtsi"
#include "msm8953-cdp.dtsi"
#include "msm8953-pmi8950.dtsi"
+#include "msm8953-camera-sensor-cdp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 RCM";
diff --git a/arch/arm64/boot/dts/qcom/sdm632-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm632-camera-sensor-cdp.dtsi
new file mode 100644
index 0000000..e9295ad
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-camera-sensor-cdp.dtsi
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&cci {
+ actuator0: qcom,actuator@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vaf";
+ qcom,cam-vreg-min-voltage = <2850000>;
+ qcom,cam-vreg-max-voltage = <2850000>;
+ qcom,cam-vreg-op-mode = <80000>;
+ };
+
+ actuator1: qcom,actuator@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <1>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vaf";
+ qcom,cam-vreg-min-voltage = <2850000>;
+ qcom,cam-vreg-max-voltage = <2850000>;
+ qcom,cam-vreg-op-mode = <80000>;
+ };
+
+ eeprom0: qcom,eeprom@0 {
+ cell-index = <0>;
+ compatible = "qcom,eeprom";
+ qcom,cci-master = <0>;
+ reg = <0x0>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+ qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-op-mode = <0 105000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_default
+ &cam_sensor_rear_default
+ &cam_sensor_rear_vana>;
+ pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+ &cam_sensor_rear_vana_sleep>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 134 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VANA";
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk0_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ eeprom1: qcom,eeprom@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ qcom,eeprom-name = "sunny_8865";
+ compatible = "qcom,eeprom";
+ qcom,slave-addr = <0x6c>;
+ qcom,cci-master = <0>;
+ qcom,num-blocks = <8>;
+
+ qcom,page0 = <1 0x0100 2 0x01 1 1>;
+ qcom,poll0 = <0 0x0 2 0x0 1 0>;
+ qcom,mem0 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page1 = <1 0x5002 2 0x00 1 0>;
+ qcom,poll1 = <0 0x0 2 0x0 1 0>;
+ qcom,mem1 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page2 = <1 0x3d84 2 0xc0 1 0>;
+ qcom,poll2 = <0 0x0 2 0x0 1 0>;
+ qcom,mem2 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page3 = <1 0x3d88 2 0x70 1 0>;
+ qcom,poll3 = <0 0x0 2 0x0 1 0>;
+ qcom,mem3 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page4 = <1 0x3d89 2 0x10 1 0>;
+ qcom,poll4 = <0 0x0 2 0x0 1 0>;
+ qcom,mem4 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page5 = <1 0x3d8a 2 0x70 1 0>;
+ qcom,poll5 = <0 0x0 2 0x0 1 0>;
+ qcom,mem5 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page6 = <1 0x3d8b 2 0xf4 1 0>;
+ qcom,poll6 = <0 0x0 2 0x0 1 0>;
+ qcom,mem6 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page7 = <1 0x3d81 2 0x01 1 10>;
+ qcom,poll7 = <0 0x0 2 0x0 1 1>;
+ qcom,mem7 = <1536 0x7010 2 0 1 0>;
+
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_default
+ &cam_sensor_front1_default>;
+ pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front1_sleep>;
+ gpios = <&tlmm 27 0>,
+ <&tlmm 129 0>,
+ <&tlmm 130 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
+ qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg",
+ "sensor_vreg",
+ "sensor_gpio", "sensor_gpio" , "sensor_clk";
+ qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio",
+ "sensor_gpio_reset", "sensor_gpio_standby",
+ "sensor_cam_mclk";
+ qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+ qcom,cam-power-seq-delay = <1 1 1 30 30 5>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk1_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk1_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ eeprom2: qcom,eeprom@2 {
+ cell-index = <2>;
+ compatible = "qcom,eeprom";
+ qcom,cci-master = <1>;
+ reg = <0x2>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_default
+ &cam_sensor_front_default>;
+ pinctrl-1 = <&cam_sensor_mclk2_sleep
+ &cam_sensor_front_sleep>;
+ gpios = <&tlmm 28 0>,
+ <&tlmm 131 0>,
+ <&tlmm 132 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_STANDBY1";
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk2_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ qcom,camera@0 {
+ cell-index = <0>;
+ compatible = "qcom,camera";
+ reg = <0x0>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <270>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,eeprom-src = <&eeprom0>;
+ qcom,actuator-src = <&actuator0>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+ qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-op-mode = <0 105000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_default
+ &cam_sensor_rear_default
+ &cam_sensor_rear_vana>;
+ pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+ &cam_sensor_rear_vana_sleep>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 134 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VANA";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk0_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@1 {
+ cell-index = <1>;
+ compatible = "qcom,camera";
+ reg = <0x1>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <90>;
+ qcom,eeprom-src = <&eeprom2>;
+ qcom,actuator-src = <&actuator1>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_default
+ &cam_sensor_front_default>;
+ pinctrl-1 = <&cam_sensor_mclk2_sleep
+ &cam_sensor_front_sleep>;
+ gpios = <&tlmm 28 0>,
+ <&tlmm 131 0>,
+ <&tlmm 132 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_STANDBY1";
+ qcom,sensor-position = <0x100>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk2_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@2 {
+ cell-index = <2>;
+ compatible = "qcom,camera";
+ reg = <0x02>;
+ qcom,csiphy-sd-index = <2>;
+ qcom,csid-sd-index = <2>;
+ qcom,mount-angle = <90>;
+ qcom,eeprom-src = <&eeprom1>;
+ qcom,actuator-src = <&actuator1>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1175000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1175000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_default
+ &cam_sensor_front1_default>;
+ pinctrl-1 = <&cam_sensor_mclk1_sleep
+ &cam_sensor_front1_sleep>;
+ gpios = <&tlmm 27 0>,
+ <&tlmm 129 0>,
+ <&tlmm 130 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk1_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk1_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm632-camera-sensor-mtp.dtsi
new file mode 100644
index 0000000..07b3811
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-camera-sensor-mtp.dtsi
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&cci {
+ actuator0: qcom,actuator@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vaf";
+ qcom,cam-vreg-min-voltage = <2850000>;
+ qcom,cam-vreg-max-voltage = <2850000>;
+ qcom,cam-vreg-op-mode = <80000>;
+ };
+
+ actuator1: qcom,actuator@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <1>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vaf";
+ qcom,cam-vreg-min-voltage = <2850000>;
+ qcom,cam-vreg-max-voltage = <2850000>;
+ qcom,cam-vreg-op-mode = <80000>;
+ };
+
+ eeprom0: qcom,eeprom@0 {
+ cell-index = <0>;
+ compatible = "qcom,eeprom";
+ qcom,cci-master = <0>;
+ reg = <0x0>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+ qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+ qcom,cam-vreg-op-mode = <0 105000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_default
+ &cam_sensor_rear_default
+ &cam_sensor_rear_vana>;
+ pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+ &cam_sensor_rear_vana_sleep>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 134 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VANA";
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk0_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ eeprom1: qcom,eeprom@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ qcom,eeprom-name = "sunny_8865";
+ compatible = "qcom,eeprom";
+ qcom,slave-addr = <0x6c>;
+ qcom,cci-master = <0>;
+ qcom,num-blocks = <8>;
+
+ qcom,page0 = <1 0x0100 2 0x01 1 1>;
+ qcom,poll0 = <0 0x0 2 0x0 1 0>;
+ qcom,mem0 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page1 = <1 0x5002 2 0x00 1 0>;
+ qcom,poll1 = <0 0x0 2 0x0 1 0>;
+ qcom,mem1 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page2 = <1 0x3d84 2 0xc0 1 0>;
+ qcom,poll2 = <0 0x0 2 0x0 1 0>;
+ qcom,mem2 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page3 = <1 0x3d88 2 0x70 1 0>;
+ qcom,poll3 = <0 0x0 2 0x0 1 0>;
+ qcom,mem3 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page4 = <1 0x3d89 2 0x10 1 0>;
+ qcom,poll4 = <0 0x0 2 0x0 1 0>;
+ qcom,mem4 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page5 = <1 0x3d8a 2 0x70 1 0>;
+ qcom,poll5 = <0 0x0 2 0x0 1 0>;
+ qcom,mem5 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page6 = <1 0x3d8b 2 0xf4 1 0>;
+ qcom,poll6 = <0 0x0 2 0x0 1 0>;
+ qcom,mem6 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page7 = <1 0x3d81 2 0x01 1 10>;
+ qcom,poll7 = <0 0x0 2 0x0 1 1>;
+ qcom,mem7 = <1536 0x7010 2 0 1 0>;
+
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_default
+ &cam_sensor_front1_default>;
+ pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front1_sleep>;
+ gpios = <&tlmm 27 0>,
+ <&tlmm 129 0>,
+ <&tlmm 130 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
+ qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg",
+ "sensor_vreg",
+ "sensor_gpio", "sensor_gpio" , "sensor_clk";
+ qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio",
+ "sensor_gpio_reset", "sensor_gpio_standby",
+ "sensor_cam_mclk";
+ qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+ qcom,cam-power-seq-delay = <1 1 1 30 30 5>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk1_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk1_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ eeprom2: qcom,eeprom@2 {
+ cell-index = <2>;
+ compatible = "qcom,eeprom";
+ qcom,cci-master = <1>;
+ reg = <0x2>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_default
+ &cam_sensor_front_default>;
+ pinctrl-1 = <&cam_sensor_mclk2_sleep
+ &cam_sensor_front_sleep>;
+ gpios = <&tlmm 28 0>,
+ <&tlmm 131 0>,
+ <&tlmm 132 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_STANDBY1";
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk2_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ qcom,camera@0 {
+ cell-index = <0>;
+ compatible = "qcom,camera";
+ reg = <0x0>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <270>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,eeprom-src = <&eeprom0>;
+ qcom,actuator-src = <&actuator0>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vaf-supply = <&pm8953_l17>;
+ cam_vana-supply = <&pm8953_l22>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf",
+ "cam_vana";
+ qcom,cam-vreg-min-voltage = <0 1100000 2850000 2800000>;
+ qcom,cam-vreg-max-voltage = <0 1100000 2850000 2800000>;
+ qcom,cam-vreg-op-mode = <0 105000 100000 80000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_default
+ &cam_sensor_rear_default
+ &cam_sensor_rear_vana>;
+ pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+ &cam_sensor_rear_vana_sleep>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 134 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VANA";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk0_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@1 {
+ cell-index = <1>;
+ compatible = "qcom,camera";
+ reg = <0x1>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <90>;
+ qcom,eeprom-src = <&eeprom2>;
+ qcom,actuator-src = <&actuator1>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_default
+ &cam_sensor_front_default>;
+ pinctrl-1 = <&cam_sensor_mclk2_sleep
+ &cam_sensor_front_sleep>;
+ gpios = <&tlmm 28 0>,
+ <&tlmm 131 0>,
+ <&tlmm 132 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_STANDBY1";
+ qcom,sensor-position = <0x100>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk2_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@2 {
+ cell-index = <2>;
+ compatible = "qcom,camera";
+ reg = <0x02>;
+ qcom,csiphy-sd-index = <2>;
+ qcom,csid-sd-index = <2>;
+ qcom,mount-angle = <90>;
+ qcom,eeprom-src = <&eeprom1>;
+ qcom,actuator-src = <&actuator1>;
+ cam_vdig-supply = <&pm8953_l23>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vaf-supply = <&pm8953_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1175000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1175000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_default
+ &cam_sensor_front1_default>;
+ pinctrl-1 = <&cam_sensor_mclk1_sleep
+ &cam_sensor_front1_sleep>;
+ gpios = <&tlmm 27 0>,
+ <&tlmm 129 0>,
+ <&tlmm 130 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk1_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk1_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts b/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts
index 903b432..51c323c 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts
@@ -16,6 +16,7 @@
#include "sdm632.dtsi"
#include "sdm450-pmi632-cdp-s2.dtsi"
#include "sdm450-pmi632.dtsi"
+#include "sdm632-camera-sensor-cdp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM632 + PMI632 + PMI8004 CDP S2";
@@ -24,3 +25,33 @@
qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
};
+
+&soc {
+ gpio_keys {
+ /delete-node/home;
+ };
+};
+
+&tlmm {
+ tlmm_gpio_key {
+ gpio_key_active: gpio_key_active {
+ mux {
+ pins = "gpio85", "gpio86", "gpio87";
+ };
+
+ config {
+ pins = "gpio85", "gpio86", "gpio87";
+ };
+ };
+
+ gpio_key_suspend: gpio_key_suspend {
+ mux {
+ pins = "gpio85", "gpio86", "gpio87";
+ };
+
+ config {
+ pins = "gpio85", "gpio86", "gpio87";
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
index 031fd7e..c53bb56 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
@@ -58,6 +58,7 @@
efficiency = <1024>;
sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
next-level-cache = <&L2_0>;
+ #cooling-cells = <2>;
L2_0: l2-cache {
compatible = "arm,arch-cache";
cache-level = <2>;
@@ -85,6 +86,7 @@
efficiency = <1024>;
sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
next-level-cache = <&L2_0>;
+ #cooling-cells = <2>;
L1_I_1: l1-icache {
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
@@ -106,6 +108,7 @@
efficiency = <1024>;
sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
next-level-cache = <&L2_0>;
+ #cooling-cells = <2>;
L1_I_2: l1-icache {
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
@@ -127,6 +130,7 @@
efficiency = <1024>;
sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
next-level-cache = <&L2_0>;
+ #cooling-cells = <2>;
L1_I_3: l1-icache {
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
@@ -146,8 +150,9 @@
enable-method = "psci";
reg = <0x0 0x100>;
efficiency = <1638>;
- sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+ sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
L2_1: l2-cache {
compatible = "arm,arch-cache";
cache-level = <2>;
@@ -171,8 +176,9 @@
enable-method = "psci";
reg = <0x0 0x101>;
efficiency = <1638>;
- sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+ sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
L1_I_101: l1-icache {
compatible = "arm,arch-cache";
qcom,dump-size = <0x12000>;
@@ -192,8 +198,9 @@
enable-method = "psci";
reg = <0x0 0x102>;
efficiency = <1638>;
- sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+ sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
L1_I_102: l1-icache {
compatible = "arm,arch-cache";
qcom,dump-size = <0x12000>;
@@ -213,8 +220,9 @@
enable-method = "psci";
reg = <0x0 0x103>;
efficiency = <1638>;
- sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+ sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
L1_I_103: l1-icache {
compatible = "arm,arch-cache";
qcom,dump-size = <0x12000>;
@@ -228,6 +236,69 @@
};
};
};
+
+ energy_costs: energy-costs {
+ compatible = "sched-energy";
+
+ CPU_COST_0: core-cost0 {
+ busy-cost-data = <
+ 614400 23
+ 883200 41
+ 1036800 56
+ 1363200 88
+ 1536000 112
+ 1670400 151
+ 1785600 192
+ >;
+ idle-cost-data = <
+ 20 16 12 8
+ >;
+ };
+ CPU_COST_1: core-cost1 {
+ busy-cost-data = <
+ 633600 722
+ 902400 1287
+ 1036800 1739
+ 1401600 2819
+ 1555200 3532
+ 1785600 4985
+ 1996000 6624
+ 2082800 6905
+ >;
+ idle-cost-data = <
+ 100 80 60 40
+ >;
+ };
+ CLUSTER_COST_0: cluster-cost0 {
+ busy-cost-data = <
+ 614400 8
+ 883200 14
+ 1036800 18
+ 1363200 28
+ 1536000 35
+ 1670400 43
+ 1785600 54
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ CLUSTER_COST_1: cluster-cost1 {
+ busy-cost-data = <
+ 633600 68
+ 902400 103
+ 1036800 132
+ 1401600 193
+ 1555200 233
+ 1785600 289
+ 1996000 374
+ 2082800 386
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ };
};
&cpuss_dump {
diff --git a/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts
index 6339c3c..f7770af 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts
@@ -16,6 +16,7 @@
#include "sdm632.dtsi"
#include "sdm450-pmi632-mtp-s3.dtsi"
#include "sdm450-pmi632.dtsi"
+#include "sdm632-camera-sensor-mtp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM632 + PMI632 + PMI8004 MTP S3";
diff --git a/arch/arm64/boot/dts/qcom/sdm632-qrd-sku4.dts b/arch/arm64/boot/dts/qcom/sdm632-qrd-sku4.dts
index 9f33721..c3cc988 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-qrd-sku4.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-qrd-sku4.dts
@@ -16,6 +16,7 @@
#include "sdm632.dtsi"
#include "sdm450-qrd-sku4.dtsi"
#include "sdm450-pmi632.dtsi"
+#include "msm8953-camera-sensor-qrd.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM632 + PMI632 + PMI8004 QRD SKU4";
@@ -24,3 +25,28 @@
qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
};
+&pmi632_vadc {
+ chan@4a {
+ qcom,scale-function = <22>;
+ };
+};
+
+&soc {
+ gpio_keys {
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&tlmm 87 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ debounce-interval = <15>;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&tlmm 86 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ debounce-interval = <15>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi
new file mode 100644
index 0000000..ed7ec2a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&rpm_bus {
+ rpm-regulator-ldoc1 {
+ status = "okay";
+ pm8004_l1: regulator-l1 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1200000>;
+ status = "okay";
+ };
+ };
+};
+
+&spmi_bus {
+ qcom,pm8953@1 {
+ /delete-node/ spm-regulator@2000;
+ };
+
+ pmic@5 {
+ #size-cells = <1>;
+
+ /* PM8004 S2 + S4 + S5 = VDD_APC supply */
+ pm8004_s2: spm-regulator@1d00 {
+ compatible = "qcom,spm-regulator";
+ reg = <0x1d00 0x100>;
+ regulator-name = "pm8004_s2";
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1140000>;
+
+ pm8004_s2_limit: avs-limit-regulator {
+ regulator-name = "pm8004_s2_avs_limit";
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1140000>;
+ };
+ };
+ };
+};
+
+&soc {
+ /delete-node/ regulator@19461d4;
+ /delete-node/ cpr4-ctrl@b018000;
+ /delete-node/ regulator@194415c;
+ /delete-node/ ldo@185f000;
+
+ apc_mem_acc_vreg: apc-mem-acc-regulator {
+ compatible = "qcom,mem-acc-regulator";
+ regulator-name = "apc_mem_acc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <3>;
+ qcom,acc-reg-addr-list = <0x0b1d1360 0x0b1d1364
+ 0x0b1d1368 0x0b1d136c 0x0b1d1370>;
+ qcom,num-acc-corners = <3>;
+ qcom,boot-acc-corner = <1>;
+ qcom,corner1-reg-config =
+ /* 1 -> 1 */
+ <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ /* 1 -> 2 */
+ < 1 0x0>, < 2 0x0>,
+ < 3 0x0>, < 4 0x0>, < 5 0x0>,
+ /* 1 -> 3 */
+ < 1 0x0>, < 2 0x1>,
+ < 3 0x0>, < 4 0x10000>, < 5 0x0>;
+ qcom,corner2-reg-config =
+ /* 2 -> 1 */
+ < 1 0x0>, < 2 0x80000000>,
+ < 3 0x0>, < 4 0x0>, < 5 0x80000000>,
+ /* 2 -> 2 */
+ <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>,
+ /* 2 -> 3 */
+ < 1 0x0>, < 2 0x1>,
+ < 3 0x0>, < 4 0x10000>, < 5 0x0>;
+ qcom,corner3-reg-config =
+ /* 3 -> 1 */
+ < 1 0x0>, < 2 0x80000000>,
+ < 3 0x0>, < 4 0x0>, < 5 0x80000000>,
+ /* 3 -> 2 */
+ < 1 0x0>, < 2 0x0>,
+ < 3 0x0>, < 4 0x0>, < 5 0x0>,
+ /* 3 -> 3 */
+ <(-1) (-1)>, <(-1) (-1)>,
+ <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>;
+ };
+
+ apc_cpr: cpr4-ctrl@b018000 {
+ compatible = "qcom,cpr4-sdm632-apss-regulator";
+ reg = <0xb018000 0x4000>, <0xa4000 0x1000>;
+ reg-names = "cpr_ctrl", "fuse_base";
+ interrupts = <GIC_SPI 15 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "cpr";
+
+ qcom,cpr-ctrl-name = "apc";
+
+ qcom,cpr-sensor-time = <1000>;
+ qcom,cpr-loop-time = <5000000>;
+ qcom,cpr-idle-cycles = <15>;
+ qcom,cpr-step-quot-init-min = <12>;
+ qcom,cpr-step-quot-init-max = <14>;
+ qcom,cpr-count-mode = <0>; /* All-at-once */
+ qcom,cpr-count-repeat = <14>;
+ qcom,cpr-down-error-step-limit = <1>;
+ qcom,cpr-up-error-step-limit = <1>;
+
+ qcom,apm-ctrl = <&apc_apm>;
+ qcom,apm-threshold-voltage = <875000>;
+ qcom,apm-hysteresis-voltage = <20000>;
+
+ vdd-supply = <&pm8004_s2>;
+ qcom,voltage-step = <5000>;
+ vdd-limit-supply = <&pm8004_s2_limit>;
+ mem-acc-supply = <&apc_mem_acc_vreg>;
+
+ qcom,cpr-panic-reg-addr-list =
+ <0xb1d2c18 0xb1d2900 0x0b1112b0 0xb018798>;
+ qcom,cpr-panic-reg-name-list =
+ "CCI_SAW4_PMIC_STS", "CCI_SAW4_VCTL",
+ "APCS_ALIAS0_APM_CTLER_STATUS",
+ "APCS0_CPR_CORE_ADJ_MODE_REG";
+
+ thread@0 {
+ qcom,cpr-thread-id = <0>;
+ qcom,cpr-consecutive-up = <0>;
+ qcom,cpr-consecutive-down = <2>;
+ qcom,cpr-up-threshold = <2>;
+ qcom,cpr-down-threshold = <1>;
+
+ apc0_pwrcl_vreg: regulator {
+ regulator-name = "apc0_pwrcl_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+
+ qcom,cpr-fuse-corners = <5>;
+ qcom,cpr-fuse-combos = <8>;
+ qcom,cpr-corners = <7>;
+ qcom,cpr-corner-fmax-map = <1 2 3 4 7>;
+
+ qcom,cpr-voltage-ceiling =
+ <720000 720000 790000 865000 920000
+ 990000 1065000>;
+
+ qcom,cpr-voltage-floor =
+ <500000 500000 500000 500000 500000
+ 500000 500000>;
+
+ qcom,mem-acc-voltage = <1 1 2 2 2 2 3>;
+
+ qcom,corner-frequencies =
+ <614400000 883200000 1036800000
+ 1363200000 1536000000 1670400000
+ 1785600000>;
+
+ qcom,cpr-ro-scaling-factor =
+ <3600 3600 3830 2430 2520 2700 1790 1760
+ 1970 1880 2110 2010 2510 4900 4370 4780>,
+ <3600 3600 3830 2430 2520 2700 1790 1760
+ 1970 1880 2110 2010 2510 4900 4370 4780>,
+ <3600 3600 3830 2430 2520 2700 1790 1760
+ 1970 1880 2110 2010 2510 4900 4370 4780>,
+ <3600 3600 3830 2430 2520 2700 1790 1760
+ 1970 1880 2110 2010 2510 4900 4370 4780>,
+ <3600 3600 3830 2430 2520 2700 1790 1760
+ 1970 1880 2110 2010 2510 4900 4370 4780>;
+
+ qcom,allow-voltage-interpolation;
+ qcom,allow-quotient-interpolation;
+ qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+ };
+ };
+
+ thread@1 {
+ qcom,cpr-thread-id = <1>;
+ qcom,cpr-consecutive-up = <0>;
+ qcom,cpr-consecutive-down = <2>;
+ qcom,cpr-up-threshold = <2>;
+ qcom,cpr-down-threshold = <1>;
+
+ apc1_perfcl_vreg: regulator {
+ regulator-name = "apc1_perfcl_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <5>;
+
+ qcom,cpr-fuse-corners = <3>;
+ qcom,cpr-fuse-combos = <8>;
+ qcom,cpr-corners = <5>;
+ qcom,cpr-corner-fmax-map = <1 2 5>;
+
+ qcom,cpr-voltage-ceiling =
+ <790000 865000 920000 990000 1065000>;
+
+ qcom,cpr-voltage-floor =
+ <500000 500000 500000 500000 500000>;
+
+ qcom,mem-acc-voltage = <2 2 2 2 3>;
+
+ qcom,corner-frequencies =
+ <1094400000 1401600000 1555200000
+ 1785600000 1996200000>;
+
+ qcom,cpr-ro-scaling-factor =
+ <3600 3600 3830 2430 2520 2700 1790 1760
+ 1970 1880 2110 2010 2510 4900 4370 4780>,
+ <3600 3600 3830 2430 2520 2700 1790 1760
+ 1970 1880 2110 2010 2510 4900 4370 4780>,
+ <3600 3600 3830 2430 2520 2700 1790 1760
+ 1970 1880 2110 2010 2510 4900 4370 4780>;
+
+ qcom,allow-voltage-interpolation;
+ qcom,allow-quotient-interpolation;
+ qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+ };
+ };
+ };
+
+ gfx_mem_acc: regulator@194415c {
+ compatible = "qcom,mem-acc-regulator";
+ reg = <0x0194415c 0x4>;
+ reg-names = "acc-sel-l1";
+ regulator-name = "gfx_mem_acc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <2>;
+
+ qcom,acc-sel-l1-bit-pos = <0>;
+ qcom,acc-sel-l1-bit-size = <1>;
+ qcom,corner-acc-map = <0x1 0x0>;
+ };
+
+ gfx_vreg_corner: ldo@185f000 {
+ compatible = "qcom,msm8953-gfx-ldo";
+ reg = <0x0185f000 0x30>, <0xa4000 0x1000>;
+ reg-names = "ldo_addr", "efuse_addr";
+
+ regulator-name = "msm_gfx_ldo";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+
+ qcom,ldo-voltage-ceiling = <620000 680000 750000>;
+ qcom,ldo-voltage-floor = <510000 510000 600000>;
+
+ qcom,num-corners = <7>;
+ qcom,num-ldo-corners = <3>;
+ qcom,ldo-enable-corner-map = <0 0 0 0 0 0 0>;
+ qcom,init-corner = <4>;
+
+ vdd-cx-supply = <&pm8953_s2_level>;
+ qcom,vdd-cx-corner-map = <RPM_SMD_REGULATOR_LEVEL_LOW_SVS>,
+ <RPM_SMD_REGULATOR_LEVEL_LOW_SVS>,
+ <RPM_SMD_REGULATOR_LEVEL_SVS>,
+ <RPM_SMD_REGULATOR_LEVEL_SVS_PLUS>,
+ <RPM_SMD_REGULATOR_LEVEL_NOM>,
+ <RPM_SMD_REGULATOR_LEVEL_NOM_PLUS>,
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+
+ mem-acc-supply = <&gfx_mem_acc>;
+ qcom,mem-acc-corner-map = <1 1 1 2 2 2 2>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi
index 80e6749..e397355 100644
--- a/arch/arm64/boot/dts/qcom/sdm632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi
@@ -13,6 +13,9 @@
#include "msm8953.dtsi"
#include "sdm632-cpu.dtsi"
+#include "pm8004.dtsi"
+#include "pm8004-rpm-regulator.dtsi"
+#include "sdm632-regulator.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM632";
@@ -36,3 +39,586 @@
&clock_gcc_gfx {
compatible = "qcom,gcc-gfx-sdm632";
};
+
+&thermal_zones {
+ /delete-node/ camera-usr;
+ /delete-node/ apc1-l2-usr;
+ /delete-node/ apc0-cpu0-usr;
+ /delete-node/ apc0-cpu1-usr;
+ /delete-node/ apc0-cpu2-usr;
+ /delete-node/ apc0-cpu3-usr;
+ /delete-node/ apc0-l2-usr;
+ /delete-node/ gpu0-usr;
+ /delete-node/ gpu1-usr;
+ /delete-node/ gpu1-step;
+ /delete-node/ deca-cpu-max-step;
+ /delete-node/ apc0-cpu0-step;
+ /delete-node/ apc0-cpu1-step;
+ /delete-node/ apc0-cpu2-step;
+ /delete-node/ apc0-cpu3-step;
+ /delete-node/ camera-lowf;
+ /delete-node/ apc1-l2-lowf;
+ /delete-node/ apc0-cpu0-lowf;
+ /delete-node/ apc0-cpu1-lowf;
+ /delete-node/ apc0-cpu2-lowf;
+ /delete-node/ apc0-cpu3-lowf;
+ /delete-node/ apc0-l2-lowf;
+ /delete-node/ gpu0-lowf;
+ /delete-node/ gpu1-lowf;
+
+ case-therm-step {
+ status = "disabled";
+ };
+
+ video-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";
+ };
+ };
+ };
+
+ cpuss0-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";
+ };
+ };
+ };
+
+ cpuss1-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";
+ };
+ };
+ };
+
+ cpuss3-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 13>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ camera-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 14>;
+ 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 15>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ gpu0-step {
+ polling-delay-passive = <250>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 15>;
+ thermal-governor = "step_wise";
+
+ trips {
+ sdm632_gpu_trip0: gpu-trip0 {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ gpu_cdev0 {
+ trip = <&sdm632_gpu_trip0>;
+ cooling-device =
+ <&msm_gpu THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+
+ hepta-cpu-max-step {
+ polling-delay-passive = <50>;
+ polling-delay = <100>;
+ thermal-governor = "step_wise";
+
+ trips {
+ sdm632_cpu_trip:cpu-trip {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+
+ cooling-maps {
+ cpu0_cdev {
+ trip = <&sdm632_cpu_trip>;
+ cooling-device =
+ <&CPU0 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu1_cdev {
+ trip = <&sdm632_cpu_trip>;
+ cooling-device =
+ <&CPU1 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu2_cdev {
+ trip = <&sdm632_cpu_trip>;
+ cooling-device =
+ <&CPU2 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu3_cdev {
+ trip = <&sdm632_cpu_trip>;
+ cooling-device =
+ <&CPU3 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu4_cdev {
+ trip = <&sdm632_cpu_trip>;
+ cooling-device =
+ <&CPU4 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu5_cdev {
+ trip = <&sdm632_cpu_trip>;
+ cooling-device =
+ <&CPU5 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu6_cdev {
+ trip = <&sdm632_cpu_trip>;
+ cooling-device =
+ <&CPU6 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ cpu7_cdev {
+ trip = <&sdm632_cpu_trip>;
+ cooling-device =
+ <&CPU7 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ };
+ };
+
+ cpuss3-step {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 13>;
+ thermal-governor = "step_wise";
+
+ trips {
+ cpuss3_trip: cpuss3-trip {
+ temperature = <105000>;
+ hysteresis = <15000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_cdev {
+ trip = <&cpuss3_trip>;
+ cooling-device =
+ <&CPU0 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ cpu1_cdev {
+ trip = <&cpuss3_trip>;
+ cooling-device =
+ <&CPU1 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ cpu2_cdev {
+ trip = <&cpuss3_trip>;
+ cooling-device =
+ <&CPU2 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ cpu3_cdev {
+ trip = <&cpuss3_trip>;
+ cooling-device =
+ <&CPU3 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ video-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 3>;
+ tracks-low;
+
+ trips {
+ video_trip: video-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&video_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
+ (THERMAL_MAX_LIMIT - 4)>;
+ };
+ gpu_vdd_cdev {
+ trip = <&video_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
+ cx_vdd_cdev {
+ trip = <&video_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&video_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ cpuss0-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 8>;
+ tracks-low;
+
+ trips {
+ sdm632_cpuss0_trip: cpuss0-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&sdm632_cpuss0_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
+ (THERMAL_MAX_LIMIT - 4)>;
+ };
+ gpu_vdd_cdev {
+ trip = <&sdm632_cpuss0_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
+ cx_vdd_cdev {
+ trip = <&sdm632_cpuss0_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&sdm632_cpuss0_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ cpuss1-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 9>;
+ tracks-low;
+
+ trips {
+ sdm632_cpuss1_trip: cpuss1-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&sdm632_cpuss1_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
+ (THERMAL_MAX_LIMIT - 4)>;
+ };
+ gpu_vdd_cdev {
+ trip = <&sdm632_cpuss1_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
+ cx_vdd_cdev {
+ trip = <&sdm632_cpuss1_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&sdm632_cpuss1_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ cpuss3-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 13>;
+ tracks-low;
+
+ trips {
+ sdm632_cpuss3_trip: cpuss3-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&sdm632_cpuss3_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
+ (THERMAL_MAX_LIMIT - 4)>;
+ };
+ gpu_vdd_cdev {
+ trip = <&sdm632_cpuss3_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
+ cx_vdd_cdev {
+ trip = <&sdm632_cpuss3_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&sdm632_cpuss3_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ camera-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 14>;
+ tracks-low;
+
+ trips {
+ sdm632_camera_trip: camera-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&sdm632_camera_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
+ (THERMAL_MAX_LIMIT - 4)>;
+ };
+ gpu_vdd_cdev {
+ trip = <&sdm632_camera_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
+ cx_vdd_cdev {
+ trip = <&sdm632_camera_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&sdm632_camera_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+
+ gpu0-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 15>;
+ tracks-low;
+
+ trips {
+ sdm632_gpu0_trip: gpu0-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&sdm632_gpu0_trip>;
+ cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
+ (THERMAL_MAX_LIMIT - 4)>;
+ };
+ gpu_vdd_cdev {
+ trip = <&sdm632_gpu0_trip>;
+ cooling-device = <&msm_gpu 2 2>;
+ };
+ cx_vdd_cdev {
+ trip = <&sdm632_gpu0_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&sdm632_gpu0_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ };
+ };
+};
+
+&clock_cpu {
+ /delete-property/ vdd-cl-supply;
+ status = "disabled";
+ compatible = "qcom,cpu-clock-sdm632";
+ reg = <0xb114000 0x68>,
+ <0xb014000 0x68>,
+ <0xb016000 0x8>,
+ <0xb116000 0x8>,
+ <0xb1d0000 0x8>,
+ <0xb011050 0x8>,
+ <0xb111050 0x8>,
+ <0xb1d1050 0x8>,
+ <0x00a412c 0x8>;
+ reg-names = "rcgwr-c0-base", "rcgwr-c1-base",
+ "apcs-c1-pll-base", "apcs-c0-pll-base",
+ "apcs-cci-pll-base", "apcs-c1-rcg-base",
+ "apcs-c0-rcg-base", "apcs-cci-rcg-base",
+ "efuse";
+ qcom,num-clusters = <2>;
+ clocks = <&clock_gcc clk_xo_a_clk_src>;
+ clock-names = "xo_a";
+ qcom,speed0-bin-v0-c0 =
+ < 0 0>,
+ < 614400000 1>,
+ < 883200000 2>,
+ < 1036200000 3>,
+ < 1363200000 4>,
+ < 1563000000 5>,
+ < 1670400000 6>,
+ < 1785600000 7>;
+ qcom,speed0-bin-v0-c1 =
+ < 0 0>,
+ < 633600000 1>,
+ < 902400000 2>,
+ < 1094400000 3>,
+ < 1401600000 4>,
+ < 1555200000 5>,
+ < 1785600000 6>;
+ qcom,speed0-bin-v0-cci =
+ < 0 0>,
+ < 307200000 1>,
+ < 403200000 2>,
+ < 499200000 3>,
+ < 691200000 4>,
+ < 768000000 5>,
+ < 787200000 6>;
+ #clock-cells = <1>;
+};
+
+&soc {
+ /delete-node/ msm_cpufreq;
+ msm_cpufreq: qcom,msm-cpufreq {
+ compatible = "qcom,msm-cpufreq";
+ clock-names =
+ "l2_clk",
+ "cpu0_clk",
+ "cpu4_clk";
+ clocks =
+ <&clock_cpu clk_a53_cci_clk >,
+ <&clock_cpu clk_a53_pwr_clk >,
+ <&clock_cpu clk_a53_perf_clk >;
+
+ qcom,governor-per-policy;
+
+ qcom,cpufreq-table-0 =
+ < 614400 >,
+ < 883200 >,
+ < 1036800 >,
+ < 1363200 >,
+ < 1536000 >,
+ < 1670400 >,
+ < 1785600 >;
+
+ qcom,cpufreq-table-4 =
+ < 1094400 >,
+ < 1401600 >,
+ < 1555200 >,
+ < 1785600 >,
+ < 1996200 >,
+ < 2082800 >;
+ };
+
+ cci_cache: qcom,cci {
+ compatible = "devfreq-simple-dev";
+ clock-names = "devfreq_clk";
+ clocks = <&clock_cpu clk_a53_cci_clk >;
+ governor = "cpufreq";
+ freq-tbl-khz =
+ < 307200 >,
+ < 403200 >,
+ < 499200 >,
+ < 691200 >,
+ < 768000 >,
+ < 787200 >;
+ };
+
+ /delete-node/ devfreq-cpufreq;
+ devfreq-cpufreq {
+ mincpubw-cpufreq {
+ target-dev = <&mincpubw>;
+ cpu-to-dev-map-0 =
+ < 614400 1611>,
+ < 1363200 3221>,
+ < 1785600 5859>;
+ cpu-to-dev-map-4 =
+ < 1094400 1611>,
+ < 1401600 3221>,
+ < 1785600 5859>,
+ < 2082800 7104>;
+ };
+
+ cci-cpufreq {
+ target-dev = <&cci_cache>;
+ cpu-to-dev-map-0 =
+ < 614400 307200>, /* SVS */
+ < 883200 403200>,
+ < 1036800 499200>,
+ < 1363200 691200>, /* NOM */
+ < 1536000 768000>, /* NOM+ */
+ < 1670400 787200>; /* TURBO */
+ cpu-to-dev-map-4 =
+ < 1094400 499200>, /* SVS */
+ < 1401600 691200>, /* NOM */
+ < 1555200 768000>, /* NOM+ */
+ < 1785600 787200>; /* TURBO */
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
index 96c4640..9402294 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
@@ -234,9 +234,7 @@
msm_cam_smmu_lrme {
compatible = "qcom,msm-cam-smmu-cb";
iommus = <&apps_smmu 0x1038 0x0>,
- <&apps_smmu 0x1058 0x0>,
- <&apps_smmu 0x1039 0x0>,
- <&apps_smmu 0x1059 0x0>;
+ <&apps_smmu 0x1058 0x0>;
label = "lrme";
lrme_iova_mem_map: iova-mem-map {
iova-mem-region-shared {
@@ -338,13 +336,23 @@
};
iova-mem-region-io {
- /* IO region is approximately 3.3 GB */
+ /* IO region is approximately 3 GB */
iova-region-name = "io";
- iova-region-start = <0xd900000>;
- iova-region-len = <0xd2700000>;
+ iova-region-start = <0xd911000>;
+ iova-region-len = <0xd26ef000>;
iova-region-id = <0x3>;
status = "ok";
};
+
+ iova-mem-qdss-region {
+ /* qdss region is approximately 64K */
+ iova-region-name = "qdss";
+ iova-region-start = <0xd900000>;
+ iova-region-len = <0x10000>;
+ iova-region-id = <0x5>;
+ qdss-phy-addr = <0x16790000>;
+ status = "ok";
+ };
};
};
@@ -393,13 +401,16 @@
label = "cpas";
arch-compat = "cpas_top";
status = "ok";
- reg-names = "cam_cpas_top", "cam_camnoc";
+ reg-names = "cam_cpas_top", "cam_camnoc", "core_top_csr_tcsr";
reg = <0xac40000 0x1000>,
- <0xac42000 0x5000>;
- reg-cam-base = <0x40000 0x42000>;
+ <0xac42000 0x5000>,
+ <0x01fc0000 0x30000>;
+ reg-cam-base = <0x40000 0x42000 0x0>;
interrupt-names = "cpas_camnoc";
interrupts = <0 459 0>;
qcom,cpas-hw-ver = <0x170110>; /* Titan v170 v1.1.0 */
+ nvmem-cells = <&minor_rev>;
+ nvmem-cell-names = "minor_rev";
regulator-names = "camss-vdd";
camss-vdd-supply = <&titan_top_gdsc>;
clock-names = "gcc_ahb_clk",
diff --git a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
index 6dc5c2c..dc9e54e 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
@@ -11,6 +11,19 @@
*/
&soc {
+ csr: csr@6001000 {
+ compatible = "qcom,coresight-csr";
+ reg = <0x6001000 0x1000>;
+ reg-names = "csr-base";
+
+ coresight-name = "coresight-csr";
+
+ qcom,usb-bam-support;
+ qcom,hwctrl-set-support;
+ qcom,set-byte-cntr-support;
+ qcom,blk-size = <1>;
+ };
+
replicator_qdss: replicator@6046000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b909>;
@@ -59,6 +72,7 @@
coresight-name = "coresight-tmc-etr";
coresight-ctis = <&cti0 &cti8>;
+ coresight-csr = <&csr>;
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
@@ -117,6 +131,7 @@
reg-names = "tmc-base";
coresight-name = "coresight-tmc-etf-swao";
+ coresight-csr = <&csr>;
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
@@ -284,6 +299,7 @@
coresight-name = "coresight-tmc-etf";
coresight-ctis = <&cti0 &cti8>;
arm,default-sink;
+ coresight-csr = <&csr>;
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
@@ -395,22 +411,13 @@
reg-names = "ddr-ch0-cfg", "ddr-ch23-cfg", "ddr-ch0-ctrl",
"ddr-ch23-ctrl";
+ coresight-csr = <&csr>;
coresight-name = "coresight-hwevent";
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
};
- csr: csr@6001000 {
- compatible = "qcom,coresight-csr";
- reg = <0x6001000 0x1000>;
- reg-names = "csr-base";
-
- coresight-name = "coresight-csr";
-
- qcom,blk-size = <1>;
- };
-
funnel_in0: funnel@0x6041000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b908>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
index 9acef75..a77f4a0 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
@@ -122,8 +122,8 @@
cache-slices = <&llcc 12>, <&llcc 11>;
/* CPU latency parameter */
- qcom,pm-qos-active-latency = <899>;
- qcom,pm-qos-wakeup-latency = <899>;
+ qcom,pm-qos-active-latency = <67>;
+ qcom,pm-qos-wakeup-latency = <67>;
/* Enable context aware freq. scaling */
qcom,enable-ca-jump;
@@ -239,6 +239,7 @@
qcom,speed-bin = <0>;
qcom,initial-pwrlevel = <3>;
+ qcom,ca-target-pwrlevel = <1>;
/* SVS_L1 */
qcom,gpu-pwrlevel@0 {
@@ -293,6 +294,7 @@
qcom,speed-bin = <90>;
qcom,initial-pwrlevel = <3>;
+ qcom,ca-target-pwrlevel = <1>;
/* SVS_L1 */
qcom,gpu-pwrlevel@0 {
@@ -348,6 +350,7 @@
qcom,speed-bin = <146>;
qcom,initial-pwrlevel = <6>;
+ qcom,ca-target-pwrlevel = <4>;
/* TURBO */
qcom,gpu-pwrlevel@0 {
@@ -429,38 +432,75 @@
qcom,speed-bin = <163>;
- qcom,initial-pwrlevel = <3>;
+ qcom,initial-pwrlevel = <7>;
+ qcom,ca-target-pwrlevel = <5>;
- /* SVS_L1 */
+ /* TURBO_L1 */
qcom,gpu-pwrlevel@0 {
reg = <0>;
- qcom,gpu-freq = <430000000>;
+ qcom,gpu-freq = <780000000>;
qcom,bus-freq = <11>;
+ qcom,bus-min = <10>;
+ qcom,bus-max = <11>;
+ };
+
+ /* TURBO */
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <750000000>;
+ qcom,bus-freq = <11>;
+ qcom,bus-min = <9>;
+ qcom,bus-max = <11>;
+ };
+
+ /* NOM_L1 */
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <650000000>;
+ qcom,bus-freq = <10>;
qcom,bus-min = <8>;
qcom,bus-max = <11>;
};
- /* SVS */
- qcom,gpu-pwrlevel@1 {
- reg = <1>;
- qcom,gpu-freq = <355000000>;
- qcom,bus-freq = <8>;
- qcom,bus-min = <5>;
- qcom,bus-max = <9>;
+ /* NOM */
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <565000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <8>;
+ qcom,bus-max = <10>;
};
- /* LOW SVS */
- qcom,gpu-pwrlevel@2 {
- reg = <2>;
- qcom,gpu-freq = <267000000>;
- qcom,bus-freq = <6>;
- qcom,bus-min = <4>;
+ /* SVS_L1 */
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
+ qcom,gpu-freq = <430000000>;
+ qcom,bus-freq = <8>;
+ qcom,bus-min = <7>;
+ qcom,bus-max = <10>;
+ };
+
+ /* SVS */
+ qcom,gpu-pwrlevel@5 {
+ reg = <5>;
+ qcom,gpu-freq = <355000000>;
+ qcom,bus-freq = <7>;
+ qcom,bus-min = <5>;
qcom,bus-max = <8>;
};
+ /* LOW SVS */
+ qcom,gpu-pwrlevel@6 {
+ reg = <6>;
+ qcom,gpu-freq = <267000000>;
+ qcom,bus-freq = <6>;
+ qcom,bus-min = <4>;
+ qcom,bus-max = <7>;
+ };
+
/* MIN SVS */
- qcom,gpu-pwrlevel@3 {
- reg = <3>;
+ qcom,gpu-pwrlevel@7 {
+ reg = <7>;
qcom,gpu-freq = <180000000>;
qcom,bus-freq = <4>;
qcom,bus-min = <3>;
@@ -468,8 +508,8 @@
};
/* XO */
- qcom,gpu-pwrlevel@4 {
- reg = <4>;
+ qcom,gpu-pwrlevel@8 {
+ reg = <8>;
qcom,gpu-freq = <0>;
qcom,bus-freq = <0>;
qcom,bus-min = <0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
index de9e40e..68f51e2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -365,13 +365,7 @@
};
&thermal_zones {
- xo-therm-cpu-step {
- status = "disabled";
- };
- xo-therm-mdm-step {
- status = "disabled";
- };
- xo-therm-batt-step {
+ xo-therm-step {
status = "disabled";
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
index 6652ba5..27be1fd 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
@@ -387,12 +387,7 @@
};
&thermal_zones {
- xo-therm-batt-step {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&pm660_adc_tm 0x4c>;
- thermal-governor = "step_wise";
-
+ xo-therm-step {
trips {
batt_trip1: batt-trip1 {
temperature = <50000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi
index 3022998..4ca4001 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi
@@ -399,7 +399,7 @@
qcom,mdss-inline-rot-safe-lut = <0x0000f000 0x0000ff00>;
qcom,mdss-rot-qos-cpu-mask = <0xf>;
- qcom,mdss-rot-qos-cpu-dma-latency = <75>;
+ qcom,mdss-rot-qos-cpu-dma-latency = <67>;
qcom,mdss-default-ot-rd-limit = <32>;
qcom,mdss-default-ot-wr-limit = <32>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi b/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
index f3e5ddb..b2601ee 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -268,4 +268,16 @@
interrupt-controller;
#interrupt-cells = <2>;
};
+
+ /* wlan - inbound entry from mss/WLAN PD */
+ smp2pgpio_wlan_1_in: qcom,smp2pgpio-wlan-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "wlan";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
index f259838..8707af2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
@@ -576,7 +576,7 @@
};
};
- xo-therm-cpu-step {
+ xo-therm-step {
polling-delay-passive = <2000>;
polling-delay = <0>;
thermal-sensors = <&pm660_adc_tm 0x4c>;
@@ -593,6 +593,26 @@
hysteresis = <0>;
type = "passive";
};
+ modem_trip0: modem-trip0 {
+ temperature = <48000>;
+ hysteresis = <4000>;
+ type = "passive";
+ };
+ modem_trip1: modem-trip1 {
+ temperature = <50000>;
+ hysteresis = <4000>;
+ type = "passive";
+ };
+ modem_trip2: modem-trip2 {
+ temperature = <52000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ modem_trip3: modem-trip3 {
+ temperature = <56000>;
+ hysteresis = <4000>;
+ type = "passive";
+ };
};
cooling-maps {
@@ -634,39 +654,6 @@
trip = <&silver_trip1>;
cooling-device = <&CPU5 THERMAL_NO_LIMIT 2>;
};
- };
- };
-
- xo-therm-mdm-step {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&pm660_adc_tm 0x4c>;
- thermal-governor = "step_wise";
-
- trips {
- modem_trip0: modem-trip0 {
- temperature = <48000>;
- hysteresis = <4000>;
- type = "passive";
- };
- modem_trip1: modem-trip1 {
- temperature = <50000>;
- hysteresis = <4000>;
- type = "passive";
- };
- modem_trip2: modem-trip2 {
- temperature = <52000>;
- hysteresis = <2000>;
- type = "passive";
- };
- modem_trip3: modem-trip3 {
- temperature = <56000>;
- hysteresis = <4000>;
- type = "passive";
- };
- };
-
- cooling-maps {
modem_lvl1 {
trip = <&modem_trip1>;
cooling-device = <&modem_pa 1 1>;
@@ -689,4 +676,133 @@
};
};
};
+
+ vbat_adc {
+ cooling-maps {
+ vbat_map6 {
+ trip = <&pm660_vbat_adc>;
+ cooling-device =
+ <&CPU6 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ vbat_map7 {
+ trip = <&pm660_vbat_adc>;
+ cooling-device =
+ <&CPU7 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ soc {
+ cooling-maps {
+ soc_map6 {
+ trip = <&pm660_low_soc>;
+ cooling-device =
+ <&CPU6 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ soc_map7 {
+ trip = <&pm660_low_soc>;
+ cooling-device =
+ <&CPU7 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ pm660_temp_alarm: pm660_tz {
+ cooling-maps {
+ trip0_cpu0 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU0 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu1 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU1 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu2 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU2 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu3 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU3 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu4 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU4 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu5 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU5 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu6 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU6 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu7 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU7 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip1_cpu1 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU1 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu2 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU2 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu3 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU3 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu4 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU4 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu5 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU5 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu6 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU6 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu7 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU7 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
index 3df6d09..1e84e2c 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
@@ -27,7 +27,7 @@
};
&usb0 {
- qcom,pm-qos-latency = <601>; /* CPU-CLUSTER-WFI-LVL latency +1 */
+ qcom,pm-qos-latency = <67>; /* CPU WFI latency + 1 */
extcon = <0>, <0>, <&eud>, <0>, <0>;
};
@@ -35,6 +35,27 @@
vdd-supply = <&pm660l_l1>;
vdda18-supply = <&pm660_l10>;
vdda33-supply = <&pm660l_l7>;
+ qcom,host-chirp-erratum;
+ qcom,qusb-phy-host-init-seq =
+ /* <value reg_offset> */
+ <0x23 0x210 /* PWR_CTRL1 */
+ 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */
+ 0x7c 0x18c /* PLL_CLOCK_INVERTERS */
+ 0x80 0x2c /* PLL_CMODE */
+ 0x0a 0x184 /* PLL_LOCK_DELAY */
+ 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */
+ 0x40 0x194 /* PLL_BIAS_CONTROL_1 */
+ 0x20 0x198 /* PLL_BIAS_CONTROL_2 */
+ 0x21 0x214 /* PWR_CTRL2 */
+ 0x08 0x220 /* IMP_CTRL1 */
+ 0x58 0x224 /* IMP_CTRL2 */
+ 0x45 0x240 /* TUNE1 */
+ 0x29 0x244 /* TUNE2 */
+ 0xca 0x248 /* TUNE3 */
+ 0x04 0x24c /* TUNE4 */
+ 0x03 0x250 /* TUNE5 */
+ 0x00 0x23c /* CHG_CTRL2 */
+ 0x22 0x210>; /* PWR_CTRL1 */
qcom,qusb-phy-init-seq =
/* <value reg_offset> */
<0x23 0x210 /* PWR_CTRL1 */
diff --git a/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi
index 01d4057..a0b4a22 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -42,7 +42,7 @@
"bus_clk", "core0_clk", "core0_bus_clk",
"core1_clk", "core1_bus_clk";
qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0 0x1 0x0>;
- qcom,allowed-clock-rates = <100000000 200000000 320000000
+ qcom,allowed-clock-rates = <100000000 200000000 330000000
380000000 444000000 533000000>;
/* Buses */
@@ -138,7 +138,7 @@
qcom,proxy-clock-names = "core_clk", "iface_clk",
"bus_clk", "core0_clk", "core0_bus_clk";
qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0>;
- qcom,allowed-clock-rates = <100000000 200000000 320000000
+ qcom,allowed-clock-rates = <100000000 200000000 330000000
364700000>;
/* Buses */
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 8993e1f..152b760 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -372,6 +372,7 @@
1747200 641
1843200 659
1996800 696
+ 2016000 865
2054400 876
2169600 900
2208000 924
@@ -413,6 +414,7 @@
1747200 64
1843200 65
1996800 69
+ 2016000 85
2054400 87
2169600 90
2208000 92
@@ -809,6 +811,10 @@
<&apps_smmu 0x716 0x1>;
};
+ qcom_msmhdcp: qcom,msm_hdcp {
+ compatible = "qcom,msm-hdcp";
+ };
+
qcom_crypto: qcrypto@1de0000 {
compatible = "qcom,qcrypto";
reg = <0x1de0000 0x20000>,
@@ -1037,6 +1043,20 @@
vdd_mx-supply = <&pm660l_s1_level>;
#clock-cells = <1>;
#reset-cells = <1>;
+ qcom,cam_cc_csi0phytimer_clk_src-opp-handle = <&cam_csiphy0>;
+ qcom,cam_cc_csi1phytimer_clk_src-opp-handle = <&cam_csiphy1>;
+ qcom,cam_cc_csi2phytimer_clk_src-opp-handle = <&cam_csiphy2>;
+ qcom,cam_cc_cci_clk_src-opp-handle = <&cam_cci>;
+ qcom,cam_cc_ife_0_csid_clk_src-opp-handle = <&cam_csid0>;
+ qcom,cam_cc_ife_0_clk_src-opp-handle = <&cam_vfe0>;
+ qcom,cam_cc_ife_1_csid_clk_src-opp-handle = <&cam_csid1>;
+ qcom,cam_cc_ife_1_clk_src-opp-handle = <&cam_vfe1>;
+ qcom,cam_cc_ife_lite_csid_clk_src-opp-handle = <&cam_csid_lite>;
+ qcom,cam_cc_ife_lite_clk_src-opp-handle = <&cam_vfe_lite>;
+ qcom,cam_cc_icp_clk_src-opp-handle = <&cam_a5>;
+ qcom,cam_cc_ipe_0_clk_src-opp-handle = <&cam_ipe0>;
+ qcom,cam_cc_ipe_1_clk_src-opp-handle = <&cam_ipe1>;
+ qcom,cam_cc_bps_clk_src-opp-handle = <&cam_bps>;
};
clock_dispcc: qcom,dispcc@af00000 {
@@ -1657,7 +1677,7 @@
};
};
- qcom,chd_sliver {
+ qcom,chd_silver {
compatible = "qcom,core-hang-detect";
label = "silver";
qcom,threshold-arr = <0x17e00058 0x17e10058 0x17e20058
@@ -1912,7 +1932,7 @@
/* PM QoS */
qcom,pm-qos-cpu-groups = <0x3f 0xC0>;
- qcom,pm-qos-cpu-group-latency-us = <70 70>;
+ qcom,pm-qos-cpu-group-latency-us = <67 67>;
qcom,pm-qos-default-cpu = <0>;
resets = <&clock_gcc GCC_UFS_PHY_BCR>;
@@ -2350,10 +2370,10 @@
/* PM QoS */
qcom,pm-qos-irq-type = "affine_irq";
- qcom,pm-qos-irq-latency = <70 70>;
+ qcom,pm-qos-irq-latency = <67 67>;
qcom,pm-qos-cpu-groups = <0x3f 0xc0>;
- qcom,pm-qos-cmdq-latency-us = <70 70>, <70 70>;
- qcom,pm-qos-legacy-latency-us = <70 70>, <70 70>;
+ qcom,pm-qos-cmdq-latency-us = <67 67>, <67 67>;
+ qcom,pm-qos-legacy-latency-us = <67 67>, <67 67>;
clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>,
<&clock_gcc GCC_SDCC1_APPS_CLK>,
@@ -2423,9 +2443,9 @@
/* PM QoS */
qcom,pm-qos-irq-type = "affine_irq";
- qcom,pm-qos-irq-latency = <70 70>;
+ qcom,pm-qos-irq-latency = <67 67>;
qcom,pm-qos-cpu-groups = <0x3f 0xc0>;
- qcom,pm-qos-legacy-latency-us = <70 70>, <70 70>;
+ qcom,pm-qos-legacy-latency-us = <67 67>, <67 67>;
clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>,
<&clock_gcc GCC_SDCC2_APPS_CLK>;
@@ -2567,6 +2587,8 @@
qcom,vdd-3.3-ch0-config = <3000000 3312000>;
qcom,wlan-msa-memory = <0x100000>;
qcom,wlan-msa-fixed-region = <&wlan_msa_mem>;
+ qcom,gpio-force-fatal-error = <&smp2pgpio_wlan_1_in 0 0>;
+ qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>;
qcom,smmu-s1-bypass;
};
@@ -2650,6 +2672,18 @@
< 1 >;
};
+ bus_proxy_client: qcom,bus_proxy_client {
+ compatible = "qcom,bus-proxy-client";
+ qcom,msm-bus,name = "bus-proxy-client";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ <22 512 0 0>, <23 512 0 0>,
+ <22 512 0 5000000>, <23 512 0 5000000>;
+ qcom,msm-bus,active-only;
+ status = "ok";
+ };
+
devfreq_memlat_0: qcom,cpu0-memlat-mon {
compatible = "qcom,arm-memlat-mon";
qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr-dvt.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr-dvt.dtsi
new file mode 100644
index 0000000..b671d0e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr-dvt.dtsi
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2017-2018, 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 "sdm845-camera-sensor-qvr.dtsi"
+/* PMD ToF MD101D */
+&cam_cci {
+ qcom,cam-sensor@4 {
+ cell-index = <4>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x4>;
+ csiphy-sd-index = <3>;
+ sensor-position-roll = <270>; /* checked, MTP845 */
+ sensor-position-pitch = <0>; /* checked, MTP845 */
+ sensor-position-yaw = <180>; /* checked, MTP845 */
+ cam_vio-supply = <&pm8998_lvs1>; /* checked, MTP845 */
+ cam_vana-supply = <&pmi8998_bob>;
+ cam_vdig-supply = <&camera_eyetracking_force>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <0 3312000 1050000 0>;
+ rgltr-max-voltage = <0 3600000 1050000 0>;
+ rgltr-load-current = <0 80000 105000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk3_active
+ &cam_sensor_depth_active>;
+ pinctrl-1 = <&cam_sensor_mclk3_suspend
+ &cam_sensor_depth_suspend>;
+ gpios = <&tlmm 16 0>, //MCLK1
+ <&tlmm 28 0>, //RESET
+ <&tlmm 23 0>, //vana
+ <&tlmm 24 0>;
+ gpio-reset = <1>; //RESET
+ gpio-vana = <2>;
+ gpio-vdig = <3>;
+ gpio-req-tbl-num = <0 1 2 3> ;
+ gpio-req-tbl-flags = <1 0 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_VANA1",
+ "CAM_VDIG1";
+ sensor-mode = <0>; // 0 -> back camera 2D
+ cci-master = <1>; /* checked, MTP845 we are on I2C 0 */
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK3_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+/* 6dof */
+ qcom,camera@6 {
+ cell-index = <6>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x6>;
+ csiphy-sd-index = <1>;
+ sensor-position-roll = <270>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <0>;
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ cam_vdig-supply = <&pm8998_s3>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <0 3312000 1050000 0>;
+ rgltr-max-voltage = <0 3600000 1050000 0>;
+ rgltr-load-current = <0 80000 105000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_active
+ &max_6dof_active>;
+ pinctrl-1 = <&cam_sensor_mclk1_suspend
+ &max_6dof_suspend>;
+ gpios = <&tlmm 14 0>,
+ <&tlmm 30 0>,
+ <&tlmm 95 0>,
+ <&tlmm 94 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-vdig = <3>;
+ gpio-req-tbl-num = <0 1 2 3 >;
+ gpio-req-tbl-flags = <1 0 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK3",
+ "CAM_RESET3",
+ "CAM_VANA3",
+ "CAM_VDIG3" ;
+ sensor-mode = <0>;
+ cci-master = <0>;
+ 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-qvr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr.dtsi
index 8ad5f3c..71566d0 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -71,6 +71,30 @@
pinctrl-0 = <&camera_dvdd_en_default>;
vin-supply = <&pm8998_s3>;
};
+
+ camera_eyetracking_force: gpio-regulator@3 {
+ compatible = "regulator-fixed";
+ reg = <0x03 0x00>;
+ regulator-name = "camera_eyetracking_force";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ regulator-enable-ramp-delay = <100>;
+ enable-active-high;
+ gpio = <&tlmm 77 0>;
+ vin-supply = <&pm8998_s3>;
+ };
+
+ camera_eyetracking_force_front: gpio-regulator@4 {
+ compatible = "regulator-fixed";
+ reg = <0x04 0x00>;
+ regulator-name = "camera_eyetracking_force_front";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ regulator-enable-ramp-delay = <100>;
+ enable-active-high;
+ gpio = <&tlmm 77 0>;
+ vin-supply = <&pm8998_lvs1>;
+ };
};
&cam_cci {
@@ -343,7 +367,7 @@
sensor-position-yaw = <0>;
eeprom-src = <&eeprom_front>;
cam_vdig-supply = <&camera_ldo>;
- cam_vio-supply = <&pm8998_lvs1>;
+ cam_vio-supply = <&camera_eyetracking_force_front>;
cam_vana-supply = <&pmi8998_bob>;
cam_clk-supply = <&titan_top_gdsc>;
regulator-names = "cam_vdig", "cam_vio", "cam_vana",
@@ -376,4 +400,187 @@
clock-cntl-level = "turbo";
clock-rates = <24000000>;
};
+
+ qcom,camera@3 {
+ cell-index = <3>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x3>;
+ csiphy-sd-index = <2>;
+ sensor-position-roll = <270>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <0>;
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ cam_vdig-supply = <&pm8998_s3>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <0 3312000 1050000 0>;
+ rgltr-max-voltage = <0 3600000 1050000 0>;
+ rgltr-load-current = <0 80000 105000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_active
+ &max_rst_active>;
+ pinctrl-1 = <&cam_sensor_mclk2_suspend
+ &max_rst_suspend>;
+ gpios = <&tlmm 15 0>,
+ <&tlmm 31 0>,
+ <&tlmm 77 0>,
+ <&tlmm 78 0>,
+ <&tlmm 32 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-custom1 = <3>;
+ gpio-custom2 = <4>;
+ gpio-req-tbl-num = <0 1 2 3 4>;
+ gpio-req-tbl-flags = <1 0 0 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_VANA2",
+ "CAM_CUSTOM1",
+ "CAM_CUSTOM2";
+ sensor-mode = <0>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ qcom,cam-sensor@5 {
+ cell-index = <5>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x05>;
+ csiphy-sd-index = <1>;
+ sensor-position-roll = <270>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <0>;
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ cam_vdig-supply = <&camera_eyetracking_force>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <0 3312000 1050000 0>;
+ rgltr-max-voltage = <0 3600000 1050000 0>;
+ rgltr-load-current = <0 80000 105000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_active
+ &cam_sensor_fisheye_active>;
+ pinctrl-1 = <&cam_sensor_mclk1_suspend
+ &cam_sensor_fisheye_suspend>;
+ gpios = <&tlmm 14 0>,
+ <&tlmm 76 0>,
+ <&tlmm 75 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-req-tbl-num = <0 1 2>;
+ gpio-req-tbl-flags = <1 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_VANA1";
+ sensor-mode = <0>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ qcom,cam-sensor@4 {
+ cell-index = <4>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x4>;
+ csiphy-sd-index = <1>;
+ sensor-position-roll = <270>; /* checked, MTP845 */
+ sensor-position-pitch = <0>; /* checked, MTP845 */
+ sensor-position-yaw = <180>; /* checked, MTP845 */
+ cam_vio-supply = <&pm8998_lvs1>; /* checked, MTP845 */
+ cam_vana-supply = <&pmi8998_bob>;
+ cam_vdig-supply = <&camera_eyetracking_force>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <0 3312000 1050000 0>;
+ rgltr-max-voltage = <0 3600000 1050000 0>;
+ rgltr-load-current = <0 80000 105000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_active
+ &cam_sensor_depth_active>;
+ pinctrl-1 = <&cam_sensor_mclk1_suspend
+ &cam_sensor_depth_suspend>;
+ gpios = <&tlmm 14 0>, //MCLK1
+ <&tlmm 28 0>, //RESET
+ <&tlmm 23 0>, //vana
+ <&tlmm 24 0>;
+ gpio-reset = <1>; //RESET
+ gpio-vana = <2>;
+ gpio-vdig = <3>;
+ gpio-req-tbl-num = <0 1 2 3> ;
+ gpio-req-tbl-flags = <1 0 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_VANA1",
+ "CAM_VDIG1";
+ sensor-mode = <0>; // 0 -> back camera 2D
+ cci-master = <1>; /* checked, MTP845 we are on I2C 0 */
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+
+ qcom,camera@6 {
+ cell-index = <6>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x6>;
+ csiphy-sd-index = <3>;
+ sensor-position-roll = <270>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <0>;
+ cam_vio-supply = <&pm8998_lvs1>;
+ cam_vana-supply = <&pmi8998_bob>;
+ cam_vdig-supply = <&pm8998_s3>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+ "cam_clk";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <0 3312000 1050000 0>;
+ rgltr-max-voltage = <0 3600000 1050000 0>;
+ rgltr-load-current = <0 80000 105000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk3_active
+ &max_6dof_active>;
+ pinctrl-1 = <&cam_sensor_mclk3_suspend
+ &max_6dof_suspend>;
+ gpios = <&tlmm 16 0>,
+ <&tlmm 30 0>,
+ <&tlmm 95 0>,
+ <&tlmm 94 0>;
+ gpio-reset = <1>;
+ gpio-vana = <2>;
+ gpio-vdig = <3>;
+ gpio-req-tbl-num = <0 1 2 3 >;
+ gpio-req-tbl-flags = <1 0 0 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK3",
+ "CAM_RESET3",
+ "CAM_VANA3",
+ "CAM_VDIG3" ;
+ sensor-mode = <0>;
+ cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK3_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index ec1e9c7..fd6a0c7 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -309,13 +309,23 @@
};
iova-mem-region-io {
- /* IO region is approximately 3.3 GB */
+ /* IO region is approximately 3 GB */
iova-region-name = "io";
- iova-region-start = <0xd900000>;
- iova-region-len = <0xd2700000>;
+ iova-region-start = <0xd911000>;
+ iova-region-len = <0xd26ef000>;
iova-region-id = <0x3>;
status = "ok";
};
+
+ iova-mem-qdss-region {
+ /* qdss region is approximately 64K */
+ iova-region-name = "qdss";
+ iova-region-start = <0xd900000>;
+ iova-region-len = <0x10000>;
+ iova-region-id = <0x5>;
+ qdss-phy-addr = <0x16790000>;
+ status = "ok";
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index 000f5d3..e8f85a9 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -83,10 +83,11 @@
<&clock_gpucc GPU_CC_CXO_CLK>,
<&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
<&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>,
- <&clock_gpucc GPU_CC_CX_GMU_CLK>;
+ <&clock_gpucc GPU_CC_CX_GMU_CLK>,
+ <&clock_cpucc L3_GPU_VOTE_CLK>;
clock-names = "core_clk", "rbbmtimer_clk", "mem_clk",
- "mem_iface_clk", "gmu_clk";
+ "mem_iface_clk", "gmu_clk", "l3_vote";
qcom,isense-clk-on-level = <1>;
@@ -155,6 +156,28 @@
};
};
+ qcom,l3-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,l3-pwrlevels";
+
+ qcom,l3-pwrlevel@0 {
+ reg = <0>;
+ qcom,l3-freq = <0>;
+ };
+
+ qcom,l3-pwrlevel@1 {
+ reg = <1>;
+ qcom,l3-freq = <806400000>;
+ };
+
+ qcom,l3-pwrlevel@2 {
+ reg = <2>;
+ qcom,l3-freq = <1305600000>;
+ };
+ };
+
/* GPU Mempools */
qcom,gpu-mempools {
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index 5aaef8d..019607c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -2993,6 +2993,119 @@
};
};
+ cam_sensor_fisheye_active: cam_sensor_fisheye_active {
+ /* RESET, AVDD LO */
+ mux {
+ pins = "gpio76","gpio75";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio76","gpio75";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_fisheye_suspend: cam_sensor_fisheye_suspend {
+ /* RESET, AVDD LO*/
+ mux {
+ pins = "gpio76","gpio75";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio76","gpio75";
+ bias-pull-down; /* PULL DOWN */
+ drive-strength = <2>; /* 2 MA */
+ output-low;
+ };
+ };
+
+ cam_sensor_depth_active: cam_sensor_depth_active {
+ /* RESET,AVDD LO ,IMG_START, ILLU_EN */
+ mux {
+ pins = "gpio28","gpio23","gpio24";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio28","gpio23","gpio24";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_depth_suspend: cam_sensor_depth_suspend {
+ /* RESET, AVDD LO ,IMG_START, ILLU_EN */
+ mux {
+ pins = "gpio28","gpio23","gpio24";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio28","gpio23","gpio24";
+ bias-pull-down; /* PULL DOWN */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ max_rst_active: max_rst_active {
+ /* RESET */
+ mux {
+ pins = "gpio31","gpio77","gpio78","gpio32";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio31","gpio77","gpio78","gpio32";
+ bias-disable; /* No PULL */
+ drive-strength = <8>; /* 2 MA */
+ };
+ };
+
+ max_rst_suspend: max_rst_suspend {
+ /* RESET */
+ mux {
+ pins = "gpio31","gpio77","gpio78","gpio32";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio31","gpio77","gpio78","gpio32";
+ bias-pull-down; /* PULL DOWN */
+ drive-strength = <8>; /* 2 MA */
+ };
+ };
+
+ max_6dof_active: max_6dof_active {
+ /* RESET */
+ mux {
+ pins = "gpio30","gpio95","gpio94";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio30","gpio95","gpio94";
+ bias-disable; /* No PULL */
+ drive-strength = <8>; /* 2 MA */
+ };
+ };
+
+ max_6dof_suspend: max_6dof_suspend {
+ /* RESET */
+ mux {
+ pins = "gpio30","gpio95","gpio94";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio30","gpio95","gpio94";
+ bias-pull-down; /* PULL DOWN */
+ drive-strength = <8>; /* 2 MA */
+ };
+ };
+
cam_sensor_mclk0_active: cam_sensor_mclk0_active {
/* MCLK0 */
mux {
@@ -3159,7 +3272,7 @@
config {
pins = "gpio9";
- bias-disable; /* No PULL */
+ bias-pull-down; /* PULL DOWN */
drive-strength = <2>; /* 2 MA */
output-low;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 8b67649..8d4d7df 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -536,6 +536,11 @@
&dsi_dual_nt35597_truly_video {
qcom,mdss-dsi-t-clk-post = <0x0D>;
qcom,mdss-dsi-t-clk-pre = <0x2D>;
+ qcom,mdss-dsi-min-refresh-rate = <53>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update =
+ "dfps_immediate_porch_mode_vfp";
qcom,esd-check-enabled;
qcom,mdss-dsi-panel-status-check-mode = "reg_read";
qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
@@ -601,6 +606,11 @@
&dsi_nt35597_truly_dsc_video {
qcom,mdss-dsi-t-clk-post = <0x0b>;
qcom,mdss-dsi-t-clk-pre = <0x23>;
+ qcom,mdss-dsi-min-refresh-rate = <53>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update =
+ "dfps_immediate_porch_mode_vfp";
qcom,esd-check-enabled;
qcom,mdss-dsi-panel-status-check-mode = "reg_read";
qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
index 05d77d3..85419c8 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -161,9 +161,7 @@
msm_cam_smmu_lrme {
compatible = "qcom,msm-cam-smmu-cb";
iommus = <&apps_smmu 0x1038 0x0>,
- <&apps_smmu 0x1058 0x0>,
- <&apps_smmu 0x1039 0x0>,
- <&apps_smmu 0x1059 0x0>;
+ <&apps_smmu 0x1058 0x0>;
label = "lrme";
lrme_iova_mem_map: iova-mem-map {
iova-mem-region-shared {
@@ -248,13 +246,23 @@
};
iova-mem-region-io {
- /* IO region is approximately 3.3 GB */
+ /* IO region is approximately 3 GB */
iova-region-name = "io";
- iova-region-start = <0xd900000>;
- iova-region-len = <0xd2700000>;
+ iova-region-start = <0xd911000>;
+ iova-region-len = <0xd26ef000>;
iova-region-id = <0x3>;
status = "ok";
};
+
+ iova-mem-qdss-region {
+ /* qdss region is approximately 64K */
+ iova-region-name = "qdss";
+ iova-region-start = <0xd900000>;
+ iova-region-len = <0x10000>;
+ iova-region-id = <0x5>;
+ qdss-phy-addr = <0x16790000>;
+ status = "ok";
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dtsi
index c629c53..7dd7017 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dtsi
@@ -11,5 +11,5 @@
*/
#include "sdm845-qvr.dtsi"
#include "sdm845-sde-display.dtsi"
-#include "sdm845-camera-sensor-qvr.dtsi"
+#include "sdm845-camera-sensor-qvr-dvt.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 1551952..575cf12 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -430,7 +430,7 @@
1766400 160
>;
idle-cost-data = <
- 22 18 14 12
+ 10 8 6 4
>;
};
CPU_COST_1: core-cost1 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index f158f07..aa16a77 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -87,7 +87,7 @@
qcom,dump-size = <0xa000>;
};
L1_TLB_0: l1-tlb {
- qcom,dump-size = <0x3000>;
+ qcom,dump-size = <0x6000>;
};
};
@@ -118,7 +118,7 @@
qcom,dump-size = <0xa000>;
};
L1_TLB_100: l1-tlb {
- qcom,dump-size = <0x3000>;
+ qcom,dump-size = <0x6000>;
};
};
@@ -149,7 +149,7 @@
qcom,dump-size = <0xa000>;
};
L1_TLB_200: l1-tlb {
- qcom,dump-size = <0x3000>;
+ qcom,dump-size = <0x6000>;
};
};
@@ -180,7 +180,7 @@
qcom,dump-size = <0xa000>;
};
L1_TLB_300: l1-tlb {
- qcom,dump-size = <0x3000>;
+ qcom,dump-size = <0x6000>;
};
};
@@ -211,7 +211,7 @@
qcom,dump-size = <0x14000>;
};
L1_TLB_400: l1-tlb {
- qcom,dump-size = <0x3c00>;
+ qcom,dump-size = <0x6800>;
};
};
@@ -242,7 +242,7 @@
qcom,dump-size = <0x14000>;
};
L1_TLB_500: l1-tlb {
- qcom,dump-size = <0x3c00>;
+ qcom,dump-size = <0x6800>;
};
};
@@ -273,7 +273,7 @@
qcom,dump-size = <0x14000>;
};
L1_TLB_600: l1-tlb {
- qcom,dump-size = <0x3c00>;
+ qcom,dump-size = <0x6800>;
};
};
@@ -304,7 +304,7 @@
qcom,dump-size = <0x14000>;
};
L1_TLB_700: l1-tlb {
- qcom,dump-size = <0x3c00>;
+ qcom,dump-size = <0x6800>;
};
};
@@ -1267,7 +1267,7 @@
vdd_pwrcl_mx_ao-supply = <&pm8998_s6_level_ao>;
qcom,mx-turbo-freq = <1478400000 1689600000 3300000001>;
- l3-devs = <&l3_cpu0 &l3_cpu4 &l3_cdsp>;
+ l3-devs = <&l3_cpu0 &l3_cpu4 &l3_cdsp &msm_gpu>;
clock-names = "xo_ao";
clocks = <&clock_rpmh RPMH_CXO_CLK_A>;
@@ -2045,35 +2045,35 @@
};
qcom,l1_tlb_dump0 {
qcom,dump-node = <&L1_TLB_0>;
- qcom,dump-id = <0x20>;
+ qcom,dump-id = <0x120>;
};
qcom,l1_tlb_dump100 {
qcom,dump-node = <&L1_TLB_100>;
- qcom,dump-id = <0x21>;
+ qcom,dump-id = <0x121>;
};
qcom,l1_tlb_dump200 {
qcom,dump-node = <&L1_TLB_200>;
- qcom,dump-id = <0x22>;
+ qcom,dump-id = <0x122>;
};
qcom,l1_tlb_dump300 {
qcom,dump-node = <&L1_TLB_300>;
- qcom,dump-id = <0x23>;
+ qcom,dump-id = <0x123>;
};
qcom,l1_tlb_dump400 {
qcom,dump-node = <&L1_TLB_400>;
- qcom,dump-id = <0x24>;
+ qcom,dump-id = <0x124>;
};
qcom,l1_tlb_dump500 {
qcom,dump-node = <&L1_TLB_500>;
- qcom,dump-id = <0x25>;
+ qcom,dump-id = <0x125>;
};
qcom,l1_tlb_dump600 {
qcom,dump-node = <&L1_TLB_600>;
- qcom,dump-id = <0x26>;
+ qcom,dump-id = <0x126>;
};
qcom,l1_tlb_dump700 {
qcom,dump-node = <&L1_TLB_700>;
- qcom,dump-id = <0x27>;
+ qcom,dump-id = <0x127>;
};
};
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index 2b01389..f5410c1 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -65,6 +65,7 @@
CONFIG_ZSMALLOC=y
CONFIG_BALANCE_ANON_FILE_RECLAIM=y
CONFIG_SECCOMP=y
+CONFIG_HARDEN_BRANCH_PREDICTOR=y
CONFIG_ARMV8_DEPRECATED=y
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
@@ -277,6 +278,7 @@
CONFIG_PPPOPNS=y
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_USBNET=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_CLD_LL_CORE=y
CONFIG_INPUT_EVDEV=y
@@ -291,8 +293,6 @@
# CONFIG_SERIO_SERPORT is not set
# CONFIG_VT is not set
# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM=y
-CONFIG_SERIAL_MSM_CONSOLE=y
CONFIG_SERIAL_MSM_HS=y
CONFIG_SERIAL_MSM_SMD=y
CONFIG_DIAG_CHAR=y
@@ -312,6 +312,7 @@
CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
CONFIG_PINCTRL_MSM8953=y
CONFIG_PINCTRL_MSM8937=y
+CONFIG_PINCTRL_MSM8917=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
@@ -342,6 +343,8 @@
CONFIG_QTI_VIRTUAL_SENSOR=y
CONFIG_QTI_QMI_COOLING_DEVICE=y
CONFIG_REGULATOR_COOLING_DEVICE=y
+CONFIG_QTI_BCL_PMIC5=y
+CONFIG_QTI_BCL_SOC_DRIVER=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_CPR=y
@@ -423,6 +426,7 @@
CONFIG_USB_MON=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
@@ -451,10 +455,12 @@
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_DEBUG_FS=y
CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CI13XXX_MSM=y
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_SERIAL=y
CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RNDIS=y
CONFIG_USB_CONFIGFS_RMNET_BAM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
@@ -463,9 +469,11 @@
CONFIG_USB_CONFIGFS_F_ACC=y
CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_DIAG=y
CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
@@ -479,12 +487,15 @@
CONFIG_MMC_SDHCI_MSM=y
CONFIG_MMC_SDHCI_MSM_ICE=y
CONFIG_MMC_CQ_HCI=y
+CONFIG_LEDS_QTI_TRI_LED=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_QPNP_FLASH=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
CONFIG_LEDS_QPNP_WLED=y
CONFIG_LEDS_QPNP_HAPTICS=y
CONFIG_LEDS_QPNP_VIBRATOR_LDO=y
CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_EDAC=y
CONFIG_EDAC_MM_EDAC=y
CONFIG_RTC_CLASS=y
@@ -511,6 +522,7 @@
CONFIG_MAILBOX=y
CONFIG_ARM_SMMU=y
CONFIG_QCOM_LAZY_MAPPING=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
CONFIG_MSM_SPM=y
CONFIG_MSM_L2_SPM=y
CONFIG_MSM_BOOT_STATS=y
@@ -535,23 +547,33 @@
CONFIG_ICNSS=y
CONFIG_MSM_PERFORMANCE=y
CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_AVTIMER=y
CONFIG_MSM_PM=y
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_MEM_SHARE_QMI_SERVICE=y
+CONFIG_MSM_BAM_DMUX=y
CONFIG_WCNSS_CORE=y
CONFIG_WCNSS_CORE_PRONTO=y
CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
CONFIG_QCOM_DEVFREQ_DEVBW=y
CONFIG_SPDM_SCM=y
CONFIG_DEVFREQ_SPDM=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
+CONFIG_PWM_QTI_LPG=y
CONFIG_ARM_GIC_V3_ACL=y
+CONFIG_QTI_MPM=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_SENSORS_SSC=y
CONFIG_MSM_TZ_LOG=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V2=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index f95beaa..b9d1c38 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -71,6 +71,7 @@
CONFIG_ZSMALLOC=y
CONFIG_BALANCE_ANON_FILE_RECLAIM=y
CONFIG_SECCOMP=y
+CONFIG_HARDEN_BRANCH_PREDICTOR=y
CONFIG_ARMV8_DEPRECATED=y
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
@@ -287,6 +288,7 @@
CONFIG_PPPOPNS=y
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_USBNET=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_CLD_LL_CORE=y
CONFIG_INPUT_EVDEV=y
@@ -322,6 +324,7 @@
CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
CONFIG_PINCTRL_MSM8953=y
CONFIG_PINCTRL_MSM8937=y
+CONFIG_PINCTRL_MSM8917=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
@@ -352,6 +355,8 @@
CONFIG_QTI_VIRTUAL_SENSOR=y
CONFIG_QTI_QMI_COOLING_DEVICE=y
CONFIG_REGULATOR_COOLING_DEVICE=y
+CONFIG_QTI_BCL_PMIC5=y
+CONFIG_QTI_BCL_SOC_DRIVER=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_CPR=y
@@ -434,6 +439,7 @@
CONFIG_USB_MON=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
@@ -462,10 +468,12 @@
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_DEBUG_FS=y
CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CI13XXX_MSM=y
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_SERIAL=y
CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RNDIS=y
CONFIG_USB_CONFIGFS_RMNET_BAM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
@@ -474,9 +482,11 @@
CONFIG_USB_CONFIGFS_F_ACC=y
CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_DIAG=y
CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
@@ -491,12 +501,15 @@
CONFIG_MMC_SDHCI_MSM=y
CONFIG_MMC_SDHCI_MSM_ICE=y
CONFIG_MMC_CQ_HCI=y
+CONFIG_LEDS_QTI_TRI_LED=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_QPNP_FLASH=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
CONFIG_LEDS_QPNP_WLED=y
CONFIG_LEDS_QPNP_HAPTICS=y
CONFIG_LEDS_QPNP_VIBRATOR_LDO=y
CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_EDAC=y
CONFIG_EDAC_MM_EDAC=y
CONFIG_RTC_CLASS=y
@@ -526,6 +539,7 @@
CONFIG_IOMMU_DEBUG=y
CONFIG_IOMMU_DEBUG_TRACKING=y
CONFIG_IOMMU_TESTS=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
CONFIG_MSM_SPM=y
CONFIG_MSM_L2_SPM=y
CONFIG_MSM_BOOT_STATS=y
@@ -553,20 +567,27 @@
CONFIG_ICNSS=y
CONFIG_MSM_PERFORMANCE=y
CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_AVTIMER=y
CONFIG_MSM_PM=y
CONFIG_QCOM_DCC=y
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_MEM_SHARE_QMI_SERVICE=y
+CONFIG_MSM_BAM_DMUX=y
CONFIG_WCNSS_CORE=y
CONFIG_WCNSS_CORE_PRONTO=y
CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_DEVFREQ_SIMPLE_DEV=y
CONFIG_QCOM_DEVFREQ_DEVBW=y
CONFIG_SPDM_SCM=y
CONFIG_DEVFREQ_SPDM=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
+CONFIG_PWM_QTI_LPG=y
CONFIG_ARM_GIC_V3_ACL=y
+CONFIG_QTI_MPM=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_SENSORS_SSC=y
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
index 83b0d66..c2a9aa5 100644
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -378,6 +378,7 @@
CONFIG_DRM=y
CONFIG_DRM_SDE_EVTLOG_DEBUG=y
CONFIG_DRM_SDE_RSC=y
+CONFIG_DRM_LT_LT9611=y
CONFIG_FB_VIRTUAL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -572,8 +573,6 @@
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_EXT4_ENCRYPTION=y
-CONFIG_EXT4_FS_ENCRYPTION=y
-CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V2=y
@@ -605,7 +604,6 @@
CONFIG_CORESIGHT_EVENT=y
CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_DUMMY=y
-CONFIG_PFK=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 0e8ef8f..961864b 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -466,7 +466,6 @@
CONFIG_EDAC=y
CONFIG_EDAC_MM_EDAC=y
CONFIG_EDAC_KRYO3XX_ARM64=y
-CONFIG_EDAC_KRYO3XX_ARM64_PANIC_ON_CE=y
CONFIG_EDAC_KRYO3XX_ARM64_PANIC_ON_UE=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_QPNP=y
@@ -592,8 +591,6 @@
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_EXT4_ENCRYPTION=y
-CONFIG_EXT4_FS_ENCRYPTION=y
-CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V2=y
@@ -671,7 +668,6 @@
CONFIG_CORESIGHT_TGU=y
CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_DUMMY=y
-CONFIG_PFK=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index c154576..b8f98df 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -248,13 +248,11 @@
CONFIG_CHR_DEV_SG=y
CONFIG_CHR_DEV_SCH=y
CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_SCSI_UFSHCD=y
CONFIG_SCSI_UFSHCD_PLATFORM=y
CONFIG_SCSI_UFS_QCOM=y
CONFIG_SCSI_UFS_QCOM_ICE=y
-CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
CONFIG_MD=y
CONFIG_BLK_DEV_DM=y
CONFIG_DM_DEBUG=y
@@ -572,8 +570,6 @@
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_EXT4_ENCRYPTION=y
-CONFIG_EXT4_FS_ENCRYPTION=y
-CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_F2FS_FS=y
CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
@@ -607,13 +603,13 @@
CONFIG_CORESIGHT_EVENT=y
CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_DUMMY=y
-CONFIG_PFK=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_FORTIFY_SOURCE=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_GCM=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 0b0d26d..7868efe 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -590,8 +590,6 @@
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_EXT4_ENCRYPTION=y
-CONFIG_EXT4_FS_ENCRYPTION=y
-CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_F2FS_FS=y
CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
@@ -673,13 +671,13 @@
CONFIG_CORESIGHT_TGU=y
CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_DUMMY=y
-CONFIG_PFK=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_FORTIFY_SOURCE=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_GCM=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/crypto/crc32-arm64.c b/arch/arm64/crypto/crc32-arm64.c
index 6a37c3c..3ec568a 100644
--- a/arch/arm64/crypto/crc32-arm64.c
+++ b/arch/arm64/crypto/crc32-arm64.c
@@ -232,6 +232,7 @@
.cra_name = "crc32",
.cra_driver_name = "crc32-arm64-hw",
.cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
.cra_blocksize = CHKSUM_BLOCK_SIZE,
.cra_alignmask = 0,
.cra_ctxsize = sizeof(struct chksum_ctx),
@@ -253,6 +254,7 @@
.cra_name = "crc32c",
.cra_driver_name = "crc32c-arm64-hw",
.cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
.cra_blocksize = CHKSUM_BLOCK_SIZE,
.cra_alignmask = 0,
.cra_ctxsize = sizeof(struct chksum_ctx),
diff --git a/arch/arm64/crypto/sha1-ce-core.S b/arch/arm64/crypto/sha1-ce-core.S
index c98e7e8..8550408 100644
--- a/arch/arm64/crypto/sha1-ce-core.S
+++ b/arch/arm64/crypto/sha1-ce-core.S
@@ -82,7 +82,8 @@
ldr dgb, [x0, #16]
/* load sha1_ce_state::finalize */
- ldr w4, [x0, #:lo12:sha1_ce_offsetof_finalize]
+ ldr_l w4, sha1_ce_offsetof_finalize, x4
+ ldr w4, [x0, x4]
/* load input */
0: ld1 {v8.4s-v11.4s}, [x1], #64
@@ -132,7 +133,8 @@
* the padding is handled by the C code in that case.
*/
cbz x4, 3f
- ldr x4, [x0, #:lo12:sha1_ce_offsetof_count]
+ ldr_l w4, sha1_ce_offsetof_count, x4
+ ldr x4, [x0, x4]
movi v9.2d, #0
mov x8, #0x80000000
movi v10.2d, #0
diff --git a/arch/arm64/crypto/sha1-ce-glue.c b/arch/arm64/crypto/sha1-ce-glue.c
index aefda98..ea319c0 100644
--- a/arch/arm64/crypto/sha1-ce-glue.c
+++ b/arch/arm64/crypto/sha1-ce-glue.c
@@ -17,9 +17,6 @@
#include <linux/crypto.h>
#include <linux/module.h>
-#define ASM_EXPORT(sym, val) \
- asm(".globl " #sym "; .set " #sym ", %0" :: "I"(val));
-
MODULE_DESCRIPTION("SHA1 secure hash using ARMv8 Crypto Extensions");
MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
MODULE_LICENSE("GPL v2");
@@ -32,6 +29,9 @@
asmlinkage void sha1_ce_transform(struct sha1_ce_state *sst, u8 const *src,
int blocks);
+const u32 sha1_ce_offsetof_count = offsetof(struct sha1_ce_state, sst.count);
+const u32 sha1_ce_offsetof_finalize = offsetof(struct sha1_ce_state, finalize);
+
static int sha1_ce_update(struct shash_desc *desc, const u8 *data,
unsigned int len)
{
@@ -52,11 +52,6 @@
struct sha1_ce_state *sctx = shash_desc_ctx(desc);
bool finalize = !sctx->sst.count && !(len % SHA1_BLOCK_SIZE);
- ASM_EXPORT(sha1_ce_offsetof_count,
- offsetof(struct sha1_ce_state, sst.count));
- ASM_EXPORT(sha1_ce_offsetof_finalize,
- offsetof(struct sha1_ce_state, finalize));
-
/*
* Allow the asm code to perform the finalization if there is no
* partial data and the input is a round multiple of the block size.
diff --git a/arch/arm64/crypto/sha2-ce-core.S b/arch/arm64/crypto/sha2-ce-core.S
index 01cfee0..679c6c0 100644
--- a/arch/arm64/crypto/sha2-ce-core.S
+++ b/arch/arm64/crypto/sha2-ce-core.S
@@ -88,7 +88,8 @@
ld1 {dgav.4s, dgbv.4s}, [x0]
/* load sha256_ce_state::finalize */
- ldr w4, [x0, #:lo12:sha256_ce_offsetof_finalize]
+ ldr_l w4, sha256_ce_offsetof_finalize, x4
+ ldr w4, [x0, x4]
/* load input */
0: ld1 {v16.4s-v19.4s}, [x1], #64
@@ -136,7 +137,8 @@
* the padding is handled by the C code in that case.
*/
cbz x4, 3f
- ldr x4, [x0, #:lo12:sha256_ce_offsetof_count]
+ ldr_l w4, sha256_ce_offsetof_count, x4
+ ldr x4, [x0, x4]
movi v17.2d, #0
mov x8, #0x80000000
movi v18.2d, #0
diff --git a/arch/arm64/crypto/sha2-ce-glue.c b/arch/arm64/crypto/sha2-ce-glue.c
index 7cd5875..0ed9486 100644
--- a/arch/arm64/crypto/sha2-ce-glue.c
+++ b/arch/arm64/crypto/sha2-ce-glue.c
@@ -17,9 +17,6 @@
#include <linux/crypto.h>
#include <linux/module.h>
-#define ASM_EXPORT(sym, val) \
- asm(".globl " #sym "; .set " #sym ", %0" :: "I"(val));
-
MODULE_DESCRIPTION("SHA-224/SHA-256 secure hash using ARMv8 Crypto Extensions");
MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
MODULE_LICENSE("GPL v2");
@@ -32,6 +29,11 @@
asmlinkage void sha2_ce_transform(struct sha256_ce_state *sst, u8 const *src,
int blocks);
+const u32 sha256_ce_offsetof_count = offsetof(struct sha256_ce_state,
+ sst.count);
+const u32 sha256_ce_offsetof_finalize = offsetof(struct sha256_ce_state,
+ finalize);
+
static int sha256_ce_update(struct shash_desc *desc, const u8 *data,
unsigned int len)
{
@@ -52,11 +54,6 @@
struct sha256_ce_state *sctx = shash_desc_ctx(desc);
bool finalize = !sctx->sst.count && !(len % SHA256_BLOCK_SIZE);
- ASM_EXPORT(sha256_ce_offsetof_count,
- offsetof(struct sha256_ce_state, sst.count));
- ASM_EXPORT(sha256_ce_offsetof_finalize,
- offsetof(struct sha256_ce_state, finalize));
-
/*
* Allow the asm code to perform the finalization if there is no
* partial data and the input is a round multiple of the block size.
diff --git a/arch/arm64/include/asm/bug.h b/arch/arm64/include/asm/bug.h
index 561190d..0bfe1df1 100644
--- a/arch/arm64/include/asm/bug.h
+++ b/arch/arm64/include/asm/bug.h
@@ -20,9 +20,6 @@
#include <asm/brk-imm.h>
-#ifdef CONFIG_GENERIC_BUG
-#define HAVE_ARCH_BUG
-
#ifdef CONFIG_DEBUG_BUGVERBOSE
#define _BUGVERBOSE_LOCATION(file, line) __BUGVERBOSE_LOCATION(file, line)
#define __BUGVERBOSE_LOCATION(file, line) \
@@ -36,28 +33,36 @@
#define _BUGVERBOSE_LOCATION(file, line)
#endif
-#define _BUG_FLAGS(flags) __BUG_FLAGS(flags)
+#ifdef CONFIG_GENERIC_BUG
-#define __BUG_FLAGS(flags) asm volatile ( \
+#define __BUG_ENTRY(flags) \
".pushsection __bug_table,\"a\"\n\t" \
".align 2\n\t" \
"0: .long 1f - 0b\n\t" \
_BUGVERBOSE_LOCATION(__FILE__, __LINE__) \
".short " #flags "\n\t" \
".popsection\n" \
- \
- "1: brk %[imm]" \
- :: [imm] "i" (BUG_BRK_IMM) \
-)
+ "1: "
+#else
+#define __BUG_ENTRY(flags) ""
+#endif
-#define BUG() do { \
- _BUG_FLAGS(0); \
- unreachable(); \
+#define __BUG_FLAGS(flags) \
+ asm volatile ( \
+ __BUG_ENTRY(flags) \
+ "brk %[imm]" :: [imm] "i" (BUG_BRK_IMM) \
+ );
+
+
+#define BUG() do { \
+ __BUG_FLAGS(0); \
+ unreachable(); \
} while (0)
-#define __WARN_TAINT(taint) _BUG_FLAGS(BUGFLAG_TAINT(taint))
+#define __WARN_TAINT(taint) \
+ __BUG_FLAGS(BUGFLAG_TAINT(taint))
-#endif /* ! CONFIG_GENERIC_BUG */
+#define HAVE_ARCH_BUG
#include <asm-generic/bug.h>
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index c088c4f..847bfe6 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -85,6 +85,8 @@
#define ARM_CPU_PART_KRYO3S 0x803
#define ARM_CPU_PART_KRYO3G 0x802
#define ARM_CPU_PART_CORTEX_A55 0xD05
+#define ARM_CPU_PART_KRYO2XX_GOLD 0x800
+#define ARM_CPU_PART_KRYO2XX_SILVER 0x801
#define APM_CPU_PART_POTENZA 0x000
@@ -103,6 +105,8 @@
#define MIDR_CORTEX_A55 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A55)
#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
+#define MIDR_KRYO2XX_GOLD \
+ MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO2XX_GOLD)
#ifndef __ASSEMBLY__
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index ea06f3f..a5df094 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -55,6 +55,9 @@
#define alloc_screen_info(x...) &screen_info
#define free_screen_info(x...)
+/* redeclare as 'hidden' so the compiler will generate relative references */
+extern struct screen_info screen_info __attribute__((__visibility__("hidden")));
+
static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
{
}
diff --git a/arch/arm64/include/asm/signal32.h b/arch/arm64/include/asm/signal32.h
index eeaa975..81abea0 100644
--- a/arch/arm64/include/asm/signal32.h
+++ b/arch/arm64/include/asm/signal32.h
@@ -22,8 +22,6 @@
#define AARCH32_KERN_SIGRET_CODE_OFFSET 0x500
-extern const compat_ulong_t aarch32_sigret_code[6];
-
int compat_setup_frame(int usig, struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs);
int compat_setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
index b58f429..866c518 100644
--- a/arch/arm64/include/asm/topology.h
+++ b/arch/arm64/include/asm/topology.h
@@ -36,7 +36,10 @@
#ifdef CONFIG_CPU_FREQ
#define arch_scale_freq_capacity cpufreq_scale_freq_capacity
extern unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu);
-extern unsigned long cpufreq_scale_max_freq_capacity(int cpu);
+#define arch_scale_max_freq_capacity cpufreq_scale_max_freq_capacity
+extern unsigned long cpufreq_scale_max_freq_capacity(struct sched_domain *sd, int cpu);
+#define arch_scale_min_freq_capacity cpufreq_scale_min_freq_capacity
+extern unsigned long cpufreq_scale_min_freq_capacity(struct sched_domain *sd, int cpu);
#endif
#define arch_scale_cpu_capacity scale_cpu_capacity
extern unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu);
diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h
index 02e9035..47a9066 100644
--- a/arch/arm64/include/asm/traps.h
+++ b/arch/arm64/include/asm/traps.h
@@ -37,18 +37,11 @@
void arm64_notify_segfault(struct pt_regs *regs, unsigned long addr);
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
static inline int __in_irqentry_text(unsigned long ptr)
{
return ptr >= (unsigned long)&__irqentry_text_start &&
ptr < (unsigned long)&__irqentry_text_end;
}
-#else
-static inline int __in_irqentry_text(unsigned long ptr)
-{
- return 0;
-}
-#endif
static inline int in_exception_text(unsigned long ptr)
{
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index c7b3ba68..7c8e185 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -260,6 +260,11 @@
MIDR_ALL_VERSIONS(MIDR_KRYO3G),
.enable = enable_psci_bp_hardening,
},
+ {
+ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
+ MIDR_ALL_VERSIONS(MIDR_KRYO2XX_GOLD),
+ .enable = enable_psci_bp_hardening,
+ },
#endif
{
}
diff --git a/arch/arm64/kernel/io.c b/arch/arm64/kernel/io.c
index b08c4eb..9b36267 100644
--- a/arch/arm64/kernel/io.c
+++ b/arch/arm64/kernel/io.c
@@ -25,8 +25,7 @@
*/
void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
{
- while (count && (!IS_ALIGNED((unsigned long)from, 8) ||
- !IS_ALIGNED((unsigned long)to, 8))) {
+ while (count && !IS_ALIGNED((unsigned long)from, 8)) {
*(u8 *)to = __raw_readb_no_log(from);
from++;
to++;
@@ -54,23 +53,22 @@
*/
void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
{
- while (count && (!IS_ALIGNED((unsigned long)to, 8) ||
- !IS_ALIGNED((unsigned long)from, 8))) {
- __raw_writeb_no_log(*(volatile u8 *)from, to);
+ while (count && !IS_ALIGNED((unsigned long)to, 8)) {
+ __raw_writeb_no_log(*(u8 *)from, to);
from++;
to++;
count--;
}
while (count >= 8) {
- __raw_writeq_no_log(*(volatile u64 *)from, to);
+ __raw_writeq_no_log(*(u64 *)from, to);
from += 8;
to += 8;
count -= 8;
}
while (count) {
- __raw_writeb_no_log(*(volatile u8 *)from, to);
+ __raw_writeb_no_log(*(u8 *)from, to);
from++;
to++;
count--;
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index f58539f..b46ac33 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -319,7 +319,7 @@
* faults in case uaccess_enable() is inadvertently called by the init
* thread.
*/
- init_task.thread_info.ttbr0 = virt_to_phys(empty_zero_page);
+ init_task.thread_info.ttbr0 = __pa_symbol(empty_zero_page);
#endif
#ifdef CONFIG_VT
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index f2fe96f..e3bc878 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -50,13 +50,7 @@
unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu)
{
-#ifdef CONFIG_CPU_FREQ
- unsigned long max_freq_scale = cpufreq_scale_max_freq_capacity(cpu);
-
- return per_cpu(cpu_scale, cpu) * max_freq_scale >> SCHED_CAPACITY_SHIFT;
-#else
return per_cpu(cpu_scale, cpu);
-#endif
}
static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index ef3bdfd..e8f759f 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -220,10 +220,8 @@
if (!use_syscall) {
/* tkr_mono.cycle_last == tkr_raw.cycle_last */
vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last;
- vdso_data->raw_time_sec = tk->raw_time.tv_sec;
- vdso_data->raw_time_nsec = (tk->raw_time.tv_nsec <<
- tk->tkr_raw.shift) +
- tk->tkr_raw.xtime_nsec;
+ vdso_data->raw_time_sec = tk->raw_sec;
+ vdso_data->raw_time_nsec = tk->tkr_raw.xtime_nsec;
vdso_data->xtime_clock_sec = tk->xtime_sec;
vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec;
vdso_data->cs_mono_mult = tk->tkr_mono.mult;
diff --git a/arch/arm64/kernel/vdso/gettimeofday.S b/arch/arm64/kernel/vdso/gettimeofday.S
index 76320e9..c39872a 100644
--- a/arch/arm64/kernel/vdso/gettimeofday.S
+++ b/arch/arm64/kernel/vdso/gettimeofday.S
@@ -309,7 +309,7 @@
b.ne 4f
ldr x2, 6f
2:
- cbz w1, 3f
+ cbz x1, 3f
stp xzr, x2, [x1]
3: /* res == NULL. */
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
index da5add9..c841cce 100644
--- a/arch/arm64/mm/context.c
+++ b/arch/arm64/mm/context.c
@@ -230,6 +230,9 @@
raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
switch_mm_fastpath:
+
+ arm64_apply_bp_hardening();
+
/*
* Defer TTBR0_EL1 setting for user threads to uaccess_enable() when
* emulating PAN.
@@ -245,8 +248,6 @@
"ic iallu; dsb nsh; isb",
ARM64_WORKAROUND_CAVIUM_27456,
CONFIG_CAVIUM_ERRATUM_27456));
-
- arm64_apply_bp_hardening();
}
static int asids_init(void)
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index c66fa93..b4e526d 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -549,7 +549,7 @@
* To do this we need to go via a temporary pgd.
*/
cpu_replace_ttbr1(__va(pgd_phys));
- memcpy(swapper_pg_dir, pgd, PAGE_SIZE);
+ memcpy(swapper_pg_dir, pgd, PGD_SIZE);
cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
pgd_clear_fixmap();
@@ -823,6 +823,10 @@
int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot)
{
+ /* ioremap_page_range doesn't honour BBM */
+ if (pud_present(READ_ONCE(*pud)))
+ return 0;
+
BUG_ON(phys & ~PUD_MASK);
set_pud(pud, __pud(phys | PUD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))));
return 1;
@@ -830,6 +834,10 @@
int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot)
{
+ /* ioremap_page_range doesn't honour BBM */
+ if (pmd_present(READ_ONCE(*pmd)))
+ return 0;
+
BUG_ON(phys & ~PMD_MASK);
set_pmd(pmd, __pmd(phys | PMD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))));
return 1;
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 3686d6a..9edda54 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -50,32 +50,10 @@
# The gate DSO image is built using a special linker script.
include $(src)/Makefile.gate
-# Calculate NR_IRQ = max(IA64_NATIVE_NR_IRQS, XEN_NR_IRQS, ...) based on config
-define sed-y
- "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"
-endef
-quiet_cmd_nr_irqs = GEN $@
-define cmd_nr_irqs
- (set -e; \
- echo "#ifndef __ASM_NR_IRQS_H__"; \
- echo "#define __ASM_NR_IRQS_H__"; \
- echo "/*"; \
- echo " * DO NOT MODIFY."; \
- echo " *"; \
- echo " * This file was generated by Kbuild"; \
- echo " *"; \
- echo " */"; \
- echo ""; \
- sed -ne $(sed-y) $<; \
- echo ""; \
- echo "#endif" ) > $@
-endef
-
# We use internal kbuild rules to avoid the "is up to date" message from make
arch/$(SRCARCH)/kernel/nr-irqs.s: arch/$(SRCARCH)/kernel/nr-irqs.c
$(Q)mkdir -p $(dir $@)
$(call if_changed_dep,cc_s_c)
-include/generated/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s
- $(Q)mkdir -p $(dir $@)
- $(call cmd,nr_irqs)
+include/generated/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s FORCE
+ $(call filechk,offsets,__ASM_NR_IRQS_H__)
diff --git a/arch/m68k/kernel/vmlinux-nommu.lds b/arch/m68k/kernel/vmlinux-nommu.lds
index d2c8abf..e958abe 100644
--- a/arch/m68k/kernel/vmlinux-nommu.lds
+++ b/arch/m68k/kernel/vmlinux-nommu.lds
@@ -44,6 +44,8 @@
.text : {
HEAD_TEXT
TEXT_TEXT
+ IRQENTRY_TEXT
+ SOFTIRQENTRY_TEXT
SCHED_TEXT
CPUIDLE_TEXT
LOCK_TEXT
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index 5b5ce1e..1656ae8 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -15,6 +15,8 @@
.text : {
HEAD_TEXT
TEXT_TEXT
+ IRQENTRY_TEXT
+ SOFTIRQENTRY_TEXT
SCHED_TEXT
CPUIDLE_TEXT
LOCK_TEXT
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
index fe5ea19..07b9818 100644
--- a/arch/m68k/kernel/vmlinux-sun3.lds
+++ b/arch/m68k/kernel/vmlinux-sun3.lds
@@ -15,6 +15,8 @@
.text : {
HEAD_TEXT
TEXT_TEXT
+ IRQENTRY_TEXT
+ SOFTIRQENTRY_TEXT
SCHED_TEXT
CPUIDLE_TEXT
LOCK_TEXT
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 5e844f6..2d2fd79 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -112,12 +112,12 @@
select SYS_SUPPORTS_MULTITHREADING
select SYS_SUPPORTS_RELOCATABLE
select SYS_SUPPORTS_SMARTMIPS
- select USB_EHCI_BIG_ENDIAN_DESC if BIG_ENDIAN
- select USB_EHCI_BIG_ENDIAN_MMIO if BIG_ENDIAN
- select USB_OHCI_BIG_ENDIAN_DESC if BIG_ENDIAN
- select USB_OHCI_BIG_ENDIAN_MMIO if BIG_ENDIAN
- select USB_UHCI_BIG_ENDIAN_DESC if BIG_ENDIAN
- select USB_UHCI_BIG_ENDIAN_MMIO if BIG_ENDIAN
+ select USB_EHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN
+ select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
+ select USB_OHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN
+ select USB_OHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
+ select USB_UHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN
+ select USB_UHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
select USE_OF
help
Select this to build a kernel which aims to support multiple boards,
diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c
index b9920b1..70cef54 100644
--- a/arch/mn10300/mm/misalignment.c
+++ b/arch/mn10300/mm/misalignment.c
@@ -437,7 +437,7 @@
info.si_signo = SIGSEGV;
info.si_errno = 0;
- info.si_code = 0;
+ info.si_code = SEGV_MAPERR;
info.si_addr = (void *) regs->pc;
force_sig_info(SIGSEGV, &info, current);
return;
diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c
index 3d3f606..605a284 100644
--- a/arch/openrisc/kernel/traps.c
+++ b/arch/openrisc/kernel/traps.c
@@ -302,12 +302,12 @@
siginfo_t info;
if (user_mode(regs)) {
- /* Send a SIGSEGV */
- info.si_signo = SIGSEGV;
+ /* Send a SIGBUS */
+ info.si_signo = SIGBUS;
info.si_errno = 0;
- /* info.si_code has been set above */
- info.si_addr = (void *)address;
- force_sig_info(SIGSEGV, &info, current);
+ info.si_code = BUS_ADRALN;
+ info.si_addr = (void __user *)address;
+ force_sig_info(SIGBUS, &info, current);
} else {
printk("KERNEL: Unaligned Access 0x%.8lx\n", address);
show_registers(regs);
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index acb6026..bc11d709f 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -129,6 +129,7 @@
select ARCH_HAS_GCOV_PROFILE_ALL
select GENERIC_SMP_IDLE_THREAD
select GENERIC_CMOS_UPDATE
+ select GENERIC_CPU_VULNERABILITIES if PPC_BOOK3S_64
select GENERIC_TIME_VSYSCALL_OLD
select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
diff --git a/arch/powerpc/crypto/crc32c-vpmsum_glue.c b/arch/powerpc/crypto/crc32c-vpmsum_glue.c
index f058e0c..fd1d6c8 100644
--- a/arch/powerpc/crypto/crc32c-vpmsum_glue.c
+++ b/arch/powerpc/crypto/crc32c-vpmsum_glue.c
@@ -141,6 +141,7 @@
.cra_name = "crc32c",
.cra_driver_name = "crc32c-vpmsum",
.cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
.cra_blocksize = CHKSUM_BLOCK_SIZE,
.cra_ctxsize = sizeof(u32),
.cra_module = THIS_MODULE,
diff --git a/arch/powerpc/include/asm/exception-64e.h b/arch/powerpc/include/asm/exception-64e.h
index a703452..555e22d 100644
--- a/arch/powerpc/include/asm/exception-64e.h
+++ b/arch/powerpc/include/asm/exception-64e.h
@@ -209,5 +209,11 @@
ori r3,r3,vector_offset@l; \
mtspr SPRN_IVOR##vector_number,r3;
+#define RFI_TO_KERNEL \
+ rfi
+
+#define RFI_TO_USER \
+ rfi
+
#endif /* _ASM_POWERPC_EXCEPTION_64E_H */
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 9a3eee6..903e76a 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -51,6 +51,59 @@
#define EX_PPR 88 /* SMT thread status register (priority) */
#define EX_CTR 96
+/*
+ * Macros for annotating the expected destination of (h)rfid
+ *
+ * The nop instructions allow us to insert one or more instructions to flush the
+ * L1-D cache when returning to userspace or a guest.
+ */
+#define RFI_FLUSH_SLOT \
+ RFI_FLUSH_FIXUP_SECTION; \
+ nop; \
+ nop; \
+ nop
+
+#define RFI_TO_KERNEL \
+ rfid
+
+#define RFI_TO_USER \
+ RFI_FLUSH_SLOT; \
+ rfid; \
+ b rfi_flush_fallback
+
+#define RFI_TO_USER_OR_KERNEL \
+ RFI_FLUSH_SLOT; \
+ rfid; \
+ b rfi_flush_fallback
+
+#define RFI_TO_GUEST \
+ RFI_FLUSH_SLOT; \
+ rfid; \
+ b rfi_flush_fallback
+
+#define HRFI_TO_KERNEL \
+ hrfid
+
+#define HRFI_TO_USER \
+ RFI_FLUSH_SLOT; \
+ hrfid; \
+ b hrfi_flush_fallback
+
+#define HRFI_TO_USER_OR_KERNEL \
+ RFI_FLUSH_SLOT; \
+ hrfid; \
+ b hrfi_flush_fallback
+
+#define HRFI_TO_GUEST \
+ RFI_FLUSH_SLOT; \
+ hrfid; \
+ b hrfi_flush_fallback
+
+#define HRFI_TO_UNKNOWN \
+ RFI_FLUSH_SLOT; \
+ hrfid; \
+ b hrfi_flush_fallback
+
#ifdef CONFIG_RELOCATABLE
#define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \
mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \
@@ -189,7 +242,7 @@
mtspr SPRN_##h##SRR0,r12; \
mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \
mtspr SPRN_##h##SRR1,r10; \
- h##rfid; \
+ h##RFI_TO_KERNEL; \
b . /* prevent speculative execution */
#define EXCEPTION_PROLOG_PSERIES_1(label, h) \
__EXCEPTION_PROLOG_PSERIES_1(label, h)
diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h
index ddf54f5..7b33234 100644
--- a/arch/powerpc/include/asm/feature-fixups.h
+++ b/arch/powerpc/include/asm/feature-fixups.h
@@ -189,4 +189,19 @@
void setup_feature_keys(void);
#endif
+#define RFI_FLUSH_FIXUP_SECTION \
+951: \
+ .pushsection __rfi_flush_fixup,"a"; \
+ .align 2; \
+952: \
+ FTR_ENTRY_OFFSET 951b-952b; \
+ .popsection;
+
+
+#ifndef __ASSEMBLY__
+
+extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup;
+
+#endif
+
#endif /* __ASM_POWERPC_FEATURE_FIXUPS_H */
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 708edeb..dc0996b 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -240,6 +240,7 @@
#define H_GET_HCA_INFO 0x1B8
#define H_GET_PERF_COUNT 0x1BC
#define H_MANAGE_TRACE 0x1C0
+#define H_GET_CPU_CHARACTERISTICS 0x1C8
#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
#define H_QUERY_INT_STATE 0x1E4
#define H_POLL_PENDING 0x1D8
@@ -306,7 +307,19 @@
#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE 3
#define H_SET_MODE_RESOURCE_LE 4
+/* H_GET_CPU_CHARACTERISTICS return values */
+#define H_CPU_CHAR_SPEC_BAR_ORI31 (1ull << 63) // IBM bit 0
+#define H_CPU_CHAR_BCCTRL_SERIALISED (1ull << 62) // IBM bit 1
+#define H_CPU_CHAR_L1D_FLUSH_ORI30 (1ull << 61) // IBM bit 2
+#define H_CPU_CHAR_L1D_FLUSH_TRIG2 (1ull << 60) // IBM bit 3
+#define H_CPU_CHAR_L1D_THREAD_PRIV (1ull << 59) // IBM bit 4
+
+#define H_CPU_BEHAV_FAVOUR_SECURITY (1ull << 63) // IBM bit 0
+#define H_CPU_BEHAV_L1D_FLUSH_PR (1ull << 62) // IBM bit 1
+#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR (1ull << 61) // IBM bit 2
+
#ifndef __ASSEMBLY__
+#include <linux/types.h>
/**
* plpar_hcall_norets: - Make a pseries hypervisor call with no return arguments
@@ -433,6 +446,11 @@
}
#endif /* CONFIG_PPC_PSERIES */
+struct h_cpu_char_result {
+ u64 character;
+ u64 behaviour;
+};
+
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_HVCALL_H */
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 6a6792b..c75ee2d 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -205,6 +205,15 @@
struct sibling_subcore_state *sibling_subcore_state;
#endif
#endif
+#ifdef CONFIG_PPC_BOOK3S_64
+ /*
+ * rfi fallback flush must be in its own cacheline to prevent
+ * other paca data leaking into the L1d
+ */
+ u64 exrfi[13] __aligned(0x80);
+ void *rfi_flush_fallback_area;
+ u64 l1d_flush_size;
+#endif
};
#ifdef CONFIG_PPC_BOOK3S
diff --git a/arch/powerpc/include/asm/plpar_wrappers.h b/arch/powerpc/include/asm/plpar_wrappers.h
index 1b39424..4e53b85 100644
--- a/arch/powerpc/include/asm/plpar_wrappers.h
+++ b/arch/powerpc/include/asm/plpar_wrappers.h
@@ -340,4 +340,18 @@
return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_DAWR, dawr0, dawrx0);
}
+static inline long plpar_get_cpu_characteristics(struct h_cpu_char_result *p)
+{
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+ long rc;
+
+ rc = plpar_hcall(H_GET_CPU_CHARACTERISTICS, retbuf);
+ if (rc == H_SUCCESS) {
+ p->character = retbuf[0];
+ p->behaviour = retbuf[1];
+ }
+
+ return rc;
+}
+
#endif /* _ASM_POWERPC_PLPAR_WRAPPERS_H */
diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h
index 654d64c..6825a67 100644
--- a/arch/powerpc/include/asm/setup.h
+++ b/arch/powerpc/include/asm/setup.h
@@ -38,6 +38,19 @@
static inline void pseries_little_endian_exceptions(void) {}
#endif /* CONFIG_PPC_PSERIES */
+void rfi_flush_enable(bool enable);
+
+/* These are bit flags */
+enum l1d_flush_type {
+ L1D_FLUSH_NONE = 0x1,
+ L1D_FLUSH_FALLBACK = 0x2,
+ L1D_FLUSH_ORI = 0x4,
+ L1D_FLUSH_MTTRIG = 0x8,
+};
+
+void __init setup_rfi_flush(enum l1d_flush_type, bool enable);
+void do_rfi_flush_fixups(enum l1d_flush_type types);
+
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_POWERPC_SETUP_H */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index c833d88..14fbbd9 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -240,6 +240,9 @@
#ifdef CONFIG_PPC_BOOK3S_64
DEFINE(PACAMCEMERGSP, offsetof(struct paca_struct, mc_emergency_sp));
DEFINE(PACA_IN_MCE, offsetof(struct paca_struct, in_mce));
+ DEFINE(PACA_RFI_FLUSH_FALLBACK_AREA, offsetof(struct paca_struct, rfi_flush_fallback_area));
+ DEFINE(PACA_EXRFI, offsetof(struct paca_struct, exrfi));
+ DEFINE(PACA_L1D_FLUSH_SIZE, offsetof(struct paca_struct, l1d_flush_size));
#endif
DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state));
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index caa6596..2dc52e6 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -39,6 +39,11 @@
#include <asm/tm.h>
#include <asm/ppc-opcode.h>
#include <asm/export.h>
+#ifdef CONFIG_PPC_BOOK3S
+#include <asm/exception-64s.h>
+#else
+#include <asm/exception-64e.h>
+#endif
/*
* System calls.
@@ -251,13 +256,23 @@
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
ld r13,GPR13(r1) /* only restore r13 if returning to usermode */
+ ld r2,GPR2(r1)
+ ld r1,GPR1(r1)
+ mtlr r4
+ mtcr r5
+ mtspr SPRN_SRR0,r7
+ mtspr SPRN_SRR1,r8
+ RFI_TO_USER
+ b . /* prevent speculative execution */
+
+ /* exit to kernel */
1: ld r2,GPR2(r1)
ld r1,GPR1(r1)
mtlr r4
mtcr r5
mtspr SPRN_SRR0,r7
mtspr SPRN_SRR1,r8
- RFI
+ RFI_TO_KERNEL
b . /* prevent speculative execution */
syscall_error:
@@ -386,8 +401,7 @@
mtmsrd r10, 1
mtspr SPRN_SRR0, r11
mtspr SPRN_SRR1, r12
-
- rfid
+ RFI_TO_USER
b . /* prevent speculative execution */
#endif
@@ -859,7 +873,7 @@
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
ACCOUNT_CPU_USER_EXIT(r13, r2, r4)
REST_GPR(13, r1)
-1:
+
mtspr SPRN_SRR1,r3
ld r2,_CCR(r1)
@@ -872,8 +886,22 @@
ld r3,GPR3(r1)
ld r4,GPR4(r1)
ld r1,GPR1(r1)
+ RFI_TO_USER
+ b . /* prevent speculative execution */
- rfid
+1: mtspr SPRN_SRR1,r3
+
+ ld r2,_CCR(r1)
+ mtcrf 0xFF,r2
+ ld r2,_NIP(r1)
+ mtspr SPRN_SRR0,r2
+
+ ld r0,GPR0(r1)
+ ld r2,GPR2(r1)
+ ld r3,GPR3(r1)
+ ld r4,GPR4(r1)
+ ld r1,GPR1(r1)
+ RFI_TO_KERNEL
b . /* prevent speculative execution */
#endif /* CONFIG_PPC_BOOK3E */
@@ -1049,7 +1077,7 @@
mtspr SPRN_SRR0,r5
mtspr SPRN_SRR1,r6
- rfid
+ RFI_TO_KERNEL
b . /* prevent speculative execution */
rtas_return_loc:
@@ -1074,7 +1102,7 @@
mtspr SPRN_SRR0,r3
mtspr SPRN_SRR1,r4
- rfid
+ RFI_TO_KERNEL
b . /* prevent speculative execution */
.align 3
@@ -1145,7 +1173,7 @@
LOAD_REG_IMMEDIATE(r12, MSR_SF | MSR_ISF | MSR_LE)
andc r11,r11,r12
mtsrr1 r11
- rfid
+ RFI_TO_KERNEL
#endif /* CONFIG_PPC_BOOK3E */
1: /* Return from OF */
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index fd68e19..7614d1d 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -244,7 +244,7 @@
LOAD_HANDLER(r12, machine_check_handle_early)
1: mtspr SPRN_SRR0,r12
mtspr SPRN_SRR1,r11
- rfid
+ RFI_TO_KERNEL
b . /* prevent speculative execution */
2:
/* Stack overflow. Stay on emergency stack and panic.
@@ -280,7 +280,7 @@
mtspr SPRN_SRR0,r12
mfspr r12,SPRN_SRR1
mtspr SPRN_SRR1,r10
- rfid
+ RFI_TO_KERNEL
b . /* prevent speculative execution */
TRAMP_KVM_SKIP(PACA_EXMC, 0x200)
@@ -446,7 +446,7 @@
li r3,MSR_ME
andc r10,r10,r3 /* Turn off MSR_ME */
mtspr SPRN_SRR1,r10
- rfid
+ RFI_TO_KERNEL
b .
2:
/*
@@ -464,7 +464,7 @@
*/
bl machine_check_queue_event
MACHINE_CHECK_HANDLER_WINDUP
- rfid
+ RFI_TO_USER_OR_KERNEL
9:
/* Deliver the machine check to host kernel in V mode. */
MACHINE_CHECK_HANDLER_WINDUP
@@ -655,6 +655,8 @@
andi. r10,r12,MSR_RI /* check for unrecoverable exception */
beq- 2f
+ andi. r10,r12,MSR_PR /* check for user mode (PR != 0) */
+ bne 1f
/* All done -- return from exception. */
@@ -671,7 +673,24 @@
ld r11,PACA_EXSLB+EX_R11(r13)
ld r12,PACA_EXSLB+EX_R12(r13)
ld r13,PACA_EXSLB+EX_R13(r13)
- rfid
+ RFI_TO_KERNEL
+ b . /* prevent speculative execution */
+
+1:
+.machine push
+.machine "power4"
+ mtcrf 0x80,r9
+ mtcrf 0x02,r9 /* I/D indication is in cr6 */
+ mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */
+.machine pop
+
+ RESTORE_PPR_PACA(PACA_EXSLB, r9)
+ ld r9,PACA_EXSLB+EX_R9(r13)
+ ld r10,PACA_EXSLB+EX_R10(r13)
+ ld r11,PACA_EXSLB+EX_R11(r13)
+ ld r12,PACA_EXSLB+EX_R12(r13)
+ ld r13,PACA_EXSLB+EX_R13(r13)
+ RFI_TO_USER
b . /* prevent speculative execution */
2: mfspr r11,SPRN_SRR0
@@ -679,7 +698,7 @@
mtspr SPRN_SRR0,r10
ld r10,PACAKMSR(r13)
mtspr SPRN_SRR1,r10
- rfid
+ RFI_TO_KERNEL
b .
8: mfspr r11,SPRN_SRR0
@@ -687,7 +706,7 @@
mtspr SPRN_SRR0,r10
ld r10,PACAKMSR(r13)
mtspr SPRN_SRR1,r10
- rfid
+ RFI_TO_KERNEL
b .
EXC_COMMON_BEGIN(unrecov_slb)
@@ -874,7 +893,7 @@
mtspr SPRN_SRR0,r10 ; \
ld r10,PACAKMSR(r13) ; \
mtspr SPRN_SRR1,r10 ; \
- rfid ; \
+ RFI_TO_KERNEL ; \
b . ; /* prevent speculative execution */
#define SYSCALL_PSERIES_3 \
@@ -882,7 +901,7 @@
1: mfspr r12,SPRN_SRR1 ; \
xori r12,r12,MSR_LE ; \
mtspr SPRN_SRR1,r12 ; \
- rfid ; /* return to userspace */ \
+ RFI_TO_USER ; /* return to userspace */ \
b . ; /* prevent speculative execution */
#if defined(CONFIG_RELOCATABLE)
@@ -1257,7 +1276,7 @@
ld r11,PACA_EXGEN+EX_R11(r13)
ld r12,PACA_EXGEN+EX_R12(r13)
ld r13,PACA_EXGEN+EX_R13(r13)
- HRFID
+ HRFI_TO_UNKNOWN
b .
#endif
@@ -1331,7 +1350,7 @@
ld r10,PACA_EXGEN+EX_R10(r13); \
ld r11,PACA_EXGEN+EX_R11(r13); \
GET_SCRATCH0(r13); \
- ##_H##rfid; \
+ ##_H##RFI_TO_KERNEL; \
b .
/*
@@ -1353,7 +1372,7 @@
addi r13, r13, 4
mtspr SPRN_SRR0, r13
GET_SCRATCH0(r13)
- rfid
+ RFI_TO_KERNEL
b .
TRAMP_REAL_BEGIN(kvmppc_skip_Hinterrupt)
@@ -1365,7 +1384,7 @@
addi r13, r13, 4
mtspr SPRN_HSRR0, r13
GET_SCRATCH0(r13)
- hrfid
+ HRFI_TO_KERNEL
b .
#endif
@@ -1576,6 +1595,88 @@
bl kernel_bad_stack
b 1b
+ .globl rfi_flush_fallback
+rfi_flush_fallback:
+ SET_SCRATCH0(r13);
+ GET_PACA(r13);
+ std r9,PACA_EXRFI+EX_R9(r13)
+ std r10,PACA_EXRFI+EX_R10(r13)
+ std r11,PACA_EXRFI+EX_R11(r13)
+ mfctr r9
+ ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13)
+ ld r11,PACA_L1D_FLUSH_SIZE(r13)
+ srdi r11,r11,(7 + 3) /* 128 byte lines, unrolled 8x */
+ mtctr r11
+ DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */
+
+ /* order ld/st prior to dcbt stop all streams with flushing */
+ sync
+
+ /*
+ * The load adresses are at staggered offsets within cachelines,
+ * which suits some pipelines better (on others it should not
+ * hurt).
+ */
+1:
+ ld r11,(0x80 + 8)*0(r10)
+ ld r11,(0x80 + 8)*1(r10)
+ ld r11,(0x80 + 8)*2(r10)
+ ld r11,(0x80 + 8)*3(r10)
+ ld r11,(0x80 + 8)*4(r10)
+ ld r11,(0x80 + 8)*5(r10)
+ ld r11,(0x80 + 8)*6(r10)
+ ld r11,(0x80 + 8)*7(r10)
+ addi r10,r10,0x80*8
+ bdnz 1b
+
+ mtctr r9
+ ld r9,PACA_EXRFI+EX_R9(r13)
+ ld r10,PACA_EXRFI+EX_R10(r13)
+ ld r11,PACA_EXRFI+EX_R11(r13)
+ GET_SCRATCH0(r13);
+ rfid
+
+ .globl hrfi_flush_fallback
+hrfi_flush_fallback:
+ SET_SCRATCH0(r13);
+ GET_PACA(r13);
+ std r9,PACA_EXRFI+EX_R9(r13)
+ std r10,PACA_EXRFI+EX_R10(r13)
+ std r11,PACA_EXRFI+EX_R11(r13)
+ mfctr r9
+ ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13)
+ ld r11,PACA_L1D_FLUSH_SIZE(r13)
+ srdi r11,r11,(7 + 3) /* 128 byte lines, unrolled 8x */
+ mtctr r11
+ DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */
+
+ /* order ld/st prior to dcbt stop all streams with flushing */
+ sync
+
+ /*
+ * The load adresses are at staggered offsets within cachelines,
+ * which suits some pipelines better (on others it should not
+ * hurt).
+ */
+1:
+ ld r11,(0x80 + 8)*0(r10)
+ ld r11,(0x80 + 8)*1(r10)
+ ld r11,(0x80 + 8)*2(r10)
+ ld r11,(0x80 + 8)*3(r10)
+ ld r11,(0x80 + 8)*4(r10)
+ ld r11,(0x80 + 8)*5(r10)
+ ld r11,(0x80 + 8)*6(r10)
+ ld r11,(0x80 + 8)*7(r10)
+ addi r10,r10,0x80*8
+ bdnz 1b
+
+ mtctr r9
+ ld r9,PACA_EXRFI+EX_R9(r13)
+ ld r10,PACA_EXRFI+EX_R10(r13)
+ ld r11,PACA_EXRFI+EX_R11(r13)
+ GET_SCRATCH0(r13);
+ hrfid
+
/*
* Called from arch_local_irq_enable when an interrupt needs
* to be resent. r3 contains 0x500, 0x900, 0xa00 or 0xe80 to indicate
diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S
index b350ac5..d92c953 100644
--- a/arch/powerpc/kernel/idle_book3s.S
+++ b/arch/powerpc/kernel/idle_book3s.S
@@ -9,6 +9,7 @@
*/
#include <linux/threads.h>
+#include <asm/exception-64s.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/cputable.h>
@@ -178,7 +179,7 @@
mtmsrd r6, 1 /* clear RI before setting SRR0/1 */
mtspr SPRN_SRR0, r5
mtspr SPRN_SRR1, r7
- rfid
+ RFI_TO_KERNEL
.globl pnv_enter_arch207_idle_mode
pnv_enter_arch207_idle_mode:
@@ -668,7 +669,7 @@
mtcr r6
mtspr SPRN_SRR1,r4
mtspr SPRN_SRR0,r5
- rfid
+ RFI_TO_KERNEL
/*
* R3 here contains the value that will be returned to the caller
@@ -689,4 +690,4 @@
mtcr r6
mtspr SPRN_SRR1,r4
mtspr SPRN_SRR0,r5
- rfid
+ RFI_TO_KERNEL
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index a12be60..5243501 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -37,6 +37,7 @@
#include <linux/memblock.h>
#include <linux/memory.h>
#include <linux/nmi.h>
+#include <linux/debugfs.h>
#include <asm/io.h>
#include <asm/kdump.h>
@@ -678,4 +679,131 @@
return 0;
}
early_initcall(disable_hardlockup_detector);
+
+#ifdef CONFIG_PPC_BOOK3S_64
+static enum l1d_flush_type enabled_flush_types;
+static void *l1d_flush_fallback_area;
+static bool no_rfi_flush;
+bool rfi_flush;
+
+static int __init handle_no_rfi_flush(char *p)
+{
+ pr_info("rfi-flush: disabled on command line.");
+ no_rfi_flush = true;
+ return 0;
+}
+early_param("no_rfi_flush", handle_no_rfi_flush);
+
+/*
+ * The RFI flush is not KPTI, but because users will see doco that says to use
+ * nopti we hijack that option here to also disable the RFI flush.
+ */
+static int __init handle_no_pti(char *p)
+{
+ pr_info("rfi-flush: disabling due to 'nopti' on command line.\n");
+ handle_no_rfi_flush(NULL);
+ return 0;
+}
+early_param("nopti", handle_no_pti);
+
+static void do_nothing(void *unused)
+{
+ /*
+ * We don't need to do the flush explicitly, just enter+exit kernel is
+ * sufficient, the RFI exit handlers will do the right thing.
+ */
+}
+
+void rfi_flush_enable(bool enable)
+{
+ if (rfi_flush == enable)
+ return;
+
+ if (enable) {
+ do_rfi_flush_fixups(enabled_flush_types);
+ on_each_cpu(do_nothing, NULL, 1);
+ } else
+ do_rfi_flush_fixups(L1D_FLUSH_NONE);
+
+ rfi_flush = enable;
+}
+
+static void init_fallback_flush(void)
+{
+ u64 l1d_size, limit;
+ int cpu;
+
+ l1d_size = ppc64_caches.dsize;
+ limit = min(safe_stack_limit(), ppc64_rma_size);
+
+ /*
+ * Align to L1d size, and size it at 2x L1d size, to catch possible
+ * hardware prefetch runoff. We don't have a recipe for load patterns to
+ * reliably avoid the prefetcher.
+ */
+ l1d_flush_fallback_area = __va(memblock_alloc_base(l1d_size * 2, l1d_size, limit));
+ memset(l1d_flush_fallback_area, 0, l1d_size * 2);
+
+ for_each_possible_cpu(cpu) {
+ paca[cpu].rfi_flush_fallback_area = l1d_flush_fallback_area;
+ paca[cpu].l1d_flush_size = l1d_size;
+ }
+}
+
+void __init setup_rfi_flush(enum l1d_flush_type types, bool enable)
+{
+ if (types & L1D_FLUSH_FALLBACK) {
+ pr_info("rfi-flush: Using fallback displacement flush\n");
+ init_fallback_flush();
+ }
+
+ if (types & L1D_FLUSH_ORI)
+ pr_info("rfi-flush: Using ori type flush\n");
+
+ if (types & L1D_FLUSH_MTTRIG)
+ pr_info("rfi-flush: Using mttrig type flush\n");
+
+ enabled_flush_types = types;
+
+ if (!no_rfi_flush)
+ rfi_flush_enable(enable);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int rfi_flush_set(void *data, u64 val)
+{
+ if (val == 1)
+ rfi_flush_enable(true);
+ else if (val == 0)
+ rfi_flush_enable(false);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int rfi_flush_get(void *data, u64 *val)
+{
+ *val = rfi_flush ? 1 : 0;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_rfi_flush, rfi_flush_get, rfi_flush_set, "%llu\n");
+
+static __init int rfi_flush_debugfs_init(void)
+{
+ debugfs_create_file("rfi_flush", 0600, powerpc_debugfs_root, NULL, &fops_rfi_flush);
+ return 0;
+}
+device_initcall(rfi_flush_debugfs_init);
+#endif
+
+ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ if (rfi_flush)
+ return sprintf(buf, "Mitigation: RFI Flush\n");
+
+ return sprintf(buf, "Vulnerable\n");
+}
+#endif /* CONFIG_PPC_BOOK3S_64 */
#endif
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 7394b77..b61fb79 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -132,6 +132,15 @@
/* Read-only data */
RODATA
+#ifdef CONFIG_PPC64
+ . = ALIGN(8);
+ __rfi_flush_fixup : AT(ADDR(__rfi_flush_fixup) - LOAD_OFFSET) {
+ __start___rfi_flush_fixup = .;
+ *(__rfi_flush_fixup)
+ __stop___rfi_flush_fixup = .;
+ }
+#endif
+
EXCEPTION_TABLE(0)
NOTES :kernel :notes
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 0447a22..55fbc0c 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -65,7 +65,7 @@
mtmsrd r0,1 /* clear RI in MSR */
mtsrr0 r5
mtsrr1 r6
- RFI
+ RFI_TO_KERNEL
kvmppc_call_hv_entry:
ld r4, HSTATE_KVM_VCPU(r13)
@@ -171,7 +171,7 @@
mtsrr0 r8
mtsrr1 r7
beq cr1, 13f /* machine check */
- RFI
+ RFI_TO_KERNEL
/* On POWER7, we have external interrupts set to use HSRR0/1 */
11: mtspr SPRN_HSRR0, r8
@@ -1018,8 +1018,7 @@
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
ld r0, VCPU_GPR(R0)(r4)
ld r4, VCPU_GPR(R4)(r4)
-
- hrfid
+ HRFI_TO_GUEST
b .
secondary_too_late:
diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S
index 42a4b23..34a5ade 100644
--- a/arch/powerpc/kvm/book3s_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_rmhandlers.S
@@ -46,6 +46,9 @@
#define FUNC(name) name
+#define RFI_TO_KERNEL RFI
+#define RFI_TO_GUEST RFI
+
.macro INTERRUPT_TRAMPOLINE intno
.global kvmppc_trampoline_\intno
@@ -141,7 +144,7 @@
GET_SCRATCH0(r13)
/* And get back into the code */
- RFI
+ RFI_TO_KERNEL
#endif
/*
@@ -164,6 +167,6 @@
ori r5, r5, MSR_EE
mtsrr0 r7
mtsrr1 r6
- RFI
+ RFI_TO_KERNEL
#include "book3s_segment.S"
diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S
index ca8f174..7c98295 100644
--- a/arch/powerpc/kvm/book3s_segment.S
+++ b/arch/powerpc/kvm/book3s_segment.S
@@ -156,7 +156,7 @@
PPC_LL r9, SVCPU_R9(r3)
PPC_LL r3, (SVCPU_R3)(r3)
- RFI
+ RFI_TO_GUEST
kvmppc_handler_trampoline_enter_end:
@@ -389,5 +389,5 @@
cmpwi r12, BOOK3S_INTERRUPT_DOORBELL
beqa BOOK3S_INTERRUPT_DOORBELL
- RFI
+ RFI_TO_KERNEL
kvmppc_handler_trampoline_exit_end:
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index 043415f..e86bfa1 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -23,6 +23,7 @@
#include <asm/sections.h>
#include <asm/setup.h>
#include <asm/firmware.h>
+#include <asm/setup.h>
struct fixup_entry {
unsigned long mask;
@@ -115,6 +116,47 @@
}
}
+#ifdef CONFIG_PPC_BOOK3S_64
+void do_rfi_flush_fixups(enum l1d_flush_type types)
+{
+ unsigned int instrs[3], *dest;
+ long *start, *end;
+ int i;
+
+ start = PTRRELOC(&__start___rfi_flush_fixup),
+ end = PTRRELOC(&__stop___rfi_flush_fixup);
+
+ instrs[0] = 0x60000000; /* nop */
+ instrs[1] = 0x60000000; /* nop */
+ instrs[2] = 0x60000000; /* nop */
+
+ if (types & L1D_FLUSH_FALLBACK)
+ /* b .+16 to fallback flush */
+ instrs[0] = 0x48000010;
+
+ i = 0;
+ if (types & L1D_FLUSH_ORI) {
+ instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
+ instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
+ }
+
+ if (types & L1D_FLUSH_MTTRIG)
+ instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
+
+ for (i = 0; start < end; start++, i++) {
+ dest = (void *)start + *start;
+
+ pr_devel("patching dest %lx\n", (unsigned long)dest);
+
+ patch_instruction(dest, instrs[0]);
+ patch_instruction(dest + 1, instrs[1]);
+ patch_instruction(dest + 2, instrs[2]);
+ }
+
+ printk(KERN_DEBUG "rfi-flush: patched %d locations\n", i);
+}
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
{
long *start, *end;
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 083f9274..bf94962 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -1381,7 +1381,7 @@
int n = 0;
struct perf_event *event;
- if (!is_software_event(group)) {
+ if (group->pmu->task_ctx_nr == perf_hw_context) {
if (n >= max_count)
return -1;
ctrs[n] = group;
@@ -1389,7 +1389,7 @@
events[n++] = group->hw.config;
}
list_for_each_entry(event, &group->sibling_list, group_entry) {
- if (!is_software_event(event) &&
+ if (event->pmu->task_ctx_nr == perf_hw_context &&
event->state != PERF_EVENT_STATE_OFF) {
if (n >= max_count)
return -1;
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index b33faa0..6f8b4c1 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -35,13 +35,63 @@
#include <asm/opal.h>
#include <asm/kexec.h>
#include <asm/smp.h>
+#include <asm/tm.h>
+#include <asm/setup.h>
#include "powernv.h"
+static void pnv_setup_rfi_flush(void)
+{
+ struct device_node *np, *fw_features;
+ enum l1d_flush_type type;
+ int enable;
+
+ /* Default to fallback in case fw-features are not available */
+ type = L1D_FLUSH_FALLBACK;
+ enable = 1;
+
+ np = of_find_node_by_name(NULL, "ibm,opal");
+ fw_features = of_get_child_by_name(np, "fw-features");
+ of_node_put(np);
+
+ if (fw_features) {
+ np = of_get_child_by_name(fw_features, "inst-l1d-flush-trig2");
+ if (np && of_property_read_bool(np, "enabled"))
+ type = L1D_FLUSH_MTTRIG;
+
+ of_node_put(np);
+
+ np = of_get_child_by_name(fw_features, "inst-l1d-flush-ori30,30,0");
+ if (np && of_property_read_bool(np, "enabled"))
+ type = L1D_FLUSH_ORI;
+
+ of_node_put(np);
+
+ /* Enable unless firmware says NOT to */
+ enable = 2;
+ np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-hv-1-to-0");
+ if (np && of_property_read_bool(np, "disabled"))
+ enable--;
+
+ of_node_put(np);
+
+ np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-pr-0-to-1");
+ if (np && of_property_read_bool(np, "disabled"))
+ enable--;
+
+ of_node_put(np);
+ of_node_put(fw_features);
+ }
+
+ setup_rfi_flush(type, enable > 0);
+}
+
static void __init pnv_setup_arch(void)
{
set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
+ pnv_setup_rfi_flush();
+
/* Initialize SMP */
pnv_smp_init();
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 97aa3f3..1845fc6 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -450,6 +450,39 @@
of_pci_check_probe_only();
}
+static void pseries_setup_rfi_flush(void)
+{
+ struct h_cpu_char_result result;
+ enum l1d_flush_type types;
+ bool enable;
+ long rc;
+
+ /* Enable by default */
+ enable = true;
+
+ rc = plpar_get_cpu_characteristics(&result);
+ if (rc == H_SUCCESS) {
+ types = L1D_FLUSH_NONE;
+
+ if (result.character & H_CPU_CHAR_L1D_FLUSH_TRIG2)
+ types |= L1D_FLUSH_MTTRIG;
+ if (result.character & H_CPU_CHAR_L1D_FLUSH_ORI30)
+ types |= L1D_FLUSH_ORI;
+
+ /* Use fallback if nothing set in hcall */
+ if (types == L1D_FLUSH_NONE)
+ types = L1D_FLUSH_FALLBACK;
+
+ if (!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR))
+ enable = false;
+ } else {
+ /* Default to fallback if case hcall is not available */
+ types = L1D_FLUSH_FALLBACK;
+ }
+
+ setup_rfi_flush(types, enable);
+}
+
static void __init pSeries_setup_arch(void)
{
set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
@@ -467,6 +500,8 @@
fwnmi_init();
+ pseries_setup_rfi_flush();
+
/* By default, only probe PCI (can be overridden by rtas_pci) */
pci_add_flags(PCI_PROBE_ONLY);
diff --git a/arch/s390/crypto/crc32-vx.c b/arch/s390/crypto/crc32-vx.c
index 992e630..6f4985f 100644
--- a/arch/s390/crypto/crc32-vx.c
+++ b/arch/s390/crypto/crc32-vx.c
@@ -238,6 +238,7 @@
.cra_name = "crc32",
.cra_driver_name = "crc32-vx",
.cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
.cra_blocksize = CRC32_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crc_ctx),
.cra_module = THIS_MODULE,
@@ -258,6 +259,7 @@
.cra_name = "crc32be",
.cra_driver_name = "crc32be-vx",
.cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
.cra_blocksize = CRC32_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crc_ctx),
.cra_module = THIS_MODULE,
@@ -278,6 +280,7 @@
.cra_name = "crc32c",
.cra_driver_name = "crc32c-vx",
.cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
.cra_blocksize = CRC32_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crc_ctx),
.cra_module = THIS_MODULE,
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index f06a9a0..d0724a9 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -110,7 +110,7 @@
COMPAT_SYSCALL_DEFINE1(s390_setgid16, u16, gid)
{
- return sys_setgid((gid_t)gid);
+ return sys_setgid(low2highgid(gid));
}
COMPAT_SYSCALL_DEFINE2(s390_setreuid16, u16, ruid, u16, euid)
@@ -120,7 +120,7 @@
COMPAT_SYSCALL_DEFINE1(s390_setuid16, u16, uid)
{
- return sys_setuid((uid_t)uid);
+ return sys_setuid(low2highuid(uid));
}
COMPAT_SYSCALL_DEFINE3(s390_setresuid16, u16, ruid, u16, euid, u16, suid)
@@ -173,12 +173,12 @@
COMPAT_SYSCALL_DEFINE1(s390_setfsuid16, u16, uid)
{
- return sys_setfsuid((uid_t)uid);
+ return sys_setfsuid(low2highuid(uid));
}
COMPAT_SYSCALL_DEFINE1(s390_setfsgid16, u16, gid)
{
- return sys_setfsgid((gid_t)gid);
+ return sys_setfsgid(low2highgid(gid));
}
static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index ff63934..c5b9977 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -607,7 +607,8 @@
break;
}
- force_sig_info(SIGFPE, &info, current);
+ info.si_signo = SIGFPE;
+ force_sig_info(info.si_signo, &info, current);
}
#endif
diff --git a/arch/sparc/crypto/crc32c_glue.c b/arch/sparc/crypto/crc32c_glue.c
index d1064e4..8aa6646 100644
--- a/arch/sparc/crypto/crc32c_glue.c
+++ b/arch/sparc/crypto/crc32c_glue.c
@@ -133,6 +133,7 @@
.cra_name = "crc32c",
.cra_driver_name = "crc32c-sparc64",
.cra_priority = SPARC_CR_OPCODE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
.cra_blocksize = CHKSUM_BLOCK_SIZE,
.cra_ctxsize = sizeof(u32),
.cra_alignmask = 7,
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index d2f5372..957731d 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1058,7 +1058,7 @@
def_bool y
config X86_MCE_INJECT
- depends on X86_MCE
+ depends on X86_MCE && X86_LOCAL_APIC
tristate "Machine check injector support"
---help---
Provide support for injecting machine checks for testing purposes.
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 67eec55..4386440 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -352,6 +352,7 @@
config PUNIT_ATOM_DEBUG
tristate "ATOM Punit debug driver"
+ depends on PCI
select DEBUG_FS
select IOSF_MBI
---help---
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 10a7d0f..ea24114 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -11,6 +11,16 @@
KBUILD_DEFCONFIG := $(ARCH)_defconfig
endif
+# For gcc stack alignment is specified with -mpreferred-stack-boundary,
+# clang has the option -mstack-alignment for that purpose.
+ifneq ($(call cc-option, -mpreferred-stack-boundary=4),)
+ cc_stack_align4 := -mpreferred-stack-boundary=2
+ cc_stack_align8 := -mpreferred-stack-boundary=3
+else ifneq ($(call cc-option, -mstack-alignment=16),)
+ cc_stack_align4 := -mstack-alignment=4
+ cc_stack_align8 := -mstack-alignment=8
+endif
+
# How to compile the 16-bit code. Note we always compile for -march=i386;
# that way we can complain to the user if the CPU is insufficient.
#
@@ -24,10 +34,11 @@
-DDISABLE_BRANCH_PROFILING \
-Wall -Wstrict-prototypes -march=i386 -mregparm=3 \
-fno-strict-aliasing -fomit-frame-pointer -fno-pic \
- -mno-mmx -mno-sse \
- $(call cc-option, -ffreestanding) \
- $(call cc-option, -fno-stack-protector) \
- $(call cc-option, -mpreferred-stack-boundary=2)
+ -mno-mmx -mno-sse
+
+REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), -ffreestanding)
+REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), -fno-stack-protector)
+REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), $(cc_stack_align4))
export REALMODE_CFLAGS
# BITS is used as extension for files which are available in a 32 bit
@@ -64,8 +75,10 @@
# with nonstandard options
KBUILD_CFLAGS += -fno-pic
- # prevent gcc from keeping the stack 16 byte aligned
- KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2)
+ # Align the stack to the register width instead of using the default
+ # alignment of 16 bytes. This reduces stack usage and the number of
+ # alignment instructions.
+ KBUILD_CFLAGS += $(call cc-option,$(cc_stack_align4))
# Disable unit-at-a-time mode on pre-gcc-4.0 compilers, it makes gcc use
# a lot more stack due to the lack of sharing of stacklots:
@@ -88,10 +101,10 @@
KBUILD_CFLAGS += -m64
# Align jump targets to 1 byte, not the default 16 bytes:
- KBUILD_CFLAGS += -falign-jumps=1
+ KBUILD_CFLAGS += $(call cc-option,-falign-jumps=1)
# Pack loops tightly as well:
- KBUILD_CFLAGS += -falign-loops=1
+ KBUILD_CFLAGS += $(call cc-option,-falign-loops=1)
# Don't autogenerate traditional x87 instructions
KBUILD_CFLAGS += $(call cc-option,-mno-80387)
@@ -99,8 +112,14 @@
KBUILD_CFLAGS += -fno-pic
- # Use -mpreferred-stack-boundary=3 if supported.
- KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=3)
+ # By default gcc and clang use a stack alignment of 16 bytes for x86.
+ # However the standard kernel entry on x86-64 leaves the stack on an
+ # 8-byte boundary. If the compiler isn't informed about the actual
+ # alignment it will generate extra alignment instructions for the
+ # default alignment which keep the stack *mis*aligned.
+ # Furthermore an alignment to the register width reduces stack usage
+ # and the number of alignment instructions.
+ KBUILD_CFLAGS += $(call cc-option,$(cc_stack_align8))
# Use -mskip-rax-setup if supported.
KBUILD_CFLAGS += $(call cc-option,-mskip-rax-setup)
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 12ea8f8..3b7156f 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -73,12 +73,13 @@
$(obj)/bzImage: asflags-y := $(SVGA_MODE)
quiet_cmd_image = BUILD $@
+silent_redirect_image = >/dev/null
cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \
- $(obj)/zoffset.h $@
+ $(obj)/zoffset.h $@ $($(quiet)redirect_image)
$(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
$(call if_changed,image)
- @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
+ @$(kecho) 'Kernel: $@ is ready' ' (#'`cat .version`')'
OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S
$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c
index 9e240fc..08dfce0 100644
--- a/arch/x86/boot/string.c
+++ b/arch/x86/boot/string.c
@@ -16,6 +16,15 @@
#include "ctype.h"
#include "string.h"
+/*
+ * Undef these macros so that the functions that we provide
+ * here will have the correct names regardless of how string.h
+ * may have chosen to #define them.
+ */
+#undef memcpy
+#undef memset
+#undef memcmp
+
int memcmp(const void *s1, const void *s2, size_t len)
{
bool diff;
diff --git a/arch/x86/crypto/aes_ctrby8_avx-x86_64.S b/arch/x86/crypto/aes_ctrby8_avx-x86_64.S
index a916c4a..5f6a5af 100644
--- a/arch/x86/crypto/aes_ctrby8_avx-x86_64.S
+++ b/arch/x86/crypto/aes_ctrby8_avx-x86_64.S
@@ -65,7 +65,6 @@
#include <linux/linkage.h>
#include <asm/inst.h>
-#define CONCAT(a,b) a##b
#define VMOVDQ vmovdqu
#define xdata0 %xmm0
@@ -92,8 +91,6 @@
#define num_bytes %r8
#define tmp %r10
-#define DDQ(i) CONCAT(ddq_add_,i)
-#define XMM(i) CONCAT(%xmm, i)
#define DDQ_DATA 0
#define XDATA 1
#define KEY_128 1
@@ -131,12 +128,12 @@
/* generate a unique variable for ddq_add_x */
.macro setddq n
- var_ddq_add = DDQ(\n)
+ var_ddq_add = ddq_add_\n
.endm
/* generate a unique variable for xmm register */
.macro setxdata n
- var_xdata = XMM(\n)
+ var_xdata = %xmm\n
.endm
/* club the numeric 'id' to the symbol 'name' */
diff --git a/arch/x86/crypto/crc32-pclmul_glue.c b/arch/x86/crypto/crc32-pclmul_glue.c
index 27226df..c8d9cda 100644
--- a/arch/x86/crypto/crc32-pclmul_glue.c
+++ b/arch/x86/crypto/crc32-pclmul_glue.c
@@ -162,6 +162,7 @@
.cra_name = "crc32",
.cra_driver_name = "crc32-pclmul",
.cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
.cra_blocksize = CHKSUM_BLOCK_SIZE,
.cra_ctxsize = sizeof(u32),
.cra_module = THIS_MODULE,
diff --git a/arch/x86/crypto/crc32c-intel_glue.c b/arch/x86/crypto/crc32c-intel_glue.c
index 0857b1a..60a391b 100644
--- a/arch/x86/crypto/crc32c-intel_glue.c
+++ b/arch/x86/crypto/crc32c-intel_glue.c
@@ -239,6 +239,7 @@
.cra_name = "crc32c",
.cra_driver_name = "crc32c-intel",
.cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
.cra_blocksize = CHKSUM_BLOCK_SIZE,
.cra_ctxsize = sizeof(u32),
.cra_module = THIS_MODULE,
diff --git a/arch/x86/crypto/poly1305_glue.c b/arch/x86/crypto/poly1305_glue.c
index e32142b..28c3720 100644
--- a/arch/x86/crypto/poly1305_glue.c
+++ b/arch/x86/crypto/poly1305_glue.c
@@ -164,7 +164,6 @@
.init = poly1305_simd_init,
.update = poly1305_simd_update,
.final = crypto_poly1305_final,
- .setkey = crypto_poly1305_setkey,
.descsize = sizeof(struct poly1305_simd_desc_ctx),
.base = {
.cra_name = "poly1305",
diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c b/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c
index 36870b2..d088050 100644
--- a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c
+++ b/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c
@@ -57,10 +57,12 @@
{
unsigned int j;
- state->lens[0] = 0;
- state->lens[1] = 1;
- state->lens[2] = 2;
- state->lens[3] = 3;
+ /* initially all lanes are unused */
+ state->lens[0] = 0xFFFFFFFF00000000;
+ state->lens[1] = 0xFFFFFFFF00000001;
+ state->lens[2] = 0xFFFFFFFF00000002;
+ state->lens[3] = 0xFFFFFFFF00000003;
+
state->unused_lanes = 0xFF03020100;
for (j = 0; j < 4; j++)
state->ldata[j].job_in_lane = NULL;
diff --git a/arch/x86/crypto/twofish-x86_64-asm_64-3way.S b/arch/x86/crypto/twofish-x86_64-asm_64-3way.S
index 1c3b7ce..e7273a6 100644
--- a/arch/x86/crypto/twofish-x86_64-asm_64-3way.S
+++ b/arch/x86/crypto/twofish-x86_64-asm_64-3way.S
@@ -55,29 +55,31 @@
#define RAB1bl %bl
#define RAB2bl %cl
+#define CD0 0x0(%rsp)
+#define CD1 0x8(%rsp)
+#define CD2 0x10(%rsp)
+
+# used only before/after all rounds
#define RCD0 %r8
#define RCD1 %r9
#define RCD2 %r10
-#define RCD0d %r8d
-#define RCD1d %r9d
-#define RCD2d %r10d
+# used only during rounds
+#define RX0 %r8
+#define RX1 %r9
+#define RX2 %r10
-#define RX0 %rbp
-#define RX1 %r11
-#define RX2 %r12
+#define RX0d %r8d
+#define RX1d %r9d
+#define RX2d %r10d
-#define RX0d %ebp
-#define RX1d %r11d
-#define RX2d %r12d
+#define RY0 %r11
+#define RY1 %r12
+#define RY2 %r13
-#define RY0 %r13
-#define RY1 %r14
-#define RY2 %r15
-
-#define RY0d %r13d
-#define RY1d %r14d
-#define RY2d %r15d
+#define RY0d %r11d
+#define RY1d %r12d
+#define RY2d %r13d
#define RT0 %rdx
#define RT1 %rsi
@@ -85,6 +87,8 @@
#define RT0d %edx
#define RT1d %esi
+#define RT1bl %sil
+
#define do16bit_ror(rot, op1, op2, T0, T1, tmp1, tmp2, ab, dst) \
movzbl ab ## bl, tmp2 ## d; \
movzbl ab ## bh, tmp1 ## d; \
@@ -92,6 +96,11 @@
op1##l T0(CTX, tmp2, 4), dst ## d; \
op2##l T1(CTX, tmp1, 4), dst ## d;
+#define swap_ab_with_cd(ab, cd, tmp) \
+ movq cd, tmp; \
+ movq ab, cd; \
+ movq tmp, ab;
+
/*
* Combined G1 & G2 function. Reordered with help of rotates to have moves
* at begining.
@@ -110,15 +119,15 @@
/* G1,2 && G2,2 */ \
do16bit_ror(32, xor, xor, Tx2, Tx3, RT0, RT1, ab ## 0, x ## 0); \
do16bit_ror(16, xor, xor, Ty3, Ty0, RT0, RT1, ab ## 0, y ## 0); \
- xchgq cd ## 0, ab ## 0; \
+ swap_ab_with_cd(ab ## 0, cd ## 0, RT0); \
\
do16bit_ror(32, xor, xor, Tx2, Tx3, RT0, RT1, ab ## 1, x ## 1); \
do16bit_ror(16, xor, xor, Ty3, Ty0, RT0, RT1, ab ## 1, y ## 1); \
- xchgq cd ## 1, ab ## 1; \
+ swap_ab_with_cd(ab ## 1, cd ## 1, RT0); \
\
do16bit_ror(32, xor, xor, Tx2, Tx3, RT0, RT1, ab ## 2, x ## 2); \
do16bit_ror(16, xor, xor, Ty3, Ty0, RT0, RT1, ab ## 2, y ## 2); \
- xchgq cd ## 2, ab ## 2;
+ swap_ab_with_cd(ab ## 2, cd ## 2, RT0);
#define enc_round_end(ab, x, y, n) \
addl y ## d, x ## d; \
@@ -168,6 +177,16 @@
decrypt_round3(ba, dc, (n*2)+1); \
decrypt_round3(ba, dc, (n*2));
+#define push_cd() \
+ pushq RCD2; \
+ pushq RCD1; \
+ pushq RCD0;
+
+#define pop_cd() \
+ popq RCD0; \
+ popq RCD1; \
+ popq RCD2;
+
#define inpack3(in, n, xy, m) \
movq 4*(n)(in), xy ## 0; \
xorq w+4*m(CTX), xy ## 0; \
@@ -223,11 +242,8 @@
* %rdx: src, RIO
* %rcx: bool, if true: xor output
*/
- pushq %r15;
- pushq %r14;
pushq %r13;
pushq %r12;
- pushq %rbp;
pushq %rbx;
pushq %rcx; /* bool xor */
@@ -235,40 +251,36 @@
inpack_enc3();
- encrypt_cycle3(RAB, RCD, 0);
- encrypt_cycle3(RAB, RCD, 1);
- encrypt_cycle3(RAB, RCD, 2);
- encrypt_cycle3(RAB, RCD, 3);
- encrypt_cycle3(RAB, RCD, 4);
- encrypt_cycle3(RAB, RCD, 5);
- encrypt_cycle3(RAB, RCD, 6);
- encrypt_cycle3(RAB, RCD, 7);
+ push_cd();
+ encrypt_cycle3(RAB, CD, 0);
+ encrypt_cycle3(RAB, CD, 1);
+ encrypt_cycle3(RAB, CD, 2);
+ encrypt_cycle3(RAB, CD, 3);
+ encrypt_cycle3(RAB, CD, 4);
+ encrypt_cycle3(RAB, CD, 5);
+ encrypt_cycle3(RAB, CD, 6);
+ encrypt_cycle3(RAB, CD, 7);
+ pop_cd();
popq RIO; /* dst */
- popq %rbp; /* bool xor */
+ popq RT1; /* bool xor */
- testb %bpl, %bpl;
+ testb RT1bl, RT1bl;
jnz .L__enc_xor3;
outunpack_enc3(mov);
popq %rbx;
- popq %rbp;
popq %r12;
popq %r13;
- popq %r14;
- popq %r15;
ret;
.L__enc_xor3:
outunpack_enc3(xor);
popq %rbx;
- popq %rbp;
popq %r12;
popq %r13;
- popq %r14;
- popq %r15;
ret;
ENDPROC(__twofish_enc_blk_3way)
@@ -278,35 +290,31 @@
* %rsi: dst
* %rdx: src, RIO
*/
- pushq %r15;
- pushq %r14;
pushq %r13;
pushq %r12;
- pushq %rbp;
pushq %rbx;
pushq %rsi; /* dst */
inpack_dec3();
- decrypt_cycle3(RAB, RCD, 7);
- decrypt_cycle3(RAB, RCD, 6);
- decrypt_cycle3(RAB, RCD, 5);
- decrypt_cycle3(RAB, RCD, 4);
- decrypt_cycle3(RAB, RCD, 3);
- decrypt_cycle3(RAB, RCD, 2);
- decrypt_cycle3(RAB, RCD, 1);
- decrypt_cycle3(RAB, RCD, 0);
+ push_cd();
+ decrypt_cycle3(RAB, CD, 7);
+ decrypt_cycle3(RAB, CD, 6);
+ decrypt_cycle3(RAB, CD, 5);
+ decrypt_cycle3(RAB, CD, 4);
+ decrypt_cycle3(RAB, CD, 3);
+ decrypt_cycle3(RAB, CD, 2);
+ decrypt_cycle3(RAB, CD, 1);
+ decrypt_cycle3(RAB, CD, 0);
+ pop_cd();
popq RIO; /* dst */
outunpack_dec3();
popq %rbx;
- popq %rbp;
popq %r12;
popq %r13;
- popq %r14;
- popq %r15;
ret;
ENDPROC(twofish_dec_blk_3way)
diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c
index bdd9cc5..b0cd306 100644
--- a/arch/x86/entry/common.c
+++ b/arch/x86/entry/common.c
@@ -20,6 +20,7 @@
#include <linux/export.h>
#include <linux/context_tracking.h>
#include <linux/user-return-notifier.h>
+#include <linux/nospec.h>
#include <linux/uprobes.h>
#include <asm/desc.h>
@@ -201,7 +202,7 @@
* special case only applies after poking regs and before the
* very next return to user mode.
*/
- current->thread.status &= ~(TS_COMPAT|TS_I386_REGS_POKED);
+ ti->status &= ~(TS_COMPAT|TS_I386_REGS_POKED);
#endif
user_enter_irqoff();
@@ -277,7 +278,8 @@
* regs->orig_ax, which changes the behavior of some syscalls.
*/
if (likely((nr & __SYSCALL_MASK) < NR_syscalls)) {
- regs->ax = sys_call_table[nr & __SYSCALL_MASK](
+ nr = array_index_nospec(nr & __SYSCALL_MASK, NR_syscalls);
+ regs->ax = sys_call_table[nr](
regs->di, regs->si, regs->dx,
regs->r10, regs->r8, regs->r9);
}
@@ -299,7 +301,7 @@
unsigned int nr = (unsigned int)regs->orig_ax;
#ifdef CONFIG_IA32_EMULATION
- current->thread.status |= TS_COMPAT;
+ ti->status |= TS_COMPAT;
#endif
if (READ_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY) {
@@ -313,6 +315,7 @@
}
if (likely(nr < IA32_NR_syscalls)) {
+ nr = array_index_nospec(nr, IA32_NR_syscalls);
/*
* It's possible that a 32-bit syscall implementation
* takes a 64-bit parameter but nonetheless assumes that
diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S
index a76dc73..f5434b4 100644
--- a/arch/x86/entry/entry_32.S
+++ b/arch/x86/entry/entry_32.S
@@ -237,7 +237,8 @@
* exist, overwrite the RSB with entries which capture
* speculative execution to prevent attack.
*/
- FILL_RETURN_BUFFER %ebx, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
+ /* Clobbers %ebx */
+ FILL_RETURN_BUFFER RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
#endif
/* restore callee-saved registers */
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index e729e15..8be2aaa 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -177,96 +177,17 @@
pushq %r9 /* pt_regs->r9 */
pushq %r10 /* pt_regs->r10 */
pushq %r11 /* pt_regs->r11 */
- sub $(6*8), %rsp /* pt_regs->bp, bx, r12-15 not saved */
+ pushq %rbx /* pt_regs->rbx */
+ pushq %rbp /* pt_regs->rbp */
+ pushq %r12 /* pt_regs->r12 */
+ pushq %r13 /* pt_regs->r13 */
+ pushq %r14 /* pt_regs->r14 */
+ pushq %r15 /* pt_regs->r15 */
- /*
- * If we need to do entry work or if we guess we'll need to do
- * exit work, go straight to the slow path.
- */
- movq PER_CPU_VAR(current_task), %r11
- testl $_TIF_WORK_SYSCALL_ENTRY|_TIF_ALLWORK_MASK, TASK_TI_flags(%r11)
- jnz entry_SYSCALL64_slow_path
-
-entry_SYSCALL_64_fastpath:
- /*
- * Easy case: enable interrupts and issue the syscall. If the syscall
- * needs pt_regs, we'll call a stub that disables interrupts again
- * and jumps to the slow path.
- */
- TRACE_IRQS_ON
- ENABLE_INTERRUPTS(CLBR_NONE)
-#if __SYSCALL_MASK == ~0
- cmpq $__NR_syscall_max, %rax
-#else
- andl $__SYSCALL_MASK, %eax
- cmpl $__NR_syscall_max, %eax
-#endif
- ja 1f /* return -ENOSYS (already in pt_regs->ax) */
- movq %r10, %rcx
-
- /*
- * This call instruction is handled specially in stub_ptregs_64.
- * It might end up jumping to the slow path. If it jumps, RAX
- * and all argument registers are clobbered.
- */
-#ifdef CONFIG_RETPOLINE
- movq sys_call_table(, %rax, 8), %rax
- call __x86_indirect_thunk_rax
-#else
- call *sys_call_table(, %rax, 8)
-#endif
-.Lentry_SYSCALL_64_after_fastpath_call:
-
- movq %rax, RAX(%rsp)
-1:
-
- /*
- * If we get here, then we know that pt_regs is clean for SYSRET64.
- * If we see that no exit work is required (which we are required
- * to check with IRQs off), then we can go straight to SYSRET64.
- */
- DISABLE_INTERRUPTS(CLBR_NONE)
- TRACE_IRQS_OFF
- movq PER_CPU_VAR(current_task), %r11
- testl $_TIF_ALLWORK_MASK, TASK_TI_flags(%r11)
- jnz 1f
-
- LOCKDEP_SYS_EXIT
- TRACE_IRQS_ON /* user mode is traced as IRQs on */
- movq RIP(%rsp), %rcx
- movq EFLAGS(%rsp), %r11
- RESTORE_C_REGS_EXCEPT_RCX_R11
- /*
- * This opens a window where we have a user CR3, but are
- * running in the kernel. This makes using the CS
- * register useless for telling whether or not we need to
- * switch CR3 in NMIs. Normal interrupts are OK because
- * they are off here.
- */
- SWITCH_USER_CR3
- movq RSP(%rsp), %rsp
- USERGS_SYSRET64
-
-1:
- /*
- * The fast path looked good when we started, but something changed
- * along the way and we need to switch to the slow path. Calling
- * raise(3) will trigger this, for example. IRQs are off.
- */
- TRACE_IRQS_ON
- ENABLE_INTERRUPTS(CLBR_NONE)
- SAVE_EXTRA_REGS
- movq %rsp, %rdi
- call syscall_return_slowpath /* returns with IRQs disabled */
- jmp return_from_SYSCALL_64
-
-entry_SYSCALL64_slow_path:
/* IRQs are off. */
- SAVE_EXTRA_REGS
movq %rsp, %rdi
call do_syscall_64 /* returns with IRQs disabled */
-return_from_SYSCALL_64:
RESTORE_EXTRA_REGS
TRACE_IRQS_IRETQ /* we're about to change IF */
@@ -339,6 +260,7 @@
syscall_return_via_sysret:
/* rcx and r11 are already restored (see code above) */
RESTORE_C_REGS_EXCEPT_RCX_R11
+
/*
* This opens a window where we have a user CR3, but are
* running in the kernel. This makes using the CS
@@ -363,45 +285,6 @@
jmp restore_c_regs_and_iret
END(entry_SYSCALL_64)
-ENTRY(stub_ptregs_64)
- /*
- * Syscalls marked as needing ptregs land here.
- * If we are on the fast path, we need to save the extra regs,
- * which we achieve by trying again on the slow path. If we are on
- * the slow path, the extra regs are already saved.
- *
- * RAX stores a pointer to the C function implementing the syscall.
- * IRQs are on.
- */
- cmpq $.Lentry_SYSCALL_64_after_fastpath_call, (%rsp)
- jne 1f
-
- /*
- * Called from fast path -- disable IRQs again, pop return address
- * and jump to slow path
- */
- DISABLE_INTERRUPTS(CLBR_NONE)
- TRACE_IRQS_OFF
- popq %rax
- jmp entry_SYSCALL64_slow_path
-
-1:
- JMP_NOSPEC %rax /* Called from C */
-END(stub_ptregs_64)
-
-.macro ptregs_stub func
-ENTRY(ptregs_\func)
- leaq \func(%rip), %rax
- jmp stub_ptregs_64
-END(ptregs_\func)
-.endm
-
-/* Instantiate ptregs_stub for each ptregs-using syscall */
-#define __SYSCALL_64_QUAL_(sym)
-#define __SYSCALL_64_QUAL_ptregs(sym) ptregs_stub sym
-#define __SYSCALL_64(nr, sym, qual) __SYSCALL_64_QUAL_##qual(sym)
-#include <asm/syscalls_64.h>
-
/*
* %rdi: prev task
* %rsi: next task
@@ -435,7 +318,8 @@
* exist, overwrite the RSB with entries which capture
* speculative execution to prevent attack.
*/
- FILL_RETURN_BUFFER %r12, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
+ /* Clobbers %rbx */
+ FILL_RETURN_BUFFER RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
#endif
/* restore callee-saved registers */
@@ -730,13 +614,8 @@
#endif
/* Make sure APIC interrupt handlers end up in the irqentry section: */
-#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN)
-# define PUSH_SECTION_IRQENTRY .pushsection .irqentry.text, "ax"
-# define POP_SECTION_IRQENTRY .popsection
-#else
-# define PUSH_SECTION_IRQENTRY
-# define POP_SECTION_IRQENTRY
-#endif
+#define PUSH_SECTION_IRQENTRY .pushsection .irqentry.text, "ax"
+#define POP_SECTION_IRQENTRY .popsection
.macro apicinterrupt num sym do_sym
PUSH_SECTION_IRQENTRY
diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S
index d76a976..92c5573 100644
--- a/arch/x86/entry/entry_64_compat.S
+++ b/arch/x86/entry/entry_64_compat.S
@@ -83,15 +83,25 @@
pushq %rcx /* pt_regs->cx */
pushq $-ENOSYS /* pt_regs->ax */
pushq $0 /* pt_regs->r8 = 0 */
+ xorq %r8, %r8 /* nospec r8 */
pushq $0 /* pt_regs->r9 = 0 */
+ xorq %r9, %r9 /* nospec r9 */
pushq $0 /* pt_regs->r10 = 0 */
+ xorq %r10, %r10 /* nospec r10 */
pushq $0 /* pt_regs->r11 = 0 */
+ xorq %r11, %r11 /* nospec r11 */
pushq %rbx /* pt_regs->rbx */
+ xorl %ebx, %ebx /* nospec rbx */
pushq %rbp /* pt_regs->rbp (will be overwritten) */
+ xorl %ebp, %ebp /* nospec rbp */
pushq $0 /* pt_regs->r12 = 0 */
+ xorq %r12, %r12 /* nospec r12 */
pushq $0 /* pt_regs->r13 = 0 */
+ xorq %r13, %r13 /* nospec r13 */
pushq $0 /* pt_regs->r14 = 0 */
+ xorq %r14, %r14 /* nospec r14 */
pushq $0 /* pt_regs->r15 = 0 */
+ xorq %r15, %r15 /* nospec r15 */
cld
/*
@@ -209,15 +219,25 @@
pushq %rbp /* pt_regs->cx (stashed in bp) */
pushq $-ENOSYS /* pt_regs->ax */
pushq $0 /* pt_regs->r8 = 0 */
+ xorq %r8, %r8 /* nospec r8 */
pushq $0 /* pt_regs->r9 = 0 */
+ xorq %r9, %r9 /* nospec r9 */
pushq $0 /* pt_regs->r10 = 0 */
+ xorq %r10, %r10 /* nospec r10 */
pushq $0 /* pt_regs->r11 = 0 */
+ xorq %r11, %r11 /* nospec r11 */
pushq %rbx /* pt_regs->rbx */
+ xorl %ebx, %ebx /* nospec rbx */
pushq %rbp /* pt_regs->rbp (will be overwritten) */
+ xorl %ebp, %ebp /* nospec rbp */
pushq $0 /* pt_regs->r12 = 0 */
+ xorq %r12, %r12 /* nospec r12 */
pushq $0 /* pt_regs->r13 = 0 */
+ xorq %r13, %r13 /* nospec r13 */
pushq $0 /* pt_regs->r14 = 0 */
+ xorq %r14, %r14 /* nospec r14 */
pushq $0 /* pt_regs->r15 = 0 */
+ xorq %r15, %r15 /* nospec r15 */
/*
* User mode is traced as though IRQs are on, and SYSENTER
@@ -320,15 +340,25 @@
pushq %rcx /* pt_regs->cx */
pushq $-ENOSYS /* pt_regs->ax */
pushq $0 /* pt_regs->r8 = 0 */
+ xorq %r8, %r8 /* nospec r8 */
pushq $0 /* pt_regs->r9 = 0 */
+ xorq %r9, %r9 /* nospec r9 */
pushq $0 /* pt_regs->r10 = 0 */
+ xorq %r10, %r10 /* nospec r10 */
pushq $0 /* pt_regs->r11 = 0 */
+ xorq %r11, %r11 /* nospec r11 */
pushq %rbx /* pt_regs->rbx */
+ xorl %ebx, %ebx /* nospec rbx */
pushq %rbp /* pt_regs->rbp */
+ xorl %ebp, %ebp /* nospec rbp */
pushq %r12 /* pt_regs->r12 */
+ xorq %r12, %r12 /* nospec r12 */
pushq %r13 /* pt_regs->r13 */
+ xorq %r13, %r13 /* nospec r13 */
pushq %r14 /* pt_regs->r14 */
+ xorq %r14, %r14 /* nospec r14 */
pushq %r15 /* pt_regs->r15 */
+ xorq %r15, %r15 /* nospec r15 */
cld
/*
diff --git a/arch/x86/entry/syscall_64.c b/arch/x86/entry/syscall_64.c
index 9dbc5ab..6705edd 100644
--- a/arch/x86/entry/syscall_64.c
+++ b/arch/x86/entry/syscall_64.c
@@ -6,14 +6,11 @@
#include <asm/asm-offsets.h>
#include <asm/syscall.h>
-#define __SYSCALL_64_QUAL_(sym) sym
-#define __SYSCALL_64_QUAL_ptregs(sym) ptregs_##sym
-
-#define __SYSCALL_64(nr, sym, qual) extern asmlinkage long __SYSCALL_64_QUAL_##qual(sym)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
+#define __SYSCALL_64(nr, sym, qual) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
#include <asm/syscalls_64.h>
#undef __SYSCALL_64
-#define __SYSCALL_64(nr, sym, qual) [nr] = __SYSCALL_64_QUAL_##qual(sym),
+#define __SYSCALL_64(nr, sym, qual) [nr] = sym,
extern long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 9604b25..f73796d 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -190,8 +190,8 @@
static bool check_hw_exists(void)
{
- u64 val, val_fail, val_new= ~0;
- int i, reg, reg_fail, ret = 0;
+ u64 val, val_fail = -1, val_new= ~0;
+ int i, reg, reg_fail = -1, ret = 0;
int bios_fail = 0;
int reg_safe = -1;
diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c
index 982c9e3..21298c1 100644
--- a/arch/x86/events/intel/bts.c
+++ b/arch/x86/events/intel/bts.c
@@ -22,6 +22,7 @@
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/coredump.h>
+#include <linux/kaiser.h>
#include <asm-generic/sizes.h>
#include <asm/perf_event.h>
@@ -77,6 +78,23 @@
return 1 << (PAGE_SHIFT + page_private(page));
}
+static void bts_buffer_free_aux(void *data)
+{
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+ struct bts_buffer *buf = data;
+ int nbuf;
+
+ for (nbuf = 0; nbuf < buf->nr_bufs; nbuf++) {
+ struct page *page = buf->buf[nbuf].page;
+ void *kaddr = page_address(page);
+ size_t page_size = buf_size(page);
+
+ kaiser_remove_mapping((unsigned long)kaddr, page_size);
+ }
+#endif
+ kfree(data);
+}
+
static void *
bts_buffer_setup_aux(int cpu, void **pages, int nr_pages, bool overwrite)
{
@@ -113,29 +131,33 @@
buf->real_size = size - size % BTS_RECORD_SIZE;
for (pg = 0, nbuf = 0, offset = 0, pad = 0; nbuf < buf->nr_bufs; nbuf++) {
- unsigned int __nr_pages;
+ void *kaddr = pages[pg];
+ size_t page_size;
- page = virt_to_page(pages[pg]);
- __nr_pages = PagePrivate(page) ? 1 << page_private(page) : 1;
+ page = virt_to_page(kaddr);
+ page_size = buf_size(page);
+
+ if (kaiser_add_mapping((unsigned long)kaddr,
+ page_size, __PAGE_KERNEL) < 0) {
+ buf->nr_bufs = nbuf;
+ bts_buffer_free_aux(buf);
+ return NULL;
+ }
+
buf->buf[nbuf].page = page;
buf->buf[nbuf].offset = offset;
buf->buf[nbuf].displacement = (pad ? BTS_RECORD_SIZE - pad : 0);
- buf->buf[nbuf].size = buf_size(page) - buf->buf[nbuf].displacement;
+ buf->buf[nbuf].size = page_size - buf->buf[nbuf].displacement;
pad = buf->buf[nbuf].size % BTS_RECORD_SIZE;
buf->buf[nbuf].size -= pad;
- pg += __nr_pages;
- offset += __nr_pages << PAGE_SHIFT;
+ pg += page_size >> PAGE_SHIFT;
+ offset += page_size;
}
return buf;
}
-static void bts_buffer_free_aux(void *data)
-{
- kfree(data);
-}
-
static unsigned long bts_buffer_offset(struct bts_buffer *buf, unsigned int idx)
{
return buf->buf[idx].offset + buf->buf[idx].displacement;
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index f0f197f..0bd0c1c 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -3363,7 +3363,7 @@
break;
case INTEL_FAM6_SANDYBRIDGE_X:
- switch (cpu_data(cpu).x86_mask) {
+ switch (cpu_data(cpu).x86_stepping) {
case 6: rev = 0x618; break;
case 7: rev = 0x70c; break;
}
diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c
index f924629..5d103a8 100644
--- a/arch/x86/events/intel/lbr.c
+++ b/arch/x86/events/intel/lbr.c
@@ -1131,7 +1131,7 @@
* on PMU interrupt
*/
if (boot_cpu_data.x86_model == 28
- && boot_cpu_data.x86_mask < 10) {
+ && boot_cpu_data.x86_stepping < 10) {
pr_cont("LBR disabled due to erratum");
return;
}
diff --git a/arch/x86/events/intel/p6.c b/arch/x86/events/intel/p6.c
index 1f5c47a..c5e441b 100644
--- a/arch/x86/events/intel/p6.c
+++ b/arch/x86/events/intel/p6.c
@@ -233,7 +233,7 @@
static __init void p6_pmu_rdpmc_quirk(void)
{
- if (boot_cpu_data.x86_mask < 9) {
+ if (boot_cpu_data.x86_stepping < 9) {
/*
* PPro erratum 26; fixed in stepping 9 and above.
*/
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h
index 5391b0a..d32bab6 100644
--- a/arch/x86/include/asm/acpi.h
+++ b/arch/x86/include/asm/acpi.h
@@ -92,7 +92,7 @@
if (boot_cpu_data.x86 == 0x0F &&
boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
boot_cpu_data.x86_model <= 0x05 &&
- boot_cpu_data.x86_mask < 0x0A)
+ boot_cpu_data.x86_stepping < 0x0A)
return 1;
else if (amd_e400_c1e_detected)
return 1;
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h
index deca9b9..6665000 100644
--- a/arch/x86/include/asm/alternative.h
+++ b/arch/x86/include/asm/alternative.h
@@ -218,10 +218,9 @@
#define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2, \
output, input...) \
{ \
- register void *__sp asm(_ASM_SP); \
asm volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1,\
"call %P[new2]", feature2) \
- : output, "+r" (__sp) \
+ : output, ASM_CALL_CONSTRAINT \
: [old] "i" (oldfunc), [new1] "i" (newfunc1), \
[new2] "i" (newfunc2), ## input); \
}
diff --git a/arch/x86/include/asm/asm-prototypes.h b/arch/x86/include/asm/asm-prototypes.h
index b15aa40..1666542 100644
--- a/arch/x86/include/asm/asm-prototypes.h
+++ b/arch/x86/include/asm/asm-prototypes.h
@@ -37,5 +37,7 @@
INDIRECT_THUNK(si)
INDIRECT_THUNK(di)
INDIRECT_THUNK(bp)
-INDIRECT_THUNK(sp)
+asmlinkage void __fill_rsb(void);
+asmlinkage void __clear_rsb(void);
+
#endif /* CONFIG_RETPOLINE */
diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h
index 0052352..08684b3 100644
--- a/arch/x86/include/asm/asm.h
+++ b/arch/x86/include/asm/asm.h
@@ -11,10 +11,12 @@
# define __ASM_FORM_COMMA(x) " " #x ","
#endif
-#ifdef CONFIG_X86_32
+#ifndef __x86_64__
+/* 32 bit */
# define __ASM_SEL(a,b) __ASM_FORM(a)
# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a)
#else
+/* 64 bit */
# define __ASM_SEL(a,b) __ASM_FORM(b)
# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b)
#endif
@@ -32,6 +34,7 @@
#define _ASM_ADD __ASM_SIZE(add)
#define _ASM_SUB __ASM_SIZE(sub)
#define _ASM_XADD __ASM_SIZE(xadd)
+#define _ASM_MUL __ASM_SIZE(mul)
#define _ASM_AX __ASM_REG(ax)
#define _ASM_BX __ASM_REG(bx)
diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h
index bfb28ca..78d1c6a 100644
--- a/arch/x86/include/asm/barrier.h
+++ b/arch/x86/include/asm/barrier.h
@@ -23,6 +23,34 @@
#define wmb() asm volatile("sfence" ::: "memory")
#endif
+/**
+ * array_index_mask_nospec() - generate a mask that is ~0UL when the
+ * bounds check succeeds and 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ *
+ * Returns:
+ * 0 - (index < size)
+ */
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+ unsigned long size)
+{
+ unsigned long mask;
+
+ asm ("cmp %1,%2; sbb %0,%0;"
+ :"=r" (mask)
+ :"g"(size),"r" (index)
+ :"cc");
+ return mask;
+}
+
+/* Override the default implementation from linux/nospec.h. */
+#define array_index_mask_nospec array_index_mask_nospec
+
+/* Prevent speculative execution past this barrier. */
+#define barrier_nospec() alternative_2("", "mfence", X86_FEATURE_MFENCE_RDTSC, \
+ "lfence", X86_FEATURE_LFENCE_RDTSC)
+
#ifdef CONFIG_X86_PPRO_FENCE
#define dma_rmb() rmb()
#else
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 9ea67a0..8c10157 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -28,6 +28,7 @@
CPUID_8000_000A_EDX,
CPUID_7_ECX,
CPUID_8000_0007_EBX,
+ CPUID_7_EDX,
};
#ifdef CONFIG_X86_FEATURE_NAMES
@@ -78,8 +79,9 @@
CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 15, feature_bit) || \
CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 16, feature_bit) || \
CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 17, feature_bit) || \
+ CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 18, feature_bit) || \
REQUIRED_MASK_CHECK || \
- BUILD_BUG_ON_ZERO(NCAPINTS != 18))
+ BUILD_BUG_ON_ZERO(NCAPINTS != 19))
#define DISABLED_MASK_BIT_SET(feature_bit) \
( CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 0, feature_bit) || \
@@ -100,8 +102,9 @@
CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 15, feature_bit) || \
CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 16, feature_bit) || \
CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 17, feature_bit) || \
+ CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 18, feature_bit) || \
DISABLED_MASK_CHECK || \
- BUILD_BUG_ON_ZERO(NCAPINTS != 18))
+ BUILD_BUG_ON_ZERO(NCAPINTS != 19))
#define cpu_has(c, bit) \
(__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 8537a21..8eb23f5 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -12,7 +12,7 @@
/*
* Defines x86 CPU feature bits
*/
-#define NCAPINTS 18 /* N 32-bit words worth of info */
+#define NCAPINTS 19 /* N 32-bit words worth of info */
#define NBUGINTS 1 /* N 32-bit bug flags */
/*
@@ -194,16 +194,16 @@
#define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */
#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
-#define X86_FEATURE_RETPOLINE ( 7*32+12) /* Generic Retpoline mitigation for Spectre variant 2 */
-#define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* AMD Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */
-#define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */
-#define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */
-#define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* Fill RSB on context switches */
+#define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* "" Fill RSB on context switches */
/* Because the ALTERNATIVE scheme is for members of the X86_FEATURE club... */
#define X86_FEATURE_KAISER ( 7*32+31) /* CONFIG_PAGE_TABLE_ISOLATION w/o nokaiser */
+#define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */
+
/* Virtualization flags: Linux defined, word 8 */
#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */
#define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */
@@ -260,6 +260,9 @@
/* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */
#define X86_FEATURE_CLZERO (13*32+0) /* CLZERO instruction */
#define X86_FEATURE_IRPERF (13*32+1) /* Instructions Retired Count */
+#define X86_FEATURE_IBPB (13*32+12) /* Indirect Branch Prediction Barrier */
+#define X86_FEATURE_IBRS (13*32+14) /* Indirect Branch Restricted Speculation */
+#define X86_FEATURE_STIBP (13*32+15) /* Single Thread Indirect Branch Predictors */
/* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */
#define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */
@@ -295,6 +298,13 @@
#define X86_FEATURE_SUCCOR (17*32+1) /* Uncorrectable error containment and recovery */
#define X86_FEATURE_SMCA (17*32+3) /* Scalable MCA */
+/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */
+#define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */
+#define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */
+#define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */
+#define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */
+#define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */
+
/*
* BUG word(s)
*/
diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h
index 21c5ac1..1f8cca4 100644
--- a/arch/x86/include/asm/disabled-features.h
+++ b/arch/x86/include/asm/disabled-features.h
@@ -59,6 +59,7 @@
#define DISABLED_MASK15 0
#define DISABLED_MASK16 (DISABLE_PKU|DISABLE_OSPKE)
#define DISABLED_MASK17 0
-#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18)
+#define DISABLED_MASK18 0
+#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19)
#endif /* _ASM_X86_DISABLED_FEATURES_H */
diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h
index 34a46dc..75b748a 100644
--- a/arch/x86/include/asm/intel-family.h
+++ b/arch/x86/include/asm/intel-family.h
@@ -12,6 +12,7 @@
*/
#define INTEL_FAM6_CORE_YONAH 0x0E
+
#define INTEL_FAM6_CORE2_MEROM 0x0F
#define INTEL_FAM6_CORE2_MEROM_L 0x16
#define INTEL_FAM6_CORE2_PENRYN 0x17
@@ -21,6 +22,7 @@
#define INTEL_FAM6_NEHALEM_G 0x1F /* Auburndale / Havendale */
#define INTEL_FAM6_NEHALEM_EP 0x1A
#define INTEL_FAM6_NEHALEM_EX 0x2E
+
#define INTEL_FAM6_WESTMERE 0x25
#define INTEL_FAM6_WESTMERE_EP 0x2C
#define INTEL_FAM6_WESTMERE_EX 0x2F
@@ -36,9 +38,9 @@
#define INTEL_FAM6_HASWELL_GT3E 0x46
#define INTEL_FAM6_BROADWELL_CORE 0x3D
-#define INTEL_FAM6_BROADWELL_XEON_D 0x56
#define INTEL_FAM6_BROADWELL_GT3E 0x47
#define INTEL_FAM6_BROADWELL_X 0x4F
+#define INTEL_FAM6_BROADWELL_XEON_D 0x56
#define INTEL_FAM6_SKYLAKE_MOBILE 0x4E
#define INTEL_FAM6_SKYLAKE_DESKTOP 0x5E
@@ -57,9 +59,10 @@
#define INTEL_FAM6_ATOM_SILVERMONT2 0x4D /* Avaton/Rangely */
#define INTEL_FAM6_ATOM_AIRMONT 0x4C /* CherryTrail / Braswell */
#define INTEL_FAM6_ATOM_MERRIFIELD 0x4A /* Tangier */
-#define INTEL_FAM6_ATOM_MOOREFIELD 0x5A /* Annidale */
+#define INTEL_FAM6_ATOM_MOOREFIELD 0x5A /* Anniedale */
#define INTEL_FAM6_ATOM_GOLDMONT 0x5C
#define INTEL_FAM6_ATOM_DENVERTON 0x5F /* Goldmont Microserver */
+#define INTEL_FAM6_ATOM_GEMINI_LAKE 0x7A
/* Xeon Phi */
diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h
index 15eb754..98ccbd1 100644
--- a/arch/x86/include/asm/microcode_amd.h
+++ b/arch/x86/include/asm/microcode_amd.h
@@ -59,7 +59,6 @@
extern int __apply_microcode_amd(struct microcode_amd *mc_amd);
extern int apply_microcode_amd(int cpu);
-extern enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size);
#define PATCH_MAX_SIZE PAGE_SIZE
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index b11c4c0..c768bc1 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -37,6 +37,13 @@
#define EFER_FFXSR (1<<_EFER_FFXSR)
/* Intel MSRs. Some also available on other CPUs */
+#define MSR_IA32_SPEC_CTRL 0x00000048 /* Speculation Control */
+#define SPEC_CTRL_IBRS (1 << 0) /* Indirect Branch Restricted Speculation */
+#define SPEC_CTRL_STIBP (1 << 1) /* Single Thread Indirect Branch Predictors */
+
+#define MSR_IA32_PRED_CMD 0x00000049 /* Prediction Command */
+#define PRED_CMD_IBPB (1 << 0) /* Indirect Branch Prediction Barrier */
+
#define MSR_IA32_PERFCTR0 0x000000c1
#define MSR_IA32_PERFCTR1 0x000000c2
#define MSR_FSB_FREQ 0x000000cd
@@ -50,6 +57,11 @@
#define SNB_C3_AUTO_UNDEMOTE (1UL << 28)
#define MSR_MTRRcap 0x000000fe
+
+#define MSR_IA32_ARCH_CAPABILITIES 0x0000010a
+#define ARCH_CAP_RDCL_NO (1 << 0) /* Not susceptible to Meltdown */
+#define ARCH_CAP_IBRS_ALL (1 << 1) /* Enhanced IBRS support */
+
#define MSR_IA32_BBL_CR_CTL 0x00000119
#define MSR_IA32_BBL_CR_CTL3 0x0000011e
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index b5fee97..ed35b91 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -188,8 +188,7 @@
* that some other imaginary CPU is updating continuously with a
* time stamp.
*/
- alternative_2("", "mfence", X86_FEATURE_MFENCE_RDTSC,
- "lfence", X86_FEATURE_LFENCE_RDTSC);
+ barrier_nospec();
return rdtsc();
}
diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
index 4ad4108..76b0585 100644
--- a/arch/x86/include/asm/nospec-branch.h
+++ b/arch/x86/include/asm/nospec-branch.h
@@ -1,55 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __NOSPEC_BRANCH_H__
-#define __NOSPEC_BRANCH_H__
+#ifndef _ASM_X86_NOSPEC_BRANCH_H_
+#define _ASM_X86_NOSPEC_BRANCH_H_
#include <asm/alternative.h>
#include <asm/alternative-asm.h>
#include <asm/cpufeatures.h>
-
-/*
- * Fill the CPU return stack buffer.
- *
- * Each entry in the RSB, if used for a speculative 'ret', contains an
- * infinite 'pause; lfence; jmp' loop to capture speculative execution.
- *
- * This is required in various cases for retpoline and IBRS-based
- * mitigations for the Spectre variant 2 vulnerability. Sometimes to
- * eliminate potentially bogus entries from the RSB, and sometimes
- * purely to ensure that it doesn't get empty, which on some CPUs would
- * allow predictions from other (unwanted!) sources to be used.
- *
- * We define a CPP macro such that it can be used from both .S files and
- * inline assembly. It's possible to do a .macro and then include that
- * from C via asm(".include <asm/nospec-branch.h>") but let's not go there.
- */
-
-#define RSB_CLEAR_LOOPS 32 /* To forcibly overwrite all entries */
-#define RSB_FILL_LOOPS 16 /* To avoid underflow */
-
-/*
- * Google experimented with loop-unrolling and this turned out to be
- * the optimal version — two calls, each with their own speculation
- * trap should their return address end up getting used, in a loop.
- */
-#define __FILL_RETURN_BUFFER(reg, nr, sp) \
- mov $(nr/2), reg; \
-771: \
- call 772f; \
-773: /* speculation trap */ \
- pause; \
- lfence; \
- jmp 773b; \
-772: \
- call 774f; \
-775: /* speculation trap */ \
- pause; \
- lfence; \
- jmp 775b; \
-774: \
- dec reg; \
- jnz 771b; \
- add $(BITS_PER_LONG/8) * nr, sp;
+#include <asm/msr-index.h>
#ifdef __ASSEMBLY__
@@ -121,17 +78,10 @@
#endif
.endm
- /*
- * A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP
- * monstrosity above, manually.
- */
-.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req
+/* This clobbers the BX register */
+.macro FILL_RETURN_BUFFER nr:req ftr:req
#ifdef CONFIG_RETPOLINE
- ANNOTATE_NOSPEC_ALTERNATIVE
- ALTERNATIVE "jmp .Lskip_rsb_\@", \
- __stringify(__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)) \
- \ftr
-.Lskip_rsb_\@:
+ ALTERNATIVE "", "call __clear_rsb", \ftr
#endif
.endm
@@ -201,22 +151,30 @@
* On VMEXIT we must ensure that no RSB predictions learned in the guest
* can be followed in the host, by overwriting the RSB completely. Both
* retpoline and IBRS mitigations for Spectre v2 need this; only on future
- * CPUs with IBRS_ATT *might* it be avoided.
+ * CPUs with IBRS_ALL *might* it be avoided.
*/
static inline void vmexit_fill_RSB(void)
{
#ifdef CONFIG_RETPOLINE
- unsigned long loops;
-
- asm volatile (ANNOTATE_NOSPEC_ALTERNATIVE
- ALTERNATIVE("jmp 910f",
- __stringify(__FILL_RETURN_BUFFER(%0, RSB_CLEAR_LOOPS, %1)),
- X86_FEATURE_RETPOLINE)
- "910:"
- : "=r" (loops), ASM_CALL_CONSTRAINT
- : : "memory" );
+ alternative_input("",
+ "call __fill_rsb",
+ X86_FEATURE_RETPOLINE,
+ ASM_NO_INPUT_CLOBBER(_ASM_BX, "memory"));
#endif
}
+static inline void indirect_branch_prediction_barrier(void)
+{
+ asm volatile(ALTERNATIVE("",
+ "movl %[msr], %%ecx\n\t"
+ "movl %[val], %%eax\n\t"
+ "movl $0, %%edx\n\t"
+ "wrmsr",
+ X86_FEATURE_USE_IBPB)
+ : : [msr] "i" (MSR_IA32_PRED_CMD),
+ [val] "i" (PRED_CMD_IBPB)
+ : "eax", "ecx", "edx", "memory");
+}
+
#endif /* __ASSEMBLY__ */
-#endif /* __NOSPEC_BRANCH_H__ */
+#endif /* _ASM_X86_NOSPEC_BRANCH_H_ */
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index 0f400c0..bc5902c 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -459,8 +459,8 @@
*/
#ifdef CONFIG_X86_32
#define PVOP_VCALL_ARGS \
- unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx; \
- register void *__sp asm("esp")
+ unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx;
+
#define PVOP_CALL_ARGS PVOP_VCALL_ARGS
#define PVOP_CALL_ARG1(x) "a" ((unsigned long)(x))
@@ -480,8 +480,8 @@
/* [re]ax isn't an arg, but the return val */
#define PVOP_VCALL_ARGS \
unsigned long __edi = __edi, __esi = __esi, \
- __edx = __edx, __ecx = __ecx, __eax = __eax; \
- register void *__sp asm("rsp")
+ __edx = __edx, __ecx = __ecx, __eax = __eax;
+
#define PVOP_CALL_ARGS PVOP_VCALL_ARGS
#define PVOP_CALL_ARG1(x) "D" ((unsigned long)(x))
@@ -520,7 +520,7 @@
asm volatile(pre \
paravirt_alt(PARAVIRT_CALL) \
post \
- : call_clbr, "+r" (__sp) \
+ : call_clbr, ASM_CALL_CONSTRAINT \
: paravirt_type(op), \
paravirt_clobber(clbr), \
##__VA_ARGS__ \
@@ -530,7 +530,7 @@
asm volatile(pre \
paravirt_alt(PARAVIRT_CALL) \
post \
- : call_clbr, "+r" (__sp) \
+ : call_clbr, ASM_CALL_CONSTRAINT \
: paravirt_type(op), \
paravirt_clobber(clbr), \
##__VA_ARGS__ \
@@ -557,7 +557,7 @@
asm volatile(pre \
paravirt_alt(PARAVIRT_CALL) \
post \
- : call_clbr, "+r" (__sp) \
+ : call_clbr, ASM_CALL_CONSTRAINT \
: paravirt_type(op), \
paravirt_clobber(clbr), \
##__VA_ARGS__ \
diff --git a/arch/x86/include/asm/pgalloc.h b/arch/x86/include/asm/pgalloc.h
index 1178a51..b6d4259 100644
--- a/arch/x86/include/asm/pgalloc.h
+++ b/arch/x86/include/asm/pgalloc.h
@@ -27,17 +27,6 @@
*/
extern gfp_t __userpte_alloc_gfp;
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
-/*
- * Instead of one PGD, we acquire two PGDs. Being order-1, it is
- * both 8k in size and 8k-aligned. That lets us just flip bit 12
- * in a pointer to swap between the two 4k halves.
- */
-#define PGD_ALLOCATION_ORDER 1
-#else
-#define PGD_ALLOCATION_ORDER 0
-#endif
-
/*
* Allocate and free page tables.
*/
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 2536f90..5af0401 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -20,9 +20,15 @@
#ifdef CONFIG_PAGE_TABLE_ISOLATION
extern int kaiser_enabled;
+/*
+ * Instead of one PGD, we acquire two PGDs. Being order-1, it is
+ * both 8k in size and 8k-aligned. That lets us just flip bit 12
+ * in a pointer to swap between the two 4k halves.
+ */
#else
#define kaiser_enabled 0
#endif
+#define PGD_ALLOCATION_ORDER kaiser_enabled
void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd);
void ptdump_walk_pgd_level_checkwx(void);
diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h
index 17f2186..4939f6e 100644
--- a/arch/x86/include/asm/preempt.h
+++ b/arch/x86/include/asm/preempt.h
@@ -94,19 +94,14 @@
#ifdef CONFIG_PREEMPT
extern asmlinkage void ___preempt_schedule(void);
-# define __preempt_schedule() \
-({ \
- register void *__sp asm(_ASM_SP); \
- asm volatile ("call ___preempt_schedule" : "+r"(__sp)); \
-})
+# define __preempt_schedule() \
+ asm volatile ("call ___preempt_schedule" : ASM_CALL_CONSTRAINT)
extern asmlinkage void preempt_schedule(void);
extern asmlinkage void ___preempt_schedule_notrace(void);
-# define __preempt_schedule_notrace() \
-({ \
- register void *__sp asm(_ASM_SP); \
- asm volatile ("call ___preempt_schedule_notrace" : "+r"(__sp)); \
-})
+# define __preempt_schedule_notrace() \
+ asm volatile ("call ___preempt_schedule_notrace" : ASM_CALL_CONSTRAINT)
+
extern asmlinkage void preempt_schedule_notrace(void);
#endif
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 353f038..ec15ca2 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -88,7 +88,7 @@
__u8 x86; /* CPU family */
__u8 x86_vendor; /* CPU vendor */
__u8 x86_model;
- __u8 x86_mask;
+ __u8 x86_stepping;
#ifdef CONFIG_X86_32
char wp_works_ok; /* It doesn't on 386's */
@@ -113,7 +113,7 @@
char x86_vendor_id[16];
char x86_model_id[64];
/* in KB - valid for CPUS which support this call: */
- int x86_cache_size;
+ unsigned int x86_cache_size;
int x86_cache_alignment; /* In bytes */
/* Cache QoS architectural values: */
int x86_cache_max_rmid; /* max index */
@@ -391,8 +391,6 @@
unsigned short gsindex;
#endif
- u32 status; /* thread synchronous flags */
-
#ifdef CONFIG_X86_64
unsigned long fsbase;
unsigned long gsbase;
diff --git a/arch/x86/include/asm/required-features.h b/arch/x86/include/asm/required-features.h
index fac9a5c..6847d85 100644
--- a/arch/x86/include/asm/required-features.h
+++ b/arch/x86/include/asm/required-features.h
@@ -100,6 +100,7 @@
#define REQUIRED_MASK15 0
#define REQUIRED_MASK16 0
#define REQUIRED_MASK17 0
-#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18)
+#define REQUIRED_MASK18 0
+#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19)
#endif /* _ASM_X86_REQUIRED_FEATURES_H */
diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
index a34e0d4..7116b79 100644
--- a/arch/x86/include/asm/rwsem.h
+++ b/arch/x86/include/asm/rwsem.h
@@ -103,7 +103,6 @@
({ \
long tmp; \
struct rw_semaphore* ret; \
- register void *__sp asm(_ASM_SP); \
\
asm volatile("# beginning down_write\n\t" \
LOCK_PREFIX " xadd %1,(%4)\n\t" \
@@ -114,7 +113,8 @@
" call " slow_path "\n" \
"1:\n" \
"# ending down_write" \
- : "+m" (sem->count), "=d" (tmp), "=a" (ret), "+r" (__sp) \
+ : "+m" (sem->count), "=d" (tmp), \
+ "=a" (ret), ASM_CALL_CONSTRAINT \
: "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
: "memory", "cc"); \
ret; \
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
index e3c95e8..03eedc2 100644
--- a/arch/x86/include/asm/syscall.h
+++ b/arch/x86/include/asm/syscall.h
@@ -60,7 +60,7 @@
* TS_COMPAT is set for 32-bit syscall entries and then
* remains set until we return to user mode.
*/
- if (task->thread.status & (TS_COMPAT|TS_I386_REGS_POKED))
+ if (task->thread_info.status & (TS_COMPAT|TS_I386_REGS_POKED))
/*
* Sign-extend the value so (int)-EFOO becomes (long)-EFOO
* and will match correctly in comparisons.
@@ -116,7 +116,7 @@
unsigned long *args)
{
# ifdef CONFIG_IA32_EMULATION
- if (task->thread.status & TS_COMPAT)
+ if (task->thread_info.status & TS_COMPAT)
switch (i) {
case 0:
if (!n--) break;
@@ -177,7 +177,7 @@
const unsigned long *args)
{
# ifdef CONFIG_IA32_EMULATION
- if (task->thread.status & TS_COMPAT)
+ if (task->thread_info.status & TS_COMPAT)
switch (i) {
case 0:
if (!n--) break;
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index bdf9c4c..89978b9 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -54,6 +54,7 @@
struct thread_info {
unsigned long flags; /* low level flags */
+ u32 status; /* thread synchronous flags */
};
#define INIT_THREAD_INFO(tsk) \
@@ -213,7 +214,7 @@
#define in_ia32_syscall() true
#else
#define in_ia32_syscall() (IS_ENABLED(CONFIG_IA32_EMULATION) && \
- current->thread.status & TS_COMPAT)
+ current_thread_info()->status & TS_COMPAT)
#endif
/*
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index dead0f3..0c87840 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -123,6 +123,11 @@
#define __uaccess_begin() stac()
#define __uaccess_end() clac()
+#define __uaccess_begin_nospec() \
+({ \
+ stac(); \
+ barrier_nospec(); \
+})
/*
* This is a type: either unsigned long, if the argument fits into
@@ -166,11 +171,11 @@
({ \
int __ret_gu; \
register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX); \
- register void *__sp asm(_ASM_SP); \
__chk_user_ptr(ptr); \
might_fault(); \
asm volatile("call __get_user_%P4" \
- : "=a" (__ret_gu), "=r" (__val_gu), "+r" (__sp) \
+ : "=a" (__ret_gu), "=r" (__val_gu), \
+ ASM_CALL_CONSTRAINT \
: "0" (ptr), "i" (sizeof(*(ptr)))); \
(x) = (__force __typeof__(*(ptr))) __val_gu; \
__builtin_expect(__ret_gu, 0); \
@@ -432,7 +437,7 @@
({ \
int __gu_err; \
__inttype(*(ptr)) __gu_val; \
- __uaccess_begin(); \
+ __uaccess_begin_nospec(); \
__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
__uaccess_end(); \
(x) = (__force __typeof__(*(ptr)))__gu_val; \
@@ -474,6 +479,10 @@
__uaccess_begin(); \
barrier();
+#define uaccess_try_nospec do { \
+ current->thread.uaccess_err = 0; \
+ __uaccess_begin_nospec(); \
+
#define uaccess_catch(err) \
__uaccess_end(); \
(err) |= (current->thread.uaccess_err ? -EFAULT : 0); \
@@ -538,7 +547,7 @@
* get_user_ex(...);
* } get_user_catch(err)
*/
-#define get_user_try uaccess_try
+#define get_user_try uaccess_try_nospec
#define get_user_catch(err) uaccess_catch(err)
#define get_user_ex(x, ptr) do { \
@@ -573,7 +582,7 @@
__typeof__(ptr) __uval = (uval); \
__typeof__(*(ptr)) __old = (old); \
__typeof__(*(ptr)) __new = (new); \
- __uaccess_begin(); \
+ __uaccess_begin_nospec(); \
switch (size) { \
case 1: \
{ \
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h
index 7d3bdd1..d6d2450 100644
--- a/arch/x86/include/asm/uaccess_32.h
+++ b/arch/x86/include/asm/uaccess_32.h
@@ -102,17 +102,17 @@
switch (n) {
case 1:
- __uaccess_begin();
+ __uaccess_begin_nospec();
__get_user_size(*(u8 *)to, from, 1, ret, 1);
__uaccess_end();
return ret;
case 2:
- __uaccess_begin();
+ __uaccess_begin_nospec();
__get_user_size(*(u16 *)to, from, 2, ret, 2);
__uaccess_end();
return ret;
case 4:
- __uaccess_begin();
+ __uaccess_begin_nospec();
__get_user_size(*(u32 *)to, from, 4, ret, 4);
__uaccess_end();
return ret;
@@ -130,17 +130,17 @@
switch (n) {
case 1:
- __uaccess_begin();
+ __uaccess_begin_nospec();
__get_user_size(*(u8 *)to, from, 1, ret, 1);
__uaccess_end();
return ret;
case 2:
- __uaccess_begin();
+ __uaccess_begin_nospec();
__get_user_size(*(u16 *)to, from, 2, ret, 2);
__uaccess_end();
return ret;
case 4:
- __uaccess_begin();
+ __uaccess_begin_nospec();
__get_user_size(*(u32 *)to, from, 4, ret, 4);
__uaccess_end();
return ret;
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
index 673059a..6e5cc08 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -59,31 +59,31 @@
return copy_user_generic(dst, (__force void *)src, size);
switch (size) {
case 1:
- __uaccess_begin();
+ __uaccess_begin_nospec();
__get_user_asm(*(u8 *)dst, (u8 __user *)src,
ret, "b", "b", "=q", 1);
__uaccess_end();
return ret;
case 2:
- __uaccess_begin();
+ __uaccess_begin_nospec();
__get_user_asm(*(u16 *)dst, (u16 __user *)src,
ret, "w", "w", "=r", 2);
__uaccess_end();
return ret;
case 4:
- __uaccess_begin();
+ __uaccess_begin_nospec();
__get_user_asm(*(u32 *)dst, (u32 __user *)src,
ret, "l", "k", "=r", 4);
__uaccess_end();
return ret;
case 8:
- __uaccess_begin();
+ __uaccess_begin_nospec();
__get_user_asm(*(u64 *)dst, (u64 __user *)src,
ret, "q", "", "=r", 8);
__uaccess_end();
return ret;
case 10:
- __uaccess_begin();
+ __uaccess_begin_nospec();
__get_user_asm(*(u64 *)dst, (u64 __user *)src,
ret, "q", "", "=r", 10);
if (likely(!ret))
@@ -93,7 +93,7 @@
__uaccess_end();
return ret;
case 16:
- __uaccess_begin();
+ __uaccess_begin_nospec();
__get_user_asm(*(u64 *)dst, (u64 __user *)src,
ret, "q", "", "=r", 16);
if (likely(!ret))
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index a002b07..6899cf1 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -399,10 +399,11 @@
#define IDENTITY_PAGETABLE_PRIVATE_MEMSLOT (KVM_USER_MEM_SLOTS + 2)
#define VMX_NR_VPIDS (1 << 16)
+#define VMX_VPID_EXTENT_INDIVIDUAL_ADDR 0
#define VMX_VPID_EXTENT_SINGLE_CONTEXT 1
#define VMX_VPID_EXTENT_ALL_CONTEXT 2
+#define VMX_VPID_EXTENT_SINGLE_NON_GLOBAL 3
-#define VMX_EPT_EXTENT_INDIVIDUAL_ADDR 0
#define VMX_EPT_EXTENT_CONTEXT 1
#define VMX_EPT_EXTENT_GLOBAL 2
#define VMX_EPT_EXTENT_SHIFT 24
@@ -419,8 +420,10 @@
#define VMX_EPT_EXTENT_GLOBAL_BIT (1ull << 26)
#define VMX_VPID_INVVPID_BIT (1ull << 0) /* (32 - 32) */
+#define VMX_VPID_EXTENT_INDIVIDUAL_ADDR_BIT (1ull << 8) /* (40 - 32) */
#define VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT (1ull << 9) /* (41 - 32) */
#define VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT (1ull << 10) /* (42 - 32) */
+#define VMX_VPID_EXTENT_SINGLE_NON_GLOBAL_BIT (1ull << 11) /* (43 - 32) */
#define VMX_EPT_DEFAULT_GAW 3
#define VMX_EPT_MAX_GAW 0x4
diff --git a/arch/x86/include/asm/vsyscall.h b/arch/x86/include/asm/vsyscall.h
index 9ee8506..62210da 100644
--- a/arch/x86/include/asm/vsyscall.h
+++ b/arch/x86/include/asm/vsyscall.h
@@ -13,7 +13,6 @@
*/
extern bool emulate_vsyscall(struct pt_regs *regs, unsigned long address);
extern bool vsyscall_enabled(void);
-extern unsigned long vsyscall_pgprot;
#else
static inline void map_vsyscall(void) {}
static inline bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
@@ -22,5 +21,6 @@
}
static inline bool vsyscall_enabled(void) { return false; }
#endif
+extern unsigned long vsyscall_pgprot;
#endif /* _ASM_X86_VSYSCALL_H */
diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h
index ccdc23d..1fdcb8c 100644
--- a/arch/x86/include/asm/xen/hypercall.h
+++ b/arch/x86/include/asm/xen/hypercall.h
@@ -112,10 +112,9 @@
register unsigned long __arg2 asm(__HYPERCALL_ARG2REG) = __arg2; \
register unsigned long __arg3 asm(__HYPERCALL_ARG3REG) = __arg3; \
register unsigned long __arg4 asm(__HYPERCALL_ARG4REG) = __arg4; \
- register unsigned long __arg5 asm(__HYPERCALL_ARG5REG) = __arg5; \
- register void *__sp asm(_ASM_SP);
+ register unsigned long __arg5 asm(__HYPERCALL_ARG5REG) = __arg5;
-#define __HYPERCALL_0PARAM "=r" (__res), "+r" (__sp)
+#define __HYPERCALL_0PARAM "=r" (__res), ASM_CALL_CONSTRAINT
#define __HYPERCALL_1PARAM __HYPERCALL_0PARAM, "+r" (__arg1)
#define __HYPERCALL_2PARAM __HYPERCALL_1PARAM, "+r" (__arg2)
#define __HYPERCALL_3PARAM __HYPERCALL_2PARAM, "+r" (__arg3)
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 10d5a3d..03b6e5c 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -46,17 +46,6 @@
}
__setup("noreplace-smp", setup_noreplace_smp);
-#ifdef CONFIG_PARAVIRT
-static int __initdata_or_module noreplace_paravirt = 0;
-
-static int __init setup_noreplace_paravirt(char *str)
-{
- noreplace_paravirt = 1;
- return 1;
-}
-__setup("noreplace-paravirt", setup_noreplace_paravirt);
-#endif
-
#define DPRINTK(fmt, args...) \
do { \
if (debug_alternative) \
@@ -588,9 +577,6 @@
struct paravirt_patch_site *p;
char insnbuf[MAX_PATCH_LEN];
- if (noreplace_paravirt)
- return;
-
for (p = start; p < end; p++) {
unsigned int used;
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
index 4fdf623..8462e2d 100644
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
@@ -105,7 +105,7 @@
if (boot_cpu_data.x86 == 0x10 &&
boot_cpu_data.x86_model >= 0x8 &&
(boot_cpu_data.x86_model > 0x9 ||
- boot_cpu_data.x86_mask >= 0x1))
+ boot_cpu_data.x86_stepping >= 0x1))
amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
if (boot_cpu_data.x86 == 0x15)
diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c
index 880aa09..36ebb6d 100644
--- a/arch/x86/kernel/asm-offsets_32.c
+++ b/arch/x86/kernel/asm-offsets_32.c
@@ -20,7 +20,7 @@
OFFSET(CPUINFO_x86, cpuinfo_x86, x86);
OFFSET(CPUINFO_x86_vendor, cpuinfo_x86, x86_vendor);
OFFSET(CPUINFO_x86_model, cpuinfo_x86, x86_model);
- OFFSET(CPUINFO_x86_mask, cpuinfo_x86, x86_mask);
+ OFFSET(CPUINFO_x86_stepping, cpuinfo_x86, x86_stepping);
OFFSET(CPUINFO_cpuid_level, cpuinfo_x86, cpuid_level);
OFFSET(CPUINFO_x86_capability, cpuinfo_x86, x86_capability);
OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id);
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 1b89f0c..c375bc6 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -118,7 +118,7 @@
return;
}
- if (c->x86_model == 6 && c->x86_mask == 1) {
+ if (c->x86_model == 6 && c->x86_stepping == 1) {
const int K6_BUG_LOOP = 1000000;
int n;
void (*f_vide)(void);
@@ -147,7 +147,7 @@
/* K6 with old style WHCR */
if (c->x86_model < 8 ||
- (c->x86_model == 8 && c->x86_mask < 8)) {
+ (c->x86_model == 8 && c->x86_stepping < 8)) {
/* We can only write allocate on the low 508Mb */
if (mbytes > 508)
mbytes = 508;
@@ -166,7 +166,7 @@
return;
}
- if ((c->x86_model == 8 && c->x86_mask > 7) ||
+ if ((c->x86_model == 8 && c->x86_stepping > 7) ||
c->x86_model == 9 || c->x86_model == 13) {
/* The more serious chips .. */
@@ -219,7 +219,7 @@
* are more robust with CLK_CTL set to 200xxxxx instead of 600xxxxx
* As per AMD technical note 27212 0.2
*/
- if ((c->x86_model == 8 && c->x86_mask >= 1) || (c->x86_model > 8)) {
+ if ((c->x86_model == 8 && c->x86_stepping >= 1) || (c->x86_model > 8)) {
rdmsr(MSR_K7_CLK_CTL, l, h);
if ((l & 0xfff00000) != 0x20000000) {
pr_info("CPU: CLK_CTL MSR was %x. Reprogramming to %x\n",
@@ -239,12 +239,12 @@
* but they are not certified as MP capable.
*/
/* Athlon 660/661 is valid. */
- if ((c->x86_model == 6) && ((c->x86_mask == 0) ||
- (c->x86_mask == 1)))
+ if ((c->x86_model == 6) && ((c->x86_stepping == 0) ||
+ (c->x86_stepping == 1)))
return;
/* Duron 670 is valid */
- if ((c->x86_model == 7) && (c->x86_mask == 0))
+ if ((c->x86_model == 7) && (c->x86_stepping == 0))
return;
/*
@@ -254,8 +254,8 @@
* See http://www.heise.de/newsticker/data/jow-18.10.01-000 for
* more.
*/
- if (((c->x86_model == 6) && (c->x86_mask >= 2)) ||
- ((c->x86_model == 7) && (c->x86_mask >= 1)) ||
+ if (((c->x86_model == 6) && (c->x86_stepping >= 2)) ||
+ ((c->x86_model == 7) && (c->x86_stepping >= 1)) ||
(c->x86_model > 7))
if (cpu_has(c, X86_FEATURE_MP))
return;
@@ -569,7 +569,7 @@
/* Set MTRR capability flag if appropriate */
if (c->x86 == 5)
if (c->x86_model == 13 || c->x86_model == 9 ||
- (c->x86_model == 8 && c->x86_mask >= 8))
+ (c->x86_model == 8 && c->x86_stepping >= 8))
set_cpu_cap(c, X86_FEATURE_K6_MTRR);
#endif
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PCI)
@@ -834,11 +834,11 @@
/* AMD errata T13 (order #21922) */
if ((c->x86 == 6)) {
/* Duron Rev A0 */
- if (c->x86_model == 3 && c->x86_mask == 0)
+ if (c->x86_model == 3 && c->x86_stepping == 0)
size = 64;
/* Tbird rev A1/A2 */
if (c->x86_model == 4 &&
- (c->x86_mask == 0 || c->x86_mask == 1))
+ (c->x86_stepping == 0 || c->x86_stepping == 1))
size = 256;
}
return size;
@@ -975,7 +975,7 @@
}
/* OSVW unavailable or ID unknown, match family-model-stepping range */
- ms = (cpu->x86_model << 4) | cpu->x86_mask;
+ ms = (cpu->x86_model << 4) | cpu->x86_stepping;
while ((range = *erratum++))
if ((cpu->x86 == AMD_MODEL_RANGE_FAMILY(range)) &&
(ms >= AMD_MODEL_RANGE_START(range)) &&
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 8cacf62..baddc9e 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -10,6 +10,7 @@
#include <linux/init.h>
#include <linux/utsname.h>
#include <linux/cpu.h>
+#include <linux/module.h>
#include <asm/nospec-branch.h>
#include <asm/cmdline.h>
@@ -89,20 +90,41 @@
};
#undef pr_fmt
-#define pr_fmt(fmt) "Spectre V2 mitigation: " fmt
+#define pr_fmt(fmt) "Spectre V2 : " fmt
static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE;
+#ifdef RETPOLINE
+static bool spectre_v2_bad_module;
+
+bool retpoline_module_ok(bool has_retpoline)
+{
+ if (spectre_v2_enabled == SPECTRE_V2_NONE || has_retpoline)
+ return true;
+
+ pr_err("System may be vulnerable to spectre v2\n");
+ spectre_v2_bad_module = true;
+ return false;
+}
+
+static inline const char *spectre_v2_module_string(void)
+{
+ return spectre_v2_bad_module ? " - vulnerable module loaded" : "";
+}
+#else
+static inline const char *spectre_v2_module_string(void) { return ""; }
+#endif
+
static void __init spec2_print_if_insecure(const char *reason)
{
if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
- pr_info("%s\n", reason);
+ pr_info("%s selected on command line.\n", reason);
}
static void __init spec2_print_if_secure(const char *reason)
{
if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
- pr_info("%s\n", reason);
+ pr_info("%s selected on command line.\n", reason);
}
static inline bool retp_compiler(void)
@@ -117,42 +139,65 @@
return len == arglen && !strncmp(arg, opt, len);
}
+static const struct {
+ const char *option;
+ enum spectre_v2_mitigation_cmd cmd;
+ bool secure;
+} mitigation_options[] = {
+ { "off", SPECTRE_V2_CMD_NONE, false },
+ { "on", SPECTRE_V2_CMD_FORCE, true },
+ { "retpoline", SPECTRE_V2_CMD_RETPOLINE, false },
+ { "retpoline,amd", SPECTRE_V2_CMD_RETPOLINE_AMD, false },
+ { "retpoline,generic", SPECTRE_V2_CMD_RETPOLINE_GENERIC, false },
+ { "auto", SPECTRE_V2_CMD_AUTO, false },
+};
+
static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
{
char arg[20];
- int ret;
+ int ret, i;
+ enum spectre_v2_mitigation_cmd cmd = SPECTRE_V2_CMD_AUTO;
- ret = cmdline_find_option(boot_command_line, "spectre_v2", arg,
- sizeof(arg));
- if (ret > 0) {
- if (match_option(arg, ret, "off")) {
- goto disable;
- } else if (match_option(arg, ret, "on")) {
- spec2_print_if_secure("force enabled on command line.");
- return SPECTRE_V2_CMD_FORCE;
- } else if (match_option(arg, ret, "retpoline")) {
- spec2_print_if_insecure("retpoline selected on command line.");
- return SPECTRE_V2_CMD_RETPOLINE;
- } else if (match_option(arg, ret, "retpoline,amd")) {
- if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
- pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n");
- return SPECTRE_V2_CMD_AUTO;
- }
- spec2_print_if_insecure("AMD retpoline selected on command line.");
- return SPECTRE_V2_CMD_RETPOLINE_AMD;
- } else if (match_option(arg, ret, "retpoline,generic")) {
- spec2_print_if_insecure("generic retpoline selected on command line.");
- return SPECTRE_V2_CMD_RETPOLINE_GENERIC;
- } else if (match_option(arg, ret, "auto")) {
+ if (cmdline_find_option_bool(boot_command_line, "nospectre_v2"))
+ return SPECTRE_V2_CMD_NONE;
+ else {
+ ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, sizeof(arg));
+ if (ret < 0)
+ return SPECTRE_V2_CMD_AUTO;
+
+ for (i = 0; i < ARRAY_SIZE(mitigation_options); i++) {
+ if (!match_option(arg, ret, mitigation_options[i].option))
+ continue;
+ cmd = mitigation_options[i].cmd;
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(mitigation_options)) {
+ pr_err("unknown option (%s). Switching to AUTO select\n", arg);
return SPECTRE_V2_CMD_AUTO;
}
}
- if (!cmdline_find_option_bool(boot_command_line, "nospectre_v2"))
+ if ((cmd == SPECTRE_V2_CMD_RETPOLINE ||
+ cmd == SPECTRE_V2_CMD_RETPOLINE_AMD ||
+ cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC) &&
+ !IS_ENABLED(CONFIG_RETPOLINE)) {
+ pr_err("%s selected but not compiled in. Switching to AUTO select\n", mitigation_options[i].option);
return SPECTRE_V2_CMD_AUTO;
-disable:
- spec2_print_if_insecure("disabled on command line.");
- return SPECTRE_V2_CMD_NONE;
+ }
+
+ if (cmd == SPECTRE_V2_CMD_RETPOLINE_AMD &&
+ boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
+ pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n");
+ return SPECTRE_V2_CMD_AUTO;
+ }
+
+ if (mitigation_options[i].secure)
+ spec2_print_if_secure(mitigation_options[i].option);
+ else
+ spec2_print_if_insecure(mitigation_options[i].option);
+
+ return cmd;
}
/* Check for Skylake-like CPUs (for RSB handling) */
@@ -190,10 +235,10 @@
return;
case SPECTRE_V2_CMD_FORCE:
- /* FALLTRHU */
case SPECTRE_V2_CMD_AUTO:
- goto retpoline_auto;
-
+ if (IS_ENABLED(CONFIG_RETPOLINE))
+ goto retpoline_auto;
+ break;
case SPECTRE_V2_CMD_RETPOLINE_AMD:
if (IS_ENABLED(CONFIG_RETPOLINE))
goto retpoline_amd;
@@ -207,14 +252,14 @@
goto retpoline_auto;
break;
}
- pr_err("kernel not compiled with retpoline; no mitigation available!");
+ pr_err("Spectre mitigation: kernel not compiled with retpoline; no mitigation available!");
return;
retpoline_auto:
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
retpoline_amd:
if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
- pr_err("LFENCE not serializing. Switching to generic retpoline\n");
+ pr_err("Spectre mitigation: LFENCE not serializing, switching to generic retpoline\n");
goto retpoline_generic;
}
mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_AMD :
@@ -232,7 +277,7 @@
pr_info("%s\n", spectre_v2_strings[mode]);
/*
- * If neither SMEP or KPTI are available, there is a risk of
+ * If neither SMEP nor PTI are available, there is a risk of
* hitting userspace addresses in the RSB after a context switch
* from a shallow call stack to a deeper one. To prevent this fill
* the entire RSB, even when using IBRS.
@@ -246,15 +291,20 @@
if ((!boot_cpu_has(X86_FEATURE_KAISER) &&
!boot_cpu_has(X86_FEATURE_SMEP)) || is_skylake_era()) {
setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
- pr_info("Filling RSB on context switch\n");
+ pr_info("Spectre v2 mitigation: Filling RSB on context switch\n");
+ }
+
+ /* Initialize Indirect Branch Prediction Barrier if supported */
+ if (boot_cpu_has(X86_FEATURE_IBPB)) {
+ setup_force_cpu_cap(X86_FEATURE_USE_IBPB);
+ pr_info("Spectre v2 mitigation: Enabling Indirect Branch Prediction Barrier\n");
}
}
#undef pr_fmt
#ifdef CONFIG_SYSFS
-ssize_t cpu_show_meltdown(struct device *dev,
- struct device_attribute *attr, char *buf)
+ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf)
{
if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN))
return sprintf(buf, "Not affected\n");
@@ -263,20 +313,20 @@
return sprintf(buf, "Vulnerable\n");
}
-ssize_t cpu_show_spectre_v1(struct device *dev,
- struct device_attribute *attr, char *buf)
+ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf)
{
if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1))
return sprintf(buf, "Not affected\n");
- return sprintf(buf, "Vulnerable\n");
+ return sprintf(buf, "Mitigation: __user pointer sanitization\n");
}
-ssize_t cpu_show_spectre_v2(struct device *dev,
- struct device_attribute *attr, char *buf)
+ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf)
{
if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
return sprintf(buf, "Not affected\n");
- return sprintf(buf, "%s\n", spectre_v2_strings[spectre_v2_enabled]);
+ return sprintf(buf, "%s%s%s\n", spectre_v2_strings[spectre_v2_enabled],
+ boot_cpu_has(X86_FEATURE_USE_IBPB) ? ", IBPB" : "",
+ spectre_v2_module_string());
}
#endif
diff --git a/arch/x86/kernel/cpu/centaur.c b/arch/x86/kernel/cpu/centaur.c
index 1661d8e..4d2f61f 100644
--- a/arch/x86/kernel/cpu/centaur.c
+++ b/arch/x86/kernel/cpu/centaur.c
@@ -134,7 +134,7 @@
clear_cpu_cap(c, X86_FEATURE_TSC);
break;
case 8:
- switch (c->x86_mask) {
+ switch (c->x86_stepping) {
default:
name = "2";
break;
@@ -209,7 +209,7 @@
* - Note, it seems this may only be in engineering samples.
*/
if ((c->x86 == 6) && (c->x86_model == 9) &&
- (c->x86_mask == 1) && (size == 65))
+ (c->x86_stepping == 1) && (size == 65))
size -= 1;
return size;
}
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index d198ae0..301bbd1 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -44,6 +44,8 @@
#include <asm/pat.h>
#include <asm/microcode.h>
#include <asm/microcode_intel.h>
+#include <asm/intel-family.h>
+#include <asm/cpu_device_id.h>
#ifdef CONFIG_X86_LOCAL_APIC
#include <asm/uv/uv.h>
@@ -697,7 +699,7 @@
cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
c->x86 = x86_family(tfms);
c->x86_model = x86_model(tfms);
- c->x86_mask = x86_stepping(tfms);
+ c->x86_stepping = x86_stepping(tfms);
if (cap0 & (1<<19)) {
c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
@@ -716,6 +718,26 @@
}
}
+static void init_speculation_control(struct cpuinfo_x86 *c)
+{
+ /*
+ * The Intel SPEC_CTRL CPUID bit implies IBRS and IBPB support,
+ * and they also have a different bit for STIBP support. Also,
+ * a hypervisor might have set the individual AMD bits even on
+ * Intel CPUs, for finer-grained selection of what's available.
+ *
+ * We use the AMD bits in 0x8000_0008 EBX as the generic hardware
+ * features, which are visible in /proc/cpuinfo and used by the
+ * kernel. So set those accordingly from the Intel bits.
+ */
+ if (cpu_has(c, X86_FEATURE_SPEC_CTRL)) {
+ set_cpu_cap(c, X86_FEATURE_IBRS);
+ set_cpu_cap(c, X86_FEATURE_IBPB);
+ }
+ if (cpu_has(c, X86_FEATURE_INTEL_STIBP))
+ set_cpu_cap(c, X86_FEATURE_STIBP);
+}
+
void get_cpu_cap(struct cpuinfo_x86 *c)
{
u32 eax, ebx, ecx, edx;
@@ -737,6 +759,7 @@
cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx);
c->x86_capability[CPUID_7_0_EBX] = ebx;
c->x86_capability[CPUID_7_ECX] = ecx;
+ c->x86_capability[CPUID_7_EDX] = edx;
}
/* Extended state features: level 0x0000000d */
@@ -809,6 +832,7 @@
c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a);
init_scattered_cpuid_features(c);
+ init_speculation_control(c);
}
static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
@@ -837,6 +861,41 @@
#endif
}
+static const __initconst struct x86_cpu_id cpu_no_speculation[] = {
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_CEDARVIEW, X86_FEATURE_ANY },
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_CLOVERVIEW, X86_FEATURE_ANY },
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_LINCROFT, X86_FEATURE_ANY },
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_PENWELL, X86_FEATURE_ANY },
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_PINEVIEW, X86_FEATURE_ANY },
+ { X86_VENDOR_CENTAUR, 5 },
+ { X86_VENDOR_INTEL, 5 },
+ { X86_VENDOR_NSC, 5 },
+ { X86_VENDOR_ANY, 4 },
+ {}
+};
+
+static const __initconst struct x86_cpu_id cpu_no_meltdown[] = {
+ { X86_VENDOR_AMD },
+ {}
+};
+
+static bool __init cpu_vulnerable_to_meltdown(struct cpuinfo_x86 *c)
+{
+ u64 ia32_cap = 0;
+
+ if (x86_match_cpu(cpu_no_meltdown))
+ return false;
+
+ if (cpu_has(c, X86_FEATURE_ARCH_CAPABILITIES))
+ rdmsrl(MSR_IA32_ARCH_CAPABILITIES, ia32_cap);
+
+ /* Rogue Data Cache Load? No! */
+ if (ia32_cap & ARCH_CAP_RDCL_NO)
+ return false;
+
+ return true;
+}
+
/*
* Do minimum CPU detection early.
* Fields really needed: vendor, cpuid_level, family, model, mask,
@@ -883,11 +942,12 @@
setup_force_cpu_cap(X86_FEATURE_ALWAYS);
- if (c->x86_vendor != X86_VENDOR_AMD)
- setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN);
-
- setup_force_cpu_bug(X86_BUG_SPECTRE_V1);
- setup_force_cpu_bug(X86_BUG_SPECTRE_V2);
+ if (!x86_match_cpu(cpu_no_speculation)) {
+ if (cpu_vulnerable_to_meltdown(c))
+ setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN);
+ setup_force_cpu_bug(X86_BUG_SPECTRE_V1);
+ setup_force_cpu_bug(X86_BUG_SPECTRE_V2);
+ }
fpu__init_system(c);
@@ -1084,9 +1144,9 @@
int i;
c->loops_per_jiffy = loops_per_jiffy;
- c->x86_cache_size = -1;
+ c->x86_cache_size = 0;
c->x86_vendor = X86_VENDOR_UNKNOWN;
- c->x86_model = c->x86_mask = 0; /* So far unknown... */
+ c->x86_model = c->x86_stepping = 0; /* So far unknown... */
c->x86_vendor_id[0] = '\0'; /* Unset */
c->x86_model_id[0] = '\0'; /* Unset */
c->x86_max_cores = 1;
@@ -1331,8 +1391,8 @@
pr_cont(" (family: 0x%x, model: 0x%x", c->x86, c->x86_model);
- if (c->x86_mask || c->cpuid_level >= 0)
- pr_cont(", stepping: 0x%x)\n", c->x86_mask);
+ if (c->x86_stepping || c->cpuid_level >= 0)
+ pr_cont(", stepping: 0x%x)\n", c->x86_stepping);
else
pr_cont(")\n");
diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c
index bd9dcd6..455d8ad 100644
--- a/arch/x86/kernel/cpu/cyrix.c
+++ b/arch/x86/kernel/cpu/cyrix.c
@@ -212,7 +212,7 @@
/* common case step number/rev -- exceptions handled below */
c->x86_model = (dir1 >> 4) + 1;
- c->x86_mask = dir1 & 0xf;
+ c->x86_stepping = dir1 & 0xf;
/* Now cook; the original recipe is by Channing Corn, from Cyrix.
* We do the same thing for each generation: we work out
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index fcd484d..6ed206b 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -61,6 +61,56 @@
}
}
+/*
+ * Early microcode releases for the Spectre v2 mitigation were broken.
+ * Information taken from;
+ * - https://newsroom.intel.com/wp-content/uploads/sites/11/2018/01/microcode-update-guidance.pdf
+ * - https://kb.vmware.com/s/article/52345
+ * - Microcode revisions observed in the wild
+ * - Release note from 20180108 microcode release
+ */
+struct sku_microcode {
+ u8 model;
+ u8 stepping;
+ u32 microcode;
+};
+static const struct sku_microcode spectre_bad_microcodes[] = {
+ { INTEL_FAM6_KABYLAKE_DESKTOP, 0x0B, 0x80 },
+ { INTEL_FAM6_KABYLAKE_DESKTOP, 0x0A, 0x80 },
+ { INTEL_FAM6_KABYLAKE_DESKTOP, 0x09, 0x80 },
+ { INTEL_FAM6_KABYLAKE_MOBILE, 0x0A, 0x80 },
+ { INTEL_FAM6_KABYLAKE_MOBILE, 0x09, 0x80 },
+ { INTEL_FAM6_SKYLAKE_X, 0x03, 0x0100013e },
+ { INTEL_FAM6_SKYLAKE_X, 0x04, 0x0200003c },
+ { INTEL_FAM6_SKYLAKE_DESKTOP, 0x03, 0xc2 },
+ { INTEL_FAM6_BROADWELL_CORE, 0x04, 0x28 },
+ { INTEL_FAM6_BROADWELL_GT3E, 0x01, 0x1b },
+ { INTEL_FAM6_BROADWELL_XEON_D, 0x02, 0x14 },
+ { INTEL_FAM6_BROADWELL_XEON_D, 0x03, 0x07000011 },
+ { INTEL_FAM6_BROADWELL_X, 0x01, 0x0b000025 },
+ { INTEL_FAM6_HASWELL_ULT, 0x01, 0x21 },
+ { INTEL_FAM6_HASWELL_GT3E, 0x01, 0x18 },
+ { INTEL_FAM6_HASWELL_CORE, 0x03, 0x23 },
+ { INTEL_FAM6_HASWELL_X, 0x02, 0x3b },
+ { INTEL_FAM6_HASWELL_X, 0x04, 0x10 },
+ { INTEL_FAM6_IVYBRIDGE_X, 0x04, 0x42a },
+ /* Observed in the wild */
+ { INTEL_FAM6_SANDYBRIDGE_X, 0x06, 0x61b },
+ { INTEL_FAM6_SANDYBRIDGE_X, 0x07, 0x712 },
+};
+
+static bool bad_spectre_microcode(struct cpuinfo_x86 *c)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(spectre_bad_microcodes); i++) {
+ if (c->x86_model == spectre_bad_microcodes[i].model &&
+ c->x86_stepping == spectre_bad_microcodes[i].stepping)
+ return (c->microcode <= spectre_bad_microcodes[i].microcode);
+ }
+ return false;
+}
+
static void early_init_intel(struct cpuinfo_x86 *c)
{
u64 misc_enable;
@@ -87,6 +137,19 @@
rdmsr(MSR_IA32_UCODE_REV, lower_word, c->microcode);
}
+ /* Now if any of them are set, check the blacklist and clear the lot */
+ if ((cpu_has(c, X86_FEATURE_SPEC_CTRL) ||
+ cpu_has(c, X86_FEATURE_INTEL_STIBP) ||
+ cpu_has(c, X86_FEATURE_IBRS) || cpu_has(c, X86_FEATURE_IBPB) ||
+ cpu_has(c, X86_FEATURE_STIBP)) && bad_spectre_microcode(c)) {
+ pr_warn("Intel Spectre v2 broken microcode detected; disabling Speculation Control\n");
+ setup_clear_cpu_cap(X86_FEATURE_IBRS);
+ setup_clear_cpu_cap(X86_FEATURE_IBPB);
+ setup_clear_cpu_cap(X86_FEATURE_STIBP);
+ setup_clear_cpu_cap(X86_FEATURE_SPEC_CTRL);
+ setup_clear_cpu_cap(X86_FEATURE_INTEL_STIBP);
+ }
+
/*
* Atom erratum AAE44/AAF40/AAG38/AAH41:
*
@@ -95,7 +158,7 @@
* need the microcode to have already been loaded... so if it is
* not, recommend a BIOS update and disable large pages.
*/
- if (c->x86 == 6 && c->x86_model == 0x1c && c->x86_mask <= 2 &&
+ if (c->x86 == 6 && c->x86_model == 0x1c && c->x86_stepping <= 2 &&
c->microcode < 0x20e) {
pr_warn("Atom PSE erratum detected, BIOS microcode update recommended\n");
clear_cpu_cap(c, X86_FEATURE_PSE);
@@ -111,7 +174,7 @@
/* CPUID workaround for 0F33/0F34 CPU */
if (c->x86 == 0xF && c->x86_model == 0x3
- && (c->x86_mask == 0x3 || c->x86_mask == 0x4))
+ && (c->x86_stepping == 0x3 || c->x86_stepping == 0x4))
c->x86_phys_bits = 36;
/*
@@ -226,7 +289,7 @@
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
boot_cpu_data.x86 == 6 &&
boot_cpu_data.x86_model == 1 &&
- boot_cpu_data.x86_mask < 8) {
+ boot_cpu_data.x86_stepping < 8) {
pr_info("Pentium Pro with Errata#50 detected. Taking evasive action.\n");
return 1;
}
@@ -243,7 +306,7 @@
* Mask B, Pentium, but not Pentium MMX
*/
if (c->x86 == 5 &&
- c->x86_mask >= 1 && c->x86_mask <= 4 &&
+ c->x86_stepping >= 1 && c->x86_stepping <= 4 &&
c->x86_model <= 3) {
/*
* Remember we have B step Pentia with bugs
@@ -286,7 +349,7 @@
* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until
* model 3 mask 3
*/
- if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633)
+ if ((c->x86<<8 | c->x86_model<<4 | c->x86_stepping) < 0x633)
clear_cpu_cap(c, X86_FEATURE_SEP);
/*
@@ -304,7 +367,7 @@
* P4 Xeon erratum 037 workaround.
* Hardware prefetcher may cause stale data to be loaded into the cache.
*/
- if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) {
+ if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_stepping == 1)) {
if (msr_set_bit(MSR_IA32_MISC_ENABLE,
MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT) > 0) {
pr_info("CPU: C0 stepping P4 Xeon detected.\n");
@@ -319,7 +382,7 @@
* Specification Update").
*/
if (boot_cpu_has(X86_FEATURE_APIC) && (c->x86<<8 | c->x86_model<<4) == 0x520 &&
- (c->x86_mask < 0x6 || c->x86_mask == 0xb))
+ (c->x86_stepping < 0x6 || c->x86_stepping == 0xb))
set_cpu_bug(c, X86_BUG_11AP);
@@ -538,7 +601,7 @@
case 6:
if (l2 == 128)
p = "Celeron (Mendocino)";
- else if (c->x86_mask == 0 || c->x86_mask == 5)
+ else if (c->x86_stepping == 0 || c->x86_stepping == 5)
p = "Celeron-A";
break;
diff --git a/arch/x86/kernel/cpu/mcheck/mce-inject.c b/arch/x86/kernel/cpu/mcheck/mce-inject.c
index 517619e..99165b2 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-inject.c
+++ b/arch/x86/kernel/cpu/mcheck/mce-inject.c
@@ -152,7 +152,6 @@
if (context == MCJ_CTX_RANDOM)
return;
-#ifdef CONFIG_X86_LOCAL_APIC
if (m->inject_flags & (MCJ_IRQ_BROADCAST | MCJ_NMI_BROADCAST)) {
unsigned long start;
int cpu;
@@ -192,9 +191,7 @@
raise_local();
put_cpu();
put_online_cpus();
- } else
-#endif
- {
+ } else {
preempt_disable();
raise_local();
preempt_enable();
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c
index b74bb29..732bb03 100644
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -135,6 +135,9 @@
return size;
}
+static enum ucode_state
+load_microcode_amd(bool save, u8 family, const u8 *data, size_t size);
+
/*
* Early load occurs before we can vmalloc(). So we look for the microcode
* patch container file in initrd, traverse equivalent cpu table, look for a
@@ -451,7 +454,7 @@
eax = cpuid_eax(0x00000001);
eax = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
- ret = load_microcode_amd(smp_processor_id(), eax, container, container_size);
+ ret = load_microcode_amd(true, eax, container, container_size);
if (ret != UCODE_OK)
retval = -EINVAL;
@@ -864,7 +867,8 @@
return UCODE_OK;
}
-enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size)
+static enum ucode_state
+load_microcode_amd(bool save, u8 family, const u8 *data, size_t size)
{
enum ucode_state ret;
@@ -878,8 +882,8 @@
#ifdef CONFIG_X86_32
/* save BSP's matching patch for early load */
- if (cpu_data(cpu).cpu_index == boot_cpu_data.cpu_index) {
- struct ucode_patch *p = find_patch(cpu);
+ if (save) {
+ struct ucode_patch *p = find_patch(0);
if (p) {
memset(amd_ucode_patch, 0, PATCH_MAX_SIZE);
memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data),
@@ -911,11 +915,12 @@
{
char fw_name[36] = "amd-ucode/microcode_amd.bin";
struct cpuinfo_x86 *c = &cpu_data(cpu);
+ bool bsp = c->cpu_index == boot_cpu_data.cpu_index;
enum ucode_state ret = UCODE_NFOUND;
const struct firmware *fw;
/* reload ucode container only on the boot cpu */
- if (!refresh_fw || c->cpu_index != boot_cpu_data.cpu_index)
+ if (!refresh_fw || !bsp)
return UCODE_OK;
if (c->x86 >= 0x15)
@@ -932,7 +937,7 @@
goto fw_release;
}
- ret = load_microcode_amd(cpu, c->x86, fw->data, fw->size);
+ ret = load_microcode_amd(bsp, c->x86, fw->data, fw->size);
fw_release:
release_firmware(fw);
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index 5ce5155..0afaf00 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -43,7 +43,7 @@
#define MICROCODE_VERSION "2.01"
static struct microcode_ops *microcode_ops;
-static bool dis_ucode_ldr;
+static bool dis_ucode_ldr = true;
/*
* Synchronization.
@@ -73,6 +73,7 @@
static bool __init check_loader_disabled_bsp(void)
{
static const char *__dis_opt_str = "dis_ucode_ldr";
+ u32 a, b, c, d;
#ifdef CONFIG_X86_32
const char *cmdline = (const char *)__pa_nodebug(boot_command_line);
@@ -85,8 +86,20 @@
bool *res = &dis_ucode_ldr;
#endif
- if (cmdline_find_option_bool(cmdline, option))
- *res = true;
+ a = 1;
+ c = 0;
+ native_cpuid(&a, &b, &c, &d);
+
+ /*
+ * CPUID(1).ECX[31]: reserved for hypervisor use. This is still not
+ * completely accurate as xen pv guests don't see that CPUID bit set but
+ * that's good enough as they don't land on the BSP path anyway.
+ */
+ if (c & BIT(31))
+ return *res;
+
+ if (cmdline_find_option_bool(cmdline, option) <= 0)
+ *res = false;
return *res;
}
@@ -114,9 +127,7 @@
{
int vendor;
unsigned int family;
-
- if (check_loader_disabled_bsp())
- return;
+ bool intel = true;
if (!have_cpuid_p())
return;
@@ -126,16 +137,27 @@
switch (vendor) {
case X86_VENDOR_INTEL:
- if (family >= 6)
- load_ucode_intel_bsp();
+ if (family < 6)
+ return;
break;
+
case X86_VENDOR_AMD:
- if (family >= 0x10)
- load_ucode_amd_bsp(family);
+ if (family < 0x10)
+ return;
+ intel = false;
break;
+
default:
- break;
+ return;
}
+
+ if (check_loader_disabled_bsp())
+ return;
+
+ if (intel)
+ load_ucode_intel_bsp();
+ else
+ load_ucode_amd_bsp(family);
}
static bool check_loader_disabled_ap(void)
@@ -154,9 +176,6 @@
if (check_loader_disabled_ap())
return;
- if (!have_cpuid_p())
- return;
-
vendor = x86_cpuid_vendor();
family = x86_cpuid_family();
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index f90f176..4bcd30c 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -1062,7 +1062,7 @@
*/
if (c->x86 == 6 &&
c->x86_model == INTEL_FAM6_BROADWELL_X &&
- c->x86_mask == 0x01 &&
+ c->x86_stepping == 0x01 &&
llc_size_per_core > 2621440 &&
c->microcode < 0x0b000021) {
pr_err_once("Erratum BDF90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode);
@@ -1085,7 +1085,7 @@
return UCODE_NFOUND;
sprintf(name, "intel-ucode/%02x-%02x-%02x",
- c->x86, c->x86_model, c->x86_mask);
+ c->x86, c->x86_model, c->x86_stepping);
if (request_firmware_direct(&firmware, name, device)) {
pr_debug("data file %s load failed\n", name);
@@ -1132,7 +1132,7 @@
static int __init calc_llc_size_per_core(struct cpuinfo_x86 *c)
{
- u64 llc_size = c->x86_cache_size * 1024;
+ u64 llc_size = c->x86_cache_size * 1024ULL;
do_div(llc_size, c->x86_max_cores);
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
index fdc5521..e12ee86 100644
--- a/arch/x86/kernel/cpu/mtrr/generic.c
+++ b/arch/x86/kernel/cpu/mtrr/generic.c
@@ -859,7 +859,7 @@
*/
if (is_cpu(INTEL) && boot_cpu_data.x86 == 6 &&
boot_cpu_data.x86_model == 1 &&
- boot_cpu_data.x86_mask <= 7) {
+ boot_cpu_data.x86_stepping <= 7) {
if (base & ((1 << (22 - PAGE_SHIFT)) - 1)) {
pr_warn("mtrr: base(0x%lx000) is not 4 MiB aligned\n", base);
return -EINVAL;
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index 24e87e7..fae740c 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -699,8 +699,8 @@
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
boot_cpu_data.x86 == 0xF &&
boot_cpu_data.x86_model == 0x3 &&
- (boot_cpu_data.x86_mask == 0x3 ||
- boot_cpu_data.x86_mask == 0x4))
+ (boot_cpu_data.x86_stepping == 0x3 ||
+ boot_cpu_data.x86_stepping == 0x4))
phys_addr = 36;
size_or_mask = SIZE_OR_MASK_BITS(phys_addr);
diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c
index 18ca99f..c4f772d 100644
--- a/arch/x86/kernel/cpu/proc.c
+++ b/arch/x86/kernel/cpu/proc.c
@@ -70,8 +70,8 @@
c->x86_model,
c->x86_model_id[0] ? c->x86_model_id : "unknown");
- if (c->x86_mask || c->cpuid_level >= 0)
- seq_printf(m, "stepping\t: %d\n", c->x86_mask);
+ if (c->x86_stepping || c->cpuid_level >= 0)
+ seq_printf(m, "stepping\t: %d\n", c->x86_stepping);
else
seq_puts(m, "stepping\t: unknown\n");
if (c->microcode)
@@ -87,8 +87,8 @@
}
/* Cache size */
- if (c->x86_cache_size >= 0)
- seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
+ if (c->x86_cache_size)
+ seq_printf(m, "cache size\t: %u KB\n", c->x86_cache_size);
show_cpuinfo_core(m, c, cpu);
show_cpuinfo_misc(m, c);
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index b0dd9ae..afbb525 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -31,8 +31,6 @@
const struct cpuid_bit *cb;
static const struct cpuid_bit cpuid_bits[] = {
- { X86_FEATURE_AVX512_4VNNIW, CR_EDX, 2, 0x00000007, 0 },
- { X86_FEATURE_AVX512_4FMAPS, CR_EDX, 3, 0x00000007, 0 },
{ X86_FEATURE_APERFMPERF, CR_ECX, 0, 0x00000006, 0 },
{ X86_FEATURE_EPB, CR_ECX, 3, 0x00000006, 0 },
{ X86_FEATURE_HW_PSTATE, CR_EDX, 7, 0x80000007, 0 },
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 2dabea4..82155d0 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -35,7 +35,7 @@
#define X86 new_cpu_data+CPUINFO_x86
#define X86_VENDOR new_cpu_data+CPUINFO_x86_vendor
#define X86_MODEL new_cpu_data+CPUINFO_x86_model
-#define X86_MASK new_cpu_data+CPUINFO_x86_mask
+#define X86_STEPPING new_cpu_data+CPUINFO_x86_stepping
#define X86_HARD_MATH new_cpu_data+CPUINFO_hard_math
#define X86_CPUID new_cpu_data+CPUINFO_cpuid_level
#define X86_CAPABILITY new_cpu_data+CPUINFO_x86_capability
@@ -441,7 +441,7 @@
shrb $4,%al
movb %al,X86_MODEL
andb $0x0f,%cl # mask mask revision
- movb %cl,X86_MASK
+ movb %cl,X86_STEPPING
movl %edx,X86_CAPABILITY
is486:
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index 0f8d204..d0fb941 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -406,7 +406,7 @@
processor.apicver = mpc_default_type > 4 ? 0x10 : 0x01;
processor.cpuflag = CPU_ENABLED;
processor.cpufeature = (boot_cpu_data.x86 << 8) |
- (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask;
+ (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_stepping;
processor.featureflag = boot_cpu_data.x86_capability[CPUID_1_EDX];
processor.reserved[0] = 0;
processor.reserved[1] = 0;
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 0887d2a..dffe81d 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -538,7 +538,7 @@
current->personality &= ~READ_IMPLIES_EXEC;
/* in_compat_syscall() uses the presence of the x32
syscall bit flag to determine compat status */
- current->thread.status &= ~TS_COMPAT;
+ current_thread_info()->status &= ~TS_COMPAT;
} else {
set_thread_flag(TIF_IA32);
clear_thread_flag(TIF_X32);
@@ -546,7 +546,7 @@
current->mm->context.ia32_compat = TIF_IA32;
current->personality |= force_personality32;
/* Prepare the first "return" to user space */
- current->thread.status |= TS_COMPAT;
+ current_thread_info()->status |= TS_COMPAT;
}
}
EXPORT_SYMBOL_GPL(set_personality_ia32);
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 0e63c02..e497d37 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -934,7 +934,7 @@
*/
regs->orig_ax = value;
if (syscall_get_nr(child, regs) >= 0)
- child->thread.status |= TS_I386_REGS_POKED;
+ child->thread_info.status |= TS_I386_REGS_POKED;
break;
case offsetof(struct user32, regs.eflags):
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 763af1d..b1a5d25 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -785,7 +785,7 @@
* than the tracee.
*/
#ifdef CONFIG_IA32_EMULATION
- if (current->thread.status & (TS_COMPAT|TS_I386_REGS_POKED))
+ if (current_thread_info()->status & (TS_COMPAT|TS_I386_REGS_POKED))
return __NR_ia32_restart_syscall;
#endif
#ifdef CONFIG_X86_X32_ABI
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
index 8402907..21454e2 100644
--- a/arch/x86/kernel/tboot.c
+++ b/arch/x86/kernel/tboot.c
@@ -134,6 +134,16 @@
return -1;
set_pte_at(&tboot_mm, vaddr, pte, pfn_pte(pfn, prot));
pte_unmap(pte);
+
+ /*
+ * PTI poisons low addresses in the kernel page tables in the
+ * name of making them unusable for userspace. To execute
+ * code at such a low address, the poison must be cleared.
+ *
+ * Note: 'pgd' actually gets set in pud_alloc().
+ */
+ pgd->pgd &= ~_PAGE_NX;
+
return 0;
}
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index 4b30128..8a1d635 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -160,11 +160,12 @@
static void mark_screen_rdonly(struct mm_struct *mm)
{
+ struct vm_area_struct *vma;
+ spinlock_t *ptl;
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
- spinlock_t *ptl;
int i;
down_write(&mm->mmap_sem);
@@ -177,7 +178,7 @@
pmd = pmd_offset(pud, 0xA0000);
if (pmd_trans_huge(*pmd)) {
- struct vm_area_struct *vma = find_vma(mm, 0xA0000);
+ vma = find_vma(mm, 0xA0000);
split_huge_pmd(vma, pmd, 0xA0000);
}
if (pmd_none_or_clear_bad(pmd))
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index ab8e32f..9150e09 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -22,7 +22,8 @@
depends on HAVE_KVM
depends on HIGH_RES_TIMERS
# for TASKSTATS/TASK_DELAY_ACCT:
- depends on NET
+ depends on NET && MULTIUSER
+ depends on X86_LOCAL_APIC
select PREEMPT_NOTIFIERS
select MMU_NOTIFIER
select ANON_INODES
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 91af75e..93f924d 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -355,6 +355,10 @@
F(3DNOWPREFETCH) | F(OSVW) | 0 /* IBS */ | F(XOP) |
0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM);
+ /* cpuid 0x80000008.ebx */
+ const u32 kvm_cpuid_8000_0008_ebx_x86_features =
+ F(IBPB) | F(IBRS);
+
/* cpuid 0xC0000001.edx */
const u32 kvm_cpuid_C000_0001_edx_x86_features =
F(XSTORE) | F(XSTORE_EN) | F(XCRYPT) | F(XCRYPT_EN) |
@@ -376,6 +380,10 @@
/* cpuid 7.0.ecx*/
const u32 kvm_cpuid_7_0_ecx_x86_features = F(PKU) | 0 /*OSPKE*/;
+ /* cpuid 7.0.edx*/
+ const u32 kvm_cpuid_7_0_edx_x86_features =
+ F(SPEC_CTRL) | F(ARCH_CAPABILITIES);
+
/* all calls to cpuid_count() should be made on the same cpu */
get_cpu();
@@ -458,12 +466,14 @@
/* PKU is not yet implemented for shadow paging. */
if (!tdp_enabled || !boot_cpu_has(X86_FEATURE_OSPKE))
entry->ecx &= ~F(PKU);
+ entry->edx &= kvm_cpuid_7_0_edx_x86_features;
+ cpuid_mask(&entry->edx, CPUID_7_EDX);
} else {
entry->ebx = 0;
entry->ecx = 0;
+ entry->edx = 0;
}
entry->eax = 0;
- entry->edx = 0;
break;
}
case 9:
@@ -607,7 +617,14 @@
if (!g_phys_as)
g_phys_as = phys_as;
entry->eax = g_phys_as | (virt_as << 8);
- entry->ebx = entry->edx = 0;
+ entry->edx = 0;
+ /* IBRS and IBPB aren't necessarily present in hardware cpuid */
+ if (boot_cpu_has(X86_FEATURE_IBPB))
+ entry->ebx |= F(IBPB);
+ if (boot_cpu_has(X86_FEATURE_IBRS))
+ entry->ebx |= F(IBRS);
+ entry->ebx &= kvm_cpuid_8000_0008_ebx_x86_features;
+ cpuid_mask(&entry->ebx, CPUID_8000_0008_EBX);
break;
}
case 0x80000019:
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index 9368fec..d1beb71 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -160,6 +160,37 @@
return best && (best->edx & bit(X86_FEATURE_RDTSCP));
}
+static inline bool guest_cpuid_has_ibpb(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *best;
+
+ best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0);
+ if (best && (best->ebx & bit(X86_FEATURE_IBPB)))
+ return true;
+ best = kvm_find_cpuid_entry(vcpu, 7, 0);
+ return best && (best->edx & bit(X86_FEATURE_SPEC_CTRL));
+}
+
+static inline bool guest_cpuid_has_ibrs(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *best;
+
+ best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0);
+ if (best && (best->ebx & bit(X86_FEATURE_IBRS)))
+ return true;
+ best = kvm_find_cpuid_entry(vcpu, 7, 0);
+ return best && (best->edx & bit(X86_FEATURE_SPEC_CTRL));
+}
+
+static inline bool guest_cpuid_has_arch_capabilities(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *best;
+
+ best = kvm_find_cpuid_entry(vcpu, 7, 0);
+ return best && (best->edx & bit(X86_FEATURE_ARCH_CAPABILITIES));
+}
+
+
/*
* NRIPS is provided through cpuidfn 0x8000000a.edx bit 3
*/
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 6f5a3b0..c8d5738 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -25,6 +25,7 @@
#include <asm/kvm_emulate.h>
#include <linux/stringify.h>
#include <asm/debugreg.h>
+#include <asm/nospec-branch.h>
#include "x86.h"
#include "tss.h"
@@ -1012,8 +1013,8 @@
void (*fop)(void) = (void *)em_setcc + 4 * (condition & 0xf);
flags = (flags & EFLAGS_MASK) | X86_EFLAGS_IF;
- asm("push %[flags]; popf; call *%[fastop]"
- : "=a"(rc) : [fastop]"r"(fop), [flags]"r"(flags));
+ asm("push %[flags]; popf; " CALL_NOSPEC
+ : "=a"(rc) : [thunk_target]"r"(fop), [flags]"r"(flags));
return rc;
}
@@ -5306,15 +5307,14 @@
static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *))
{
- register void *__sp asm(_ASM_SP);
ulong flags = (ctxt->eflags & EFLAGS_MASK) | X86_EFLAGS_IF;
if (!(ctxt->d & ByteOp))
fop += __ffs(ctxt->dst.bytes) * FASTOP_SIZE;
- asm("push %[flags]; popf; call *%[fastop]; pushf; pop %[flags]\n"
+ asm("push %[flags]; popf; " CALL_NOSPEC " ; pushf; pop %[flags]\n"
: "+a"(ctxt->dst.val), "+d"(ctxt->src.val), [flags]"+D"(flags),
- [fastop]"+S"(fop), "+r"(__sp)
+ [thunk_target]"+S"(fop), ASM_CALL_CONSTRAINT
: "c"(ctxt->src2.val));
ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK);
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 0a324e1..a16c066 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -4640,7 +4640,7 @@
typedef bool (*slot_level_handler) (struct kvm *kvm, struct kvm_rmap_head *rmap_head);
/* The caller should hold mmu-lock before calling this function. */
-static bool
+static __always_inline bool
slot_handle_level_range(struct kvm *kvm, struct kvm_memory_slot *memslot,
slot_level_handler fn, int start_level, int end_level,
gfn_t start_gfn, gfn_t end_gfn, bool lock_flush_tlb)
@@ -4670,7 +4670,7 @@
return flush;
}
-static bool
+static __always_inline bool
slot_handle_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
slot_level_handler fn, int start_level, int end_level,
bool lock_flush_tlb)
@@ -4681,7 +4681,7 @@
lock_flush_tlb);
}
-static bool
+static __always_inline bool
slot_handle_all_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
slot_level_handler fn, bool lock_flush_tlb)
{
@@ -4689,7 +4689,7 @@
PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb);
}
-static bool
+static __always_inline bool
slot_handle_large_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
slot_level_handler fn, bool lock_flush_tlb)
{
@@ -4697,7 +4697,7 @@
PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb);
}
-static bool
+static __always_inline bool
slot_handle_leaf(struct kvm *kvm, struct kvm_memory_slot *memslot,
slot_level_handler fn, bool lock_flush_tlb)
{
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 24af898..be644af 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -183,6 +183,8 @@
u64 gs_base;
} host;
+ u64 spec_ctrl;
+
u32 *msrpm;
ulong nmi_iret_rip;
@@ -248,6 +250,8 @@
{ .index = MSR_CSTAR, .always = true },
{ .index = MSR_SYSCALL_MASK, .always = true },
#endif
+ { .index = MSR_IA32_SPEC_CTRL, .always = false },
+ { .index = MSR_IA32_PRED_CMD, .always = false },
{ .index = MSR_IA32_LASTBRANCHFROMIP, .always = false },
{ .index = MSR_IA32_LASTBRANCHTOIP, .always = false },
{ .index = MSR_IA32_LASTINTFROMIP, .always = false },
@@ -510,6 +514,7 @@
struct kvm_ldttss_desc *tss_desc;
struct page *save_area;
+ struct vmcb *current_vmcb;
};
static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);
@@ -861,6 +866,25 @@
return false;
}
+static bool msr_write_intercepted(struct kvm_vcpu *vcpu, unsigned msr)
+{
+ u8 bit_write;
+ unsigned long tmp;
+ u32 offset;
+ u32 *msrpm;
+
+ msrpm = is_guest_mode(vcpu) ? to_svm(vcpu)->nested.msrpm:
+ to_svm(vcpu)->msrpm;
+
+ offset = svm_msrpm_offset(msr);
+ bit_write = 2 * (msr & 0x0f) + 1;
+ tmp = msrpm[offset];
+
+ BUG_ON(offset == MSR_INVALID);
+
+ return !!test_bit(bit_write, &tmp);
+}
+
static void set_msr_interception(u32 *msrpm, unsigned msr,
int read, int write)
{
@@ -1535,6 +1559,8 @@
u32 dummy;
u32 eax = 1;
+ svm->spec_ctrl = 0;
+
if (!init_event) {
svm->vcpu.arch.apic_base = APIC_DEFAULT_PHYS_BASE |
MSR_IA32_APICBASE_ENABLE;
@@ -1644,11 +1670,17 @@
__free_pages(virt_to_page(svm->nested.msrpm), MSRPM_ALLOC_ORDER);
kvm_vcpu_uninit(vcpu);
kmem_cache_free(kvm_vcpu_cache, svm);
+ /*
+ * The vmcb page can be recycled, causing a false negative in
+ * svm_vcpu_load(). So do a full IBPB now.
+ */
+ indirect_branch_prediction_barrier();
}
static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
+ struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
int i;
if (unlikely(cpu != vcpu->cpu)) {
@@ -1677,6 +1709,10 @@
if (static_cpu_has(X86_FEATURE_RDTSCP))
wrmsrl(MSR_TSC_AUX, svm->tsc_aux);
+ if (sd->current_vmcb != svm->vmcb) {
+ sd->current_vmcb = svm->vmcb;
+ indirect_branch_prediction_barrier();
+ }
avic_vcpu_load(vcpu, cpu);
}
@@ -3508,6 +3544,13 @@
case MSR_VM_CR:
msr_info->data = svm->nested.vm_cr_msr;
break;
+ case MSR_IA32_SPEC_CTRL:
+ if (!msr_info->host_initiated &&
+ !guest_cpuid_has_ibrs(vcpu))
+ return 1;
+
+ msr_info->data = svm->spec_ctrl;
+ break;
case MSR_IA32_UCODE_REV:
msr_info->data = 0x01000065;
break;
@@ -3599,6 +3642,49 @@
case MSR_IA32_TSC:
kvm_write_tsc(vcpu, msr);
break;
+ case MSR_IA32_SPEC_CTRL:
+ if (!msr->host_initiated &&
+ !guest_cpuid_has_ibrs(vcpu))
+ return 1;
+
+ /* The STIBP bit doesn't fault even if it's not advertised */
+ if (data & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP))
+ return 1;
+
+ svm->spec_ctrl = data;
+
+ if (!data)
+ break;
+
+ /*
+ * For non-nested:
+ * When it's written (to non-zero) for the first time, pass
+ * it through.
+ *
+ * For nested:
+ * The handling of the MSR bitmap for L2 guests is done in
+ * nested_svm_vmrun_msrpm.
+ * We update the L1 MSR bit as well since it will end up
+ * touching the MSR anyway now.
+ */
+ set_msr_interception(svm->msrpm, MSR_IA32_SPEC_CTRL, 1, 1);
+ break;
+ case MSR_IA32_PRED_CMD:
+ if (!msr->host_initiated &&
+ !guest_cpuid_has_ibpb(vcpu))
+ return 1;
+
+ if (data & ~PRED_CMD_IBPB)
+ return 1;
+
+ if (!data)
+ break;
+
+ wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
+ if (is_guest_mode(vcpu))
+ break;
+ set_msr_interception(svm->msrpm, MSR_IA32_PRED_CMD, 0, 1);
+ break;
case MSR_STAR:
svm->vmcb->save.star = data;
break;
@@ -4826,6 +4912,15 @@
local_irq_enable();
+ /*
+ * If this vCPU has touched SPEC_CTRL, restore the guest's value if
+ * it's non-zero. Since vmentry is serialising on affected CPUs, there
+ * is no need to worry about the conditional branch over the wrmsr
+ * being speculatively taken.
+ */
+ if (svm->spec_ctrl)
+ wrmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl);
+
asm volatile (
"push %%" _ASM_BP "; \n\t"
"mov %c[rbx](%[svm]), %%" _ASM_BX " \n\t"
@@ -4918,6 +5013,27 @@
#endif
);
+ /*
+ * We do not use IBRS in the kernel. If this vCPU has used the
+ * SPEC_CTRL MSR it may have left it on; save the value and
+ * turn it off. This is much more efficient than blindly adding
+ * it to the atomic save/restore list. Especially as the former
+ * (Saving guest MSRs on vmexit) doesn't even exist in KVM.
+ *
+ * For non-nested case:
+ * If the L01 MSR bitmap does not intercept the MSR, then we need to
+ * save it.
+ *
+ * For nested case:
+ * If the L02 MSR bitmap does not intercept the MSR, then we need to
+ * save it.
+ */
+ if (!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))
+ rdmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl);
+
+ if (svm->spec_ctrl)
+ wrmsrl(MSR_IA32_SPEC_CTRL, 0);
+
/* Eliminate branch target predictions from guest mode */
vmexit_fill_RSB();
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 178a344..f2cd6bd 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -33,6 +33,7 @@
#include <linux/slab.h>
#include <linux/tboot.h>
#include <linux/hrtimer.h>
+#include <linux/nospec.h>
#include "kvm_cache_regs.h"
#include "x86.h"
@@ -109,6 +110,14 @@
static bool __read_mostly enable_pml = 1;
module_param_named(pml, enable_pml, bool, S_IRUGO);
+#define MSR_TYPE_R 1
+#define MSR_TYPE_W 2
+#define MSR_TYPE_RW 3
+
+#define MSR_BITMAP_MODE_X2APIC 1
+#define MSR_BITMAP_MODE_X2APIC_APICV 2
+#define MSR_BITMAP_MODE_LM 4
+
#define KVM_VMX_TSC_MULTIPLIER_MAX 0xffffffffffffffffULL
/* Guest_tsc -> host_tsc conversion requires 64-bit division. */
@@ -133,6 +142,12 @@
#define VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE 5
+#define VMX_VPID_EXTENT_SUPPORTED_MASK \
+ (VMX_VPID_EXTENT_INDIVIDUAL_ADDR_BIT | \
+ VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT | \
+ VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT | \
+ VMX_VPID_EXTENT_SINGLE_NON_GLOBAL_BIT)
+
/*
* These 2 parameters are used to config the controls for Pause-Loop Exiting:
* ple_gap: upper bound on the amount of time between two successive
@@ -173,7 +188,6 @@
extern const ulong vmx_return;
#define NR_AUTOLOAD_MSRS 8
-#define VMCS02_POOL_SIZE 1
struct vmcs {
u32 revision_id;
@@ -191,6 +205,7 @@
struct vmcs *shadow_vmcs;
int cpu;
int launched;
+ unsigned long *msr_bitmap;
struct list_head loaded_vmcss_on_cpu_link;
};
@@ -207,7 +222,7 @@
* stored in guest memory specified by VMPTRLD, but is opaque to the guest,
* which must access it using VMREAD/VMWRITE/VMCLEAR instructions.
* More than one of these structures may exist, if L1 runs multiple L2 guests.
- * nested_vmx_run() will use the data here to build a vmcs02: a VMCS for the
+ * nested_vmx_run() will use the data here to build the vmcs02: a VMCS for the
* underlying hardware which will be used to run L2.
* This structure is packed to ensure that its layout is identical across
* machines (necessary for live migration).
@@ -386,13 +401,6 @@
*/
#define VMCS12_SIZE 0x1000
-/* Used to remember the last vmcs02 used for some recently used vmcs12s */
-struct vmcs02_list {
- struct list_head list;
- gpa_t vmptr;
- struct loaded_vmcs vmcs02;
-};
-
/*
* The nested_vmx structure is part of vcpu_vmx, and holds information we need
* for correct emulation of VMX (i.e., nested VMX) on this vcpu.
@@ -419,15 +427,15 @@
*/
bool sync_shadow_vmcs;
- /* vmcs02_list cache of VMCSs recently used to run L2 guests */
- struct list_head vmcs02_pool;
- int vmcs02_num;
bool change_vmcs01_virtual_x2apic_mode;
/* L2 must run next, and mustn't decide to exit to L1. */
bool nested_run_pending;
+
+ struct loaded_vmcs vmcs02;
+
/*
- * Guest pages referred to in vmcs02 with host-physical pointers, so
- * we must keep them pinned while L2 runs.
+ * Guest pages referred to in the vmcs02 with host-physical
+ * pointers, so we must keep them pinned while L2 runs.
*/
struct page *apic_access_page;
struct page *virtual_apic_page;
@@ -436,8 +444,6 @@
bool pi_pending;
u16 posted_intr_nv;
- unsigned long *msr_bitmap;
-
struct hrtimer preemption_timer;
bool preemption_timer_expired;
@@ -538,6 +544,7 @@
unsigned long host_rsp;
u8 fail;
bool nmi_known_unmasked;
+ u8 msr_bitmap_mode;
u32 exit_intr_info;
u32 idt_vectoring_info;
ulong rflags;
@@ -549,6 +556,10 @@
u64 msr_host_kernel_gs_base;
u64 msr_guest_kernel_gs_base;
#endif
+
+ u64 arch_capabilities;
+ u64 spec_ctrl;
+
u32 vm_entry_controls_shadow;
u32 vm_exit_controls_shadow;
/*
@@ -856,21 +867,18 @@
static inline short vmcs_field_to_offset(unsigned long field)
{
- BUILD_BUG_ON(ARRAY_SIZE(vmcs_field_to_offset_table) > SHRT_MAX);
+ const size_t size = ARRAY_SIZE(vmcs_field_to_offset_table);
+ unsigned short offset;
- if (field >= ARRAY_SIZE(vmcs_field_to_offset_table))
+ BUILD_BUG_ON(size > SHRT_MAX);
+ if (field >= size)
return -ENOENT;
- /*
- * FIXME: Mitigation for CVE-2017-5753. To be replaced with a
- * generic mechanism.
- */
- asm("lfence");
-
- if (vmcs_field_to_offset_table[field] == 0)
+ field = array_index_nospec(field, size);
+ offset = vmcs_field_to_offset_table[field];
+ if (offset == 0)
return -ENOENT;
-
- return vmcs_field_to_offset_table[field];
+ return offset;
}
static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
@@ -912,6 +920,9 @@
static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx);
static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx);
static int alloc_identity_pagetable(struct kvm *kvm);
+static void vmx_update_msr_bitmap(struct kvm_vcpu *vcpu);
+static void __always_inline vmx_disable_intercept_for_msr(unsigned long *msr_bitmap,
+ u32 msr, int type);
static DEFINE_PER_CPU(struct vmcs *, vmxarea);
static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
@@ -931,12 +942,6 @@
static unsigned long *vmx_io_bitmap_a;
static unsigned long *vmx_io_bitmap_b;
-static unsigned long *vmx_msr_bitmap_legacy;
-static unsigned long *vmx_msr_bitmap_longmode;
-static unsigned long *vmx_msr_bitmap_legacy_x2apic;
-static unsigned long *vmx_msr_bitmap_longmode_x2apic;
-static unsigned long *vmx_msr_bitmap_legacy_x2apic_apicv_inactive;
-static unsigned long *vmx_msr_bitmap_longmode_x2apic_apicv_inactive;
static unsigned long *vmx_vmread_bitmap;
static unsigned long *vmx_vmwrite_bitmap;
@@ -1853,6 +1858,52 @@
vmcs_write32(EXCEPTION_BITMAP, eb);
}
+/*
+ * Check if MSR is intercepted for currently loaded MSR bitmap.
+ */
+static bool msr_write_intercepted(struct kvm_vcpu *vcpu, u32 msr)
+{
+ unsigned long *msr_bitmap;
+ int f = sizeof(unsigned long);
+
+ if (!cpu_has_vmx_msr_bitmap())
+ return true;
+
+ msr_bitmap = to_vmx(vcpu)->loaded_vmcs->msr_bitmap;
+
+ if (msr <= 0x1fff) {
+ return !!test_bit(msr, msr_bitmap + 0x800 / f);
+ } else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
+ msr &= 0x1fff;
+ return !!test_bit(msr, msr_bitmap + 0xc00 / f);
+ }
+
+ return true;
+}
+
+/*
+ * Check if MSR is intercepted for L01 MSR bitmap.
+ */
+static bool msr_write_intercepted_l01(struct kvm_vcpu *vcpu, u32 msr)
+{
+ unsigned long *msr_bitmap;
+ int f = sizeof(unsigned long);
+
+ if (!cpu_has_vmx_msr_bitmap())
+ return true;
+
+ msr_bitmap = to_vmx(vcpu)->vmcs01.msr_bitmap;
+
+ if (msr <= 0x1fff) {
+ return !!test_bit(msr, msr_bitmap + 0x800 / f);
+ } else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
+ msr &= 0x1fff;
+ return !!test_bit(msr, msr_bitmap + 0xc00 / f);
+ }
+
+ return true;
+}
+
static void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx,
unsigned long entry, unsigned long exit)
{
@@ -2262,6 +2313,7 @@
if (per_cpu(current_vmcs, cpu) != vmx->loaded_vmcs->vmcs) {
per_cpu(current_vmcs, cpu) = vmx->loaded_vmcs->vmcs;
vmcs_load(vmx->loaded_vmcs->vmcs);
+ indirect_branch_prediction_barrier();
}
if (!already_loaded) {
@@ -2530,36 +2582,6 @@
vmx->guest_msrs[from] = tmp;
}
-static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu)
-{
- unsigned long *msr_bitmap;
-
- if (is_guest_mode(vcpu))
- msr_bitmap = to_vmx(vcpu)->nested.msr_bitmap;
- else if (cpu_has_secondary_exec_ctrls() &&
- (vmcs_read32(SECONDARY_VM_EXEC_CONTROL) &
- SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE)) {
- if (enable_apicv && kvm_vcpu_apicv_active(vcpu)) {
- if (is_long_mode(vcpu))
- msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
- else
- msr_bitmap = vmx_msr_bitmap_legacy_x2apic;
- } else {
- if (is_long_mode(vcpu))
- msr_bitmap = vmx_msr_bitmap_longmode_x2apic_apicv_inactive;
- else
- msr_bitmap = vmx_msr_bitmap_legacy_x2apic_apicv_inactive;
- }
- } else {
- if (is_long_mode(vcpu))
- msr_bitmap = vmx_msr_bitmap_longmode;
- else
- msr_bitmap = vmx_msr_bitmap_legacy;
- }
-
- vmcs_write64(MSR_BITMAP, __pa(msr_bitmap));
-}
-
/*
* Set up the vmcs to automatically save and restore system
* msrs. Don't touch the 64-bit msrs if the guest is in legacy
@@ -2600,7 +2622,7 @@
vmx->save_nmsrs = save_nmsrs;
if (cpu_has_vmx_msr_bitmap())
- vmx_set_msr_bitmap(&vmx->vcpu);
+ vmx_update_msr_bitmap(&vmx->vcpu);
}
/*
@@ -2823,8 +2845,7 @@
*/
if (enable_vpid)
vmx->nested.nested_vmx_vpid_caps = VMX_VPID_INVVPID_BIT |
- VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT |
- VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT;
+ VMX_VPID_EXTENT_SUPPORTED_MASK;
else
vmx->nested.nested_vmx_vpid_caps = 0;
@@ -2989,6 +3010,19 @@
case MSR_IA32_TSC:
msr_info->data = guest_read_tsc(vcpu);
break;
+ case MSR_IA32_SPEC_CTRL:
+ if (!msr_info->host_initiated &&
+ !guest_cpuid_has_ibrs(vcpu))
+ return 1;
+
+ msr_info->data = to_vmx(vcpu)->spec_ctrl;
+ break;
+ case MSR_IA32_ARCH_CAPABILITIES:
+ if (!msr_info->host_initiated &&
+ !guest_cpuid_has_arch_capabilities(vcpu))
+ return 1;
+ msr_info->data = to_vmx(vcpu)->arch_capabilities;
+ break;
case MSR_IA32_SYSENTER_CS:
msr_info->data = vmcs_read32(GUEST_SYSENTER_CS);
break;
@@ -3093,6 +3127,68 @@
case MSR_IA32_TSC:
kvm_write_tsc(vcpu, msr_info);
break;
+ case MSR_IA32_SPEC_CTRL:
+ if (!msr_info->host_initiated &&
+ !guest_cpuid_has_ibrs(vcpu))
+ return 1;
+
+ /* The STIBP bit doesn't fault even if it's not advertised */
+ if (data & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP))
+ return 1;
+
+ vmx->spec_ctrl = data;
+
+ if (!data)
+ break;
+
+ /*
+ * For non-nested:
+ * When it's written (to non-zero) for the first time, pass
+ * it through.
+ *
+ * For nested:
+ * The handling of the MSR bitmap for L2 guests is done in
+ * nested_vmx_merge_msr_bitmap. We should not touch the
+ * vmcs02.msr_bitmap here since it gets completely overwritten
+ * in the merging. We update the vmcs01 here for L1 as well
+ * since it will end up touching the MSR anyway now.
+ */
+ vmx_disable_intercept_for_msr(vmx->vmcs01.msr_bitmap,
+ MSR_IA32_SPEC_CTRL,
+ MSR_TYPE_RW);
+ break;
+ case MSR_IA32_PRED_CMD:
+ if (!msr_info->host_initiated &&
+ !guest_cpuid_has_ibpb(vcpu))
+ return 1;
+
+ if (data & ~PRED_CMD_IBPB)
+ return 1;
+
+ if (!data)
+ break;
+
+ wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
+
+ /*
+ * For non-nested:
+ * When it's written (to non-zero) for the first time, pass
+ * it through.
+ *
+ * For nested:
+ * The handling of the MSR bitmap for L2 guests is done in
+ * nested_vmx_merge_msr_bitmap. We should not touch the
+ * vmcs02.msr_bitmap here since it gets completely overwritten
+ * in the merging.
+ */
+ vmx_disable_intercept_for_msr(vmx->vmcs01.msr_bitmap, MSR_IA32_PRED_CMD,
+ MSR_TYPE_W);
+ break;
+ case MSR_IA32_ARCH_CAPABILITIES:
+ if (!msr_info->host_initiated)
+ return 1;
+ vmx->arch_capabilities = data;
+ break;
case MSR_IA32_CR_PAT:
if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) {
if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data))
@@ -3532,11 +3628,6 @@
return vmcs;
}
-static struct vmcs *alloc_vmcs(void)
-{
- return alloc_vmcs_cpu(raw_smp_processor_id());
-}
-
static void free_vmcs(struct vmcs *vmcs)
{
free_pages((unsigned long)vmcs, vmcs_config.order);
@@ -3552,9 +3643,38 @@
loaded_vmcs_clear(loaded_vmcs);
free_vmcs(loaded_vmcs->vmcs);
loaded_vmcs->vmcs = NULL;
+ if (loaded_vmcs->msr_bitmap)
+ free_page((unsigned long)loaded_vmcs->msr_bitmap);
WARN_ON(loaded_vmcs->shadow_vmcs != NULL);
}
+static struct vmcs *alloc_vmcs(void)
+{
+ return alloc_vmcs_cpu(raw_smp_processor_id());
+}
+
+static int alloc_loaded_vmcs(struct loaded_vmcs *loaded_vmcs)
+{
+ loaded_vmcs->vmcs = alloc_vmcs();
+ if (!loaded_vmcs->vmcs)
+ return -ENOMEM;
+
+ loaded_vmcs->shadow_vmcs = NULL;
+ loaded_vmcs_init(loaded_vmcs);
+
+ if (cpu_has_vmx_msr_bitmap()) {
+ loaded_vmcs->msr_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL);
+ if (!loaded_vmcs->msr_bitmap)
+ goto out_vmcs;
+ memset(loaded_vmcs->msr_bitmap, 0xff, PAGE_SIZE);
+ }
+ return 0;
+
+out_vmcs:
+ free_loaded_vmcs(loaded_vmcs);
+ return -ENOMEM;
+}
+
static void free_kvm_area(void)
{
int cpu;
@@ -4561,10 +4681,8 @@
spin_unlock(&vmx_vpid_lock);
}
-#define MSR_TYPE_R 1
-#define MSR_TYPE_W 2
-static void __vmx_disable_intercept_for_msr(unsigned long *msr_bitmap,
- u32 msr, int type)
+static void __always_inline vmx_disable_intercept_for_msr(unsigned long *msr_bitmap,
+ u32 msr, int type)
{
int f = sizeof(unsigned long);
@@ -4598,8 +4716,8 @@
}
}
-static void __vmx_enable_intercept_for_msr(unsigned long *msr_bitmap,
- u32 msr, int type)
+static void __always_inline vmx_enable_intercept_for_msr(unsigned long *msr_bitmap,
+ u32 msr, int type)
{
int f = sizeof(unsigned long);
@@ -4633,6 +4751,15 @@
}
}
+static void __always_inline vmx_set_intercept_for_msr(unsigned long *msr_bitmap,
+ u32 msr, int type, bool value)
+{
+ if (value)
+ vmx_enable_intercept_for_msr(msr_bitmap, msr, type);
+ else
+ vmx_disable_intercept_for_msr(msr_bitmap, msr, type);
+}
+
/*
* If a msr is allowed by L0, we should check whether it is allowed by L1.
* The corresponding bit will be cleared unless both of L0 and L1 allow it.
@@ -4679,58 +4806,68 @@
}
}
-static void vmx_disable_intercept_for_msr(u32 msr, bool longmode_only)
+static u8 vmx_msr_bitmap_mode(struct kvm_vcpu *vcpu)
{
- if (!longmode_only)
- __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy,
- msr, MSR_TYPE_R | MSR_TYPE_W);
- __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode,
- msr, MSR_TYPE_R | MSR_TYPE_W);
+ u8 mode = 0;
+
+ if (cpu_has_secondary_exec_ctrls() &&
+ (vmcs_read32(SECONDARY_VM_EXEC_CONTROL) &
+ SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE)) {
+ mode |= MSR_BITMAP_MODE_X2APIC;
+ if (enable_apicv && kvm_vcpu_apicv_active(vcpu))
+ mode |= MSR_BITMAP_MODE_X2APIC_APICV;
+ }
+
+ if (is_long_mode(vcpu))
+ mode |= MSR_BITMAP_MODE_LM;
+
+ return mode;
}
-static void vmx_enable_intercept_msr_read_x2apic(u32 msr, bool apicv_active)
+#define X2APIC_MSR(r) (APIC_BASE_MSR + ((r) >> 4))
+
+static void vmx_update_msr_bitmap_x2apic(unsigned long *msr_bitmap,
+ u8 mode)
{
- if (apicv_active) {
- __vmx_enable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
- msr, MSR_TYPE_R);
- __vmx_enable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
- msr, MSR_TYPE_R);
- } else {
- __vmx_enable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic_apicv_inactive,
- msr, MSR_TYPE_R);
- __vmx_enable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic_apicv_inactive,
- msr, MSR_TYPE_R);
+ int msr;
+
+ for (msr = 0x800; msr <= 0x8ff; msr += BITS_PER_LONG) {
+ unsigned word = msr / BITS_PER_LONG;
+ msr_bitmap[word] = (mode & MSR_BITMAP_MODE_X2APIC_APICV) ? 0 : ~0;
+ msr_bitmap[word + (0x800 / sizeof(long))] = ~0;
+ }
+
+ if (mode & MSR_BITMAP_MODE_X2APIC) {
+ /*
+ * TPR reads and writes can be virtualized even if virtual interrupt
+ * delivery is not in use.
+ */
+ vmx_disable_intercept_for_msr(msr_bitmap, X2APIC_MSR(APIC_TASKPRI), MSR_TYPE_RW);
+ if (mode & MSR_BITMAP_MODE_X2APIC_APICV) {
+ vmx_enable_intercept_for_msr(msr_bitmap, X2APIC_MSR(APIC_TMCCT), MSR_TYPE_R);
+ vmx_disable_intercept_for_msr(msr_bitmap, X2APIC_MSR(APIC_EOI), MSR_TYPE_W);
+ vmx_disable_intercept_for_msr(msr_bitmap, X2APIC_MSR(APIC_SELF_IPI), MSR_TYPE_W);
+ }
}
}
-static void vmx_disable_intercept_msr_read_x2apic(u32 msr, bool apicv_active)
+static void vmx_update_msr_bitmap(struct kvm_vcpu *vcpu)
{
- if (apicv_active) {
- __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
- msr, MSR_TYPE_R);
- __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
- msr, MSR_TYPE_R);
- } else {
- __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic_apicv_inactive,
- msr, MSR_TYPE_R);
- __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic_apicv_inactive,
- msr, MSR_TYPE_R);
- }
-}
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ unsigned long *msr_bitmap = vmx->vmcs01.msr_bitmap;
+ u8 mode = vmx_msr_bitmap_mode(vcpu);
+ u8 changed = mode ^ vmx->msr_bitmap_mode;
-static void vmx_disable_intercept_msr_write_x2apic(u32 msr, bool apicv_active)
-{
- if (apicv_active) {
- __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
- msr, MSR_TYPE_W);
- __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
- msr, MSR_TYPE_W);
- } else {
- __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic_apicv_inactive,
- msr, MSR_TYPE_W);
- __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic_apicv_inactive,
- msr, MSR_TYPE_W);
- }
+ if (!changed)
+ return;
+
+ vmx_set_intercept_for_msr(msr_bitmap, MSR_KERNEL_GS_BASE, MSR_TYPE_RW,
+ !(mode & MSR_BITMAP_MODE_LM));
+
+ if (changed & (MSR_BITMAP_MODE_X2APIC | MSR_BITMAP_MODE_X2APIC_APICV))
+ vmx_update_msr_bitmap_x2apic(msr_bitmap, mode);
+
+ vmx->msr_bitmap_mode = mode;
}
static bool vmx_get_enable_apicv(void)
@@ -4738,30 +4875,45 @@
return enable_apicv;
}
-static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
+static void nested_mark_vmcs12_pages_dirty(struct kvm_vcpu *vcpu)
+{
+ struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+ gfn_t gfn;
+
+ /*
+ * Don't need to mark the APIC access page dirty; it is never
+ * written to by the CPU during APIC virtualization.
+ */
+
+ if (nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW)) {
+ gfn = vmcs12->virtual_apic_page_addr >> PAGE_SHIFT;
+ kvm_vcpu_mark_page_dirty(vcpu, gfn);
+ }
+
+ if (nested_cpu_has_posted_intr(vmcs12)) {
+ gfn = vmcs12->posted_intr_desc_addr >> PAGE_SHIFT;
+ kvm_vcpu_mark_page_dirty(vcpu, gfn);
+ }
+}
+
+
+static void vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
int max_irr;
void *vapic_page;
u16 status;
- if (vmx->nested.pi_desc &&
- vmx->nested.pi_pending) {
- vmx->nested.pi_pending = false;
- if (!pi_test_and_clear_on(vmx->nested.pi_desc))
- return 0;
+ if (!vmx->nested.pi_desc || !vmx->nested.pi_pending)
+ return;
- max_irr = find_last_bit(
- (unsigned long *)vmx->nested.pi_desc->pir, 256);
+ vmx->nested.pi_pending = false;
+ if (!pi_test_and_clear_on(vmx->nested.pi_desc))
+ return;
- if (max_irr == 256)
- return 0;
-
+ max_irr = find_last_bit((unsigned long *)vmx->nested.pi_desc->pir, 256);
+ if (max_irr != 256) {
vapic_page = kmap(vmx->nested.virtual_apic_page);
- if (!vapic_page) {
- WARN_ON(1);
- return -ENOMEM;
- }
__kvm_apic_update_irr(vmx->nested.pi_desc->pir, vapic_page);
kunmap(vmx->nested.virtual_apic_page);
@@ -4772,7 +4924,8 @@
vmcs_write16(GUEST_INTR_STATUS, status);
}
}
- return 0;
+
+ nested_mark_vmcs12_pages_dirty(vcpu);
}
static inline bool kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu)
@@ -4819,14 +4972,15 @@
if (is_guest_mode(vcpu) &&
vector == vmx->nested.posted_intr_nv) {
- /* the PIR and ON have been set by L1. */
- kvm_vcpu_trigger_posted_interrupt(vcpu);
/*
* If a posted intr is not recognized by hardware,
* we will accomplish it in the next vmentry.
*/
vmx->nested.pi_pending = true;
kvm_make_request(KVM_REQ_EVENT, vcpu);
+ /* the PIR and ON have been set by L1. */
+ if (!kvm_vcpu_trigger_posted_interrupt(vcpu))
+ kvm_vcpu_kick(vcpu);
return 0;
}
return -1;
@@ -4959,7 +5113,7 @@
}
if (cpu_has_vmx_msr_bitmap())
- vmx_set_msr_bitmap(vcpu);
+ vmx_update_msr_bitmap(vcpu);
}
static u32 vmx_exec_control(struct vcpu_vmx *vmx)
@@ -5048,7 +5202,7 @@
vmcs_write64(VMWRITE_BITMAP, __pa(vmx_vmwrite_bitmap));
}
if (cpu_has_vmx_msr_bitmap())
- vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_legacy));
+ vmcs_write64(MSR_BITMAP, __pa(vmx->vmcs01.msr_bitmap));
vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */
@@ -5122,6 +5276,8 @@
++vmx->nmsrs;
}
+ if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES))
+ rdmsrl(MSR_IA32_ARCH_CAPABILITIES, vmx->arch_capabilities);
vm_exit_controls_init(vmx, vmcs_config.vmexit_ctrl);
@@ -5150,6 +5306,7 @@
u64 cr0;
vmx->rmode.vm86_active = 0;
+ vmx->spec_ctrl = 0;
vmx->soft_vnmi_blocked = 0;
@@ -6379,7 +6536,7 @@
static __init int hardware_setup(void)
{
- int r = -ENOMEM, i, msr;
+ int r = -ENOMEM, i;
rdmsrl_safe(MSR_EFER, &host_efer);
@@ -6394,41 +6551,13 @@
if (!vmx_io_bitmap_b)
goto out;
- vmx_msr_bitmap_legacy = (unsigned long *)__get_free_page(GFP_KERNEL);
- if (!vmx_msr_bitmap_legacy)
- goto out1;
-
- vmx_msr_bitmap_legacy_x2apic =
- (unsigned long *)__get_free_page(GFP_KERNEL);
- if (!vmx_msr_bitmap_legacy_x2apic)
- goto out2;
-
- vmx_msr_bitmap_legacy_x2apic_apicv_inactive =
- (unsigned long *)__get_free_page(GFP_KERNEL);
- if (!vmx_msr_bitmap_legacy_x2apic_apicv_inactive)
- goto out3;
-
- vmx_msr_bitmap_longmode = (unsigned long *)__get_free_page(GFP_KERNEL);
- if (!vmx_msr_bitmap_longmode)
- goto out4;
-
- vmx_msr_bitmap_longmode_x2apic =
- (unsigned long *)__get_free_page(GFP_KERNEL);
- if (!vmx_msr_bitmap_longmode_x2apic)
- goto out5;
-
- vmx_msr_bitmap_longmode_x2apic_apicv_inactive =
- (unsigned long *)__get_free_page(GFP_KERNEL);
- if (!vmx_msr_bitmap_longmode_x2apic_apicv_inactive)
- goto out6;
-
vmx_vmread_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL);
if (!vmx_vmread_bitmap)
- goto out7;
+ goto out1;
vmx_vmwrite_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL);
if (!vmx_vmwrite_bitmap)
- goto out8;
+ goto out2;
memset(vmx_vmread_bitmap, 0xff, PAGE_SIZE);
memset(vmx_vmwrite_bitmap, 0xff, PAGE_SIZE);
@@ -6437,12 +6566,9 @@
memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE);
- memset(vmx_msr_bitmap_legacy, 0xff, PAGE_SIZE);
- memset(vmx_msr_bitmap_longmode, 0xff, PAGE_SIZE);
-
if (setup_vmcs_config(&vmcs_config) < 0) {
r = -EIO;
- goto out9;
+ goto out3;
}
if (boot_cpu_has(X86_FEATURE_NX))
@@ -6499,47 +6625,8 @@
kvm_tsc_scaling_ratio_frac_bits = 48;
}
- vmx_disable_intercept_for_msr(MSR_FS_BASE, false);
- vmx_disable_intercept_for_msr(MSR_GS_BASE, false);
- vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true);
- vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
- vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
- vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
-
- memcpy(vmx_msr_bitmap_legacy_x2apic,
- vmx_msr_bitmap_legacy, PAGE_SIZE);
- memcpy(vmx_msr_bitmap_longmode_x2apic,
- vmx_msr_bitmap_longmode, PAGE_SIZE);
- memcpy(vmx_msr_bitmap_legacy_x2apic_apicv_inactive,
- vmx_msr_bitmap_legacy, PAGE_SIZE);
- memcpy(vmx_msr_bitmap_longmode_x2apic_apicv_inactive,
- vmx_msr_bitmap_longmode, PAGE_SIZE);
-
set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
- /*
- * enable_apicv && kvm_vcpu_apicv_active()
- */
- for (msr = 0x800; msr <= 0x8ff; msr++)
- vmx_disable_intercept_msr_read_x2apic(msr, true);
-
- /* TMCCT */
- vmx_enable_intercept_msr_read_x2apic(0x839, true);
- /* TPR */
- vmx_disable_intercept_msr_write_x2apic(0x808, true);
- /* EOI */
- vmx_disable_intercept_msr_write_x2apic(0x80b, true);
- /* SELF-IPI */
- vmx_disable_intercept_msr_write_x2apic(0x83f, true);
-
- /*
- * (enable_apicv && !kvm_vcpu_apicv_active()) ||
- * !enable_apicv
- */
- /* TPR */
- vmx_disable_intercept_msr_read_x2apic(0x808, false);
- vmx_disable_intercept_msr_write_x2apic(0x808, false);
-
if (enable_ept) {
kvm_mmu_set_mask_ptes(VMX_EPT_READABLE_MASK,
(enable_ept_ad_bits) ? VMX_EPT_ACCESS_BIT : 0ull,
@@ -6585,22 +6672,10 @@
return alloc_kvm_area();
-out9:
- free_page((unsigned long)vmx_vmwrite_bitmap);
-out8:
- free_page((unsigned long)vmx_vmread_bitmap);
-out7:
- free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic_apicv_inactive);
-out6:
- free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic);
-out5:
- free_page((unsigned long)vmx_msr_bitmap_longmode);
-out4:
- free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic_apicv_inactive);
out3:
- free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic);
+ free_page((unsigned long)vmx_vmwrite_bitmap);
out2:
- free_page((unsigned long)vmx_msr_bitmap_legacy);
+ free_page((unsigned long)vmx_vmread_bitmap);
out1:
free_page((unsigned long)vmx_io_bitmap_b);
out:
@@ -6611,12 +6686,6 @@
static __exit void hardware_unsetup(void)
{
- free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic);
- free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic_apicv_inactive);
- free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic);
- free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic_apicv_inactive);
- free_page((unsigned long)vmx_msr_bitmap_legacy);
- free_page((unsigned long)vmx_msr_bitmap_longmode);
free_page((unsigned long)vmx_io_bitmap_b);
free_page((unsigned long)vmx_io_bitmap_a);
free_page((unsigned long)vmx_vmwrite_bitmap);
@@ -6664,94 +6733,6 @@
}
/*
- * To run an L2 guest, we need a vmcs02 based on the L1-specified vmcs12.
- * We could reuse a single VMCS for all the L2 guests, but we also want the
- * option to allocate a separate vmcs02 for each separate loaded vmcs12 - this
- * allows keeping them loaded on the processor, and in the future will allow
- * optimizations where prepare_vmcs02 doesn't need to set all the fields on
- * every entry if they never change.
- * So we keep, in vmx->nested.vmcs02_pool, a cache of size VMCS02_POOL_SIZE
- * (>=0) with a vmcs02 for each recently loaded vmcs12s, most recent first.
- *
- * The following functions allocate and free a vmcs02 in this pool.
- */
-
-/* Get a VMCS from the pool to use as vmcs02 for the current vmcs12. */
-static struct loaded_vmcs *nested_get_current_vmcs02(struct vcpu_vmx *vmx)
-{
- struct vmcs02_list *item;
- list_for_each_entry(item, &vmx->nested.vmcs02_pool, list)
- if (item->vmptr == vmx->nested.current_vmptr) {
- list_move(&item->list, &vmx->nested.vmcs02_pool);
- return &item->vmcs02;
- }
-
- if (vmx->nested.vmcs02_num >= max(VMCS02_POOL_SIZE, 1)) {
- /* Recycle the least recently used VMCS. */
- item = list_last_entry(&vmx->nested.vmcs02_pool,
- struct vmcs02_list, list);
- item->vmptr = vmx->nested.current_vmptr;
- list_move(&item->list, &vmx->nested.vmcs02_pool);
- return &item->vmcs02;
- }
-
- /* Create a new VMCS */
- item = kmalloc(sizeof(struct vmcs02_list), GFP_KERNEL);
- if (!item)
- return NULL;
- item->vmcs02.vmcs = alloc_vmcs();
- item->vmcs02.shadow_vmcs = NULL;
- if (!item->vmcs02.vmcs) {
- kfree(item);
- return NULL;
- }
- loaded_vmcs_init(&item->vmcs02);
- item->vmptr = vmx->nested.current_vmptr;
- list_add(&(item->list), &(vmx->nested.vmcs02_pool));
- vmx->nested.vmcs02_num++;
- return &item->vmcs02;
-}
-
-/* Free and remove from pool a vmcs02 saved for a vmcs12 (if there is one) */
-static void nested_free_vmcs02(struct vcpu_vmx *vmx, gpa_t vmptr)
-{
- struct vmcs02_list *item;
- list_for_each_entry(item, &vmx->nested.vmcs02_pool, list)
- if (item->vmptr == vmptr) {
- free_loaded_vmcs(&item->vmcs02);
- list_del(&item->list);
- kfree(item);
- vmx->nested.vmcs02_num--;
- return;
- }
-}
-
-/*
- * Free all VMCSs saved for this vcpu, except the one pointed by
- * vmx->loaded_vmcs. We must be running L1, so vmx->loaded_vmcs
- * must be &vmx->vmcs01.
- */
-static void nested_free_all_saved_vmcss(struct vcpu_vmx *vmx)
-{
- struct vmcs02_list *item, *n;
-
- WARN_ON(vmx->loaded_vmcs != &vmx->vmcs01);
- list_for_each_entry_safe(item, n, &vmx->nested.vmcs02_pool, list) {
- /*
- * Something will leak if the above WARN triggers. Better than
- * a use-after-free.
- */
- if (vmx->loaded_vmcs == &item->vmcs02)
- continue;
-
- free_loaded_vmcs(&item->vmcs02);
- list_del(&item->list);
- kfree(item);
- vmx->nested.vmcs02_num--;
- }
-}
-
-/*
* The following 3 functions, nested_vmx_succeed()/failValid()/failInvalid(),
* set the success or error code of an emulated VMX instruction, as specified
* by Vol 2B, VMX Instruction Reference, "Conventions".
@@ -7025,6 +7006,7 @@
struct vmcs *shadow_vmcs;
const u64 VMXON_NEEDED_FEATURES = FEATURE_CONTROL_LOCKED
| FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX;
+ int r;
/* The Intel VMX Instruction Reference lists a bunch of bits that
* are prerequisite to running VMXON, most notably cr4.VMXE must be
@@ -7064,12 +7046,9 @@
return 1;
}
- if (cpu_has_vmx_msr_bitmap()) {
- vmx->nested.msr_bitmap =
- (unsigned long *)__get_free_page(GFP_KERNEL);
- if (!vmx->nested.msr_bitmap)
- goto out_msr_bitmap;
- }
+ r = alloc_loaded_vmcs(&vmx->nested.vmcs02);
+ if (r < 0)
+ goto out_vmcs02;
vmx->nested.cached_vmcs12 = kmalloc(VMCS12_SIZE, GFP_KERNEL);
if (!vmx->nested.cached_vmcs12)
@@ -7086,9 +7065,6 @@
vmx->vmcs01.shadow_vmcs = shadow_vmcs;
}
- INIT_LIST_HEAD(&(vmx->nested.vmcs02_pool));
- vmx->nested.vmcs02_num = 0;
-
hrtimer_init(&vmx->nested.preemption_timer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL_PINNED);
vmx->nested.preemption_timer.function = vmx_preemption_timer_fn;
@@ -7103,9 +7079,9 @@
kfree(vmx->nested.cached_vmcs12);
out_cached_vmcs12:
- free_page((unsigned long)vmx->nested.msr_bitmap);
+ free_loaded_vmcs(&vmx->nested.vmcs02);
-out_msr_bitmap:
+out_vmcs02:
return -ENOMEM;
}
@@ -7181,17 +7157,13 @@
vmx->nested.vmxon = false;
free_vpid(vmx->nested.vpid02);
nested_release_vmcs12(vmx);
- if (vmx->nested.msr_bitmap) {
- free_page((unsigned long)vmx->nested.msr_bitmap);
- vmx->nested.msr_bitmap = NULL;
- }
if (enable_shadow_vmcs) {
vmcs_clear(vmx->vmcs01.shadow_vmcs);
free_vmcs(vmx->vmcs01.shadow_vmcs);
vmx->vmcs01.shadow_vmcs = NULL;
}
kfree(vmx->nested.cached_vmcs12);
- /* Unpin physical memory we referred to in current vmcs02 */
+ /* Unpin physical memory we referred to in the vmcs02 */
if (vmx->nested.apic_access_page) {
nested_release_page(vmx->nested.apic_access_page);
vmx->nested.apic_access_page = NULL;
@@ -7207,7 +7179,7 @@
vmx->nested.pi_desc = NULL;
}
- nested_free_all_saved_vmcss(vmx);
+ free_loaded_vmcs(&vmx->nested.vmcs02);
}
/* Emulate the VMXOFF instruction */
@@ -7241,8 +7213,6 @@
vmptr + offsetof(struct vmcs12, launch_state),
&zero, sizeof(zero));
- nested_free_vmcs02(vmx, vmptr);
-
skip_emulated_instruction(vcpu);
nested_vmx_succeed(vcpu);
return 1;
@@ -7720,7 +7690,8 @@
vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
type = kvm_register_readl(vcpu, (vmx_instruction_info >> 28) & 0xf);
- types = (vmx->nested.nested_vmx_vpid_caps >> 8) & 0x7;
+ types = (vmx->nested.nested_vmx_vpid_caps &
+ VMX_VPID_EXTENT_SUPPORTED_MASK) >> 8;
if (type >= 32 || !(types & (1 << type))) {
nested_vmx_failValid(vcpu,
@@ -7742,21 +7713,27 @@
}
switch (type) {
+ case VMX_VPID_EXTENT_INDIVIDUAL_ADDR:
case VMX_VPID_EXTENT_SINGLE_CONTEXT:
- /*
- * Old versions of KVM use the single-context version so we
- * have to support it; just treat it the same as all-context.
- */
+ case VMX_VPID_EXTENT_SINGLE_NON_GLOBAL:
+ if (!vpid) {
+ nested_vmx_failValid(vcpu,
+ VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+ skip_emulated_instruction(vcpu);
+ return 1;
+ }
+ break;
case VMX_VPID_EXTENT_ALL_CONTEXT:
- __vmx_flush_tlb(vcpu, to_vmx(vcpu)->nested.vpid02);
- nested_vmx_succeed(vcpu);
break;
default:
- /* Trap individual address invalidation invvpid calls */
- BUG_ON(1);
- break;
+ WARN_ON_ONCE(1);
+ skip_emulated_instruction(vcpu);
+ return 1;
}
+ __vmx_flush_tlb(vcpu, vmx->nested.vpid02);
+ nested_vmx_succeed(vcpu);
+
skip_emulated_instruction(vcpu);
return 1;
}
@@ -8029,6 +8006,19 @@
vmcs_read32(VM_EXIT_INTR_ERROR_CODE),
KVM_ISA_VMX);
+ /*
+ * The host physical addresses of some pages of guest memory
+ * are loaded into the vmcs02 (e.g. vmcs12's Virtual APIC
+ * Page). The CPU may write to these pages via their host
+ * physical address while L2 is running, bypassing any
+ * address-translation-based dirty tracking (e.g. EPT write
+ * protection).
+ *
+ * Mark them dirty on every exit from L2 to prevent them from
+ * getting out of sync with dirty tracking.
+ */
+ nested_mark_vmcs12_pages_dirty(vcpu);
+
if (vmx->nested.nested_run_pending)
return false;
@@ -8520,7 +8510,7 @@
}
vmcs_write32(SECONDARY_VM_EXEC_CONTROL, sec_exec_control);
- vmx_set_msr_bitmap(vcpu);
+ vmx_update_msr_bitmap(vcpu);
}
static void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu, hpa_t hpa)
@@ -8647,7 +8637,6 @@
static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
{
u32 exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
- register void *__sp asm(_ASM_SP);
/*
* If external interrupt exists, IF bit is set in rflags/eflags on the
@@ -8676,14 +8665,14 @@
#endif
"pushf\n\t"
__ASM_SIZE(push) " $%c[cs]\n\t"
- "call *%[entry]\n\t"
+ CALL_NOSPEC
:
#ifdef CONFIG_X86_64
[sp]"=&r"(tmp),
#endif
- "+r"(__sp)
+ ASM_CALL_CONSTRAINT
:
- [entry]"r"(entry),
+ THUNK_TARGET(entry),
[ss]"i"(__KERNEL_DS),
[cs]"i"(__KERNEL_CS)
);
@@ -8909,6 +8898,15 @@
vmx_arm_hv_timer(vcpu);
+ /*
+ * If this vCPU has touched SPEC_CTRL, restore the guest's value if
+ * it's non-zero. Since vmentry is serialising on affected CPUs, there
+ * is no need to worry about the conditional branch over the wrmsr
+ * being speculatively taken.
+ */
+ if (vmx->spec_ctrl)
+ wrmsrl(MSR_IA32_SPEC_CTRL, vmx->spec_ctrl);
+
vmx->__launched = vmx->loaded_vmcs->launched;
asm(
/* Store host registers */
@@ -9027,6 +9025,27 @@
#endif
);
+ /*
+ * We do not use IBRS in the kernel. If this vCPU has used the
+ * SPEC_CTRL MSR it may have left it on; save the value and
+ * turn it off. This is much more efficient than blindly adding
+ * it to the atomic save/restore list. Especially as the former
+ * (Saving guest MSRs on vmexit) doesn't even exist in KVM.
+ *
+ * For non-nested case:
+ * If the L01 MSR bitmap does not intercept the MSR, then we need to
+ * save it.
+ *
+ * For nested case:
+ * If the L02 MSR bitmap does not intercept the MSR, then we need to
+ * save it.
+ */
+ if (!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))
+ rdmsrl(MSR_IA32_SPEC_CTRL, vmx->spec_ctrl);
+
+ if (vmx->spec_ctrl)
+ wrmsrl(MSR_IA32_SPEC_CTRL, 0);
+
/* Eliminate branch target predictions from guest mode */
vmexit_fill_RSB();
@@ -9140,6 +9159,7 @@
{
int err;
struct vcpu_vmx *vmx = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+ unsigned long *msr_bitmap;
int cpu;
if (!vmx)
@@ -9172,17 +9192,24 @@
if (!vmx->guest_msrs)
goto free_pml;
- vmx->loaded_vmcs = &vmx->vmcs01;
- vmx->loaded_vmcs->vmcs = alloc_vmcs();
- vmx->loaded_vmcs->shadow_vmcs = NULL;
- if (!vmx->loaded_vmcs->vmcs)
- goto free_msrs;
if (!vmm_exclusive)
kvm_cpu_vmxon(__pa(per_cpu(vmxarea, raw_smp_processor_id())));
- loaded_vmcs_init(vmx->loaded_vmcs);
+ err = alloc_loaded_vmcs(&vmx->vmcs01);
if (!vmm_exclusive)
kvm_cpu_vmxoff();
+ if (err < 0)
+ goto free_msrs;
+ msr_bitmap = vmx->vmcs01.msr_bitmap;
+ vmx_disable_intercept_for_msr(msr_bitmap, MSR_FS_BASE, MSR_TYPE_RW);
+ vmx_disable_intercept_for_msr(msr_bitmap, MSR_GS_BASE, MSR_TYPE_RW);
+ vmx_disable_intercept_for_msr(msr_bitmap, MSR_KERNEL_GS_BASE, MSR_TYPE_RW);
+ vmx_disable_intercept_for_msr(msr_bitmap, MSR_IA32_SYSENTER_CS, MSR_TYPE_RW);
+ vmx_disable_intercept_for_msr(msr_bitmap, MSR_IA32_SYSENTER_ESP, MSR_TYPE_RW);
+ vmx_disable_intercept_for_msr(msr_bitmap, MSR_IA32_SYSENTER_EIP, MSR_TYPE_RW);
+ vmx->msr_bitmap_mode = 0;
+
+ vmx->loaded_vmcs = &vmx->vmcs01;
cpu = get_cpu();
vmx_vcpu_load(&vmx->vcpu, cpu);
vmx->vcpu.cpu = cpu;
@@ -9576,21 +9603,31 @@
int msr;
struct page *page;
unsigned long *msr_bitmap_l1;
- unsigned long *msr_bitmap_l0 = to_vmx(vcpu)->nested.msr_bitmap;
+ unsigned long *msr_bitmap_l0 = to_vmx(vcpu)->nested.vmcs02.msr_bitmap;
+ /*
+ * pred_cmd & spec_ctrl are trying to verify two things:
+ *
+ * 1. L0 gave a permission to L1 to actually passthrough the MSR. This
+ * ensures that we do not accidentally generate an L02 MSR bitmap
+ * from the L12 MSR bitmap that is too permissive.
+ * 2. That L1 or L2s have actually used the MSR. This avoids
+ * unnecessarily merging of the bitmap if the MSR is unused. This
+ * works properly because we only update the L01 MSR bitmap lazily.
+ * So even if L0 should pass L1 these MSRs, the L01 bitmap is only
+ * updated to reflect this when L1 (or its L2s) actually write to
+ * the MSR.
+ */
+ bool pred_cmd = !msr_write_intercepted_l01(vcpu, MSR_IA32_PRED_CMD);
+ bool spec_ctrl = !msr_write_intercepted_l01(vcpu, MSR_IA32_SPEC_CTRL);
- /* This shortcut is ok because we support only x2APIC MSRs so far. */
- if (!nested_cpu_has_virt_x2apic_mode(vmcs12))
+ if (!nested_cpu_has_virt_x2apic_mode(vmcs12) &&
+ !pred_cmd && !spec_ctrl)
return false;
page = nested_get_page(vcpu, vmcs12->msr_bitmap);
if (!page)
return false;
msr_bitmap_l1 = (unsigned long *)kmap(page);
- if (!msr_bitmap_l1) {
- nested_release_page_clean(page);
- WARN_ON(1);
- return false;
- }
memset(msr_bitmap_l0, 0xff, PAGE_SIZE);
@@ -9617,6 +9654,19 @@
MSR_TYPE_W);
}
}
+
+ if (spec_ctrl)
+ nested_vmx_disable_intercept_for_msr(
+ msr_bitmap_l1, msr_bitmap_l0,
+ MSR_IA32_SPEC_CTRL,
+ MSR_TYPE_R | MSR_TYPE_W);
+
+ if (pred_cmd)
+ nested_vmx_disable_intercept_for_msr(
+ msr_bitmap_l1, msr_bitmap_l0,
+ MSR_IA32_PRED_CMD,
+ MSR_TYPE_W);
+
kunmap(page);
nested_release_page_clean(page);
@@ -10096,6 +10146,9 @@
if (kvm_has_tsc_control)
decache_tsc_multiplier(vmx);
+ if (cpu_has_vmx_msr_bitmap())
+ vmcs_write64(MSR_BITMAP, __pa(vmx->nested.vmcs02.msr_bitmap));
+
if (enable_vpid) {
/*
* There is no direct mapping between vpid02 and vpid12, the
@@ -10191,7 +10244,6 @@
struct vmcs12 *vmcs12;
struct vcpu_vmx *vmx = to_vmx(vcpu);
int cpu;
- struct loaded_vmcs *vmcs02;
bool ia32e;
u32 msr_entry_idx;
@@ -10331,17 +10383,13 @@
* the nested entry.
*/
- vmcs02 = nested_get_current_vmcs02(vmx);
- if (!vmcs02)
- return -ENOMEM;
-
enter_guest_mode(vcpu);
if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
vmx->nested.vmcs01_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
cpu = get_cpu();
- vmx->loaded_vmcs = vmcs02;
+ vmx->loaded_vmcs = &vmx->nested.vmcs02;
vmx_vcpu_put(vcpu);
vmx_vcpu_load(vcpu, cpu);
vcpu->cpu = cpu;
@@ -10493,7 +10541,8 @@
return 0;
}
- return vmx_complete_nested_posted_interrupt(vcpu);
+ vmx_complete_nested_posted_interrupt(vcpu);
+ return 0;
}
static u32 vmx_get_preemption_timer_value(struct kvm_vcpu *vcpu)
@@ -10804,7 +10853,7 @@
vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
if (cpu_has_vmx_msr_bitmap())
- vmx_set_msr_bitmap(vcpu);
+ vmx_update_msr_bitmap(vcpu);
if (nested_vmx_load_msr(vcpu, vmcs12->vm_exit_msr_load_addr,
vmcs12->vm_exit_msr_load_count))
@@ -10855,10 +10904,6 @@
vm_exit_controls_reset_shadow(vmx);
vmx_segment_cache_clear(vmx);
- /* if no vmcs02 cache requested, remove the one we used */
- if (VMCS02_POOL_SIZE == 0)
- nested_free_vmcs02(vmx, vmx->nested.current_vmptr);
-
load_vmcs12_host_state(vcpu, vmcs12);
/* Update any VMCS fields that might have changed while L2 ran */
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e023ef9..4b19ec1 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -975,6 +975,7 @@
#endif
MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA,
MSR_IA32_FEATURE_CONTROL, MSR_IA32_BNDCFGS, MSR_TSC_AUX,
+ MSR_IA32_SPEC_CTRL, MSR_IA32_ARCH_CAPABILITIES
};
static unsigned num_msrs_to_save;
@@ -2846,6 +2847,12 @@
kvm_x86_ops->vcpu_put(vcpu);
kvm_put_guest_fpu(vcpu);
vcpu->arch.last_host_tsc = rdtsc();
+ /*
+ * If userspace has set any breakpoints or watchpoints, dr6 is restored
+ * on every vmexit, but if not, we might have a stale dr6 from the
+ * guest. do_debug expects dr6 to be cleared after it runs, do the same.
+ */
+ set_debugreg(0, 6);
}
static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
@@ -8420,6 +8427,13 @@
sizeof(val));
}
+static int apf_get_user(struct kvm_vcpu *vcpu, u32 *val)
+{
+
+ return kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.apf.data, val,
+ sizeof(u32));
+}
+
void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
struct kvm_async_pf *work)
{
@@ -8446,6 +8460,7 @@
struct kvm_async_pf *work)
{
struct x86_exception fault;
+ u32 val;
if (work->wakeup_all)
work->arch.token = ~0; /* broadcast wakeup */
@@ -8453,14 +8468,24 @@
kvm_del_async_pf_gfn(vcpu, work->arch.gfn);
trace_kvm_async_pf_ready(work->arch.token, work->gva);
- if ((vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED) &&
- !apf_put_user(vcpu, KVM_PV_REASON_PAGE_READY)) {
- fault.vector = PF_VECTOR;
- fault.error_code_valid = true;
- fault.error_code = 0;
- fault.nested_page_fault = false;
- fault.address = work->arch.token;
- kvm_inject_page_fault(vcpu, &fault);
+ if (vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED &&
+ !apf_get_user(vcpu, &val)) {
+ if (val == KVM_PV_REASON_PAGE_NOT_PRESENT &&
+ vcpu->arch.exception.pending &&
+ vcpu->arch.exception.nr == PF_VECTOR &&
+ !apf_put_user(vcpu, 0)) {
+ vcpu->arch.exception.pending = false;
+ vcpu->arch.exception.nr = 0;
+ vcpu->arch.exception.has_error_code = false;
+ vcpu->arch.exception.error_code = 0;
+ } else if (!apf_put_user(vcpu, KVM_PV_REASON_PAGE_READY)) {
+ fault.vector = PF_VECTOR;
+ fault.error_code_valid = true;
+ fault.error_code = 0;
+ fault.nested_page_fault = false;
+ fault.address = work->arch.token;
+ kvm_inject_page_fault(vcpu, &fault);
+ }
}
vcpu->arch.apf.halted = false;
vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 6bf1898..4ad7c4d 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -26,6 +26,7 @@
lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o
lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
lib-$(CONFIG_RETPOLINE) += retpoline.o
+OBJECT_FILES_NON_STANDARD_retpoline.o :=y
obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
diff --git a/arch/x86/lib/cpu.c b/arch/x86/lib/cpu.c
index d6f848d..2dd1fe13 100644
--- a/arch/x86/lib/cpu.c
+++ b/arch/x86/lib/cpu.c
@@ -18,7 +18,7 @@
{
unsigned int fam, model;
- fam = x86_family(sig);
+ fam = x86_family(sig);
model = (sig >> 4) & 0xf;
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index 37b62d4..b12b214 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -39,6 +39,8 @@
mov PER_CPU_VAR(current_task), %_ASM_DX
cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
jae bad_get_user
+ sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */
+ and %_ASM_DX, %_ASM_AX
ASM_STAC
1: movzbl (%_ASM_AX),%edx
xor %eax,%eax
@@ -53,6 +55,8 @@
mov PER_CPU_VAR(current_task), %_ASM_DX
cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
jae bad_get_user
+ sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */
+ and %_ASM_DX, %_ASM_AX
ASM_STAC
2: movzwl -1(%_ASM_AX),%edx
xor %eax,%eax
@@ -67,6 +71,8 @@
mov PER_CPU_VAR(current_task), %_ASM_DX
cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
jae bad_get_user
+ sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */
+ and %_ASM_DX, %_ASM_AX
ASM_STAC
3: movl -3(%_ASM_AX),%edx
xor %eax,%eax
@@ -82,6 +88,8 @@
mov PER_CPU_VAR(current_task), %_ASM_DX
cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
jae bad_get_user
+ sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */
+ and %_ASM_DX, %_ASM_AX
ASM_STAC
4: movq -7(%_ASM_AX),%rdx
xor %eax,%eax
@@ -93,6 +101,8 @@
mov PER_CPU_VAR(current_task), %_ASM_DX
cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
jae bad_get_user_8
+ sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */
+ and %_ASM_DX, %_ASM_AX
ASM_STAC
4: movl -7(%_ASM_AX),%edx
5: movl -3(%_ASM_AX),%ecx
diff --git a/arch/x86/lib/kaslr.c b/arch/x86/lib/kaslr.c
index 121f59c..0c7fe44 100644
--- a/arch/x86/lib/kaslr.c
+++ b/arch/x86/lib/kaslr.c
@@ -5,6 +5,7 @@
* kernel starts. This file is included in the compressed kernel and
* normally linked in the regular.
*/
+#include <asm/asm.h>
#include <asm/kaslr.h>
#include <asm/msr.h>
#include <asm/archrandom.h>
@@ -79,7 +80,7 @@
}
/* Circular multiply for better bit diffusion */
- asm("mul %3"
+ asm(_ASM_MUL "%3"
: "=a" (random), "=d" (raw)
: "a" (random), "rm" (mix_const));
random += raw;
diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S
index dfb2ba9..480edc3 100644
--- a/arch/x86/lib/retpoline.S
+++ b/arch/x86/lib/retpoline.S
@@ -7,6 +7,7 @@
#include <asm/alternative-asm.h>
#include <asm/export.h>
#include <asm/nospec-branch.h>
+#include <asm/bitsperlong.h>
.macro THUNK reg
.section .text.__x86.indirect_thunk
@@ -36,7 +37,6 @@
GENERATE_THUNK(_ASM_SI)
GENERATE_THUNK(_ASM_DI)
GENERATE_THUNK(_ASM_BP)
-GENERATE_THUNK(_ASM_SP)
#ifdef CONFIG_64BIT
GENERATE_THUNK(r8)
GENERATE_THUNK(r9)
@@ -47,3 +47,58 @@
GENERATE_THUNK(r14)
GENERATE_THUNK(r15)
#endif
+
+/*
+ * Fill the CPU return stack buffer.
+ *
+ * Each entry in the RSB, if used for a speculative 'ret', contains an
+ * infinite 'pause; lfence; jmp' loop to capture speculative execution.
+ *
+ * This is required in various cases for retpoline and IBRS-based
+ * mitigations for the Spectre variant 2 vulnerability. Sometimes to
+ * eliminate potentially bogus entries from the RSB, and sometimes
+ * purely to ensure that it doesn't get empty, which on some CPUs would
+ * allow predictions from other (unwanted!) sources to be used.
+ *
+ * Google experimented with loop-unrolling and this turned out to be
+ * the optimal version - two calls, each with their own speculation
+ * trap should their return address end up getting used, in a loop.
+ */
+.macro STUFF_RSB nr:req sp:req
+ mov $(\nr / 2), %_ASM_BX
+ .align 16
+771:
+ call 772f
+773: /* speculation trap */
+ pause
+ lfence
+ jmp 773b
+ .align 16
+772:
+ call 774f
+775: /* speculation trap */
+ pause
+ lfence
+ jmp 775b
+ .align 16
+774:
+ dec %_ASM_BX
+ jnz 771b
+ add $((BITS_PER_LONG/8) * \nr), \sp
+.endm
+
+#define RSB_FILL_LOOPS 16 /* To avoid underflow */
+
+ENTRY(__fill_rsb)
+ STUFF_RSB RSB_FILL_LOOPS, %_ASM_SP
+ ret
+END(__fill_rsb)
+EXPORT_SYMBOL_GPL(__fill_rsb)
+
+#define RSB_CLEAR_LOOPS 32 /* To forcibly overwrite all entries */
+
+ENTRY(__clear_rsb)
+ STUFF_RSB RSB_CLEAR_LOOPS, %_ASM_SP
+ ret
+END(__clear_rsb)
+EXPORT_SYMBOL_GPL(__clear_rsb)
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index 3bc7baf..5c06dbf 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
@@ -570,12 +570,12 @@
unsigned long __copy_to_user_ll(void __user *to, const void *from,
unsigned long n)
{
- stac();
+ __uaccess_begin_nospec();
if (movsl_is_ok(to, from, n))
__copy_user(to, from, n);
else
n = __copy_user_intel(to, from, n);
- clac();
+ __uaccess_end();
return n;
}
EXPORT_SYMBOL(__copy_to_user_ll);
@@ -627,7 +627,7 @@
unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
unsigned long n)
{
- stac();
+ __uaccess_begin_nospec();
#ifdef CONFIG_X86_INTEL_USERCOPY
if (n > 64 && static_cpu_has(X86_FEATURE_XMM2))
n = __copy_user_intel_nocache(to, from, n);
@@ -636,7 +636,7 @@
#else
__copy_user(to, from, n);
#endif
- clac();
+ __uaccess_end();
return n;
}
EXPORT_SYMBOL(__copy_from_user_ll_nocache_nozero);
diff --git a/arch/x86/math-emu/Makefile b/arch/x86/math-emu/Makefile
index 9b0c63b..1b2dac17 100644
--- a/arch/x86/math-emu/Makefile
+++ b/arch/x86/math-emu/Makefile
@@ -5,8 +5,8 @@
#DEBUG = -DDEBUGGING
DEBUG =
PARANOID = -DPARANOID
-EXTRA_CFLAGS := $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
-EXTRA_AFLAGS := $(PARANOID)
+ccflags-y += $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
+asflags-y += $(PARANOID)
# From 'C' language sources:
C_OBJS =fpu_entry.o errors.o \
diff --git a/arch/x86/math-emu/reg_compare.c b/arch/x86/math-emu/reg_compare.c
index b77360f..19b33b5 100644
--- a/arch/x86/math-emu/reg_compare.c
+++ b/arch/x86/math-emu/reg_compare.c
@@ -168,7 +168,7 @@
/* This function requires that st(0) is not empty */
int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
{
- int f = 0, c;
+ int f, c;
c = compare(loaded_data, loaded_tag);
@@ -189,12 +189,12 @@
case COMP_No_Comp:
f = SW_C3 | SW_C2 | SW_C0;
break;
-#ifdef PARANOID
default:
+#ifdef PARANOID
EXCEPTION(EX_INTERNAL | 0x121);
+#endif /* PARANOID */
f = SW_C3 | SW_C2 | SW_C0;
break;
-#endif /* PARANOID */
}
setcc(f);
if (c & COMP_Denormal) {
@@ -205,7 +205,7 @@
static int compare_st_st(int nr)
{
- int f = 0, c;
+ int f, c;
FPU_REG *st_ptr;
if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
@@ -235,12 +235,12 @@
case COMP_No_Comp:
f = SW_C3 | SW_C2 | SW_C0;
break;
-#ifdef PARANOID
default:
+#ifdef PARANOID
EXCEPTION(EX_INTERNAL | 0x122);
+#endif /* PARANOID */
f = SW_C3 | SW_C2 | SW_C0;
break;
-#endif /* PARANOID */
}
setcc(f);
if (c & COMP_Denormal) {
@@ -283,12 +283,12 @@
case COMP_No_Comp:
f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF;
break;
-#ifdef PARANOID
default:
+#ifdef PARANOID
EXCEPTION(EX_INTERNAL | 0x122);
+#endif /* PARANOID */
f = 0;
break;
-#endif /* PARANOID */
}
FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f;
if (c & COMP_Denormal) {
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 74dea7f..3d7f60f 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -759,7 +759,6 @@
if (is_vmalloc_addr((void *)address) &&
(((unsigned long)tsk->stack - 1 - address < PAGE_SIZE) ||
address - ((unsigned long)tsk->stack + THREAD_SIZE) < PAGE_SIZE)) {
- register void *__sp asm("rsp");
unsigned long stack = this_cpu_read(orig_ist.ist[DOUBLEFAULT_STACK]) - sizeof(void *);
/*
* We're likely to be running with very little stack space
@@ -774,7 +773,7 @@
asm volatile ("movq %[stack], %%rsp\n\t"
"call handle_stack_overflow\n\t"
"1: jmp 1b"
- : "+r" (__sp)
+ : ASM_CALL_CONSTRAINT
: "D" ("kernel stack overflow (page fault)"),
"S" (regs), "d" (address),
[stack] "rm" (stack));
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 7aaa263..ecae9ac 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -347,11 +347,11 @@
(void __force *)addr < phys_to_virt(ISA_END_ADDRESS))
return;
+ mmiotrace_iounmap(addr);
+
addr = (volatile void __iomem *)
(PAGE_MASK & (unsigned long __force)addr);
- mmiotrace_iounmap(addr);
-
/* Use the vm area unlocked, assuming the caller
ensures there isn't another iounmap for the same address
in parallel. Reuse of the virtual address is prevented by
diff --git a/arch/x86/mm/kmmio.c b/arch/x86/mm/kmmio.c
index afc47f5..cadb82b 100644
--- a/arch/x86/mm/kmmio.c
+++ b/arch/x86/mm/kmmio.c
@@ -434,17 +434,18 @@
unsigned long flags;
int ret = 0;
unsigned long size = 0;
+ unsigned long addr = p->addr & PAGE_MASK;
const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
unsigned int l;
pte_t *pte;
spin_lock_irqsave(&kmmio_lock, flags);
- if (get_kmmio_probe(p->addr)) {
+ if (get_kmmio_probe(addr)) {
ret = -EEXIST;
goto out;
}
- pte = lookup_address(p->addr, &l);
+ pte = lookup_address(addr, &l);
if (!pte) {
ret = -EINVAL;
goto out;
@@ -453,7 +454,7 @@
kmmio_count++;
list_add_rcu(&p->list, &kmmio_probes);
while (size < size_lim) {
- if (add_kmmio_fault_page(p->addr + size))
+ if (add_kmmio_fault_page(addr + size))
pr_err("Unable to set page fault.\n");
size += page_level_size(l);
}
@@ -527,19 +528,20 @@
{
unsigned long flags;
unsigned long size = 0;
+ unsigned long addr = p->addr & PAGE_MASK;
const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
struct kmmio_fault_page *release_list = NULL;
struct kmmio_delayed_release *drelease;
unsigned int l;
pte_t *pte;
- pte = lookup_address(p->addr, &l);
+ pte = lookup_address(addr, &l);
if (!pte)
return;
spin_lock_irqsave(&kmmio_lock, flags);
while (size < size_lim) {
- release_kmmio_fault_page(p->addr + size, &release_list);
+ release_kmmio_fault_page(addr + size, &release_list);
size += page_level_size(l);
}
list_del_rcu(&p->list);
diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h
index b39531b..72bfc1c 100644
--- a/arch/xtensa/include/asm/futex.h
+++ b/arch/xtensa/include/asm/futex.h
@@ -109,7 +109,6 @@
u32 oldval, u32 newval)
{
int ret = 0;
- u32 prev;
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;
@@ -120,26 +119,24 @@
__asm__ __volatile__ (
" # futex_atomic_cmpxchg_inatomic\n"
- "1: l32i %1, %3, 0\n"
- " mov %0, %5\n"
- " wsr %1, scompare1\n"
- "2: s32c1i %0, %3, 0\n"
- "3:\n"
+ " wsr %5, scompare1\n"
+ "1: s32c1i %1, %4, 0\n"
+ " s32i %1, %6, 0\n"
+ "2:\n"
" .section .fixup,\"ax\"\n"
" .align 4\n"
- "4: .long 3b\n"
- "5: l32r %1, 4b\n"
- " movi %0, %6\n"
+ "3: .long 2b\n"
+ "4: l32r %1, 3b\n"
+ " movi %0, %7\n"
" jx %1\n"
" .previous\n"
" .section __ex_table,\"a\"\n"
- " .long 1b,5b,2b,5b\n"
+ " .long 1b,4b\n"
" .previous\n"
- : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
- : "r" (uaddr), "r" (oldval), "r" (newval), "I" (-EFAULT)
+ : "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval)
+ : "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT)
: "memory");
- *uval = prev;
return ret;
}
diff --git a/block/bio.c b/block/bio.c
index e14a897..07f287b 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -589,7 +589,7 @@
bio->bi_opf = bio_src->bi_opf;
bio->bi_iter = bio_src->bi_iter;
bio->bi_io_vec = bio_src->bi_io_vec;
- bio->bi_dio_inode = bio_src->bi_dio_inode;
+
bio_clone_blkcg_association(bio, bio_src);
}
EXPORT_SYMBOL(__bio_clone_fast);
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 8ba0af7..d673a69 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -184,7 +184,7 @@
goto err_free_blkg;
}
- wb_congested = wb_congested_get_create(&q->backing_dev_info,
+ wb_congested = wb_congested_get_create(q->backing_dev_info,
blkcg->css.id,
GFP_NOWAIT | __GFP_NOWARN);
if (!wb_congested) {
@@ -469,8 +469,8 @@
const char *blkg_dev_name(struct blkcg_gq *blkg)
{
/* some drivers (floppy) instantiate a queue w/o disk registered */
- if (blkg->q->backing_dev_info.dev)
- return dev_name(blkg->q->backing_dev_info.dev);
+ if (blkg->q->backing_dev_info->dev)
+ return dev_name(blkg->q->backing_dev_info->dev);
return NULL;
}
EXPORT_SYMBOL_GPL(blkg_dev_name);
diff --git a/block/blk-core.c b/block/blk-core.c
index 37b814a..404629f 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -75,7 +75,7 @@
* flip its congestion state for events on other blkcgs.
*/
if (rl == &rl->q->root_rl)
- clear_wb_congested(rl->q->backing_dev_info.wb.congested, sync);
+ clear_wb_congested(rl->q->backing_dev_info->wb.congested, sync);
#endif
}
@@ -86,7 +86,7 @@
#else
/* see blk_clear_congested() */
if (rl == &rl->q->root_rl)
- set_wb_congested(rl->q->backing_dev_info.wb.congested, sync);
+ set_wb_congested(rl->q->backing_dev_info->wb.congested, sync);
#endif
}
@@ -105,22 +105,6 @@
q->nr_congestion_off = nr;
}
-/**
- * blk_get_backing_dev_info - get the address of a queue's backing_dev_info
- * @bdev: device
- *
- * Locates the passed device's request queue and returns the address of its
- * backing_dev_info. This function can only be called if @bdev is opened
- * and the return value is never NULL.
- */
-struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev)
-{
- struct request_queue *q = bdev_get_queue(bdev);
-
- return &q->backing_dev_info;
-}
-EXPORT_SYMBOL(blk_get_backing_dev_info);
-
void blk_rq_init(struct request_queue *q, struct request *rq)
{
memset(rq, 0, sizeof(*rq));
@@ -586,7 +570,7 @@
blk_flush_integrity();
/* @q won't process any more request, flush async actions */
- del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer);
+ del_timer_sync(&q->backing_dev_info->laptop_mode_wb_timer);
blk_sync_queue(q);
if (q->mq_ops)
@@ -598,8 +582,6 @@
q->queue_lock = &q->__queue_lock;
spin_unlock_irq(lock);
- bdi_unregister(&q->backing_dev_info);
-
/* @q is and will stay empty, shutdown and put */
blk_put_queue(q);
}
@@ -695,7 +677,6 @@
struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
{
struct request_queue *q;
- int err;
q = kmem_cache_alloc_node(blk_requestq_cachep,
gfp_mask | __GFP_ZERO, node_id);
@@ -710,17 +691,17 @@
if (!q->bio_split)
goto fail_id;
- q->backing_dev_info.ra_pages =
- (VM_MAX_READAHEAD * 1024) / PAGE_SIZE;
- q->backing_dev_info.capabilities = BDI_CAP_CGROUP_WRITEBACK;
- q->backing_dev_info.name = "block";
- q->node = node_id;
-
- err = bdi_init(&q->backing_dev_info);
- if (err)
+ q->backing_dev_info = bdi_alloc_node(gfp_mask, node_id);
+ if (!q->backing_dev_info)
goto fail_split;
- setup_timer(&q->backing_dev_info.laptop_mode_wb_timer,
+ q->backing_dev_info->ra_pages =
+ (VM_MAX_READAHEAD * 1024) / PAGE_SIZE;
+ q->backing_dev_info->capabilities = BDI_CAP_CGROUP_WRITEBACK;
+ q->backing_dev_info->name = "block";
+ q->node = node_id;
+
+ setup_timer(&q->backing_dev_info->laptop_mode_wb_timer,
laptop_mode_timer_fn, (unsigned long) q);
setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
INIT_WORK(&q->timeout_work, NULL);
@@ -771,7 +752,7 @@
fail_ref:
percpu_ref_exit(&q->q_usage_counter);
fail_bdi:
- bdi_destroy(&q->backing_dev_info);
+ bdi_put(q->backing_dev_info);
fail_split:
bioset_free(q->bio_split);
fail_id:
@@ -1197,7 +1178,7 @@
* disturb iosched and blkcg but weird is bettern than dead.
*/
printk_ratelimited(KERN_WARNING "%s: dev %s: request aux data allocation failed, iosched may be disturbed\n",
- __func__, dev_name(q->backing_dev_info.dev));
+ __func__, dev_name(q->backing_dev_info->dev));
rq->cmd_flags &= ~REQ_ELVPRIV;
rq->elv.icq = NULL;
@@ -2739,7 +2720,7 @@
BUG_ON(blk_queued_rq(req));
if (unlikely(laptop_mode) && req->cmd_type == REQ_TYPE_FS)
- laptop_io_completion(&req->q->backing_dev_info);
+ laptop_io_completion(req->q->backing_dev_info);
blk_delete_timer(req);
@@ -3595,76 +3576,43 @@
* TODO : If necessary, we can make the histograms per-cpu and aggregate
* them when printing them out.
*/
-void
-blk_zero_latency_hist(struct io_latency_state *s)
-{
- memset(s->latency_y_axis_read, 0,
- sizeof(s->latency_y_axis_read));
- memset(s->latency_y_axis_write, 0,
- sizeof(s->latency_y_axis_write));
- s->latency_reads_elems = 0;
- s->latency_writes_elems = 0;
-}
-EXPORT_SYMBOL(blk_zero_latency_hist);
-
ssize_t
-blk_latency_hist_show(struct io_latency_state *s, char *buf)
+blk_latency_hist_show(char* name, struct io_latency_state *s, char *buf,
+ int buf_size)
{
int i;
int bytes_written = 0;
u_int64_t num_elem, elem;
int pct;
+ u_int64_t average;
- num_elem = s->latency_reads_elems;
- if (num_elem > 0) {
- bytes_written += scnprintf(buf + bytes_written,
- PAGE_SIZE - bytes_written,
- "IO svc_time Read Latency Histogram (n = %llu):\n",
- num_elem);
- for (i = 0;
- i < ARRAY_SIZE(latency_x_axis_us);
- i++) {
- elem = s->latency_y_axis_read[i];
- pct = div64_u64(elem * 100, num_elem);
- bytes_written += scnprintf(buf + bytes_written,
- PAGE_SIZE - bytes_written,
- "\t< %5lluus%15llu%15d%%\n",
- latency_x_axis_us[i],
- elem, pct);
- }
- /* Last element in y-axis table is overflow */
- elem = s->latency_y_axis_read[i];
- pct = div64_u64(elem * 100, num_elem);
- bytes_written += scnprintf(buf + bytes_written,
- PAGE_SIZE - bytes_written,
- "\t> %5dms%15llu%15d%%\n", 10,
- elem, pct);
+ num_elem = s->latency_elems;
+ if (num_elem > 0) {
+ average = div64_u64(s->latency_sum, s->latency_elems);
+ bytes_written += scnprintf(buf + bytes_written,
+ buf_size - bytes_written,
+ "IO svc_time %s Latency Histogram (n = %llu,"
+ " average = %llu):\n", name, num_elem, average);
+ for (i = 0;
+ i < ARRAY_SIZE(latency_x_axis_us);
+ i++) {
+ elem = s->latency_y_axis[i];
+ pct = div64_u64(elem * 100, num_elem);
+ bytes_written += scnprintf(buf + bytes_written,
+ PAGE_SIZE - bytes_written,
+ "\t< %6lluus%15llu%15d%%\n",
+ latency_x_axis_us[i],
+ elem, pct);
+ }
+ /* Last element in y-axis table is overflow */
+ elem = s->latency_y_axis[i];
+ pct = div64_u64(elem * 100, num_elem);
+ bytes_written += scnprintf(buf + bytes_written,
+ PAGE_SIZE - bytes_written,
+ "\t>=%6lluus%15llu%15d%%\n",
+ latency_x_axis_us[i - 1], elem, pct);
}
- num_elem = s->latency_writes_elems;
- if (num_elem > 0) {
- bytes_written += scnprintf(buf + bytes_written,
- PAGE_SIZE - bytes_written,
- "IO svc_time Write Latency Histogram (n = %llu):\n",
- num_elem);
- for (i = 0;
- i < ARRAY_SIZE(latency_x_axis_us);
- i++) {
- elem = s->latency_y_axis_write[i];
- pct = div64_u64(elem * 100, num_elem);
- bytes_written += scnprintf(buf + bytes_written,
- PAGE_SIZE - bytes_written,
- "\t< %5lluus%15llu%15d%%\n",
- latency_x_axis_us[i],
- elem, pct);
- }
- /* Last element in y-axis table is overflow */
- elem = s->latency_y_axis_write[i];
- pct = div64_u64(elem * 100, num_elem);
- bytes_written += scnprintf(buf + bytes_written,
- PAGE_SIZE - bytes_written,
- "\t> %5dms%15llu%15d%%\n", 10,
- elem, pct);
- }
+
return bytes_written;
}
EXPORT_SYMBOL(blk_latency_hist_show);
diff --git a/block/blk-integrity.c b/block/blk-integrity.c
index 478f572..e4ebd79 100644
--- a/block/blk-integrity.c
+++ b/block/blk-integrity.c
@@ -418,7 +418,7 @@
bi->tuple_size = template->tuple_size;
bi->tag_size = template->tag_size;
- disk->queue->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES;
+ disk->queue->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES;
}
EXPORT_SYMBOL(blk_integrity_register);
@@ -431,7 +431,7 @@
*/
void blk_integrity_unregister(struct gendisk *disk)
{
- disk->queue->backing_dev_info.capabilities &= ~BDI_CAP_STABLE_WRITES;
+ disk->queue->backing_dev_info->capabilities &= ~BDI_CAP_STABLE_WRITES;
memset(&disk->queue->integrity, 0, sizeof(struct blk_integrity));
}
EXPORT_SYMBOL(blk_integrity_unregister);
diff --git a/block/blk-map.c b/block/blk-map.c
index 27fd8d92..a8b4f52 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -116,7 +116,7 @@
unsigned long align = q->dma_pad_mask | queue_dma_alignment(q);
struct bio *bio = NULL;
struct iov_iter i;
- int ret;
+ int ret = -EINVAL;
if (!iter_is_iovec(iter))
goto fail;
@@ -145,7 +145,7 @@
__blk_rq_unmap_user(bio);
fail:
rq->bio = NULL;
- return -EINVAL;
+ return ret;
}
EXPORT_SYMBOL(blk_rq_map_user_iov);
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 0272fac..abde370 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -6,7 +6,7 @@
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/scatterlist.h>
-#include <linux/pfk.h>
+
#include <trace/events/block.h>
#include "blk.h"
@@ -725,11 +725,6 @@
}
}
-static bool crypto_not_mergeable(const struct bio *bio, const struct bio *nxt)
-{
- return (!pfk_allow_merge_bio(bio, nxt));
-}
-
/*
* Has to be called with the request spinlock acquired
*/
@@ -757,8 +752,6 @@
!blk_write_same_mergeable(req->bio, next->bio))
return 0;
- if (crypto_not_mergeable(req->bio, next->bio))
- return 0;
/*
* If we are allowed to merge, then append bio list
* from next to rq and release next. merge_requests_fn
@@ -869,8 +862,6 @@
!blk_write_same_mergeable(rq->bio, bio))
return false;
- if (crypto_not_mergeable(rq->bio, bio))
- return false;
return true;
}
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 9cc8d7c..07c75d0 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -75,7 +75,7 @@
static ssize_t queue_ra_show(struct request_queue *q, char *page)
{
- unsigned long ra_kb = q->backing_dev_info.ra_pages <<
+ unsigned long ra_kb = q->backing_dev_info->ra_pages <<
(PAGE_SHIFT - 10);
return queue_var_show(ra_kb, (page));
@@ -90,7 +90,7 @@
if (ret < 0)
return ret;
- q->backing_dev_info.ra_pages = ra_kb >> (PAGE_SHIFT - 10);
+ q->backing_dev_info->ra_pages = ra_kb >> (PAGE_SHIFT - 10);
return ret;
}
@@ -627,7 +627,7 @@
struct request_queue *q =
container_of(kobj, struct request_queue, kobj);
- bdi_exit(&q->backing_dev_info);
+ bdi_put(q->backing_dev_info);
blkcg_exit_queue(q);
if (q->elevator) {
diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 556826a..570021a 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -661,7 +661,6 @@
struct block_device *bdev = inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
fmode_t mode = file->f_mode;
- struct backing_dev_info *bdi;
loff_t size;
unsigned int max_sectors;
@@ -708,9 +707,8 @@
case BLKFRAGET:
if (!arg)
return -EINVAL;
- bdi = blk_get_backing_dev_info(bdev);
return compat_put_long(arg,
- (bdi->ra_pages * PAGE_SIZE) / 512);
+ (bdev->bd_bdi->ra_pages * PAGE_SIZE) / 512);
case BLKROGET: /* compatible */
return compat_put_int(arg, bdev_read_only(bdev) != 0);
case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
@@ -728,8 +726,7 @@
case BLKFRASET:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- bdi = blk_get_backing_dev_info(bdev);
- bdi->ra_pages = (arg * 512) / PAGE_SIZE;
+ bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
return 0;
case BLKGETSIZE:
size = i_size_read(bdev->bd_inode);
diff --git a/block/genhd.c b/block/genhd.c
index c6eb25d..6ad0fd0 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -613,7 +613,7 @@
disk_alloc_events(disk);
/* Register BDI before referencing it from bdev */
- bdi = &disk->queue->backing_dev_info;
+ bdi = disk->queue->backing_dev_info;
bdi_register_owner(bdi, disk_to_dev(disk));
blk_register_region(disk_devt(disk), disk->minors, NULL,
@@ -649,16 +649,27 @@
DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
while ((part = disk_part_iter_next(&piter))) {
invalidate_partition(disk, part->partno);
+ bdev_unhash_inode(part_devt(part));
delete_partition(disk, part->partno);
}
disk_part_iter_exit(&piter);
invalidate_partition(disk, 0);
+ bdev_unhash_inode(disk_devt(disk));
set_capacity(disk, 0);
disk->flags &= ~GENHD_FL_UP;
sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
- blk_unregister_queue(disk);
+ if (disk->queue) {
+ /*
+ * Unregister bdi before releasing device numbers (as they can
+ * get reused and we'd get clashes in sysfs).
+ */
+ bdi_unregister(disk->queue->backing_dev_info);
+ blk_unregister_queue(disk);
+ } else {
+ WARN_ON(1);
+ }
blk_unregister_region(disk_devt(disk), disk->minors);
part_stat_set_all(&disk->part0, 0);
@@ -1358,7 +1369,7 @@
owner = disk->fops->owner;
if (owner && !try_module_get(owner))
return NULL;
- kobj = kobject_get(&disk_to_dev(disk)->kobj);
+ kobj = kobject_get_unless_zero(&disk_to_dev(disk)->kobj);
if (kobj == NULL) {
module_put(owner);
return NULL;
diff --git a/block/ioctl.c b/block/ioctl.c
index 755119c..c4555b1 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -502,7 +502,6 @@
int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
unsigned long arg)
{
- struct backing_dev_info *bdi;
void __user *argp = (void __user *)arg;
loff_t size;
unsigned int max_sectors;
@@ -525,8 +524,7 @@
case BLKFRAGET:
if (!arg)
return -EINVAL;
- bdi = blk_get_backing_dev_info(bdev);
- return put_long(arg, (bdi->ra_pages * PAGE_SIZE) / 512);
+ return put_long(arg, (bdev->bd_bdi->ra_pages*PAGE_SIZE) / 512);
case BLKROGET:
return put_int(arg, bdev_read_only(bdev) != 0);
case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
@@ -553,8 +551,7 @@
case BLKFRASET:
if(!capable(CAP_SYS_ADMIN))
return -EACCES;
- bdi = blk_get_backing_dev_info(bdev);
- bdi->ra_pages = (arg * 512) / PAGE_SIZE;
+ bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
return 0;
case BLKBSZSET:
return blkdev_bszset(bdev, mode, argp);
diff --git a/crypto/Kconfig b/crypto/Kconfig
index ab0d93a..0f32afc 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1444,6 +1444,20 @@
See also:
<http://www.cl.cam.ac.uk/~rja14/serpent.html>
+config CRYPTO_SPECK
+ tristate "Speck cipher algorithm"
+ select CRYPTO_ALGAPI
+ help
+ Speck is a lightweight block cipher that is tuned for optimal
+ performance in software (rather than hardware).
+
+ Speck may not be as secure as AES, and should only be used on systems
+ where AES is not fast enough.
+
+ See also: <https://eprint.iacr.org/2013/404.pdf>
+
+ If unsure, say N.
+
config CRYPTO_TEA
tristate "TEA, XTEA and XETA cipher algorithms"
select CRYPTO_ALGAPI
diff --git a/crypto/Makefile b/crypto/Makefile
index 9e52b3c..5b08597 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -106,6 +106,7 @@
obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o
obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o
obj-$(CONFIG_CRYPTO_SEED) += seed.o
+obj-$(CONFIG_CRYPTO_SPECK) += speck.o
obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
obj-$(CONFIG_CRYPTO_CHACHA20) += chacha20_generic.o
obj-$(CONFIG_CRYPTO_POLY1305) += poly1305_generic.o
diff --git a/crypto/ahash.c b/crypto/ahash.c
index cce0268..14402ef 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -192,11 +192,18 @@
unsigned int keylen)
{
unsigned long alignmask = crypto_ahash_alignmask(tfm);
+ int err;
if ((unsigned long)key & alignmask)
- return ahash_setkey_unaligned(tfm, key, keylen);
+ err = ahash_setkey_unaligned(tfm, key, keylen);
+ else
+ err = tfm->setkey(tfm, key, keylen);
- return tfm->setkey(tfm, key, keylen);
+ if (err)
+ return err;
+
+ crypto_ahash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
+ return 0;
}
EXPORT_SYMBOL_GPL(crypto_ahash_setkey);
@@ -369,7 +376,12 @@
int crypto_ahash_digest(struct ahash_request *req)
{
- return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->digest);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+
+ if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+ return -ENOKEY;
+
+ return crypto_ahash_op(req, tfm->digest);
}
EXPORT_SYMBOL_GPL(crypto_ahash_digest);
@@ -455,7 +467,6 @@
struct ahash_alg *alg = crypto_ahash_alg(hash);
hash->setkey = ahash_nosetkey;
- hash->has_setkey = false;
hash->export = ahash_no_export;
hash->import = ahash_no_import;
@@ -470,7 +481,8 @@
if (alg->setkey) {
hash->setkey = alg->setkey;
- hash->has_setkey = true;
+ if (!(alg->halg.base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY))
+ crypto_ahash_set_flags(hash, CRYPTO_TFM_NEED_KEY);
}
if (alg->export)
hash->export = alg->export;
@@ -625,5 +637,16 @@
}
EXPORT_SYMBOL_GPL(ahash_attr_alg);
+bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg)
+{
+ struct crypto_alg *alg = &halg->base;
+
+ if (alg->cra_type != &crypto_ahash_type)
+ return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg));
+
+ return __crypto_ahash_alg(alg)->setkey != NULL;
+}
+EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey);
+
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
index 54fc90e..731b5fb 100644
--- a/crypto/algif_hash.c
+++ b/crypto/algif_hash.c
@@ -34,11 +34,6 @@
struct ahash_request req;
};
-struct algif_hash_tfm {
- struct crypto_ahash *hash;
- bool has_key;
-};
-
static int hash_alloc_result(struct sock *sk, struct hash_ctx *ctx)
{
unsigned ds;
@@ -308,7 +303,7 @@
int err = 0;
struct sock *psk;
struct alg_sock *pask;
- struct algif_hash_tfm *tfm;
+ struct crypto_ahash *tfm;
struct sock *sk = sock->sk;
struct alg_sock *ask = alg_sk(sk);
@@ -322,7 +317,7 @@
err = -ENOKEY;
lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
- if (!tfm->has_key)
+ if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
goto unlock;
if (!pask->refcnt++)
@@ -413,41 +408,17 @@
static void *hash_bind(const char *name, u32 type, u32 mask)
{
- struct algif_hash_tfm *tfm;
- struct crypto_ahash *hash;
-
- tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
- if (!tfm)
- return ERR_PTR(-ENOMEM);
-
- hash = crypto_alloc_ahash(name, type, mask);
- if (IS_ERR(hash)) {
- kfree(tfm);
- return ERR_CAST(hash);
- }
-
- tfm->hash = hash;
-
- return tfm;
+ return crypto_alloc_ahash(name, type, mask);
}
static void hash_release(void *private)
{
- struct algif_hash_tfm *tfm = private;
-
- crypto_free_ahash(tfm->hash);
- kfree(tfm);
+ crypto_free_ahash(private);
}
static int hash_setkey(void *private, const u8 *key, unsigned int keylen)
{
- struct algif_hash_tfm *tfm = private;
- int err;
-
- err = crypto_ahash_setkey(tfm->hash, key, keylen);
- tfm->has_key = !err;
-
- return err;
+ return crypto_ahash_setkey(private, key, keylen);
}
static void hash_sock_destruct(struct sock *sk)
@@ -462,11 +433,10 @@
static int hash_accept_parent_nokey(void *private, struct sock *sk)
{
- struct hash_ctx *ctx;
+ struct crypto_ahash *tfm = private;
struct alg_sock *ask = alg_sk(sk);
- struct algif_hash_tfm *tfm = private;
- struct crypto_ahash *hash = tfm->hash;
- unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(hash);
+ struct hash_ctx *ctx;
+ unsigned int len = sizeof(*ctx) + crypto_ahash_reqsize(tfm);
ctx = sock_kmalloc(sk, len, GFP_KERNEL);
if (!ctx)
@@ -479,7 +449,7 @@
ask->private = ctx;
- ahash_request_set_tfm(&ctx->req, hash);
+ ahash_request_set_tfm(&ctx->req, tfm);
ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
af_alg_complete, &ctx->completion);
@@ -490,9 +460,9 @@
static int hash_accept_parent(void *private, struct sock *sk)
{
- struct algif_hash_tfm *tfm = private;
+ struct crypto_ahash *tfm = private;
- if (!tfm->has_key && crypto_ahash_has_setkey(tfm->hash))
+ if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
return -ENOKEY;
return hash_accept_parent_nokey(private, sk);
diff --git a/crypto/api.c b/crypto/api.c
index bbc147c..e5c1abf 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -24,6 +24,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/completion.h>
#include "internal.h"
LIST_HEAD(crypto_alg_list);
@@ -611,5 +612,17 @@
}
EXPORT_SYMBOL_GPL(crypto_has_alg);
+void crypto_req_done(struct crypto_async_request *req, int err)
+{
+ struct crypto_wait *wait = req->data;
+
+ if (err == -EINPROGRESS)
+ return;
+
+ wait->err = err;
+ complete(&wait->completion);
+}
+EXPORT_SYMBOL_GPL(crypto_req_done);
+
MODULE_DESCRIPTION("Cryptographic core API");
MODULE_LICENSE("GPL");
diff --git a/crypto/crc32_generic.c b/crypto/crc32_generic.c
index aa2a25f..718cbce 100644
--- a/crypto/crc32_generic.c
+++ b/crypto/crc32_generic.c
@@ -133,6 +133,7 @@
.cra_name = "crc32",
.cra_driver_name = "crc32-generic",
.cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
.cra_blocksize = CHKSUM_BLOCK_SIZE,
.cra_ctxsize = sizeof(u32),
.cra_module = THIS_MODULE,
diff --git a/crypto/crc32c_generic.c b/crypto/crc32c_generic.c
index 4c0a0e2..3723203 100644
--- a/crypto/crc32c_generic.c
+++ b/crypto/crc32c_generic.c
@@ -146,6 +146,7 @@
.cra_name = "crc32c",
.cra_driver_name = "crc32c-generic",
.cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
.cra_blocksize = CHKSUM_BLOCK_SIZE,
.cra_alignmask = 3,
.cra_ctxsize = sizeof(struct chksum_ctx),
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index 0c654e5..9b66ce7 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -673,10 +673,9 @@
if (err)
goto out_free_inst;
- type = CRYPTO_ALG_ASYNC;
- if (alg->cra_flags & CRYPTO_ALG_INTERNAL)
- type |= CRYPTO_ALG_INTERNAL;
- inst->alg.halg.base.cra_flags = type;
+ inst->alg.halg.base.cra_flags = CRYPTO_ALG_ASYNC |
+ (alg->cra_flags & (CRYPTO_ALG_INTERNAL |
+ CRYPTO_ALG_OPTIONAL_KEY));
inst->alg.halg.digestsize = salg->digestsize;
inst->alg.halg.statesize = salg->statesize;
@@ -691,7 +690,8 @@
inst->alg.finup = cryptd_hash_finup_enqueue;
inst->alg.export = cryptd_hash_export;
inst->alg.import = cryptd_hash_import;
- inst->alg.setkey = cryptd_hash_setkey;
+ if (crypto_shash_alg_has_setkey(salg))
+ inst->alg.setkey = cryptd_hash_setkey;
inst->alg.digest = cryptd_hash_digest_enqueue;
err = ahash_register_instance(tmpl, inst);
diff --git a/crypto/mcryptd.c b/crypto/mcryptd.c
index a14100e..7406ed0 100644
--- a/crypto/mcryptd.c
+++ b/crypto/mcryptd.c
@@ -516,10 +516,9 @@
if (err)
goto out_free_inst;
- type = CRYPTO_ALG_ASYNC;
- if (alg->cra_flags & CRYPTO_ALG_INTERNAL)
- type |= CRYPTO_ALG_INTERNAL;
- inst->alg.halg.base.cra_flags = type;
+ inst->alg.halg.base.cra_flags = CRYPTO_ALG_ASYNC |
+ (alg->cra_flags & (CRYPTO_ALG_INTERNAL |
+ CRYPTO_ALG_OPTIONAL_KEY));
inst->alg.halg.digestsize = halg->digestsize;
inst->alg.halg.statesize = halg->statesize;
@@ -534,7 +533,8 @@
inst->alg.finup = mcryptd_hash_finup_enqueue;
inst->alg.export = mcryptd_hash_export;
inst->alg.import = mcryptd_hash_import;
- inst->alg.setkey = mcryptd_hash_setkey;
+ if (crypto_hash_alg_has_setkey(halg))
+ inst->alg.setkey = mcryptd_hash_setkey;
inst->alg.digest = mcryptd_hash_digest_enqueue;
err = ahash_register_instance(tmpl, inst);
diff --git a/crypto/poly1305_generic.c b/crypto/poly1305_generic.c
index 2df9835d..bca9923 100644
--- a/crypto/poly1305_generic.c
+++ b/crypto/poly1305_generic.c
@@ -51,17 +51,6 @@
}
EXPORT_SYMBOL_GPL(crypto_poly1305_init);
-int crypto_poly1305_setkey(struct crypto_shash *tfm,
- const u8 *key, unsigned int keylen)
-{
- /* Poly1305 requires a unique key for each tag, which implies that
- * we can't set it on the tfm that gets accessed by multiple users
- * simultaneously. Instead we expect the key as the first 32 bytes in
- * the update() call. */
- return -ENOTSUPP;
-}
-EXPORT_SYMBOL_GPL(crypto_poly1305_setkey);
-
static void poly1305_setrkey(struct poly1305_desc_ctx *dctx, const u8 *key)
{
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
@@ -80,6 +69,11 @@
dctx->s[3] = le32_to_cpuvp(key + 12);
}
+/*
+ * Poly1305 requires a unique key for each tag, which implies that we can't set
+ * it on the tfm that gets accessed by multiple users simultaneously. Instead we
+ * expect the key as the first 32 bytes in the update() call.
+ */
unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
const u8 *src, unsigned int srclen)
{
@@ -285,7 +279,6 @@
.init = crypto_poly1305_init,
.update = crypto_poly1305_update,
.final = crypto_poly1305_final,
- .setkey = crypto_poly1305_setkey,
.descsize = sizeof(struct poly1305_desc_ctx),
.base = {
.cra_name = "poly1305",
diff --git a/crypto/shash.c b/crypto/shash.c
index 9bd5044..d5bd2f0 100644
--- a/crypto/shash.c
+++ b/crypto/shash.c
@@ -57,11 +57,18 @@
{
struct shash_alg *shash = crypto_shash_alg(tfm);
unsigned long alignmask = crypto_shash_alignmask(tfm);
+ int err;
if ((unsigned long)key & alignmask)
- return shash_setkey_unaligned(tfm, key, keylen);
+ err = shash_setkey_unaligned(tfm, key, keylen);
+ else
+ err = shash->setkey(tfm, key, keylen);
- return shash->setkey(tfm, key, keylen);
+ if (err)
+ return err;
+
+ crypto_shash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
+ return 0;
}
EXPORT_SYMBOL_GPL(crypto_shash_setkey);
@@ -180,6 +187,9 @@
struct shash_alg *shash = crypto_shash_alg(tfm);
unsigned long alignmask = crypto_shash_alignmask(tfm);
+ if (crypto_shash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+ return -ENOKEY;
+
if (((unsigned long)data | (unsigned long)out) & alignmask)
return shash_digest_unaligned(desc, data, len, out);
@@ -359,7 +369,8 @@
crt->digest = shash_async_digest;
crt->setkey = shash_async_setkey;
- crt->has_setkey = alg->setkey != shash_no_setkey;
+ crypto_ahash_set_flags(crt, crypto_shash_get_flags(shash) &
+ CRYPTO_TFM_NEED_KEY);
if (alg->export)
crt->export = shash_async_export;
@@ -374,8 +385,14 @@
static int crypto_shash_init_tfm(struct crypto_tfm *tfm)
{
struct crypto_shash *hash = __crypto_shash_cast(tfm);
+ struct shash_alg *alg = crypto_shash_alg(hash);
- hash->descsize = crypto_shash_alg(hash)->descsize;
+ hash->descsize = alg->descsize;
+
+ if (crypto_shash_alg_has_setkey(alg) &&
+ !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY))
+ crypto_shash_set_flags(hash, CRYPTO_TFM_NEED_KEY);
+
return 0;
}
diff --git a/crypto/speck.c b/crypto/speck.c
new file mode 100644
index 0000000..58aa9f7
--- /dev/null
+++ b/crypto/speck.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Speck: a lightweight block cipher
+ *
+ * Copyright (c) 2018 Google, Inc
+ *
+ * Speck has 10 variants, including 5 block sizes. For now we only implement
+ * the variants Speck128/128, Speck128/192, Speck128/256, Speck64/96, and
+ * Speck64/128. Speck${B}/${K} denotes the variant with a block size of B bits
+ * and a key size of K bits. The Speck128 variants are believed to be the most
+ * secure variants, and they use the same block size and key sizes as AES. The
+ * Speck64 variants are less secure, but on 32-bit processors are usually
+ * faster. The remaining variants (Speck32, Speck48, and Speck96) are even less
+ * secure and/or not as well suited for implementation on either 32-bit or
+ * 64-bit processors, so are omitted.
+ *
+ * Reference: "The Simon and Speck Families of Lightweight Block Ciphers"
+ * https://eprint.iacr.org/2013/404.pdf
+ *
+ * In a correspondence, the Speck designers have also clarified that the words
+ * should be interpreted in little-endian format, and the words should be
+ * ordered such that the first word of each block is 'y' rather than 'x', and
+ * the first key word (rather than the last) becomes the first round key.
+ */
+
+#include <asm/unaligned.h>
+#include <crypto/speck.h>
+#include <linux/bitops.h>
+#include <linux/crypto.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+/* Speck128 */
+
+static __always_inline void speck128_round(u64 *x, u64 *y, u64 k)
+{
+ *x = ror64(*x, 8);
+ *x += *y;
+ *x ^= k;
+ *y = rol64(*y, 3);
+ *y ^= *x;
+}
+
+static __always_inline void speck128_unround(u64 *x, u64 *y, u64 k)
+{
+ *y ^= *x;
+ *y = ror64(*y, 3);
+ *x ^= k;
+ *x -= *y;
+ *x = rol64(*x, 8);
+}
+
+void crypto_speck128_encrypt(const struct speck128_tfm_ctx *ctx,
+ u8 *out, const u8 *in)
+{
+ u64 y = get_unaligned_le64(in);
+ u64 x = get_unaligned_le64(in + 8);
+ int i;
+
+ for (i = 0; i < ctx->nrounds; i++)
+ speck128_round(&x, &y, ctx->round_keys[i]);
+
+ put_unaligned_le64(y, out);
+ put_unaligned_le64(x, out + 8);
+}
+EXPORT_SYMBOL_GPL(crypto_speck128_encrypt);
+
+static void speck128_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ crypto_speck128_encrypt(crypto_tfm_ctx(tfm), out, in);
+}
+
+void crypto_speck128_decrypt(const struct speck128_tfm_ctx *ctx,
+ u8 *out, const u8 *in)
+{
+ u64 y = get_unaligned_le64(in);
+ u64 x = get_unaligned_le64(in + 8);
+ int i;
+
+ for (i = ctx->nrounds - 1; i >= 0; i--)
+ speck128_unround(&x, &y, ctx->round_keys[i]);
+
+ put_unaligned_le64(y, out);
+ put_unaligned_le64(x, out + 8);
+}
+EXPORT_SYMBOL_GPL(crypto_speck128_decrypt);
+
+static void speck128_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ crypto_speck128_decrypt(crypto_tfm_ctx(tfm), out, in);
+}
+
+int crypto_speck128_setkey(struct speck128_tfm_ctx *ctx, const u8 *key,
+ unsigned int keylen)
+{
+ u64 l[3];
+ u64 k;
+ int i;
+
+ switch (keylen) {
+ case SPECK128_128_KEY_SIZE:
+ k = get_unaligned_le64(key);
+ l[0] = get_unaligned_le64(key + 8);
+ ctx->nrounds = SPECK128_128_NROUNDS;
+ for (i = 0; i < ctx->nrounds; i++) {
+ ctx->round_keys[i] = k;
+ speck128_round(&l[0], &k, i);
+ }
+ break;
+ case SPECK128_192_KEY_SIZE:
+ k = get_unaligned_le64(key);
+ l[0] = get_unaligned_le64(key + 8);
+ l[1] = get_unaligned_le64(key + 16);
+ ctx->nrounds = SPECK128_192_NROUNDS;
+ for (i = 0; i < ctx->nrounds; i++) {
+ ctx->round_keys[i] = k;
+ speck128_round(&l[i % 2], &k, i);
+ }
+ break;
+ case SPECK128_256_KEY_SIZE:
+ k = get_unaligned_le64(key);
+ l[0] = get_unaligned_le64(key + 8);
+ l[1] = get_unaligned_le64(key + 16);
+ l[2] = get_unaligned_le64(key + 24);
+ ctx->nrounds = SPECK128_256_NROUNDS;
+ for (i = 0; i < ctx->nrounds; i++) {
+ ctx->round_keys[i] = k;
+ speck128_round(&l[i % 3], &k, i);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_speck128_setkey);
+
+static int speck128_setkey(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ return crypto_speck128_setkey(crypto_tfm_ctx(tfm), key, keylen);
+}
+
+/* Speck64 */
+
+static __always_inline void speck64_round(u32 *x, u32 *y, u32 k)
+{
+ *x = ror32(*x, 8);
+ *x += *y;
+ *x ^= k;
+ *y = rol32(*y, 3);
+ *y ^= *x;
+}
+
+static __always_inline void speck64_unround(u32 *x, u32 *y, u32 k)
+{
+ *y ^= *x;
+ *y = ror32(*y, 3);
+ *x ^= k;
+ *x -= *y;
+ *x = rol32(*x, 8);
+}
+
+void crypto_speck64_encrypt(const struct speck64_tfm_ctx *ctx,
+ u8 *out, const u8 *in)
+{
+ u32 y = get_unaligned_le32(in);
+ u32 x = get_unaligned_le32(in + 4);
+ int i;
+
+ for (i = 0; i < ctx->nrounds; i++)
+ speck64_round(&x, &y, ctx->round_keys[i]);
+
+ put_unaligned_le32(y, out);
+ put_unaligned_le32(x, out + 4);
+}
+EXPORT_SYMBOL_GPL(crypto_speck64_encrypt);
+
+static void speck64_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ crypto_speck64_encrypt(crypto_tfm_ctx(tfm), out, in);
+}
+
+void crypto_speck64_decrypt(const struct speck64_tfm_ctx *ctx,
+ u8 *out, const u8 *in)
+{
+ u32 y = get_unaligned_le32(in);
+ u32 x = get_unaligned_le32(in + 4);
+ int i;
+
+ for (i = ctx->nrounds - 1; i >= 0; i--)
+ speck64_unround(&x, &y, ctx->round_keys[i]);
+
+ put_unaligned_le32(y, out);
+ put_unaligned_le32(x, out + 4);
+}
+EXPORT_SYMBOL_GPL(crypto_speck64_decrypt);
+
+static void speck64_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ crypto_speck64_decrypt(crypto_tfm_ctx(tfm), out, in);
+}
+
+int crypto_speck64_setkey(struct speck64_tfm_ctx *ctx, const u8 *key,
+ unsigned int keylen)
+{
+ u32 l[3];
+ u32 k;
+ int i;
+
+ switch (keylen) {
+ case SPECK64_96_KEY_SIZE:
+ k = get_unaligned_le32(key);
+ l[0] = get_unaligned_le32(key + 4);
+ l[1] = get_unaligned_le32(key + 8);
+ ctx->nrounds = SPECK64_96_NROUNDS;
+ for (i = 0; i < ctx->nrounds; i++) {
+ ctx->round_keys[i] = k;
+ speck64_round(&l[i % 2], &k, i);
+ }
+ break;
+ case SPECK64_128_KEY_SIZE:
+ k = get_unaligned_le32(key);
+ l[0] = get_unaligned_le32(key + 4);
+ l[1] = get_unaligned_le32(key + 8);
+ l[2] = get_unaligned_le32(key + 12);
+ ctx->nrounds = SPECK64_128_NROUNDS;
+ for (i = 0; i < ctx->nrounds; i++) {
+ ctx->round_keys[i] = k;
+ speck64_round(&l[i % 3], &k, i);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_speck64_setkey);
+
+static int speck64_setkey(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ return crypto_speck64_setkey(crypto_tfm_ctx(tfm), key, keylen);
+}
+
+/* Algorithm definitions */
+
+static struct crypto_alg speck_algs[] = {
+ {
+ .cra_name = "speck128",
+ .cra_driver_name = "speck128-generic",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = SPECK128_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct speck128_tfm_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = SPECK128_128_KEY_SIZE,
+ .cia_max_keysize = SPECK128_256_KEY_SIZE,
+ .cia_setkey = speck128_setkey,
+ .cia_encrypt = speck128_encrypt,
+ .cia_decrypt = speck128_decrypt
+ }
+ }
+ }, {
+ .cra_name = "speck64",
+ .cra_driver_name = "speck64-generic",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = SPECK64_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct speck64_tfm_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = SPECK64_96_KEY_SIZE,
+ .cia_max_keysize = SPECK64_128_KEY_SIZE,
+ .cia_setkey = speck64_setkey,
+ .cia_encrypt = speck64_encrypt,
+ .cia_decrypt = speck64_decrypt
+ }
+ }
+ }
+};
+
+static int __init speck_module_init(void)
+{
+ return crypto_register_algs(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+static void __exit speck_module_exit(void)
+{
+ crypto_unregister_algs(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+module_init(speck_module_init);
+module_exit(speck_module_exit);
+
+MODULE_DESCRIPTION("Speck block cipher (generic)");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
+MODULE_ALIAS_CRYPTO("speck128");
+MODULE_ALIAS_CRYPTO("speck128-generic");
+MODULE_ALIAS_CRYPTO("speck64");
+MODULE_ALIAS_CRYPTO("speck64-generic");
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index e3af318..2a07341 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -223,11 +223,13 @@
}
sg_init_table(sg, np + 1);
- np--;
+ if (rem)
+ np--;
for (k = 0; k < np; k++)
sg_set_buf(&sg[k + 1], xbuf[k], PAGE_SIZE);
- sg_set_buf(&sg[k + 1], xbuf[k], rem);
+ if (rem)
+ sg_set_buf(&sg[k + 1], xbuf[k], rem);
}
static void test_aead_speed(const char *algo, int enc, unsigned int secs,
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 62dffa0..bcbd3d4 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -3238,6 +3238,36 @@
}
}
}, {
+ .alg = "ecb(speck128)",
+ .test = alg_test_skcipher,
+ .suite = {
+ .cipher = {
+ .enc = {
+ .vecs = speck128_enc_tv_template,
+ .count = ARRAY_SIZE(speck128_enc_tv_template)
+ },
+ .dec = {
+ .vecs = speck128_dec_tv_template,
+ .count = ARRAY_SIZE(speck128_dec_tv_template)
+ }
+ }
+ }
+ }, {
+ .alg = "ecb(speck64)",
+ .test = alg_test_skcipher,
+ .suite = {
+ .cipher = {
+ .enc = {
+ .vecs = speck64_enc_tv_template,
+ .count = ARRAY_SIZE(speck64_enc_tv_template)
+ },
+ .dec = {
+ .vecs = speck64_dec_tv_template,
+ .count = ARRAY_SIZE(speck64_dec_tv_template)
+ }
+ }
+ }
+ }, {
.alg = "ecb(tea)",
.test = alg_test_skcipher,
.suite = {
@@ -4058,6 +4088,36 @@
}
}
}, {
+ .alg = "xts(speck128)",
+ .test = alg_test_skcipher,
+ .suite = {
+ .cipher = {
+ .enc = {
+ .vecs = speck128_xts_enc_tv_template,
+ .count = ARRAY_SIZE(speck128_xts_enc_tv_template)
+ },
+ .dec = {
+ .vecs = speck128_xts_dec_tv_template,
+ .count = ARRAY_SIZE(speck128_xts_dec_tv_template)
+ }
+ }
+ }
+ }, {
+ .alg = "xts(speck64)",
+ .test = alg_test_skcipher,
+ .suite = {
+ .cipher = {
+ .enc = {
+ .vecs = speck64_xts_enc_tv_template,
+ .count = ARRAY_SIZE(speck64_xts_enc_tv_template)
+ },
+ .dec = {
+ .vecs = speck64_xts_dec_tv_template,
+ .count = ARRAY_SIZE(speck64_xts_dec_tv_template)
+ }
+ }
+ }
+ }, {
.alg = "xts(twofish)",
.test = alg_test_skcipher,
.suite = {
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 9033088..daae6c1 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -13622,6 +13622,1492 @@
},
};
+/*
+ * Speck test vectors taken from the original paper:
+ * "The Simon and Speck Families of Lightweight Block Ciphers"
+ * https://eprint.iacr.org/2013/404.pdf
+ *
+ * Note that the paper does not make byte and word order clear. But it was
+ * confirmed with the authors that the intended orders are little endian byte
+ * order and (y, x) word order. Equivalently, the printed test vectors, when
+ * looking at only the bytes (ignoring the whitespace that divides them into
+ * words), are backwards: the left-most byte is actually the one with the
+ * highest memory address, while the right-most byte is actually the one with
+ * the lowest memory address.
+ */
+
+static struct cipher_testvec speck128_enc_tv_template[] = {
+ { /* Speck128/128 */
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ .klen = 16,
+ .input = "\x20\x6d\x61\x64\x65\x20\x69\x74"
+ "\x20\x65\x71\x75\x69\x76\x61\x6c",
+ .ilen = 16,
+ .result = "\x18\x0d\x57\x5c\xdf\xfe\x60\x78"
+ "\x65\x32\x78\x79\x51\x98\x5d\xa6",
+ .rlen = 16,
+ }, { /* Speck128/192 */
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ .klen = 24,
+ .input = "\x65\x6e\x74\x20\x74\x6f\x20\x43"
+ "\x68\x69\x65\x66\x20\x48\x61\x72",
+ .ilen = 16,
+ .result = "\x86\x18\x3c\xe0\x5d\x18\xbc\xf9"
+ "\x66\x55\x13\x13\x3a\xcf\xe4\x1b",
+ .rlen = 16,
+ }, { /* Speck128/256 */
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ .klen = 32,
+ .input = "\x70\x6f\x6f\x6e\x65\x72\x2e\x20"
+ "\x49\x6e\x20\x74\x68\x6f\x73\x65",
+ .ilen = 16,
+ .result = "\x43\x8f\x18\x9c\x8d\xb4\xee\x4e"
+ "\x3e\xf5\xc0\x05\x04\x01\x09\x41",
+ .rlen = 16,
+ },
+};
+
+static struct cipher_testvec speck128_dec_tv_template[] = {
+ { /* Speck128/128 */
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ .klen = 16,
+ .input = "\x18\x0d\x57\x5c\xdf\xfe\x60\x78"
+ "\x65\x32\x78\x79\x51\x98\x5d\xa6",
+ .ilen = 16,
+ .result = "\x20\x6d\x61\x64\x65\x20\x69\x74"
+ "\x20\x65\x71\x75\x69\x76\x61\x6c",
+ .rlen = 16,
+ }, { /* Speck128/192 */
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ .klen = 24,
+ .input = "\x86\x18\x3c\xe0\x5d\x18\xbc\xf9"
+ "\x66\x55\x13\x13\x3a\xcf\xe4\x1b",
+ .ilen = 16,
+ .result = "\x65\x6e\x74\x20\x74\x6f\x20\x43"
+ "\x68\x69\x65\x66\x20\x48\x61\x72",
+ .rlen = 16,
+ }, { /* Speck128/256 */
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ .klen = 32,
+ .input = "\x43\x8f\x18\x9c\x8d\xb4\xee\x4e"
+ "\x3e\xf5\xc0\x05\x04\x01\x09\x41",
+ .ilen = 16,
+ .result = "\x70\x6f\x6f\x6e\x65\x72\x2e\x20"
+ "\x49\x6e\x20\x74\x68\x6f\x73\x65",
+ .rlen = 16,
+ },
+};
+
+/*
+ * Speck128-XTS test vectors, taken from the AES-XTS test vectors with the
+ * result recomputed with Speck128 as the cipher
+ */
+
+static struct cipher_testvec speck128_xts_enc_tv_template[] = {
+ {
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .klen = 32,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .ilen = 32,
+ .result = "\xbe\xa0\xe7\x03\xd7\xfe\xab\x62"
+ "\x3b\x99\x4a\x64\x74\x77\xac\xed"
+ "\xd8\xf4\xa6\xcf\xae\xb9\x07\x42"
+ "\x51\xd9\xb6\x1d\xe0\x5e\xbc\x54",
+ .rlen = 32,
+ }, {
+ .key = "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x22\x22\x22\x22\x22\x22\x22\x22"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 32,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .ilen = 32,
+ .result = "\xfb\x53\x81\x75\x6f\x9f\x34\xad"
+ "\x7e\x01\xed\x7b\xcc\xda\x4e\x4a"
+ "\xd4\x84\xa4\x53\xd5\x88\x73\x1b"
+ "\xfd\xcb\xae\x0d\xf3\x04\xee\xe6",
+ .rlen = 32,
+ }, {
+ .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+ "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+ "\x22\x22\x22\x22\x22\x22\x22\x22"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 32,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .ilen = 32,
+ .result = "\x21\x52\x84\x15\xd1\xf7\x21\x55"
+ "\xd9\x75\x4a\xd3\xc5\xdb\x9f\x7d"
+ "\xda\x63\xb2\xf1\x82\xb0\x89\x59"
+ "\x86\xd4\xaa\xaa\xdd\xff\x4f\x92",
+ .rlen = 32,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x31\x41\x59\x26\x53\x58\x97\x93"
+ "\x23\x84\x62\x64\x33\x83\x27\x95",
+ .klen = 32,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .ilen = 512,
+ .result = "\x57\xb5\xf8\x71\x6e\x6d\xdd\x82"
+ "\x53\xd0\xed\x2d\x30\xc1\x20\xef"
+ "\x70\x67\x5e\xff\x09\x70\xbb\xc1"
+ "\x3a\x7b\x48\x26\xd9\x0b\xf4\x48"
+ "\xbe\xce\xb1\xc7\xb2\x67\xc4\xa7"
+ "\x76\xf8\x36\x30\xb7\xb4\x9a\xd9"
+ "\xf5\x9d\xd0\x7b\xc1\x06\x96\x44"
+ "\x19\xc5\x58\x84\x63\xb9\x12\x68"
+ "\x68\xc7\xaa\x18\x98\xf2\x1f\x5c"
+ "\x39\xa6\xd8\x32\x2b\xc3\x51\xfd"
+ "\x74\x79\x2e\xb4\x44\xd7\x69\xc4"
+ "\xfc\x29\xe6\xed\x26\x1e\xa6\x9d"
+ "\x1c\xbe\x00\x0e\x7f\x3a\xca\xfb"
+ "\x6d\x13\x65\xa0\xf9\x31\x12\xe2"
+ "\x26\xd1\xec\x2b\x0a\x8b\x59\x99"
+ "\xa7\x49\xa0\x0e\x09\x33\x85\x50"
+ "\xc3\x23\xca\x7a\xdd\x13\x45\x5f"
+ "\xde\x4c\xa7\xcb\x00\x8a\x66\x6f"
+ "\xa2\xb6\xb1\x2e\xe1\xa0\x18\xf6"
+ "\xad\xf3\xbd\xeb\xc7\xef\x55\x4f"
+ "\x79\x91\x8d\x36\x13\x7b\xd0\x4a"
+ "\x6c\x39\xfb\x53\xb8\x6f\x02\x51"
+ "\xa5\x20\xac\x24\x1c\x73\x59\x73"
+ "\x58\x61\x3a\x87\x58\xb3\x20\x56"
+ "\x39\x06\x2b\x4d\xd3\x20\x2b\x89"
+ "\x3f\xa2\xf0\x96\xeb\x7f\xa4\xcd"
+ "\x11\xae\xbd\xcb\x3a\xb4\xd9\x91"
+ "\x09\x35\x71\x50\x65\xac\x92\xe3"
+ "\x7b\x32\xc0\x7a\xdd\xd4\xc3\x92"
+ "\x6f\xeb\x79\xde\x6f\xd3\x25\xc9"
+ "\xcd\x63\xf5\x1e\x7a\x3b\x26\x9d"
+ "\x77\x04\x80\xa9\xbf\x38\xb5\xbd"
+ "\xb8\x05\x07\xbd\xfd\xab\x7b\xf8"
+ "\x2a\x26\xcc\x49\x14\x6d\x55\x01"
+ "\x06\x94\xd8\xb2\x2d\x53\x83\x1b"
+ "\x8f\xd4\xdd\x57\x12\x7e\x18\xba"
+ "\x8e\xe2\x4d\x80\xef\x7e\x6b\x9d"
+ "\x24\xa9\x60\xa4\x97\x85\x86\x2a"
+ "\x01\x00\x09\xf1\xcb\x4a\x24\x1c"
+ "\xd8\xf6\xe6\x5b\xe7\x5d\xf2\xc4"
+ "\x97\x1c\x10\xc6\x4d\x66\x4f\x98"
+ "\x87\x30\xac\xd5\xea\x73\x49\x10"
+ "\x80\xea\xe5\x5f\x4d\x5f\x03\x33"
+ "\x66\x02\x35\x3d\x60\x06\x36\x4f"
+ "\x14\x1c\xd8\x07\x1f\x78\xd0\xf8"
+ "\x4f\x6c\x62\x7c\x15\xa5\x7c\x28"
+ "\x7c\xcc\xeb\x1f\xd1\x07\x90\x93"
+ "\x7e\xc2\xa8\x3a\x80\xc0\xf5\x30"
+ "\xcc\x75\xcf\x16\x26\xa9\x26\x3b"
+ "\xe7\x68\x2f\x15\x21\x5b\xe4\x00"
+ "\xbd\x48\x50\xcd\x75\x70\xc4\x62"
+ "\xbb\x41\xfb\x89\x4a\x88\x3b\x3b"
+ "\x51\x66\x02\x69\x04\x97\x36\xd4"
+ "\x75\xae\x0b\xa3\x42\xf8\xca\x79"
+ "\x8f\x93\xe9\xcc\x38\xbd\xd6\xd2"
+ "\xf9\x70\x4e\xc3\x6a\x8e\x25\xbd"
+ "\xea\x15\x5a\xa0\x85\x7e\x81\x0d"
+ "\x03\xe7\x05\x39\xf5\x05\x26\xee"
+ "\xec\xaa\x1f\x3d\xc9\x98\x76\x01"
+ "\x2c\xf4\xfc\xa3\x88\x77\x38\xc4"
+ "\x50\x65\x50\x6d\x04\x1f\xdf\x5a"
+ "\xaa\xf2\x01\xa9\xc1\x8d\xee\xca"
+ "\x47\x26\xef\x39\xb8\xb4\xf2\xd1"
+ "\xd6\xbb\x1b\x2a\xc1\x34\x14\xcf",
+ .rlen = 512,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x62\x49\x77\x57\x24\x70\x93\x69"
+ "\x99\x59\x57\x49\x66\x96\x76\x27"
+ "\x31\x41\x59\x26\x53\x58\x97\x93"
+ "\x23\x84\x62\x64\x33\x83\x27\x95"
+ "\x02\x88\x41\x97\x16\x93\x99\x37"
+ "\x51\x05\x82\x09\x74\x94\x45\x92",
+ .klen = 64,
+ .iv = "\xff\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .ilen = 512,
+ .result = "\xc5\x85\x2a\x4b\x73\xe4\xf6\xf1"
+ "\x7e\xf9\xf6\xe9\xa3\x73\x36\xcb"
+ "\xaa\xb6\x22\xb0\x24\x6e\x3d\x73"
+ "\x92\x99\xde\xd3\x76\xed\xcd\x63"
+ "\x64\x3a\x22\x57\xc1\x43\x49\xd4"
+ "\x79\x36\x31\x19\x62\xae\x10\x7e"
+ "\x7d\xcf\x7a\xe2\x6b\xce\x27\xfa"
+ "\xdc\x3d\xd9\x83\xd3\x42\x4c\xe0"
+ "\x1b\xd6\x1d\x1a\x6f\xd2\x03\x00"
+ "\xfc\x81\x99\x8a\x14\x62\xf5\x7e"
+ "\x0d\xe7\x12\xe8\x17\x9d\x0b\xec"
+ "\xe2\xf7\xc9\xa7\x63\xd1\x79\xb6"
+ "\x62\x62\x37\xfe\x0a\x4c\x4a\x37"
+ "\x70\xc7\x5e\x96\x5f\xbc\x8e\x9e"
+ "\x85\x3c\x4f\x26\x64\x85\xbc\x68"
+ "\xb0\xe0\x86\x5e\x26\x41\xce\x11"
+ "\x50\xda\x97\x14\xe9\x9e\xc7\x6d"
+ "\x3b\xdc\x43\xde\x2b\x27\x69\x7d"
+ "\xfc\xb0\x28\xbd\x8f\xb1\xc6\x31"
+ "\x14\x4d\xf0\x74\x37\xfd\x07\x25"
+ "\x96\x55\xe5\xfc\x9e\x27\x2a\x74"
+ "\x1b\x83\x4d\x15\x83\xac\x57\xa0"
+ "\xac\xa5\xd0\x38\xef\x19\x56\x53"
+ "\x25\x4b\xfc\xce\x04\x23\xe5\x6b"
+ "\xf6\xc6\x6c\x32\x0b\xb3\x12\xc5"
+ "\xed\x22\x34\x1c\x5d\xed\x17\x06"
+ "\x36\xa3\xe6\x77\xb9\x97\x46\xb8"
+ "\xe9\x3f\x7e\xc7\xbc\x13\x5c\xdc"
+ "\x6e\x3f\x04\x5e\xd1\x59\xa5\x82"
+ "\x35\x91\x3d\x1b\xe4\x97\x9f\x92"
+ "\x1c\x5e\x5f\x6f\x41\xd4\x62\xa1"
+ "\x8d\x39\xfc\x42\xfb\x38\x80\xb9"
+ "\x0a\xe3\xcc\x6a\x93\xd9\x7a\xb1"
+ "\xe9\x69\xaf\x0a\x6b\x75\x38\xa7"
+ "\xa1\xbf\xf7\xda\x95\x93\x4b\x78"
+ "\x19\xf5\x94\xf9\xd2\x00\x33\x37"
+ "\xcf\xf5\x9e\x9c\xf3\xcc\xa6\xee"
+ "\x42\xb2\x9e\x2c\x5f\x48\x23\x26"
+ "\x15\x25\x17\x03\x3d\xfe\x2c\xfc"
+ "\xeb\xba\xda\xe0\x00\x05\xb6\xa6"
+ "\x07\xb3\xe8\x36\x5b\xec\x5b\xbf"
+ "\xd6\x5b\x00\x74\xc6\x97\xf1\x6a"
+ "\x49\xa1\xc3\xfa\x10\x52\xb9\x14"
+ "\xad\xb7\x73\xf8\x78\x12\xc8\x59"
+ "\x17\x80\x4c\x57\x39\xf1\x6d\x80"
+ "\x25\x77\x0f\x5e\x7d\xf0\xaf\x21"
+ "\xec\xce\xb7\xc8\x02\x8a\xed\x53"
+ "\x2c\x25\x68\x2e\x1f\x85\x5e\x67"
+ "\xd1\x07\x7a\x3a\x89\x08\xe0\x34"
+ "\xdc\xdb\x26\xb4\x6b\x77\xfc\x40"
+ "\x31\x15\x72\xa0\xf0\x73\xd9\x3b"
+ "\xd5\xdb\xfe\xfc\x8f\xa9\x44\xa2"
+ "\x09\x9f\xc6\x33\xe5\xe2\x88\xe8"
+ "\xf3\xf0\x1a\xf4\xce\x12\x0f\xd6"
+ "\xf7\x36\xe6\xa4\xf4\x7a\x10\x58"
+ "\xcc\x1f\x48\x49\x65\x47\x75\xe9"
+ "\x28\xe1\x65\x7b\xf2\xc4\xb5\x07"
+ "\xf2\xec\x76\xd8\x8f\x09\xf3\x16"
+ "\xa1\x51\x89\x3b\xeb\x96\x42\xac"
+ "\x65\xe0\x67\x63\x29\xdc\xb4\x7d"
+ "\xf2\x41\x51\x6a\xcb\xde\x3c\xfb"
+ "\x66\x8d\x13\xca\xe0\x59\x2a\x00"
+ "\xc9\x53\x4c\xe6\x9e\xe2\x73\xd5"
+ "\x67\x19\xb2\xbd\x9a\x63\xd7\x5c",
+ .rlen = 512,
+ .also_non_np = 1,
+ .np = 3,
+ .tap = { 512 - 20, 4, 16 },
+ }
+};
+
+static struct cipher_testvec speck128_xts_dec_tv_template[] = {
+ {
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .klen = 32,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\xbe\xa0\xe7\x03\xd7\xfe\xab\x62"
+ "\x3b\x99\x4a\x64\x74\x77\xac\xed"
+ "\xd8\xf4\xa6\xcf\xae\xb9\x07\x42"
+ "\x51\xd9\xb6\x1d\xe0\x5e\xbc\x54",
+ .ilen = 32,
+ .result = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .rlen = 32,
+ }, {
+ .key = "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x22\x22\x22\x22\x22\x22\x22\x22"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 32,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\xfb\x53\x81\x75\x6f\x9f\x34\xad"
+ "\x7e\x01\xed\x7b\xcc\xda\x4e\x4a"
+ "\xd4\x84\xa4\x53\xd5\x88\x73\x1b"
+ "\xfd\xcb\xae\x0d\xf3\x04\xee\xe6",
+ .ilen = 32,
+ .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .rlen = 32,
+ }, {
+ .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+ "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+ "\x22\x22\x22\x22\x22\x22\x22\x22"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 32,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x21\x52\x84\x15\xd1\xf7\x21\x55"
+ "\xd9\x75\x4a\xd3\xc5\xdb\x9f\x7d"
+ "\xda\x63\xb2\xf1\x82\xb0\x89\x59"
+ "\x86\xd4\xaa\xaa\xdd\xff\x4f\x92",
+ .ilen = 32,
+ .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .rlen = 32,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x31\x41\x59\x26\x53\x58\x97\x93"
+ "\x23\x84\x62\x64\x33\x83\x27\x95",
+ .klen = 32,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x57\xb5\xf8\x71\x6e\x6d\xdd\x82"
+ "\x53\xd0\xed\x2d\x30\xc1\x20\xef"
+ "\x70\x67\x5e\xff\x09\x70\xbb\xc1"
+ "\x3a\x7b\x48\x26\xd9\x0b\xf4\x48"
+ "\xbe\xce\xb1\xc7\xb2\x67\xc4\xa7"
+ "\x76\xf8\x36\x30\xb7\xb4\x9a\xd9"
+ "\xf5\x9d\xd0\x7b\xc1\x06\x96\x44"
+ "\x19\xc5\x58\x84\x63\xb9\x12\x68"
+ "\x68\xc7\xaa\x18\x98\xf2\x1f\x5c"
+ "\x39\xa6\xd8\x32\x2b\xc3\x51\xfd"
+ "\x74\x79\x2e\xb4\x44\xd7\x69\xc4"
+ "\xfc\x29\xe6\xed\x26\x1e\xa6\x9d"
+ "\x1c\xbe\x00\x0e\x7f\x3a\xca\xfb"
+ "\x6d\x13\x65\xa0\xf9\x31\x12\xe2"
+ "\x26\xd1\xec\x2b\x0a\x8b\x59\x99"
+ "\xa7\x49\xa0\x0e\x09\x33\x85\x50"
+ "\xc3\x23\xca\x7a\xdd\x13\x45\x5f"
+ "\xde\x4c\xa7\xcb\x00\x8a\x66\x6f"
+ "\xa2\xb6\xb1\x2e\xe1\xa0\x18\xf6"
+ "\xad\xf3\xbd\xeb\xc7\xef\x55\x4f"
+ "\x79\x91\x8d\x36\x13\x7b\xd0\x4a"
+ "\x6c\x39\xfb\x53\xb8\x6f\x02\x51"
+ "\xa5\x20\xac\x24\x1c\x73\x59\x73"
+ "\x58\x61\x3a\x87\x58\xb3\x20\x56"
+ "\x39\x06\x2b\x4d\xd3\x20\x2b\x89"
+ "\x3f\xa2\xf0\x96\xeb\x7f\xa4\xcd"
+ "\x11\xae\xbd\xcb\x3a\xb4\xd9\x91"
+ "\x09\x35\x71\x50\x65\xac\x92\xe3"
+ "\x7b\x32\xc0\x7a\xdd\xd4\xc3\x92"
+ "\x6f\xeb\x79\xde\x6f\xd3\x25\xc9"
+ "\xcd\x63\xf5\x1e\x7a\x3b\x26\x9d"
+ "\x77\x04\x80\xa9\xbf\x38\xb5\xbd"
+ "\xb8\x05\x07\xbd\xfd\xab\x7b\xf8"
+ "\x2a\x26\xcc\x49\x14\x6d\x55\x01"
+ "\x06\x94\xd8\xb2\x2d\x53\x83\x1b"
+ "\x8f\xd4\xdd\x57\x12\x7e\x18\xba"
+ "\x8e\xe2\x4d\x80\xef\x7e\x6b\x9d"
+ "\x24\xa9\x60\xa4\x97\x85\x86\x2a"
+ "\x01\x00\x09\xf1\xcb\x4a\x24\x1c"
+ "\xd8\xf6\xe6\x5b\xe7\x5d\xf2\xc4"
+ "\x97\x1c\x10\xc6\x4d\x66\x4f\x98"
+ "\x87\x30\xac\xd5\xea\x73\x49\x10"
+ "\x80\xea\xe5\x5f\x4d\x5f\x03\x33"
+ "\x66\x02\x35\x3d\x60\x06\x36\x4f"
+ "\x14\x1c\xd8\x07\x1f\x78\xd0\xf8"
+ "\x4f\x6c\x62\x7c\x15\xa5\x7c\x28"
+ "\x7c\xcc\xeb\x1f\xd1\x07\x90\x93"
+ "\x7e\xc2\xa8\x3a\x80\xc0\xf5\x30"
+ "\xcc\x75\xcf\x16\x26\xa9\x26\x3b"
+ "\xe7\x68\x2f\x15\x21\x5b\xe4\x00"
+ "\xbd\x48\x50\xcd\x75\x70\xc4\x62"
+ "\xbb\x41\xfb\x89\x4a\x88\x3b\x3b"
+ "\x51\x66\x02\x69\x04\x97\x36\xd4"
+ "\x75\xae\x0b\xa3\x42\xf8\xca\x79"
+ "\x8f\x93\xe9\xcc\x38\xbd\xd6\xd2"
+ "\xf9\x70\x4e\xc3\x6a\x8e\x25\xbd"
+ "\xea\x15\x5a\xa0\x85\x7e\x81\x0d"
+ "\x03\xe7\x05\x39\xf5\x05\x26\xee"
+ "\xec\xaa\x1f\x3d\xc9\x98\x76\x01"
+ "\x2c\xf4\xfc\xa3\x88\x77\x38\xc4"
+ "\x50\x65\x50\x6d\x04\x1f\xdf\x5a"
+ "\xaa\xf2\x01\xa9\xc1\x8d\xee\xca"
+ "\x47\x26\xef\x39\xb8\xb4\xf2\xd1"
+ "\xd6\xbb\x1b\x2a\xc1\x34\x14\xcf",
+ .ilen = 512,
+ .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .rlen = 512,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x62\x49\x77\x57\x24\x70\x93\x69"
+ "\x99\x59\x57\x49\x66\x96\x76\x27"
+ "\x31\x41\x59\x26\x53\x58\x97\x93"
+ "\x23\x84\x62\x64\x33\x83\x27\x95"
+ "\x02\x88\x41\x97\x16\x93\x99\x37"
+ "\x51\x05\x82\x09\x74\x94\x45\x92",
+ .klen = 64,
+ .iv = "\xff\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\xc5\x85\x2a\x4b\x73\xe4\xf6\xf1"
+ "\x7e\xf9\xf6\xe9\xa3\x73\x36\xcb"
+ "\xaa\xb6\x22\xb0\x24\x6e\x3d\x73"
+ "\x92\x99\xde\xd3\x76\xed\xcd\x63"
+ "\x64\x3a\x22\x57\xc1\x43\x49\xd4"
+ "\x79\x36\x31\x19\x62\xae\x10\x7e"
+ "\x7d\xcf\x7a\xe2\x6b\xce\x27\xfa"
+ "\xdc\x3d\xd9\x83\xd3\x42\x4c\xe0"
+ "\x1b\xd6\x1d\x1a\x6f\xd2\x03\x00"
+ "\xfc\x81\x99\x8a\x14\x62\xf5\x7e"
+ "\x0d\xe7\x12\xe8\x17\x9d\x0b\xec"
+ "\xe2\xf7\xc9\xa7\x63\xd1\x79\xb6"
+ "\x62\x62\x37\xfe\x0a\x4c\x4a\x37"
+ "\x70\xc7\x5e\x96\x5f\xbc\x8e\x9e"
+ "\x85\x3c\x4f\x26\x64\x85\xbc\x68"
+ "\xb0\xe0\x86\x5e\x26\x41\xce\x11"
+ "\x50\xda\x97\x14\xe9\x9e\xc7\x6d"
+ "\x3b\xdc\x43\xde\x2b\x27\x69\x7d"
+ "\xfc\xb0\x28\xbd\x8f\xb1\xc6\x31"
+ "\x14\x4d\xf0\x74\x37\xfd\x07\x25"
+ "\x96\x55\xe5\xfc\x9e\x27\x2a\x74"
+ "\x1b\x83\x4d\x15\x83\xac\x57\xa0"
+ "\xac\xa5\xd0\x38\xef\x19\x56\x53"
+ "\x25\x4b\xfc\xce\x04\x23\xe5\x6b"
+ "\xf6\xc6\x6c\x32\x0b\xb3\x12\xc5"
+ "\xed\x22\x34\x1c\x5d\xed\x17\x06"
+ "\x36\xa3\xe6\x77\xb9\x97\x46\xb8"
+ "\xe9\x3f\x7e\xc7\xbc\x13\x5c\xdc"
+ "\x6e\x3f\x04\x5e\xd1\x59\xa5\x82"
+ "\x35\x91\x3d\x1b\xe4\x97\x9f\x92"
+ "\x1c\x5e\x5f\x6f\x41\xd4\x62\xa1"
+ "\x8d\x39\xfc\x42\xfb\x38\x80\xb9"
+ "\x0a\xe3\xcc\x6a\x93\xd9\x7a\xb1"
+ "\xe9\x69\xaf\x0a\x6b\x75\x38\xa7"
+ "\xa1\xbf\xf7\xda\x95\x93\x4b\x78"
+ "\x19\xf5\x94\xf9\xd2\x00\x33\x37"
+ "\xcf\xf5\x9e\x9c\xf3\xcc\xa6\xee"
+ "\x42\xb2\x9e\x2c\x5f\x48\x23\x26"
+ "\x15\x25\x17\x03\x3d\xfe\x2c\xfc"
+ "\xeb\xba\xda\xe0\x00\x05\xb6\xa6"
+ "\x07\xb3\xe8\x36\x5b\xec\x5b\xbf"
+ "\xd6\x5b\x00\x74\xc6\x97\xf1\x6a"
+ "\x49\xa1\xc3\xfa\x10\x52\xb9\x14"
+ "\xad\xb7\x73\xf8\x78\x12\xc8\x59"
+ "\x17\x80\x4c\x57\x39\xf1\x6d\x80"
+ "\x25\x77\x0f\x5e\x7d\xf0\xaf\x21"
+ "\xec\xce\xb7\xc8\x02\x8a\xed\x53"
+ "\x2c\x25\x68\x2e\x1f\x85\x5e\x67"
+ "\xd1\x07\x7a\x3a\x89\x08\xe0\x34"
+ "\xdc\xdb\x26\xb4\x6b\x77\xfc\x40"
+ "\x31\x15\x72\xa0\xf0\x73\xd9\x3b"
+ "\xd5\xdb\xfe\xfc\x8f\xa9\x44\xa2"
+ "\x09\x9f\xc6\x33\xe5\xe2\x88\xe8"
+ "\xf3\xf0\x1a\xf4\xce\x12\x0f\xd6"
+ "\xf7\x36\xe6\xa4\xf4\x7a\x10\x58"
+ "\xcc\x1f\x48\x49\x65\x47\x75\xe9"
+ "\x28\xe1\x65\x7b\xf2\xc4\xb5\x07"
+ "\xf2\xec\x76\xd8\x8f\x09\xf3\x16"
+ "\xa1\x51\x89\x3b\xeb\x96\x42\xac"
+ "\x65\xe0\x67\x63\x29\xdc\xb4\x7d"
+ "\xf2\x41\x51\x6a\xcb\xde\x3c\xfb"
+ "\x66\x8d\x13\xca\xe0\x59\x2a\x00"
+ "\xc9\x53\x4c\xe6\x9e\xe2\x73\xd5"
+ "\x67\x19\xb2\xbd\x9a\x63\xd7\x5c",
+ .ilen = 512,
+ .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .rlen = 512,
+ .also_non_np = 1,
+ .np = 3,
+ .tap = { 512 - 20, 4, 16 },
+ }
+};
+
+static struct cipher_testvec speck64_enc_tv_template[] = {
+ { /* Speck64/96 */
+ .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b"
+ "\x10\x11\x12\x13",
+ .klen = 12,
+ .input = "\x65\x61\x6e\x73\x20\x46\x61\x74",
+ .ilen = 8,
+ .result = "\x6c\x94\x75\x41\xec\x52\x79\x9f",
+ .rlen = 8,
+ }, { /* Speck64/128 */
+ .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b"
+ "\x10\x11\x12\x13\x18\x19\x1a\x1b",
+ .klen = 16,
+ .input = "\x2d\x43\x75\x74\x74\x65\x72\x3b",
+ .ilen = 8,
+ .result = "\x8b\x02\x4e\x45\x48\xa5\x6f\x8c",
+ .rlen = 8,
+ },
+};
+
+static struct cipher_testvec speck64_dec_tv_template[] = {
+ { /* Speck64/96 */
+ .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b"
+ "\x10\x11\x12\x13",
+ .klen = 12,
+ .input = "\x6c\x94\x75\x41\xec\x52\x79\x9f",
+ .ilen = 8,
+ .result = "\x65\x61\x6e\x73\x20\x46\x61\x74",
+ .rlen = 8,
+ }, { /* Speck64/128 */
+ .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b"
+ "\x10\x11\x12\x13\x18\x19\x1a\x1b",
+ .klen = 16,
+ .input = "\x8b\x02\x4e\x45\x48\xa5\x6f\x8c",
+ .ilen = 8,
+ .result = "\x2d\x43\x75\x74\x74\x65\x72\x3b",
+ .rlen = 8,
+ },
+};
+
+/*
+ * Speck64-XTS test vectors, taken from the AES-XTS test vectors with the result
+ * recomputed with Speck64 as the cipher, and key lengths adjusted
+ */
+
+static struct cipher_testvec speck64_xts_enc_tv_template[] = {
+ {
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .klen = 24,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .ilen = 32,
+ .result = "\x84\xaf\x54\x07\x19\xd4\x7c\xa6"
+ "\xe4\xfe\xdf\xc4\x1f\x34\xc3\xc2"
+ "\x80\xf5\x72\xe7\xcd\xf0\x99\x22"
+ "\x35\xa7\x2f\x06\xef\xdc\x51\xaa",
+ .rlen = 32,
+ }, {
+ .key = "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 24,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .ilen = 32,
+ .result = "\x12\x56\x73\xcd\x15\x87\xa8\x59"
+ "\xcf\x84\xae\xd9\x1c\x66\xd6\x9f"
+ "\xb3\x12\x69\x7e\x36\xeb\x52\xff"
+ "\x62\xdd\xba\x90\xb3\xe1\xee\x99",
+ .rlen = 32,
+ }, {
+ .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+ "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 24,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .ilen = 32,
+ .result = "\x15\x1b\xe4\x2c\xa2\x5a\x2d\x2c"
+ "\x27\x36\xc0\xbf\x5d\xea\x36\x37"
+ "\x2d\x1a\x88\xbc\x66\xb5\xd0\x0b"
+ "\xa1\xbc\x19\xb2\x0f\x3b\x75\x34",
+ .rlen = 32,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x31\x41\x59\x26\x53\x58\x97\x93",
+ .klen = 24,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .ilen = 512,
+ .result = "\xaf\xa1\x81\xa6\x32\xbb\x15\x8e"
+ "\xf8\x95\x2e\xd3\xe6\xee\x7e\x09"
+ "\x0c\x1a\xf5\x02\x97\x8b\xe3\xb3"
+ "\x11\xc7\x39\x96\xd0\x95\xf4\x56"
+ "\xf4\xdd\x03\x38\x01\x44\x2c\xcf"
+ "\x88\xae\x8e\x3c\xcd\xe7\xaa\x66"
+ "\xfe\x3d\xc6\xfb\x01\x23\x51\x43"
+ "\xd5\xd2\x13\x86\x94\x34\xe9\x62"
+ "\xf9\x89\xe3\xd1\x7b\xbe\xf8\xef"
+ "\x76\x35\x04\x3f\xdb\x23\x9d\x0b"
+ "\x85\x42\xb9\x02\xd6\xcc\xdb\x96"
+ "\xa7\x6b\x27\xb6\xd4\x45\x8f\x7d"
+ "\xae\xd2\x04\xd5\xda\xc1\x7e\x24"
+ "\x8c\x73\xbe\x48\x7e\xcf\x65\x28"
+ "\x29\xe5\xbe\x54\x30\xcb\x46\x95"
+ "\x4f\x2e\x8a\x36\xc8\x27\xc5\xbe"
+ "\xd0\x1a\xaf\xab\x26\xcd\x9e\x69"
+ "\xa1\x09\x95\x71\x26\xe9\xc4\xdf"
+ "\xe6\x31\xc3\x46\xda\xaf\x0b\x41"
+ "\x1f\xab\xb1\x8e\xd6\xfc\x0b\xb3"
+ "\x82\xc0\x37\x27\xfc\x91\xa7\x05"
+ "\xfb\xc5\xdc\x2b\x74\x96\x48\x43"
+ "\x5d\x9c\x19\x0f\x60\x63\x3a\x1f"
+ "\x6f\xf0\x03\xbe\x4d\xfd\xc8\x4a"
+ "\xc6\xa4\x81\x6d\xc3\x12\x2a\x5c"
+ "\x07\xff\xf3\x72\x74\x48\xb5\x40"
+ "\x50\xb5\xdd\x90\x43\x31\x18\x15"
+ "\x7b\xf2\xa6\xdb\x83\xc8\x4b\x4a"
+ "\x29\x93\x90\x8b\xda\x07\xf0\x35"
+ "\x6d\x90\x88\x09\x4e\x83\xf5\x5b"
+ "\x94\x12\xbb\x33\x27\x1d\x3f\x23"
+ "\x51\xa8\x7c\x07\xa2\xae\x77\xa6"
+ "\x50\xfd\xcc\xc0\x4f\x80\x7a\x9f"
+ "\x66\xdd\xcd\x75\x24\x8b\x33\xf7"
+ "\x20\xdb\x83\x9b\x4f\x11\x63\x6e"
+ "\xcf\x37\xef\xc9\x11\x01\x5c\x45"
+ "\x32\x99\x7c\x3c\x9e\x42\x89\xe3"
+ "\x70\x6d\x15\x9f\xb1\xe6\xb6\x05"
+ "\xfe\x0c\xb9\x49\x2d\x90\x6d\xcc"
+ "\x5d\x3f\xc1\xfe\x89\x0a\x2e\x2d"
+ "\xa0\xa8\x89\x3b\x73\x39\xa5\x94"
+ "\x4c\xa4\xa6\xbb\xa7\x14\x46\x89"
+ "\x10\xff\xaf\xef\xca\xdd\x4f\x80"
+ "\xb3\xdf\x3b\xab\xd4\xe5\x5a\xc7"
+ "\x33\xca\x00\x8b\x8b\x3f\xea\xec"
+ "\x68\x8a\xc2\x6d\xfd\xd4\x67\x0f"
+ "\x22\x31\xe1\x0e\xfe\x5a\x04\xd5"
+ "\x64\xa3\xf1\x1a\x76\x28\xcc\x35"
+ "\x36\xa7\x0a\x74\xf7\x1c\x44\x9b"
+ "\xc7\x1b\x53\x17\x02\xea\xd1\xad"
+ "\x13\x51\x73\xc0\xa0\xb2\x05\x32"
+ "\xa8\xa2\x37\x2e\xe1\x7a\x3a\x19"
+ "\x26\xb4\x6c\x62\x5d\xb3\x1a\x1d"
+ "\x59\xda\xee\x1a\x22\x18\xda\x0d"
+ "\x88\x0f\x55\x8b\x72\x62\xfd\xc1"
+ "\x69\x13\xcd\x0d\x5f\xc1\x09\x52"
+ "\xee\xd6\xe3\x84\x4d\xee\xf6\x88"
+ "\xaf\x83\xdc\x76\xf4\xc0\x93\x3f"
+ "\x4a\x75\x2f\xb0\x0b\x3e\xc4\x54"
+ "\x7d\x69\x8d\x00\x62\x77\x0d\x14"
+ "\xbe\x7c\xa6\x7d\xc5\x24\x4f\xf3"
+ "\x50\xf7\x5f\xf4\xc2\xca\x41\x97"
+ "\x37\xbe\x75\x74\xcd\xf0\x75\x6e"
+ "\x25\x23\x94\xbd\xda\x8d\xb0\xd4",
+ .rlen = 512,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x62\x49\x77\x57\x24\x70\x93\x69"
+ "\x99\x59\x57\x49\x66\x96\x76\x27",
+ .klen = 32,
+ .iv = "\xff\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .ilen = 512,
+ .result = "\x55\xed\x71\xd3\x02\x8e\x15\x3b"
+ "\xc6\x71\x29\x2d\x3e\x89\x9f\x59"
+ "\x68\x6a\xcc\x8a\x56\x97\xf3\x95"
+ "\x4e\x51\x08\xda\x2a\xf8\x6f\x3c"
+ "\x78\x16\xea\x80\xdb\x33\x75\x94"
+ "\xf9\x29\xc4\x2b\x76\x75\x97\xc7"
+ "\xf2\x98\x2c\xf9\xff\xc8\xd5\x2b"
+ "\x18\xf1\xaf\xcf\x7c\xc5\x0b\xee"
+ "\xad\x3c\x76\x7c\xe6\x27\xa2\x2a"
+ "\xe4\x66\xe1\xab\xa2\x39\xfc\x7c"
+ "\xf5\xec\x32\x74\xa3\xb8\x03\x88"
+ "\x52\xfc\x2e\x56\x3f\xa1\xf0\x9f"
+ "\x84\x5e\x46\xed\x20\x89\xb6\x44"
+ "\x8d\xd0\xed\x54\x47\x16\xbe\x95"
+ "\x8a\xb3\x6b\x72\xc4\x32\x52\x13"
+ "\x1b\xb0\x82\xbe\xac\xf9\x70\xa6"
+ "\x44\x18\xdd\x8c\x6e\xca\x6e\x45"
+ "\x8f\x1e\x10\x07\x57\x25\x98\x7b"
+ "\x17\x8c\x78\xdd\x80\xa7\xd9\xd8"
+ "\x63\xaf\xb9\x67\x57\xfd\xbc\xdb"
+ "\x44\xe9\xc5\x65\xd1\xc7\x3b\xff"
+ "\x20\xa0\x80\x1a\xc3\x9a\xad\x5e"
+ "\x5d\x3b\xd3\x07\xd9\xf5\xfd\x3d"
+ "\x4a\x8b\xa8\xd2\x6e\x7a\x51\x65"
+ "\x6c\x8e\x95\xe0\x45\xc9\x5f\x4a"
+ "\x09\x3c\x3d\x71\x7f\x0c\x84\x2a"
+ "\xc8\x48\x52\x1a\xc2\xd5\xd6\x78"
+ "\x92\x1e\xa0\x90\x2e\xea\xf0\xf3"
+ "\xdc\x0f\xb1\xaf\x0d\x9b\x06\x2e"
+ "\x35\x10\x30\x82\x0d\xe7\xc5\x9b"
+ "\xde\x44\x18\xbd\x9f\xd1\x45\xa9"
+ "\x7b\x7a\x4a\xad\x35\x65\x27\xca"
+ "\xb2\xc3\xd4\x9b\x71\x86\x70\xee"
+ "\xf1\x89\x3b\x85\x4b\x5b\xaa\xaf"
+ "\xfc\x42\xc8\x31\x59\xbe\x16\x60"
+ "\x4f\xf9\xfa\x12\xea\xd0\xa7\x14"
+ "\xf0\x7a\xf3\xd5\x8d\xbd\x81\xef"
+ "\x52\x7f\x29\x51\x94\x20\x67\x3c"
+ "\xd1\xaf\x77\x9f\x22\x5a\x4e\x63"
+ "\xe7\xff\x73\x25\xd1\xdd\x96\x8a"
+ "\x98\x52\x6d\xf3\xac\x3e\xf2\x18"
+ "\x6d\xf6\x0a\x29\xa6\x34\x3d\xed"
+ "\xe3\x27\x0d\x9d\x0a\x02\x44\x7e"
+ "\x5a\x7e\x67\x0f\x0a\x9e\xd6\xad"
+ "\x91\xe6\x4d\x81\x8c\x5c\x59\xaa"
+ "\xfb\xeb\x56\x53\xd2\x7d\x4c\x81"
+ "\x65\x53\x0f\x41\x11\xbd\x98\x99"
+ "\xf9\xc6\xfa\x51\x2e\xa3\xdd\x8d"
+ "\x84\x98\xf9\x34\xed\x33\x2a\x1f"
+ "\x82\xed\xc1\x73\x98\xd3\x02\xdc"
+ "\xe6\xc2\x33\x1d\xa2\xb4\xca\x76"
+ "\x63\x51\x34\x9d\x96\x12\xae\xce"
+ "\x83\xc9\x76\x5e\xa4\x1b\x53\x37"
+ "\x17\xd5\xc0\x80\x1d\x62\xf8\x3d"
+ "\x54\x27\x74\xbb\x10\x86\x57\x46"
+ "\x68\xe1\xed\x14\xe7\x9d\xfc\x84"
+ "\x47\xbc\xc2\xf8\x19\x4b\x99\xcf"
+ "\x7a\xe9\xc4\xb8\x8c\x82\x72\x4d"
+ "\x7b\x4f\x38\x55\x36\x71\x64\xc1"
+ "\xfc\x5c\x75\x52\x33\x02\x18\xf8"
+ "\x17\xe1\x2b\xc2\x43\x39\xbd\x76"
+ "\x9b\x63\x76\x32\x2f\x19\x72\x10"
+ "\x9f\x21\x0c\xf1\x66\x50\x7f\xa5"
+ "\x0d\x1f\x46\xe0\xba\xd3\x2f\x3c",
+ .rlen = 512,
+ .also_non_np = 1,
+ .np = 3,
+ .tap = { 512 - 20, 4, 16 },
+ }
+};
+
+static struct cipher_testvec speck64_xts_dec_tv_template[] = {
+ {
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .klen = 24,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x84\xaf\x54\x07\x19\xd4\x7c\xa6"
+ "\xe4\xfe\xdf\xc4\x1f\x34\xc3\xc2"
+ "\x80\xf5\x72\xe7\xcd\xf0\x99\x22"
+ "\x35\xa7\x2f\x06\xef\xdc\x51\xaa",
+ .ilen = 32,
+ .result = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .rlen = 32,
+ }, {
+ .key = "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 24,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x12\x56\x73\xcd\x15\x87\xa8\x59"
+ "\xcf\x84\xae\xd9\x1c\x66\xd6\x9f"
+ "\xb3\x12\x69\x7e\x36\xeb\x52\xff"
+ "\x62\xdd\xba\x90\xb3\xe1\xee\x99",
+ .ilen = 32,
+ .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .rlen = 32,
+ }, {
+ .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+ "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 24,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x15\x1b\xe4\x2c\xa2\x5a\x2d\x2c"
+ "\x27\x36\xc0\xbf\x5d\xea\x36\x37"
+ "\x2d\x1a\x88\xbc\x66\xb5\xd0\x0b"
+ "\xa1\xbc\x19\xb2\x0f\x3b\x75\x34",
+ .ilen = 32,
+ .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .rlen = 32,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x31\x41\x59\x26\x53\x58\x97\x93",
+ .klen = 24,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\xaf\xa1\x81\xa6\x32\xbb\x15\x8e"
+ "\xf8\x95\x2e\xd3\xe6\xee\x7e\x09"
+ "\x0c\x1a\xf5\x02\x97\x8b\xe3\xb3"
+ "\x11\xc7\x39\x96\xd0\x95\xf4\x56"
+ "\xf4\xdd\x03\x38\x01\x44\x2c\xcf"
+ "\x88\xae\x8e\x3c\xcd\xe7\xaa\x66"
+ "\xfe\x3d\xc6\xfb\x01\x23\x51\x43"
+ "\xd5\xd2\x13\x86\x94\x34\xe9\x62"
+ "\xf9\x89\xe3\xd1\x7b\xbe\xf8\xef"
+ "\x76\x35\x04\x3f\xdb\x23\x9d\x0b"
+ "\x85\x42\xb9\x02\xd6\xcc\xdb\x96"
+ "\xa7\x6b\x27\xb6\xd4\x45\x8f\x7d"
+ "\xae\xd2\x04\xd5\xda\xc1\x7e\x24"
+ "\x8c\x73\xbe\x48\x7e\xcf\x65\x28"
+ "\x29\xe5\xbe\x54\x30\xcb\x46\x95"
+ "\x4f\x2e\x8a\x36\xc8\x27\xc5\xbe"
+ "\xd0\x1a\xaf\xab\x26\xcd\x9e\x69"
+ "\xa1\x09\x95\x71\x26\xe9\xc4\xdf"
+ "\xe6\x31\xc3\x46\xda\xaf\x0b\x41"
+ "\x1f\xab\xb1\x8e\xd6\xfc\x0b\xb3"
+ "\x82\xc0\x37\x27\xfc\x91\xa7\x05"
+ "\xfb\xc5\xdc\x2b\x74\x96\x48\x43"
+ "\x5d\x9c\x19\x0f\x60\x63\x3a\x1f"
+ "\x6f\xf0\x03\xbe\x4d\xfd\xc8\x4a"
+ "\xc6\xa4\x81\x6d\xc3\x12\x2a\x5c"
+ "\x07\xff\xf3\x72\x74\x48\xb5\x40"
+ "\x50\xb5\xdd\x90\x43\x31\x18\x15"
+ "\x7b\xf2\xa6\xdb\x83\xc8\x4b\x4a"
+ "\x29\x93\x90\x8b\xda\x07\xf0\x35"
+ "\x6d\x90\x88\x09\x4e\x83\xf5\x5b"
+ "\x94\x12\xbb\x33\x27\x1d\x3f\x23"
+ "\x51\xa8\x7c\x07\xa2\xae\x77\xa6"
+ "\x50\xfd\xcc\xc0\x4f\x80\x7a\x9f"
+ "\x66\xdd\xcd\x75\x24\x8b\x33\xf7"
+ "\x20\xdb\x83\x9b\x4f\x11\x63\x6e"
+ "\xcf\x37\xef\xc9\x11\x01\x5c\x45"
+ "\x32\x99\x7c\x3c\x9e\x42\x89\xe3"
+ "\x70\x6d\x15\x9f\xb1\xe6\xb6\x05"
+ "\xfe\x0c\xb9\x49\x2d\x90\x6d\xcc"
+ "\x5d\x3f\xc1\xfe\x89\x0a\x2e\x2d"
+ "\xa0\xa8\x89\x3b\x73\x39\xa5\x94"
+ "\x4c\xa4\xa6\xbb\xa7\x14\x46\x89"
+ "\x10\xff\xaf\xef\xca\xdd\x4f\x80"
+ "\xb3\xdf\x3b\xab\xd4\xe5\x5a\xc7"
+ "\x33\xca\x00\x8b\x8b\x3f\xea\xec"
+ "\x68\x8a\xc2\x6d\xfd\xd4\x67\x0f"
+ "\x22\x31\xe1\x0e\xfe\x5a\x04\xd5"
+ "\x64\xa3\xf1\x1a\x76\x28\xcc\x35"
+ "\x36\xa7\x0a\x74\xf7\x1c\x44\x9b"
+ "\xc7\x1b\x53\x17\x02\xea\xd1\xad"
+ "\x13\x51\x73\xc0\xa0\xb2\x05\x32"
+ "\xa8\xa2\x37\x2e\xe1\x7a\x3a\x19"
+ "\x26\xb4\x6c\x62\x5d\xb3\x1a\x1d"
+ "\x59\xda\xee\x1a\x22\x18\xda\x0d"
+ "\x88\x0f\x55\x8b\x72\x62\xfd\xc1"
+ "\x69\x13\xcd\x0d\x5f\xc1\x09\x52"
+ "\xee\xd6\xe3\x84\x4d\xee\xf6\x88"
+ "\xaf\x83\xdc\x76\xf4\xc0\x93\x3f"
+ "\x4a\x75\x2f\xb0\x0b\x3e\xc4\x54"
+ "\x7d\x69\x8d\x00\x62\x77\x0d\x14"
+ "\xbe\x7c\xa6\x7d\xc5\x24\x4f\xf3"
+ "\x50\xf7\x5f\xf4\xc2\xca\x41\x97"
+ "\x37\xbe\x75\x74\xcd\xf0\x75\x6e"
+ "\x25\x23\x94\xbd\xda\x8d\xb0\xd4",
+ .ilen = 512,
+ .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .rlen = 512,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x62\x49\x77\x57\x24\x70\x93\x69"
+ "\x99\x59\x57\x49\x66\x96\x76\x27",
+ .klen = 32,
+ .iv = "\xff\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x55\xed\x71\xd3\x02\x8e\x15\x3b"
+ "\xc6\x71\x29\x2d\x3e\x89\x9f\x59"
+ "\x68\x6a\xcc\x8a\x56\x97\xf3\x95"
+ "\x4e\x51\x08\xda\x2a\xf8\x6f\x3c"
+ "\x78\x16\xea\x80\xdb\x33\x75\x94"
+ "\xf9\x29\xc4\x2b\x76\x75\x97\xc7"
+ "\xf2\x98\x2c\xf9\xff\xc8\xd5\x2b"
+ "\x18\xf1\xaf\xcf\x7c\xc5\x0b\xee"
+ "\xad\x3c\x76\x7c\xe6\x27\xa2\x2a"
+ "\xe4\x66\xe1\xab\xa2\x39\xfc\x7c"
+ "\xf5\xec\x32\x74\xa3\xb8\x03\x88"
+ "\x52\xfc\x2e\x56\x3f\xa1\xf0\x9f"
+ "\x84\x5e\x46\xed\x20\x89\xb6\x44"
+ "\x8d\xd0\xed\x54\x47\x16\xbe\x95"
+ "\x8a\xb3\x6b\x72\xc4\x32\x52\x13"
+ "\x1b\xb0\x82\xbe\xac\xf9\x70\xa6"
+ "\x44\x18\xdd\x8c\x6e\xca\x6e\x45"
+ "\x8f\x1e\x10\x07\x57\x25\x98\x7b"
+ "\x17\x8c\x78\xdd\x80\xa7\xd9\xd8"
+ "\x63\xaf\xb9\x67\x57\xfd\xbc\xdb"
+ "\x44\xe9\xc5\x65\xd1\xc7\x3b\xff"
+ "\x20\xa0\x80\x1a\xc3\x9a\xad\x5e"
+ "\x5d\x3b\xd3\x07\xd9\xf5\xfd\x3d"
+ "\x4a\x8b\xa8\xd2\x6e\x7a\x51\x65"
+ "\x6c\x8e\x95\xe0\x45\xc9\x5f\x4a"
+ "\x09\x3c\x3d\x71\x7f\x0c\x84\x2a"
+ "\xc8\x48\x52\x1a\xc2\xd5\xd6\x78"
+ "\x92\x1e\xa0\x90\x2e\xea\xf0\xf3"
+ "\xdc\x0f\xb1\xaf\x0d\x9b\x06\x2e"
+ "\x35\x10\x30\x82\x0d\xe7\xc5\x9b"
+ "\xde\x44\x18\xbd\x9f\xd1\x45\xa9"
+ "\x7b\x7a\x4a\xad\x35\x65\x27\xca"
+ "\xb2\xc3\xd4\x9b\x71\x86\x70\xee"
+ "\xf1\x89\x3b\x85\x4b\x5b\xaa\xaf"
+ "\xfc\x42\xc8\x31\x59\xbe\x16\x60"
+ "\x4f\xf9\xfa\x12\xea\xd0\xa7\x14"
+ "\xf0\x7a\xf3\xd5\x8d\xbd\x81\xef"
+ "\x52\x7f\x29\x51\x94\x20\x67\x3c"
+ "\xd1\xaf\x77\x9f\x22\x5a\x4e\x63"
+ "\xe7\xff\x73\x25\xd1\xdd\x96\x8a"
+ "\x98\x52\x6d\xf3\xac\x3e\xf2\x18"
+ "\x6d\xf6\x0a\x29\xa6\x34\x3d\xed"
+ "\xe3\x27\x0d\x9d\x0a\x02\x44\x7e"
+ "\x5a\x7e\x67\x0f\x0a\x9e\xd6\xad"
+ "\x91\xe6\x4d\x81\x8c\x5c\x59\xaa"
+ "\xfb\xeb\x56\x53\xd2\x7d\x4c\x81"
+ "\x65\x53\x0f\x41\x11\xbd\x98\x99"
+ "\xf9\xc6\xfa\x51\x2e\xa3\xdd\x8d"
+ "\x84\x98\xf9\x34\xed\x33\x2a\x1f"
+ "\x82\xed\xc1\x73\x98\xd3\x02\xdc"
+ "\xe6\xc2\x33\x1d\xa2\xb4\xca\x76"
+ "\x63\x51\x34\x9d\x96\x12\xae\xce"
+ "\x83\xc9\x76\x5e\xa4\x1b\x53\x37"
+ "\x17\xd5\xc0\x80\x1d\x62\xf8\x3d"
+ "\x54\x27\x74\xbb\x10\x86\x57\x46"
+ "\x68\xe1\xed\x14\xe7\x9d\xfc\x84"
+ "\x47\xbc\xc2\xf8\x19\x4b\x99\xcf"
+ "\x7a\xe9\xc4\xb8\x8c\x82\x72\x4d"
+ "\x7b\x4f\x38\x55\x36\x71\x64\xc1"
+ "\xfc\x5c\x75\x52\x33\x02\x18\xf8"
+ "\x17\xe1\x2b\xc2\x43\x39\xbd\x76"
+ "\x9b\x63\x76\x32\x2f\x19\x72\x10"
+ "\x9f\x21\x0c\xf1\x66\x50\x7f\xa5"
+ "\x0d\x1f\x46\xe0\xba\xd3\x2f\x3c",
+ .ilen = 512,
+ .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .rlen = 512,
+ .also_non_np = 1,
+ .np = 3,
+ .tap = { 512 - 20, 4, 16 },
+ }
+};
+
/* Cast6 test vectors from RFC 2612 */
#define CAST6_ENC_TEST_VECTORS 4
#define CAST6_DEC_TEST_VECTORS 4
diff --git a/drivers/Kconfig b/drivers/Kconfig
index e37c9aa..9480d84 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -208,4 +208,6 @@
source "drivers/sensors/Kconfig"
+source "drivers/tee/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 04e2d4e..06e2bb4 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -101,6 +101,7 @@
obj-$(CONFIG_UWB) += uwb/
obj-$(CONFIG_USB_PHY) += usb/
obj-$(CONFIG_USB) += usb/
+obj-$(CONFIG_USB_SUPPORT) += usb/
obj-$(CONFIG_PCI) += usb/
obj-$(CONFIG_USB_GADGET) += usb/
obj-$(CONFIG_OF) += usb/
@@ -177,3 +178,4 @@
obj-$(CONFIG_ESOC) += esoc/
obj-$(CONFIG_FPGA) += fpga/
obj-$(CONFIG_SENSORS_SSC) += sensors/
+obj-$(CONFIG_TEE) += tee/
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index fe03d00..b1815b2 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -1535,6 +1535,9 @@
struct kernfs_node *nfit_kernfs;
nvdimm = nfit_mem->nvdimm;
+ if (!nvdimm)
+ continue;
+
nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit");
if (nfit_kernfs)
nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs,
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index 2fa8304..7a34310 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -275,8 +275,8 @@
device->driver_data = hc;
acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc);
- printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n",
- hc->ec, hc->offset, hc->query_bit);
+ dev_info(&device->dev, "SBS HC: offset = 0x%0x, query_bit = 0x%0x\n",
+ hc->offset, hc->query_bit);
return 0;
}
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 1ef2f68..ff367b8fa 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -512,8 +512,6 @@
* (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
@@ -554,7 +552,6 @@
bool is_dead;
struct list_head todo;
- wait_queue_head_t wait;
struct binder_stats stats;
struct list_head delivered_death;
int max_threads;
@@ -4538,8 +4535,29 @@
if (t)
spin_lock(&t->lock);
}
+
+ /*
+ * If this thread used poll, make sure we remove the waitqueue
+ * from any epoll data structures holding it with POLLFREE.
+ * waitqueue_active() is safe to use here because we're holding
+ * the inner lock.
+ */
+ if ((thread->looper & BINDER_LOOPER_STATE_POLL) &&
+ waitqueue_active(&thread->wait)) {
+ wake_up_poll(&thread->wait, POLLHUP | POLLFREE);
+ }
+
binder_inner_proc_unlock(thread->proc);
+ /*
+ * This is needed to avoid races between wake_up_poll() above and
+ * and ep_remove_waitqueue() called for other reasons (eg the epoll file
+ * descriptor being closed); ep_remove_waitqueue() holds an RCU read
+ * lock, so we can be sure it's done after calling synchronize_rcu().
+ */
+ if (thread->looper & BINDER_LOOPER_STATE_POLL)
+ synchronize_rcu();
+
if (send_reply)
binder_send_failed_reply(send_reply, BR_DEAD_REPLY);
binder_release_work(proc, &thread->todo);
@@ -4555,6 +4573,8 @@
bool wait_for_proc_work;
thread = binder_get_thread(proc);
+ if (!thread)
+ return POLLERR;
binder_inner_proc_lock(thread->proc);
thread->looper |= BINDER_LOOPER_STATE_POLL;
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index 3ad1bcf..1c76daa 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -281,6 +281,9 @@
goto err_vm_insert_page_failed;
}
+ if (index + 1 > alloc->pages_high)
+ alloc->pages_high = index + 1;
+
trace_binder_alloc_page_end(alloc, index);
/* vm_insert_page does not seem to increment the refcount */
}
@@ -854,6 +857,7 @@
}
mutex_unlock(&alloc->mutex);
seq_printf(m, " pages: %d:%d:%d\n", active, lru, free);
+ seq_printf(m, " pages high watermark: %zu\n", alloc->pages_high);
}
/**
diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h
index 2dd33b6..0b14530 100644
--- a/drivers/android/binder_alloc.h
+++ b/drivers/android/binder_alloc.h
@@ -92,6 +92,7 @@
* @pages: array of binder_lru_page
* @buffer_size: size of address space specified via mmap
* @pid: pid for associated binder_proc (invariant after init)
+ * @pages_high: high watermark of offset in @pages
*
* Bookkeeping structure for per-proc address space management for binder
* buffers. It is normally initialized during binder_init() and binder_mmap()
@@ -112,6 +113,7 @@
size_t buffer_size;
uint32_t buffer_free;
int pid;
+ size_t pages_high;
};
#ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index c940382..9b46ef4 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -265,9 +265,9 @@
{ PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
- { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
+ { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH M AHCI */
{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
- { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH M RAID */
{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
{ PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */
@@ -290,9 +290,9 @@
{ PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
- { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
+ { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT M AHCI */
{ PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
- { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */
+ { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT M RAID */
{ PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
{ PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
{ PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
@@ -301,20 +301,20 @@
{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */
{ PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
{ PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
- { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */
+ { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point M AHCI */
{ PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */
{ PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
{ PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
- { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
+ { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point M RAID */
{ PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
{ PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */
- { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */
+ { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point M AHCI */
{ PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */
- { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */
+ { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point M RAID */
{ PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */
- { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */
+ { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point M RAID */
{ PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
- { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */
+ { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point M RAID */
{ PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */
{ PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */
{ PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */
@@ -355,21 +355,21 @@
{ PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */
{ PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */
{ PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */
- { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */
+ { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series M AHCI */
{ PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */
- { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */
+ { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series M RAID */
{ PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */
- { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
+ { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series M RAID */
{ PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
- { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
+ { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series M RAID */
{ PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
{ PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
{ PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
{ PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */
- { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
+ { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H M AHCI */
{ PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
{ PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */
- { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
+ { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H M RAID */
{ PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/
@@ -383,6 +383,11 @@
{ PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0xa356), board_ahci }, /* Cannon Lake PCH-H RAID */
+ { PCI_VDEVICE(INTEL, 0x0f22), board_ahci }, /* Bay Trail AHCI */
+ { PCI_VDEVICE(INTEL, 0x0f23), board_ahci }, /* Bay Trail AHCI */
+ { PCI_VDEVICE(INTEL, 0x22a3), board_ahci }, /* Cherry Trail AHCI */
+ { PCI_VDEVICE(INTEL, 0x5ae3), board_ahci }, /* Apollo Lake AHCI */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
diff --git a/drivers/auxdisplay/img-ascii-lcd.c b/drivers/auxdisplay/img-ascii-lcd.c
index 83f1439..6e8eaa7 100644
--- a/drivers/auxdisplay/img-ascii-lcd.c
+++ b/drivers/auxdisplay/img-ascii-lcd.c
@@ -442,3 +442,7 @@
.remove = img_ascii_lcd_remove,
};
module_platform_driver(img_ascii_lcd_driver);
+
+MODULE_DESCRIPTION("Imagination Technologies ASCII LCD Display");
+MODULE_AUTHOR("Paul Burton <paul.burton@mips.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 0651010..0335e23 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -165,6 +165,11 @@
If you are unsure about this, say N here.
+config FW_CACHE
+ bool "Enable firmware caching during suspend"
+ depends on PM_SLEEP
+ default n
+
config WANT_DEV_COREDUMP
bool
help
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 914433f..813a191 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -994,7 +994,7 @@
return _request_firmware_load(fw_priv, opt_flags, timeout);
}
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
/* kill pending requests without uevent to avoid blocking suspend */
static void kill_requests_without_uevent(void)
{
@@ -1395,7 +1395,7 @@
}
EXPORT_SYMBOL(request_firmware_nowait);
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain);
/**
@@ -1741,7 +1741,7 @@
INIT_LIST_HEAD(&fw_cache.head);
fw_cache.state = FW_LOADER_NO_CACHE;
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
spin_lock_init(&fw_cache.name_lock);
INIT_LIST_HEAD(&fw_cache.fw_names);
@@ -1768,7 +1768,7 @@
static void __exit firmware_class_exit(void)
{
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
unregister_syscore_ops(&fw_syscore_ops);
unregister_pm_notifier(&fw_cache.pm_notify);
#endif
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index ec9d861..027b876 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -396,8 +396,8 @@
WARN_ON(d->gd);
WARN_ON(d->flags & DEVFL_UP);
blk_queue_max_hw_sectors(q, BLK_DEF_MAX_SECTORS);
- q->backing_dev_info.name = "aoe";
- q->backing_dev_info.ra_pages = READ_AHEAD / PAGE_SIZE;
+ q->backing_dev_info->name = "aoe";
+ q->backing_dev_info->ra_pages = READ_AHEAD / PAGE_SIZE;
d->bufpool = mp;
d->blkq = gd->queue = q;
q->queuedata = d;
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 8348272..d305f05 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -2462,7 +2462,7 @@
if (get_ldev(device)) {
q = bdev_get_queue(device->ldev->backing_bdev);
- r = bdi_congested(&q->backing_dev_info, bdi_bits);
+ r = bdi_congested(q->backing_dev_info, bdi_bits);
put_ldev(device);
if (r)
reason = 'b';
@@ -2834,8 +2834,8 @@
/* we have no partitions. we contain only ourselves. */
device->this_bdev->bd_contains = device->this_bdev;
- q->backing_dev_info.congested_fn = drbd_congested;
- q->backing_dev_info.congested_data = device;
+ q->backing_dev_info->congested_fn = drbd_congested;
+ q->backing_dev_info->congested_data = device;
blk_queue_make_request(q, drbd_make_request);
blk_queue_write_cache(q, true, true);
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index f35db29..908c704 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -1328,11 +1328,13 @@
if (b) {
blk_queue_stack_limits(q, b);
- if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
+ if (q->backing_dev_info->ra_pages !=
+ b->backing_dev_info->ra_pages) {
drbd_info(device, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
- q->backing_dev_info.ra_pages,
- b->backing_dev_info.ra_pages);
- q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
+ q->backing_dev_info->ra_pages,
+ b->backing_dev_info->ra_pages);
+ q->backing_dev_info->ra_pages =
+ b->backing_dev_info->ra_pages;
}
}
fixup_discard_if_not_supported(q);
@@ -3345,7 +3347,7 @@
s->dev_disk_flags = md->flags;
q = bdev_get_queue(device->ldev->backing_bdev);
s->dev_lower_blocked =
- bdi_congested(&q->backing_dev_info,
+ bdi_congested(q->backing_dev_info,
(1 << WB_async_congested) |
(1 << WB_sync_congested));
put_ldev(device);
diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c
index be2b93f..8378142 100644
--- a/drivers/block/drbd/drbd_proc.c
+++ b/drivers/block/drbd/drbd_proc.c
@@ -288,7 +288,7 @@
seq_printf(seq, "%2d: cs:Unconfigured\n", i);
} else {
/* reset device->congestion_reason */
- bdi_rw_congested(&device->rq_queue->backing_dev_info);
+ bdi_rw_congested(device->rq_queue->backing_dev_info);
nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
wp = nc ? nc->wire_protocol - DRBD_PROT_A + 'A' : ' ';
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index de279fe..cb6bdb7 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -938,7 +938,7 @@
switch (rbm) {
case RB_CONGESTED_REMOTE:
- bdi = &device->ldev->backing_bdev->bd_disk->queue->backing_dev_info;
+ bdi = device->ldev->backing_bdev->bd_disk->queue->backing_dev_info;
return bdi_read_congested(bdi);
case RB_LEAST_PENDING:
return atomic_read(&device->local_cnt) >
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 90fa4ac..4a5bccd 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -1276,7 +1276,7 @@
&& pd->bio_queue_size <= pd->write_congestion_off);
spin_unlock(&pd->lock);
if (wakeup) {
- clear_bdi_congested(&pd->disk->queue->backing_dev_info,
+ clear_bdi_congested(pd->disk->queue->backing_dev_info,
BLK_RW_ASYNC);
}
@@ -2405,7 +2405,7 @@
spin_lock(&pd->lock);
if (pd->write_congestion_on > 0
&& pd->bio_queue_size >= pd->write_congestion_on) {
- set_bdi_congested(&q->backing_dev_info, BLK_RW_ASYNC);
+ set_bdi_congested(q->backing_dev_info, BLK_RW_ASYNC);
do {
spin_unlock(&pd->lock);
congestion_wait(BLK_RW_ASYNC, HZ);
@@ -2779,7 +2779,7 @@
pd->pkt_dev = MKDEV(pktdev_major, idx);
ret = pkt_new_dev(pd, dev);
if (ret)
- goto out_new_dev;
+ goto out_mem2;
/* inherit events of the host device */
disk->events = pd->bdev->bd_disk->events;
@@ -2797,8 +2797,6 @@
mutex_unlock(&ctl_mutex);
return 0;
-out_new_dev:
- blk_cleanup_queue(disk->queue);
out_mem2:
put_disk(disk);
out_mem:
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index e32badd..194db0e2 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -3756,7 +3756,7 @@
struct rbd_device *rbd_dev = arg;
void *p = data;
void *const end = p + data_len;
- u8 struct_v;
+ u8 struct_v = 0;
u32 len;
u32 notify_op;
int ret;
@@ -4524,7 +4524,7 @@
q->limits.discard_zeroes_data = 1;
if (!ceph_test_opt(rbd_dev->rbd_client->client, NOCRC))
- q->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES;
+ q->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES;
disk->queue = q;
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index ed9de1b..58f7c39 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -122,7 +122,7 @@
{
revalidate_disk(zram->disk);
/* revalidate_disk reset the BDI_CAP_STABLE_WRITES so set again */
- zram->disk->queue->backing_dev_info.capabilities |=
+ zram->disk->queue->backing_dev_info->capabilities |=
BDI_CAP_STABLE_WRITES;
}
diff --git a/drivers/bluetooth/btfm_slim.c b/drivers/bluetooth/btfm_slim.c
index 6792e04..92ea0135 100644
--- a/drivers/bluetooth/btfm_slim.c
+++ b/drivers/bluetooth/btfm_slim.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -137,6 +137,14 @@
prop.dataf = ((rates == 48000) || (rates == 44100) ||
(rates == 88200) || (rates == 96000)) ?
SLIM_CH_DATAF_NOT_DEFINED : SLIM_CH_DATAF_LPCM_AUDIO;
+
+ /* for feedback channel PCM bit should not be set */
+ if (btfm_feedback_ch_setting) {
+ BTFMSLIM_DBG("port open for feedback ch, not setting PCM bit");
+ prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
+ /* reset so that next port open sets the data format properly */
+ btfm_feedback_ch_setting = 0;
+ }
prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
prop.ratem = ((rates == 44100) || (rates == 88200)) ?
(rates/11025) : (rates/4000);
diff --git a/drivers/bluetooth/btfm_slim.h b/drivers/bluetooth/btfm_slim.h
index cc9d14d..fc653fde 100644
--- a/drivers/bluetooth/btfm_slim.h
+++ b/drivers/bluetooth/btfm_slim.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -78,6 +78,8 @@
uint8_t rxport, uint8_t enable);
};
+extern int btfm_feedback_ch_setting;
+
/**
* btfm_slim_hw_init: Initialize slimbus slave device
* Returns:
diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c
index 53388ed..4c6986a 100644
--- a/drivers/bluetooth/btfm_slim_codec.c
+++ b/drivers/bluetooth/btfm_slim_codec.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -27,7 +27,7 @@
#include <btfm_slim.h>
static int bt_soc_enable_status;
-
+int btfm_feedback_ch_setting;
static int btfm_slim_codec_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
@@ -54,10 +54,27 @@
return 1;
}
+static int btfm_get_feedback_ch_setting(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = btfm_feedback_ch_setting;
+ return 1;
+}
+
+static int btfm_put_feedback_ch_setting(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ btfm_feedback_ch_setting = ucontrol->value.integer.value[0];
+ return 1;
+}
+
static const struct snd_kcontrol_new status_controls[] = {
SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0,
bt_soc_status_get,
- bt_soc_status_put)
+ bt_soc_status_put),
+ SOC_SINGLE_EXT("BT set feedback channel", 0, 0, 1, 0,
+ btfm_get_feedback_ch_setting,
+ btfm_put_feedback_ch_setting)
};
@@ -371,9 +388,11 @@
.capture = {
.stream_name = "SCO TX Capture",
/* 8 KHz or 16 KHz */
- .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000
+ | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000
+ | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000,
.formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */
- .rate_max = 16000,
+ .rate_max = 96000,
.rate_min = 8000,
.channels_min = 1,
.channels_max = 1,
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
index 1cb958e..94e914a 100644
--- a/drivers/bluetooth/btsdio.c
+++ b/drivers/bluetooth/btsdio.c
@@ -31,6 +31,7 @@
#include <linux/errno.h>
#include <linux/skbuff.h>
+#include <linux/mmc/host.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
@@ -291,6 +292,14 @@
tuple = tuple->next;
}
+ /* BCM43341 devices soldered onto the PCB (non-removable) use an
+ * uart connection for bluetooth, ignore the BT SDIO interface.
+ */
+ if (func->vendor == SDIO_VENDOR_ID_BROADCOM &&
+ func->device == SDIO_DEVICE_ID_BROADCOM_43341 &&
+ !mmc_card_is_removable(func->card->host))
+ return -ENODEV;
+
data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 6930286..3257647 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/usb.h>
+#include <linux/usb/quirks.h>
#include <linux/firmware.h>
#include <asm/unaligned.h>
@@ -369,8 +370,8 @@
#define BTUSB_FIRMWARE_LOADED 7
#define BTUSB_FIRMWARE_FAILED 8
#define BTUSB_BOOTING 9
-#define BTUSB_RESET_RESUME 10
-#define BTUSB_DIAG_RUNNING 11
+#define BTUSB_DIAG_RUNNING 10
+#define BTUSB_OOB_WAKE_ENABLED 11
struct btusb_data {
struct hci_dev *hdev;
@@ -2928,9 +2929,9 @@
/* QCA Rome devices lose their updated firmware over suspend,
* but the USB hub doesn't notice any status change.
- * Explicitly request a device reset on resume.
+ * explicitly request a device reset on resume.
*/
- set_bit(BTUSB_RESET_RESUME, &data->flags);
+ interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
}
#ifdef CONFIG_BT_HCIBTUSB_RTL
@@ -2941,7 +2942,7 @@
* but the USB hub doesn't notice any status change.
* Explicitly request a device reset on resume.
*/
- set_bit(BTUSB_RESET_RESUME, &data->flags);
+ interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
}
#endif
@@ -3098,14 +3099,6 @@
btusb_stop_traffic(data);
usb_kill_anchored_urbs(&data->tx_anchor);
- /* Optionally request a device reset on resume, but only when
- * wakeups are disabled. If wakeups are enabled we assume the
- * device will stay powered up throughout suspend.
- */
- if (test_bit(BTUSB_RESET_RESUME, &data->flags) &&
- !device_may_wakeup(&data->udev->dev))
- data->udev->reset_resume = 1;
-
return 0;
}
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index a6cabf7..c9ceb48 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -56,6 +56,8 @@
#define TZ_PIL_AUTH_QDSP6_PROC 1
#define ADSP_MMAP_HEAP_ADDR 4
#define ADSP_MMAP_REMOTE_HEAP_ADDR 8
+#define FASTRPC_DMAHANDLE_NOMAP (16)
+
#define FASTRPC_ENOSUCH 39
#define VMID_SSC_Q6 5
#define VMID_ADSP_Q6 6
@@ -72,6 +74,8 @@
#define M_CRCLIST (64)
#define SESSION_ID_INDEX (30)
#define FASTRPC_CTX_MAGIC (0xbeeddeed)
+#define FASTRPC_CTX_MAX (256)
+#define FASTRPC_CTXID_MASK (0xFF0)
#define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0)
@@ -210,6 +214,7 @@
unsigned int magic;
unsigned int *attrs;
uint32_t *crc;
+ uint64_t ctxid;
};
struct fastrpc_ctx_lst {
@@ -292,6 +297,8 @@
unsigned int latency;
bool glink;
bool legacy;
+ spinlock_t ctxlock;
+ struct smq_invoke_ctx *ctxtable[FASTRPC_CTX_MAX];
};
struct fastrpc_mmap {
@@ -667,6 +674,9 @@
dma_free_coherent(me->dev, map->size,
(void *)map->va, (dma_addr_t)map->phys);
}
+ } else if (map->flags == FASTRPC_DMAHANDLE_NOMAP) {
+ if (!IS_ERR_OR_NULL(map->handle))
+ ion_free(fl->apps->client, map->handle);
} else {
int destVM[1] = {VMID_HLOS};
int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC};
@@ -746,6 +756,26 @@
map->phys = (uintptr_t)region_phys;
map->size = len;
map->va = (uintptr_t)region_vaddr;
+ } else if (mflags == FASTRPC_DMAHANDLE_NOMAP) {
+ ion_phys_addr_t iphys;
+
+ VERIFY(err, !IS_ERR_OR_NULL(map->handle =
+ ion_import_dma_buf_fd(fl->apps->client, fd)));
+ if (err)
+ goto bail;
+
+ map->uncached = 1;
+ map->buf = NULL;
+ map->attach = NULL;
+ map->table = NULL;
+ map->va = 0;
+ map->phys = 0;
+
+ err = ion_phys(fl->apps->client, map->handle,
+ &iphys, &map->size);
+ if (err)
+ goto bail;
+ map->phys = (uint64_t)iphys;
} else {
if (map->attr && (map->attr & FASTRPC_ATTR_KEEP_MAP)) {
pr_info("adsprpc: buffer mapped with persist attr %x\n",
@@ -1038,7 +1068,7 @@
struct smq_invoke_ctx **po)
{
struct fastrpc_apps *me = &gfa;
- int err = 0, bufs, size = 0;
+ int err = 0, bufs, ii, size = 0;
struct smq_invoke_ctx *ctx = NULL;
struct fastrpc_ctx_lst *clst = &fl->clst;
struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
@@ -1103,6 +1133,21 @@
hlist_add_head(&ctx->hn, &clst->pending);
spin_unlock(&fl->hlock);
+ spin_lock(&me->ctxlock);
+ for (ii = 0; ii < FASTRPC_CTX_MAX; ii++) {
+ if (!me->ctxtable[ii]) {
+ me->ctxtable[ii] = ctx;
+ ctx->ctxid = (ptr_to_uint64(ctx) & ~0xFFF)|(ii << 4);
+ break;
+ }
+ }
+ spin_unlock(&me->ctxlock);
+ VERIFY(err, ii < FASTRPC_CTX_MAX);
+ if (err) {
+ pr_err("adsprpc: out of context memory\n");
+ goto bail;
+ }
+
*po = ctx;
bail:
if (ctx && err)
@@ -1125,6 +1170,7 @@
static void context_free(struct smq_invoke_ctx *ctx)
{
int i;
+ struct fastrpc_apps *me = &gfa;
int nbufs = REMOTE_SCALARS_INBUFS(ctx->sc) +
REMOTE_SCALARS_OUTBUFS(ctx->sc);
spin_lock(&ctx->fl->hlock);
@@ -1137,6 +1183,17 @@
mutex_unlock(&ctx->fl->fl_map_mutex);
fastrpc_buf_free(ctx->buf, 1);
ctx->magic = 0;
+ ctx->ctxid = 0;
+
+ spin_lock(&me->ctxlock);
+ for (i = 0; i < FASTRPC_CTX_MAX; i++) {
+ if (me->ctxtable[i] == ctx) {
+ me->ctxtable[i] = NULL;
+ break;
+ }
+ }
+ spin_unlock(&me->ctxlock);
+
kfree(ctx);
}
@@ -1298,8 +1355,12 @@
handles = REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc);
mutex_lock(&ctx->fl->fl_map_mutex);
for (i = bufs; i < bufs + handles; i++) {
+ int dmaflags = 0;
+
+ if (ctx->attrs && (ctx->attrs[i] & FASTRPC_ATTR_NOMAP))
+ dmaflags = FASTRPC_DMAHANDLE_NOMAP;
VERIFY(err, !fastrpc_mmap_create(ctx->fl, ctx->fds[i],
- FASTRPC_ATTR_NOVA, 0, 0, 0, &ctx->maps[i]));
+ FASTRPC_ATTR_NOVA, 0, 0, dmaflags, &ctx->maps[i]));
if (err) {
mutex_unlock(&ctx->fl->fl_map_mutex);
goto bail;
@@ -1643,7 +1704,7 @@
msg->tid |= (1 << SESSION_ID_INDEX);
if (kernel)
msg->pid = 0;
- msg->invoke.header.ctx = ptr_to_uint64(ctx) | fl->pd;
+ msg->invoke.header.ctx = ctx->ctxid | fl->pd;
msg->invoke.header.handle = handle;
msg->invoke.header.sc = ctx->sc;
msg->invoke.page.addr = ctx->buf ? ctx->buf->phys : 0;
@@ -1676,19 +1737,30 @@
{
struct fastrpc_apps *me = &gfa;
struct smq_invoke_rsp rsp = {0};
- struct smq_invoke_ctx *ctx;
int ret = 0, err = 0;
+ uint32_t index;
do {
ret = smd_read_from_cb(me->channel[cid].chan, &rsp,
sizeof(rsp));
if (ret != sizeof(rsp))
break;
- ctx = (struct smq_invoke_ctx *)(uint64_to_ptr(rsp.ctx & ~1));
- VERIFY(err, (ctx && ctx->magic == FASTRPC_CTX_MAGIC));
+
+ index = (uint32_t)((rsp.ctx & FASTRPC_CTXID_MASK) >> 4);
+ VERIFY(err, index < FASTRPC_CTX_MAX);
if (err)
goto bail;
- context_notify_user(uint64_to_ptr(rsp.ctx & ~1), rsp.retval);
+
+ VERIFY(err, !IS_ERR_OR_NULL(me->ctxtable[index]));
+ if (err)
+ goto bail;
+
+ VERIFY(err, ((me->ctxtable[index]->ctxid == (rsp.ctx & ~1)) &&
+ me->ctxtable[index]->magic == FASTRPC_CTX_MAGIC));
+ if (err)
+ goto bail;
+
+ context_notify_user(me->ctxtable[index], rsp.retval);
} while (ret == sizeof(rsp));
bail:
if (err)
@@ -1722,6 +1794,7 @@
INIT_HLIST_HEAD(&me->drivers);
INIT_HLIST_HEAD(&me->maps);
spin_lock_init(&me->hlock);
+ spin_lock_init(&me->ctxlock);
mutex_init(&me->smd_mutex);
me->channel = &gcinfo[0];
for (i = 0; i < NUM_CHANNELS; i++) {
@@ -2510,19 +2583,29 @@
const void *pkt_priv, const void *ptr, size_t size)
{
struct smq_invoke_rsp *rsp = (struct smq_invoke_rsp *)ptr;
- struct smq_invoke_ctx *ctx;
+ struct fastrpc_apps *me = &gfa;
+ uint32_t index;
int err = 0;
VERIFY(err, (rsp && size >= sizeof(*rsp)));
if (err)
goto bail;
- ctx = (struct smq_invoke_ctx *)(uint64_to_ptr(rsp->ctx & ~1));
- VERIFY(err, (ctx && ctx->magic == FASTRPC_CTX_MAGIC));
+ index = (uint32_t)((rsp->ctx & FASTRPC_CTXID_MASK) >> 4);
+ VERIFY(err, index < FASTRPC_CTX_MAX);
if (err)
goto bail;
- context_notify_user(ctx, rsp->retval);
+ VERIFY(err, !IS_ERR_OR_NULL(me->ctxtable[index]));
+ if (err)
+ goto bail;
+
+ VERIFY(err, ((me->ctxtable[index]->ctxid == (rsp->ctx & ~1)) &&
+ me->ctxtable[index]->magic == FASTRPC_CTX_MAGIC));
+ if (err)
+ goto bail;
+
+ context_notify_user(me->ctxtable[index], rsp->retval);
bail:
if (err)
pr_err("adsprpc: invalid response or context\n");
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index 535160a..bb7b654 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -47,6 +47,9 @@
/* Fastrpc attribute for keeping the map persistent */
#define FASTRPC_ATTR_KEEP_MAP 0x8
+/* Fastrpc attribute for no map */
+#define FASTRPC_ATTR_NOMAP (16)
+
/* Driver should operate in parallel with the co-processor */
#define FASTRPC_MODE_PARALLEL 0
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index badd12c..9988291 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, 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
@@ -36,7 +36,11 @@
#define DIAG_MAX_REQ_SIZE (16 * 1024)
#define DIAG_MAX_RSP_SIZE (16 * 1024)
+#ifdef CONFIG_USB_CI13XXX_MSM
+#define APF_DIAG_PADDING 256
+#else
#define APF_DIAG_PADDING 0
+#endif
/*
* In the worst case, the HDLC buffer can be atmost twice the size of the
* original packet. Add 3 bytes for 16 bit CRC (2 bytes) and a delimiter
@@ -619,6 +623,7 @@
/* buffer for updating mask to peripherals */
unsigned char *buf_feature_mask_update;
uint8_t hdlc_disabled;
+ uint8_t p_hdlc_disabled[NUM_MD_SESSIONS];
struct mutex hdlc_disable_mutex;
struct mutex hdlc_recovery_mutex;
struct timer_list hdlc_reset_timer;
@@ -643,6 +648,7 @@
struct work_struct diag_drain_work;
struct work_struct update_user_clients;
struct work_struct update_md_clients;
+ struct work_struct diag_hdlc_reset_work;
struct workqueue_struct *diag_cntl_wq;
uint8_t log_on_demand_support;
uint8_t *apps_req_buf;
@@ -725,5 +731,6 @@
struct diag_md_session_t *diag_md_session_get_pid(int pid);
struct diag_md_session_t *diag_md_session_get_peripheral(uint8_t peripheral);
+int diag_md_session_match_pid_peripheral(int pid, uint8_t peripheral);
#endif
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 6e1674b..d4bae2e 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -238,18 +238,13 @@
void diag_drain_work_fn(struct work_struct *work)
{
- struct diag_md_session_t *session_info = NULL;
uint8_t hdlc_disabled = 0;
timer_in_progress = 0;
mutex_lock(&apps_data_mutex);
- mutex_lock(&driver->md_session_lock);
- session_info = diag_md_session_get_peripheral(APPS_DATA);
- if (session_info)
- hdlc_disabled = session_info->hdlc_disabled;
- else
- hdlc_disabled = driver->hdlc_disabled;
- mutex_unlock(&driver->md_session_lock);
+ mutex_lock(&driver->hdlc_disable_mutex);
+ hdlc_disabled = driver->p_hdlc_disabled[APPS_DATA];
+ mutex_unlock(&driver->hdlc_disable_mutex);
if (!hdlc_disabled)
diag_drain_apps_data(&hdlc_data);
else
@@ -1003,7 +998,6 @@
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
int bridge_index = proc - 1;
- struct diag_md_session_t *session_info = NULL;
uint8_t hdlc_disabled = 0;
if (!buf)
@@ -1029,13 +1023,9 @@
if (driver->hdlc_encode_buf_len != 0)
return -EAGAIN;
- mutex_lock(&driver->md_session_lock);
- session_info = diag_md_session_get_peripheral(APPS_DATA);
- if (session_info)
- hdlc_disabled = session_info->hdlc_disabled;
- else
- hdlc_disabled = driver->hdlc_disabled;
- mutex_unlock(&driver->md_session_lock);
+ mutex_lock(&driver->hdlc_disable_mutex);
+ hdlc_disabled = driver->p_hdlc_disabled[APPS_DATA];
+ mutex_unlock(&driver->hdlc_disable_mutex);
if (hdlc_disabled) {
if (len < 4) {
pr_err("diag: In %s, invalid len: %d of non_hdlc pkt",
@@ -1451,6 +1441,43 @@
return driver->md_session_map[peripheral];
}
+/*
+ * diag_md_session_match_pid_peripheral
+ *
+ * 1. Pass valid PID and get all the peripherals in logging session
+ * for that PID
+ * 2. Pass valid Peipheral and get the pid logging for that peripheral
+ *
+ */
+
+int diag_md_session_match_pid_peripheral(int pid,
+ uint8_t peripheral)
+{
+ int i, flag = 0;
+
+ if (pid <= 0 || peripheral >= NUM_MD_SESSIONS)
+ return -EINVAL;
+
+ if (!peripheral) {
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ if (driver->md_session_map[i] &&
+ driver->md_session_map[i]->pid == pid) {
+ peripheral |= 1 << i;
+ flag = 1;
+ }
+ }
+ if (flag)
+ return peripheral;
+ }
+
+ if (!pid) {
+ if (driver->md_session_map[peripheral])
+ return driver->md_session_map[peripheral]->pid;
+ }
+
+ return -EINVAL;
+}
+
static int diag_md_peripheral_switch(int pid,
int peripheral_mask, int req_mode) {
int i, bit = 0;
@@ -1605,6 +1632,13 @@
}
err = diag_md_session_create(DIAG_MD_PERIPHERAL,
param->peripheral_mask, DIAG_LOCAL_PROC);
+ mutex_lock(&driver->hdlc_disable_mutex);
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ if ((param->peripheral_mask > 0) &&
+ (param->peripheral_mask & (1 << i)))
+ driver->p_hdlc_disabled[i] = 0;
+ }
+ mutex_unlock(&driver->hdlc_disable_mutex);
}
*change_mode = 1;
return err;
@@ -1668,7 +1702,7 @@
}
if (!param->diag_id ||
(param->pd_val < UPD_WLAN) ||
- (param->pd_val > NUM_MD_SESSIONS)) {
+ (param->pd_val >= NUM_MD_SESSIONS)) {
DIAG_LOG(DIAG_DEBUG_USERSPACE,
"diag_id support is not present for the pd mask = %d\n",
param->pd_mask);
@@ -2055,11 +2089,14 @@
static int diag_ioctl_hdlc_toggle(unsigned long ioarg)
{
- uint8_t hdlc_support;
+ uint8_t hdlc_support, i;
+ int peripheral = -EINVAL;
struct diag_md_session_t *session_info = NULL;
+
if (copy_from_user(&hdlc_support, (void __user *)ioarg,
sizeof(uint8_t)))
return -EFAULT;
+
mutex_lock(&driver->hdlc_disable_mutex);
mutex_lock(&driver->md_session_lock);
session_info = diag_md_session_get_pid(current->tgid);
@@ -2067,6 +2104,25 @@
session_info->hdlc_disabled = hdlc_support;
else
driver->hdlc_disabled = hdlc_support;
+
+ peripheral =
+ diag_md_session_match_pid_peripheral(current->tgid,
+ 0);
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ if (peripheral > 0 && session_info) {
+ if (peripheral & (1 << i))
+ driver->p_hdlc_disabled[i] =
+ session_info->hdlc_disabled;
+ else if (!diag_md_session_get_peripheral(i))
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ } else {
+ if (!diag_md_session_get_peripheral(i))
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ }
+ }
+
mutex_unlock(&driver->md_session_lock);
mutex_unlock(&driver->hdlc_disable_mutex);
diag_update_md_clients(HDLC_SUPPORT_TYPE);
@@ -3054,7 +3110,6 @@
int stm_size = 0;
const int mempool = POOL_TYPE_COPY;
unsigned char *user_space_data = NULL;
- struct diag_md_session_t *session_info = NULL;
uint8_t hdlc_disabled;
if (!buf || len <= 0 || len > DIAG_MAX_RSP_SIZE) {
@@ -3108,13 +3163,7 @@
mutex_lock(&apps_data_mutex);
mutex_lock(&driver->hdlc_disable_mutex);
- mutex_lock(&driver->md_session_lock);
- session_info = diag_md_session_get_peripheral(APPS_DATA);
- if (session_info)
- hdlc_disabled = session_info->hdlc_disabled;
- else
- hdlc_disabled = driver->hdlc_disabled;
- mutex_unlock(&driver->md_session_lock);
+ hdlc_disabled = driver->p_hdlc_disabled[APPS_DATA];
if (hdlc_disabled)
ret = diag_process_apps_data_non_hdlc(user_space_data, len,
pkt_type);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 33048e1..6247503 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -49,6 +49,11 @@
#define STM_RSP_STATUS_INDEX 8
#define STM_RSP_NUM_BYTES 9
+struct diag_md_hdlc_reset_work {
+ int pid;
+ struct work_struct work;
+};
+
static int timestamp_switch;
module_param(timestamp_switch, int, 0644);
@@ -447,6 +452,7 @@
{
struct diag_md_session_t *session_info = NULL, *info = NULL;
uint8_t hdlc_disabled;
+
mutex_lock(&driver->md_session_lock);
info = diag_md_session_get_pid(pid);
session_info = (info) ? info :
@@ -456,6 +462,7 @@
else
hdlc_disabled = driver->hdlc_disabled;
mutex_unlock(&driver->md_session_lock);
+
if (hdlc_disabled)
pack_rsp_and_send(buf, len, pid);
else
@@ -1020,7 +1027,7 @@
int diag_process_apps_pkt(unsigned char *buf, int len, int pid)
{
int i, p_mask = 0;
- int mask_ret;
+ int mask_ret, peripheral = -EINVAL;
int write_len = 0;
unsigned char *temp = NULL;
struct diag_cmd_reg_entry_t entry;
@@ -1263,6 +1270,22 @@
info->hdlc_disabled = 1;
else
driver->hdlc_disabled = 1;
+ peripheral =
+ diag_md_session_match_pid_peripheral(pid, 0);
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ if (peripheral > 0 && info) {
+ if (peripheral & (1 << i))
+ driver->p_hdlc_disabled[i] =
+ info->hdlc_disabled;
+ else if (!diag_md_session_get_peripheral(i))
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ } else {
+ if (!diag_md_session_get_peripheral(i))
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ }
+ }
mutex_unlock(&driver->md_session_lock);
diag_update_md_clients(HDLC_SUPPORT_TYPE);
mutex_unlock(&driver->hdlc_disable_mutex);
@@ -1438,8 +1461,17 @@
pr_debug("diag: In %s, re-enabling HDLC encoding\n",
__func__);
mutex_lock(&driver->hdlc_disable_mutex);
- if (driver->md_session_mode == DIAG_MD_NONE)
+ if (driver->md_session_mode == DIAG_MD_NONE) {
driver->hdlc_disabled = 0;
+ /*
+ * HDLC encoding is re-enabled when
+ * there is logical/physical disconnection of diag
+ * to USB.
+ */
+ for (i = 0; i < NUM_MD_SESSIONS; i++)
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ }
mutex_unlock(&driver->hdlc_disable_mutex);
queue_work(driver->diag_wq,
&(driver->update_user_clients));
@@ -1454,6 +1486,7 @@
static void hdlc_reset_timer_start(int pid)
{
struct diag_md_session_t *info = NULL;
+
mutex_lock(&driver->md_session_lock);
info = diag_md_session_get_pid(pid);
if (!hdlc_timer_in_progress) {
@@ -1468,30 +1501,99 @@
mutex_unlock(&driver->md_session_lock);
}
+/*
+ * diag_timer_work_fn
+ * Queued in workqueue to protect md_session_info structure
+ *
+ * Update hdlc_disabled for each peripheral
+ * which are not in any md_session_info.
+ *
+ */
+static void diag_timer_work_fn(struct work_struct *work)
+{
+ int i = 0;
+ struct diag_md_session_t *session_info = NULL;
+
+ mutex_lock(&driver->hdlc_disable_mutex);
+ driver->hdlc_disabled = 0;
+ mutex_lock(&driver->md_session_lock);
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ session_info = diag_md_session_get_peripheral(i);
+ if (!session_info)
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ }
+ mutex_unlock(&driver->md_session_lock);
+ mutex_unlock(&driver->hdlc_disable_mutex);
+}
+
+/*
+ * diag_md_timer_work_fn
+ * Queued in workqueue to protect md_session_info structure
+ *
+ * Update hdlc_disabled for each peripheral
+ * which are in any md_session_info
+ *
+ */
+static void diag_md_timer_work_fn(struct work_struct *work)
+{
+ int peripheral = -EINVAL, i = 0;
+ struct diag_md_session_t *session_info = NULL;
+ struct diag_md_hdlc_reset_work *hdlc_work = container_of(work,
+ struct diag_md_hdlc_reset_work, work);
+
+ if (!hdlc_work)
+ return;
+
+ mutex_lock(&driver->hdlc_disable_mutex);
+ mutex_lock(&driver->md_session_lock);
+ session_info = diag_md_session_get_pid(hdlc_work->pid);
+ if (session_info)
+ session_info->hdlc_disabled = 0;
+ peripheral =
+ diag_md_session_match_pid_peripheral(hdlc_work->pid, 0);
+ if (peripheral > 0 && session_info) {
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ if (peripheral & (1 << i))
+ driver->p_hdlc_disabled[i] =
+ session_info->hdlc_disabled;
+ }
+ }
+ kfree(hdlc_work);
+ mutex_unlock(&driver->md_session_lock);
+ mutex_unlock(&driver->hdlc_disable_mutex);
+}
+
static void hdlc_reset_timer_func(unsigned long data)
{
pr_debug("diag: In %s, re-enabling HDLC encoding\n",
__func__);
+
if (hdlc_reset) {
- driver->hdlc_disabled = 0;
- queue_work(driver->diag_wq,
- &(driver->update_user_clients));
+ queue_work(driver->diag_wq, &(driver->diag_hdlc_reset_work));
+ queue_work(driver->diag_wq, &(driver->update_user_clients));
}
hdlc_timer_in_progress = 0;
}
void diag_md_hdlc_reset_timer_func(unsigned long pid)
{
- struct diag_md_session_t *session_info = NULL;
+ struct diag_md_hdlc_reset_work *hdlc_reset_work = NULL;
pr_debug("diag: In %s, re-enabling HDLC encoding\n",
__func__);
+ hdlc_reset_work = kmalloc(sizeof(*hdlc_reset_work), GFP_ATOMIC);
+ if (!hdlc_reset_work) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: Could not allocate hdlc_reset_work\n");
+ hdlc_timer_in_progress = 0;
+ return;
+ }
if (hdlc_reset) {
- session_info = diag_md_session_get_pid(pid);
- if (session_info)
- session_info->hdlc_disabled = 0;
- queue_work(driver->diag_wq,
- &(driver->update_md_clients));
+ hdlc_reset_work->pid = pid;
+ INIT_WORK(&hdlc_reset_work->work, diag_md_timer_work_fn);
+ queue_work(driver->diag_wq, &(hdlc_reset_work->work));
+ queue_work(driver->diag_wq, &(driver->update_md_clients));
}
hdlc_timer_in_progress = 0;
}
@@ -1499,7 +1601,7 @@
static void diag_hdlc_start_recovery(unsigned char *buf, int len,
int pid)
{
- int i;
+ int i, peripheral = -EINVAL;
static uint32_t bad_byte_counter;
unsigned char *start_ptr = NULL;
struct diag_pkt_frame_t *actual_pkt = NULL;
@@ -1532,6 +1634,24 @@
info->hdlc_disabled = 0;
else
driver->hdlc_disabled = 0;
+
+ peripheral =
+ diag_md_session_match_pid_peripheral(pid, 0);
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ if (peripheral > 0 && info) {
+ if (peripheral & (1 << i))
+ driver->p_hdlc_disabled[i] =
+ info->hdlc_disabled;
+ else if (
+ !diag_md_session_get_peripheral(i))
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ } else {
+ if (!diag_md_session_get_peripheral(i))
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ }
+ }
mutex_unlock(&driver->md_session_lock);
mutex_unlock(&driver->hdlc_disable_mutex);
diag_update_md_clients(HDLC_SUPPORT_TYPE);
@@ -1792,6 +1912,8 @@
INIT_LIST_HEAD(&driver->cmd_reg_list);
driver->cmd_reg_count = 0;
mutex_init(&driver->cmd_reg_mutex);
+ INIT_WORK(&(driver->diag_hdlc_reset_work),
+ diag_timer_work_fn);
for (i = 0; i < NUM_PERIPHERALS; i++) {
driver->feature[i].separate_cmd_rsp = 0;
diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c
index e9683e0..59e45a7 100644
--- a/drivers/char/diag/diagfwd_glink.c
+++ b/drivers/char/diag/diagfwd_glink.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -257,7 +257,8 @@
static void diag_state_open_glink(void *ctxt);
static void diag_state_close_glink(void *ctxt);
static int diag_glink_write(void *ctxt, unsigned char *buf, int len);
-static int diag_glink_read(void *ctxt, unsigned char *buf, int buf_len);
+static int diag_glink_read(void *ctxt, unsigned char *buf, int buf_len,
+ struct diagfwd_buf_t *fwd_buf);
static void diag_glink_queue_read(void *ctxt);
static struct diag_peripheral_ops glink_ops = {
@@ -320,7 +321,8 @@
return (int)(atomic_read(&info->diag_state));
}
-static int diag_glink_read(void *ctxt, unsigned char *buf, int buf_len)
+static int diag_glink_read(void *ctxt, unsigned char *buf, int buf_len,
+ struct diagfwd_buf_t *fwd_buf)
{
struct diag_glink_info *glink_info = NULL;
int ret_val = 0;
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 7908b82..7225dc2 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -311,7 +311,6 @@
int err = 0;
int write_len = 0, peripheral = 0;
unsigned char *write_buf = NULL;
- struct diag_md_session_t *session_info = NULL;
uint8_t hdlc_disabled = 0;
if (!fwd_info || !buf || len <= 0) {
@@ -344,13 +343,9 @@
diag_ws_release();
return;
}
- mutex_lock(&driver->md_session_lock);
- session_info = diag_md_session_get_peripheral(peripheral);
- if (session_info)
- hdlc_disabled = session_info->hdlc_disabled;
- else
- hdlc_disabled = driver->hdlc_disabled;
- mutex_unlock(&driver->md_session_lock);
+
+ hdlc_disabled = driver->p_hdlc_disabled[peripheral];
+
if (hdlc_disabled) {
/* The data is raw and and on APPS side HDLC is disabled */
if (!buf) {
@@ -611,7 +606,6 @@
int write_len = 0;
unsigned char *write_buf = NULL;
struct diagfwd_buf_t *temp_buf = NULL;
- struct diag_md_session_t *session_info = NULL;
uint8_t hdlc_disabled = 0;
if (!fwd_info || !buf || len <= 0) {
@@ -633,13 +627,9 @@
mutex_lock(&driver->hdlc_disable_mutex);
mutex_lock(&fwd_info->data_mutex);
- mutex_lock(&driver->md_session_lock);
- session_info = diag_md_session_get_peripheral(fwd_info->peripheral);
- if (session_info)
- hdlc_disabled = session_info->hdlc_disabled;
- else
- hdlc_disabled = driver->hdlc_disabled;
- mutex_unlock(&driver->md_session_lock);
+
+ hdlc_disabled = driver->p_hdlc_disabled[fwd_info->peripheral];
+
if (!driver->feature[fwd_info->peripheral].encode_hdlc) {
if (fwd_info->buf_1 && fwd_info->buf_1->data == buf) {
temp_buf = fwd_info->buf_1;
@@ -1189,8 +1179,11 @@
int index;
unsigned long flags;
+ if (!fwd_info)
+ return NULL;
spin_lock_irqsave(&fwd_info->write_buf_lock, flags);
- for (index = 0 ; index < NUM_WRITE_BUFFERS; index++) {
+ for (index = 0; (index < NUM_WRITE_BUFFERS) && fwd_info->buf_ptr[index];
+ index++) {
if (!atomic_read(&(fwd_info->buf_ptr[index]->in_busy))) {
atomic_set(&(fwd_info->buf_ptr[index]->in_busy), 1);
buf = fwd_info->buf_ptr[index]->data;
@@ -1286,11 +1279,10 @@
* Logging mode here is reflecting previous mode
* status and will be updated to new mode later.
*
- * Keeping the buffers busy for Memory Device Mode.
+ * Keeping the buffers busy for Memory Device and Multi Mode.
*/
- if ((driver->logging_mode != DIAG_USB_MODE) ||
- driver->usb_connected) {
+ if (driver->logging_mode != DIAG_USB_MODE) {
if (fwd_info->buf_1) {
atomic_set(&fwd_info->buf_1->in_busy, 0);
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
@@ -1626,7 +1618,8 @@
if (!fwd_info || !ptr)
return found;
spin_lock_irqsave(&fwd_info->write_buf_lock, flags);
- for (index = 0; index < NUM_WRITE_BUFFERS; index++) {
+ for (index = 0; (index < NUM_WRITE_BUFFERS) && fwd_info->buf_ptr[index];
+ index++) {
if (fwd_info->buf_ptr[index]->data == ptr) {
atomic_set(&fwd_info->buf_ptr[index]->in_busy, 0);
found = 1;
@@ -1701,7 +1694,8 @@
DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "issued a read p: %d t: %d buf: %pK\n",
fwd_info->peripheral, fwd_info->type, read_buf);
- err = fwd_info->p_ops->read(fwd_info->ctxt, read_buf, read_len);
+ err = fwd_info->p_ops->read(fwd_info->ctxt, read_buf, read_len,
+ temp_buf);
if (err)
goto fail_return;
diff --git a/drivers/char/diag/diagfwd_peripheral.h b/drivers/char/diag/diagfwd_peripheral.h
index 4124b17..d8e0b68 100644
--- a/drivers/char/diag/diagfwd_peripheral.h
+++ b/drivers/char/diag/diagfwd_peripheral.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -65,7 +65,8 @@
void (*open)(void *ctxt);
void (*close)(void *ctxt);
int (*write)(void *ctxt, unsigned char *buf, int len);
- int (*read)(void *ctxt, unsigned char *buf, int len);
+ int (*read)(void *ctxt, unsigned char *buf, int len,
+ struct diagfwd_buf_t *fwd_buf);
void (*queue_read)(void *ctxt);
};
diff --git a/drivers/char/diag/diagfwd_smd.c b/drivers/char/diag/diagfwd_smd.c
index 27433a7..d530204 100644
--- a/drivers/char/diag/diagfwd_smd.c
+++ b/drivers/char/diag/diagfwd_smd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -198,7 +198,8 @@
static void diag_state_close_smd(void *ctxt);
static void smd_notify(void *ctxt, unsigned int event);
static int diag_smd_write(void *ctxt, unsigned char *buf, int len);
-static int diag_smd_read(void *ctxt, unsigned char *buf, int buf_len);
+static int diag_smd_read(void *ctxt, unsigned char *buf, int buf_len,
+ struct diagfwd_buf_t *fwd_buf);
static void diag_smd_queue_read(void *ctxt);
static struct diag_peripheral_ops smd_ops = {
@@ -780,7 +781,8 @@
return 0;
}
-static int diag_smd_read(void *ctxt, unsigned char *buf, int buf_len)
+static int diag_smd_read(void *ctxt, unsigned char *buf, int buf_len,
+ struct diagfwd_buf_t *fwd_buf)
{
int pkt_len = 0;
int err = 0;
@@ -791,7 +793,7 @@
uint32_t read_len = 0;
struct diag_smd_info *smd_info = NULL;
- if (!ctxt || !buf || buf_len <= 0)
+ if (!ctxt || !buf || buf_len <= 0 || !fwd_buf)
return -EIO;
smd_info = (struct diag_smd_info *)ctxt;
@@ -810,7 +812,15 @@
diagfwd_channel_read_done(smd_info->fwd_ctxt, buf, 0);
return -ERESTARTSYS;
}
-
+ if (atomic_read(&fwd_buf->in_busy) == 0) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "%s closing read thread. Buffer is already marked freed p: %d t: %d buf_num: %d\n",
+ smd_info->name, GET_BUF_PERIPHERAL(fwd_buf->ctxt),
+ GET_BUF_TYPE(fwd_buf->ctxt),
+ GET_BUF_NUM(fwd_buf->ctxt));
+ diag_ws_release();
+ return 0;
+ }
/*
* Reset the buffers. Also release the wake source hold earlier.
*/
diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c
index f3c587d..401dbb0f 100644
--- a/drivers/char/diag/diagfwd_socket.c
+++ b/drivers/char/diag/diagfwd_socket.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -224,7 +224,8 @@
static void diag_state_open_socket(void *ctxt);
static void diag_state_close_socket(void *ctxt);
static int diag_socket_write(void *ctxt, unsigned char *buf, int len);
-static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len);
+static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len,
+ struct diagfwd_buf_t *fwd_buf);
static void diag_socket_queue_read(void *ctxt);
static void socket_init_work_fn(struct work_struct *work);
static int socket_ready_notify(struct notifier_block *nb,
@@ -1062,7 +1063,8 @@
}
}
-static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len)
+static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len,
+ struct diagfwd_buf_t *fwd_buf)
{
int err = 0;
int pkt_len = 0;
@@ -1082,7 +1084,7 @@
if (!info)
return -ENODEV;
- if (!buf || !ctxt || buf_len <= 0)
+ if (!buf || !ctxt || buf_len <= 0 || !fwd_buf)
return -EINVAL;
temp = buf;
@@ -1091,13 +1093,17 @@
err = wait_event_interruptible(info->read_wait_q,
(info->data_ready > 0) || (!info->hdl) ||
(atomic_read(&info->diag_state) == 0));
- if (err) {
- mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]);
- diagfwd_channel_read_done(info->fwd_ctxt, buf, 0);
- mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]);
- return -ERESTARTSYS;
+ if (err)
+ goto fail;
+ if (atomic_read(&fwd_buf->in_busy) == 0) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "%s closing read thread. Buffer is already marked freed p: %d t: %d buf_num: %d\n",
+ info->name, GET_BUF_PERIPHERAL(fwd_buf->ctxt),
+ GET_BUF_TYPE(fwd_buf->ctxt),
+ GET_BUF_NUM(fwd_buf->ctxt));
+ diag_ws_release();
+ return 0;
}
-
/*
* There is no need to continue reading over peripheral in this case.
* Release the wake source hold earlier.
@@ -1106,10 +1112,7 @@
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
"%s closing read thread. diag state is closed\n",
info->name);
- mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]);
- diagfwd_channel_read_done(info->fwd_ctxt, buf, 0);
- mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]);
- return 0;
+ goto fail;
}
if (!info->hdl) {
@@ -1211,7 +1214,7 @@
mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]);
diagfwd_channel_read_done(info->fwd_ctxt, buf, 0);
mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]);
- return -EIO;
+ return 0;
}
static int diag_socket_write(void *ctxt, unsigned char *buf, int len)
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index 44ce806..e278125 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -166,7 +166,7 @@
/* Enable secondary noise source on CPUs where it is present. */
/* Nehemiah stepping 8 and higher */
- if ((c->x86_model == 9) && (c->x86_mask > 7))
+ if ((c->x86_model == 9) && (c->x86_stepping > 7))
lo |= VIA_NOISESRC2;
/* Esther */
diff --git a/drivers/char/msm_smd_pkt.c b/drivers/char/msm_smd_pkt.c
index ff77cb2..c93c1da 100644
--- a/drivers/char/msm_smd_pkt.c
+++ b/drivers/char/msm_smd_pkt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, 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
@@ -76,6 +76,8 @@
struct work_struct packet_arrival_work;
spinlock_t pa_spinlock;
int ws_locked;
+
+ int sigs_updated;
};
@@ -356,9 +358,12 @@
mutex_lock(&smd_pkt_devp->ch_lock);
switch (cmd) {
case TIOCMGET:
- D_STATUS("%s TIOCMGET command on smd_pkt_dev id:%d\n",
- __func__, smd_pkt_devp->i);
+ smd_pkt_devp->sigs_updated = false;
ret = smd_tiocmget(smd_pkt_devp->ch);
+ D_STATUS("%s TIOCMGET command on smd_pkt_dev id:%d [%d]\n",
+ __func__, smd_pkt_devp->i, ret);
+ if (ret > 0)
+ ret = put_user((uint32_t)ret, (uint32_t __user *)arg);
break;
case TIOCMSET:
ret = get_user(val, (uint32_t *)arg);
@@ -668,6 +673,12 @@
D_POLL("%s sets POLLIN for smd_pkt_dev id: %d\n",
__func__, smd_pkt_devp->i);
}
+
+ if (smd_pkt_devp->sigs_updated) {
+ mask |= POLLPRI;
+ D_POLL("%s sets POLLPRI for smd_pkt_dev id: %d\n",
+ __func__, smd_pkt_devp->i);
+ }
mutex_unlock(&smd_pkt_devp->ch_lock);
return mask;
@@ -773,6 +784,9 @@
schedule_delayed_work(&loopback_work,
msecs_to_jiffies(1000));
break;
+ case SMD_EVENT_STATUS:
+ smd_pkt_devp->sigs_updated = true;
+ break;
}
}
@@ -1099,6 +1113,7 @@
smd_pkt_devp->ws_locked = 0;
}
spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags);
+ smd_pkt_devp->sigs_updated = false;
}
mutex_unlock(&smd_pkt_devp->tx_lock);
mutex_unlock(&smd_pkt_devp->rx_lock);
diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 19480bc..2f29ee1 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -14,6 +14,7 @@
config COMMON_CLK_GXBB
bool
depends on COMMON_CLK_AMLOGIC
+ select RESET_CONTROLLER
help
Support for the clock controller on AmLogic S905 devices, aka gxbb.
Say Y if you want peripherals and CPU frequency scaling to work.
diff --git a/drivers/clk/msm/Makefile b/drivers/clk/msm/Makefile
index 74c8055..a7b6636 100644
--- a/drivers/clk/msm/Makefile
+++ b/drivers/clk/msm/Makefile
@@ -19,7 +19,23 @@
obj-$(CONFIG_ARCH_MSM8937) += clock-gcc-8952.o
obj-$(CONFIG_ARCH_MSM8937) += clock-cpu-8939.o
obj-$(CONFIG_ARCH_MSM8937) += clock-rcgwr.o
+obj-$(CONFIG_ARCH_MSM8953) += clock-cpu-sdm632.o
+
+# MDM9607
+obj-$(CONFIG_ARCH_MDM9607) +=clock-gcc-mdm9607.o
+
+# MDM9650
+obj-$(CONFIG_ARCH_MDM9650) += clock-gcc-mdm9650.o
+
+# MSM8909
+obj-$(CONFIG_ARCH_MSM8909) += clock-rpm-8909.o
+obj-$(CONFIG_ARCH_MSM8909) += clock-gcc-8909.o
+
+# ACPU clock
+obj-$(CONFIG_ARCH_MSM8909) += clock-a7.o
+obj-$(CONFIG_ARCH_MDM9607) += clock-a7.o
+obj-$(CONFIG_ARCH_MDM9650) += clock-a7.o
endif
-obj-y += mdss/
+obj-y += mdss/
diff --git a/drivers/clk/msm/clock-a7.c b/drivers/clk/msm/clock-a7.c
new file mode 100644
index 0000000..4ee50ff
--- /dev/null
+++ b/drivers/clk/msm/clock-a7.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2013-2018, 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <soc/qcom/clock-local2.h>
+#include <dt-bindings/clock/msm-clocks-a7.h>
+
+#include "clock.h"
+
+static DEFINE_VDD_REGS_INIT(vdd_cpu, 1);
+
+static struct mux_div_clk a7ssmux = {
+ .ops = &rcg_mux_div_ops,
+ .safe_freq = 300000000,
+ .data = {
+ .max_div = 32,
+ .min_div = 2,
+ .is_half_divider = true,
+ },
+ .c = {
+ .dbg_name = "a7ssmux",
+ .ops = &clk_ops_mux_div_clk,
+ .vdd_class = &vdd_cpu,
+ CLK_INIT(a7ssmux.c),
+ },
+ .parents = (struct clk_src[8]) {},
+ .div_mask = BM(4, 0),
+ .src_mask = BM(10, 8) >> 8,
+ .src_shift = 8,
+ .en_mask = 1,
+};
+
+static struct clk_lookup clock_tbl_a7[] = {
+ CLK_LIST(a7ssmux),
+ CLK_LOOKUP_OF("cpu0_clk", a7ssmux, "fe805664.qcom,pm"),
+ CLK_LOOKUP_OF("cpu1_clk", a7ssmux, "fe805664.qcom,pm"),
+ CLK_LOOKUP_OF("cpu2_clk", a7ssmux, "fe805664.qcom,pm"),
+ CLK_LOOKUP_OF("cpu3_clk", a7ssmux, "fe805664.qcom,pm"),
+ CLK_LOOKUP_OF("cpu0_clk", a7ssmux, "8600664.qcom,pm"),
+ CLK_LOOKUP_OF("cpu1_clk", a7ssmux, "8600664.qcom,pm"),
+ CLK_LOOKUP_OF("cpu2_clk", a7ssmux, "8600664.qcom,pm"),
+ CLK_LOOKUP_OF("cpu3_clk", a7ssmux, "8600664.qcom,pm"),
+};
+
+static void print_opp_table(int a7_cpu)
+{
+ struct dev_pm_opp *oppfmax, *oppfmin;
+ unsigned long apc0_fmax = a7ssmux.c.fmax[a7ssmux.c.num_fmax - 1];
+ unsigned long apc0_fmin = a7ssmux.c.fmax[1];
+
+ rcu_read_lock();
+ oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a7_cpu), apc0_fmax,
+ true);
+ oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a7_cpu), apc0_fmin,
+ true);
+
+ /* One time information during boot. */
+ pr_info("clock_cpu: a7: OPP voltage for %lu: %ld\n", apc0_fmin,
+ dev_pm_opp_get_voltage(oppfmin));
+ pr_info("clock_cpu: a7: OPP voltage for %lu: %ld\n", apc0_fmax,
+ dev_pm_opp_get_voltage(oppfmax));
+
+ rcu_read_unlock();
+}
+
+static int add_opp(struct clk *c, struct device *dev,
+ unsigned long max_rate)
+{
+ unsigned long rate = 0;
+ int level;
+ int uv;
+ long ret;
+ bool first = true;
+ int j = 1;
+
+ while (1) {
+ rate = c->fmax[j++];
+
+ level = find_vdd_level(c, rate);
+ if (level <= 0) {
+ pr_warn("clock-cpu: no corner for %lu\n", rate);
+ return -EINVAL;
+ }
+
+ uv = c->vdd_class->vdd_uv[level];
+ if (uv < 0) {
+ pr_warn("clock-cpu: no uv for %lu\n", rate);
+ return -EINVAL;
+ }
+
+ ret = dev_pm_opp_add(dev, rate, uv);
+ if (ret) {
+ pr_warn("clock-cpu: failed to add OPP for %lu\n",
+ rate);
+ return ret;
+ }
+
+ /*
+ * The OPP pair for the lowest and highest frequency for
+ * each device that we're populating. This is important since
+ * this information will be used by thermal mitigation and the
+ * scheduler.
+ */
+ if ((rate >= max_rate) || first) {
+ if (first)
+ first = false;
+ else
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void populate_opp_table(struct platform_device *pdev)
+{
+ struct platform_device *apc_dev;
+ struct device_node *apc_node;
+ struct device *dev;
+ unsigned long apc_fmax;
+ int cpu, a7_cpu = 0;
+
+ apc_node = of_parse_phandle(pdev->dev.of_node, "cpu-vdd-supply", 0);
+ if (!apc_node) {
+ pr_err("can't find the apc0 dt node.\n");
+ return;
+ }
+
+ apc_dev = of_find_device_by_node(apc_node);
+ if (!apc_dev) {
+ pr_err("can't find the apc0 device node.\n");
+ return;
+ }
+
+ apc_fmax = a7ssmux.c.fmax[a7ssmux.c.num_fmax - 1];
+
+ for_each_possible_cpu(cpu) {
+ a7_cpu = cpu;
+ dev = get_cpu_device(cpu);
+ if (!dev) {
+ pr_err("can't find cpu device for attaching OPPs\n");
+ return;
+ }
+
+ WARN(add_opp(&a7ssmux.c, dev, apc_fmax),
+ "Failed to add OPP levels for A7\n");
+ }
+
+ /* One time print during bootup */
+ pr_info("clock-a7: OPP tables populated (cpu %d)\n", a7_cpu);
+
+ print_opp_table(a7_cpu);
+}
+
+static int of_get_fmax_vdd_class(struct platform_device *pdev, struct clk *c,
+ char *prop_name)
+{
+ struct device_node *of = pdev->dev.of_node;
+ int prop_len, i;
+ struct clk_vdd_class *vdd = c->vdd_class;
+ u32 *array;
+
+ if (!of_find_property(of, prop_name, &prop_len)) {
+ dev_err(&pdev->dev, "missing %s\n", prop_name);
+ return -EINVAL;
+ }
+
+ prop_len /= sizeof(u32);
+ if (prop_len % 2) {
+ dev_err(&pdev->dev, "bad length %d\n", prop_len);
+ return -EINVAL;
+ }
+
+ prop_len /= 2;
+ vdd->level_votes = devm_kzalloc(&pdev->dev, prop_len * sizeof(int),
+ GFP_KERNEL);
+ if (!vdd->level_votes)
+ return -ENOMEM;
+
+ vdd->vdd_uv = devm_kzalloc(&pdev->dev, prop_len * sizeof(int),
+ GFP_KERNEL);
+ if (!vdd->vdd_uv)
+ return -ENOMEM;
+
+ c->fmax = devm_kzalloc(&pdev->dev, prop_len * sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!c->fmax)
+ return -ENOMEM;
+
+ array = devm_kzalloc(&pdev->dev,
+ prop_len * sizeof(u32) * 2, GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ of_property_read_u32_array(of, prop_name, array, prop_len * 2);
+ for (i = 0; i < prop_len; i++) {
+ c->fmax[i] = array[2 * i];
+ vdd->vdd_uv[i] = array[2 * i + 1];
+ }
+
+ devm_kfree(&pdev->dev, array);
+ vdd->num_levels = prop_len;
+ vdd->cur_level = prop_len;
+ vdd->use_max_uV = true;
+ c->num_fmax = prop_len;
+ return 0;
+}
+
+static void get_speed_bin(struct platform_device *pdev, int *bin, int *version)
+{
+ struct resource *res;
+ void __iomem *base;
+ u32 pte_efuse, redundant_sel, valid;
+
+ *bin = 0;
+ *version = 0;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+ if (!res) {
+ dev_info(&pdev->dev,
+ "No speed/PVS binning available. Defaulting to 0!\n");
+ return;
+ }
+
+ base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!base) {
+ dev_warn(&pdev->dev,
+ "Unable to read efuse data. Defaulting to 0!\n");
+ return;
+ }
+
+ pte_efuse = readl_relaxed(base);
+ devm_iounmap(&pdev->dev, base);
+
+ redundant_sel = (pte_efuse >> 24) & 0x7;
+ *bin = pte_efuse & 0x7;
+ valid = (pte_efuse >> 3) & 0x1;
+ *version = (pte_efuse >> 4) & 0x3;
+
+ if (redundant_sel == 1)
+ *bin = (pte_efuse >> 27) & 0x7;
+
+ if (!valid) {
+ dev_info(&pdev->dev, "Speed bin not set. Defaulting to 0!\n");
+ *bin = 0;
+ } else {
+ dev_info(&pdev->dev, "Speed bin: %d\n", *bin);
+ }
+
+ dev_info(&pdev->dev, "PVS version: %d\n", *version);
+
+}
+
+static void get_speed_bin_b(struct platform_device *pdev, int *bin,
+ int *version)
+{
+ struct resource *res;
+ void __iomem *base;
+ u32 pte_efuse, shift = 2, mask = 0x7;
+
+ *bin = 0;
+ *version = 0;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse1");
+ if (res) {
+ base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (base) {
+ pte_efuse = readl_relaxed(base);
+ devm_iounmap(&pdev->dev, base);
+
+ *version = (pte_efuse >> 18) & 0x3;
+ if (!(*version)) {
+ *bin = (pte_efuse >> 23) & 0x3;
+ if (*bin) {
+ dev_info(&pdev->dev, "Speed bin: %d PVS Version: %d\n",
+ *bin, *version);
+ return;
+ }
+ }
+ } else {
+ dev_warn(&pdev->dev,
+ "Unable to read efuse1 data. Defaulting to 0!\n");
+ return;
+ }
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+ if (!res) {
+ dev_info(&pdev->dev,
+ "No speed/PVS binning available. Defaulting to 0!\n");
+ return;
+ }
+ base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!base) {
+ dev_warn(&pdev->dev,
+ "Unable to read efuse data. Defaulting to 0!\n");
+ return;
+ }
+
+ pte_efuse = readl_relaxed(base);
+ devm_iounmap(&pdev->dev, base);
+
+ *bin = (pte_efuse >> shift) & mask;
+
+ dev_info(&pdev->dev, "Speed bin: %d PVS Version: %d\n", *bin,
+ *version);
+}
+
+static int of_get_clk_src(struct platform_device *pdev, struct clk_src *parents)
+{
+ struct device_node *of = pdev->dev.of_node;
+ int num_parents, i, j, index;
+ struct clk *c;
+ char clk_name[] = "clk-x";
+
+ num_parents = of_property_count_strings(of, "clock-names");
+ if (num_parents <= 0 || num_parents > 8) {
+ dev_err(&pdev->dev, "missing clock-names\n");
+ return -EINVAL;
+ }
+
+ j = 0;
+ for (i = 0; i < 8; i++) {
+ snprintf(clk_name, ARRAY_SIZE(clk_name), "clk-%d", i);
+ index = of_property_match_string(of, "clock-names", clk_name);
+ if (IS_ERR_VALUE(index))
+ continue;
+
+ parents[j].sel = i;
+ parents[j].src = c = devm_clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(c)) {
+ if (c != ERR_PTR(-EPROBE_DEFER))
+ dev_err(&pdev->dev, "clk_get: %s\n fail",
+ clk_name);
+ return PTR_ERR(c);
+ }
+ j++;
+ }
+
+ return num_parents;
+}
+
+static struct platform_device *cpu_clock_a7_dev;
+
+static int clock_a7_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int speed_bin = 0, version = 0, rc, cpu;
+ unsigned long rate, aux_rate;
+ struct clk *aux_clk, *main_pll;
+ char prop_name[] = "qcom,speedX-bin-vX";
+ const void *prop;
+ bool compat_bin = false;
+ bool compat_bin2 = false;
+ bool opp_enable;
+
+ compat_bin = of_device_is_compatible(pdev->dev.of_node,
+ "qcom,clock-a53-8916");
+ compat_bin2 = of_device_is_compatible(pdev->dev.of_node,
+ "qcom,clock-a7-mdm9607");
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rcg-base");
+ if (!res) {
+ dev_err(&pdev->dev, "missing rcg-base\n");
+ return -EINVAL;
+ }
+ a7ssmux.base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!a7ssmux.base) {
+ dev_err(&pdev->dev, "ioremap failed for rcg-base\n");
+ return -ENOMEM;
+ }
+
+ vdd_cpu.regulator[0] = devm_regulator_get(&pdev->dev, "cpu-vdd");
+ if (IS_ERR(vdd_cpu.regulator[0])) {
+ if (PTR_ERR(vdd_cpu.regulator[0]) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "unable to get regulator\n");
+ return PTR_ERR(vdd_cpu.regulator[0]);
+ }
+
+ rc = of_get_clk_src(pdev, a7ssmux.parents);
+ if (IS_ERR_VALUE(rc))
+ return rc;
+
+ a7ssmux.num_parents = rc;
+
+ /* Override the existing safe operating frequency */
+ prop = of_get_property(pdev->dev.of_node, "qcom,safe-freq", NULL);
+ if (prop)
+ a7ssmux.safe_freq = of_read_ulong(prop, 1);
+
+ if (compat_bin || compat_bin2)
+ get_speed_bin_b(pdev, &speed_bin, &version);
+ else
+ get_speed_bin(pdev, &speed_bin, &version);
+
+ snprintf(prop_name, ARRAY_SIZE(prop_name),
+ "qcom,speed%d-bin-v%d", speed_bin, version);
+ rc = of_get_fmax_vdd_class(pdev, &a7ssmux.c, prop_name);
+ if (rc) {
+ /* Fall back to most conservative PVS table */
+ dev_err(&pdev->dev, "Unable to load voltage plan %s!\n",
+ prop_name);
+ rc = of_get_fmax_vdd_class(pdev, &a7ssmux.c,
+ "qcom,speed0-bin-v0");
+ if (rc) {
+ dev_err(&pdev->dev,
+ "Unable to load safe voltage plan\n");
+ return rc;
+ }
+ dev_info(&pdev->dev, "Safe voltage plan loaded.\n");
+ }
+
+ rc = of_msm_clock_register(pdev->dev.of_node,
+ clock_tbl_a7, ARRAY_SIZE(clock_tbl_a7));
+ if (rc) {
+ dev_err(&pdev->dev, "msm_clock_register failed\n");
+ return rc;
+ }
+
+ /* Force a PLL reconfiguration */
+ aux_clk = a7ssmux.parents[0].src;
+ main_pll = a7ssmux.parents[1].src;
+
+ aux_rate = clk_get_rate(aux_clk);
+ rate = clk_get_rate(&a7ssmux.c);
+ clk_set_rate(&a7ssmux.c, aux_rate);
+ clk_set_rate(main_pll, clk_round_rate(main_pll, 1));
+ clk_set_rate(&a7ssmux.c, rate);
+
+ /*
+ * We don't want the CPU clocks to be turned off at late init
+ * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
+ * refcount of these clocks. Any cpufreq/hotplug manager can assume
+ * that the clocks have already been prepared and enabled by the time
+ * they take over.
+ */
+ get_online_cpus();
+ for_each_online_cpu(cpu)
+ WARN(clk_prepare_enable(&a7ssmux.c),
+ "Unable to turn on CPU clock");
+ put_online_cpus();
+
+ opp_enable = of_property_read_bool(pdev->dev.of_node,
+ "qcom,enable-opp");
+ if (opp_enable)
+ cpu_clock_a7_dev = pdev;
+
+ return 0;
+}
+
+static const struct of_device_id clock_a7_match_table[] = {
+ {.compatible = "qcom,clock-a53-8916"},
+ {.compatible = "qcom,clock-a7-9650"},
+ {.compatible = "qcom,clock-a7-mdm9607"},
+ {.compatible = "qcom,clock-a7-sdx20"},
+ {}
+};
+
+static struct platform_driver clock_a7_driver = {
+ .probe = clock_a7_probe,
+ .driver = {
+ .name = "clock-a7",
+ .of_match_table = clock_a7_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init clock_a7_init(void)
+{
+ return platform_driver_register(&clock_a7_driver);
+}
+arch_initcall(clock_a7_init);
+
+/* CPU devices are not currently available in arch_initcall */
+static int __init cpu_clock_a7_init_opp(void)
+{
+ if (cpu_clock_a7_dev)
+ populate_opp_table(cpu_clock_a7_dev);
+ return 0;
+}
+module_init(cpu_clock_a7_init_opp);
diff --git a/drivers/clk/msm/clock-alpha-pll.c b/drivers/clk/msm/clock-alpha-pll.c
index dbe8d8e..37e34d5 100644
--- a/drivers/clk/msm/clock-alpha-pll.c
+++ b/drivers/clk/msm/clock-alpha-pll.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -774,6 +774,13 @@
writel_relaxed(regval, USER_CTL_HI_REG(pll));
}
+ if (masks->cal_l_val_mask && pll->cal_l_val) {
+ regval = readl_relaxed(USER_CTL_HI_REG(pll));
+ regval &= ~masks->cal_l_val_mask;
+ regval |= pll->cal_l_val;
+ writel_relaxed(regval, USER_CTL_HI_REG(pll));
+ }
+
if (masks->test_ctl_lo_mask) {
regval = readl_relaxed(TEST_CTL_LO_REG(pll));
regval &= ~masks->test_ctl_lo_mask;
diff --git a/drivers/clk/msm/clock-cpu-sdm632.c b/drivers/clk/msm/clock-cpu-sdm632.c
new file mode 100644
index 0000000..b59739a
--- /dev/null
+++ b/drivers/clk/msm/clock-cpu-sdm632.c
@@ -0,0 +1,1169 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/suspend.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/pm.h>
+#include <soc/qcom/clock-pll.h>
+#include <soc/qcom/clock-alpha-pll.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+
+#include <dt-bindings/clock/msm-clocks-8953.h>
+
+#include "clock.h"
+
+#define APCS_PLL_MODE 0x0
+#define APCS_PLL_L_VAL 0x8
+#define APCS_PLL_ALPHA_VAL 0x10
+#define APCS_PLL_USER_CTL 0x18
+#define APCS_PLL_CONFIG_CTL_LO 0x20
+#define APCS_PLL_CONFIG_CTL_HI 0x24
+#define APCS_PLL_STATUS 0x28
+#define APCS_PLL_TEST_CTL_LO 0x30
+#define APCS_PLL_TEST_CTL_HI 0x34
+
+#define PLL_MODE(x) (*(x)->base + (unsigned long) (x)->mode_reg)
+
+#define GLB_DIAG 0x0b11101c
+
+static struct clk_ops clk_ops_variable_rate;
+
+DEFINE_EXT_CLK(xo_a_clk, NULL);
+DEFINE_VDD_REGS_INIT(vdd_cpu, 1);
+
+enum {
+ APCS_C0_PLL_BASE,
+ APCS_C1_PLL_BASE,
+ APCS_CCI_PLL_BASE,
+ N_PLL_BASES,
+};
+
+enum vdd_mx_pll_levels {
+ VDD_MX_OFF,
+ VDD_MX_MIN,
+ VDD_MX_LOWER,
+ VDD_MX_SVS,
+ VDD_MX_NUM,
+};
+
+static int vdd_pll_levels[] = {
+ RPM_REGULATOR_LEVEL_NONE, /* VDD_PLL_OFF */
+ RPM_REGULATOR_LEVEL_MIN_SVS, /* VDD_PLL_MIN */
+ RPM_REGULATOR_LEVEL_LOW_SVS, /* VDD_PLL_LOW_SVS */
+ RPM_REGULATOR_LEVEL_SVS, /* VDD_PLL_SVS */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_mx, VDD_MX_NUM, 1,
+ vdd_pll_levels, NULL);
+
+#define VDD_MX_FMAX_MAP2(l1, f1, l2, f2) \
+ .vdd_class = &vdd_mx, \
+ .fmax = (unsigned long[VDD_MX_NUM]) { \
+ [VDD_MX_##l1] = (f1), \
+ [VDD_MX_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_MX_NUM
+
+#define VDD_MX_FMAX_MAP1(l1, f1) \
+ .vdd_class = &vdd_mx, \
+ .fmax = (unsigned long[VDD_MX_NUM]) { \
+ [VDD_MX_##l1] = (f1), \
+ }, \
+ .num_fmax = VDD_MX_NUM
+
+static void __iomem *virt_bases[N_PLL_BASES];
+
+/* Power PLL */
+static struct pll_clk apcs_c0_pll = {
+ .mode_reg = (void __iomem *)APCS_PLL_MODE,
+ .l_reg = (void __iomem *)APCS_PLL_L_VAL,
+ .alpha_reg = (void __iomem *)APCS_PLL_ALPHA_VAL,
+ .config_reg = (void __iomem *)APCS_PLL_USER_CTL,
+ .config_ctl_reg = (void __iomem *)APCS_PLL_CONFIG_CTL_LO,
+ .config_ctl_hi_reg = (void __iomem *)APCS_PLL_CONFIG_CTL_HI,
+ .test_ctl_lo_reg = (void __iomem *)APCS_PLL_TEST_CTL_LO,
+ .test_ctl_hi_reg = (void __iomem *)APCS_PLL_TEST_CTL_HI,
+ .status_reg = (void __iomem *)APCS_PLL_MODE,
+ .init_test_ctl = true,
+ .test_ctl_dbg = true,
+ .masks = {
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+ .lock_mask = BIT(31),
+ },
+ .vals = {
+ .config_ctl_val = 0x200D4828,
+ .config_ctl_hi_val = 0x006,
+ .test_ctl_hi_val = 0x00004000,
+ .test_ctl_lo_val = 0x1C000000,
+ },
+ .max_rate = 1785600000UL,
+ .min_rate = 614400000UL,
+ .src_rate = 19200000UL,
+ .base = &virt_bases[APCS_C0_PLL_BASE],
+ .c = {
+ .parent = &xo_a_clk.c,
+ .dbg_name = "apcs_c0_pll",
+ .ops = &clk_ops_variable_rate,
+ VDD_MX_FMAX_MAP2(MIN, 1200000000UL, LOWER, 2400000000UL),
+ CLK_INIT(apcs_c0_pll.c),
+ },
+};
+
+/* Perf PLL */
+static struct pll_clk apcs_c1_pll = {
+ .mode_reg = (void __iomem *)APCS_PLL_MODE,
+ .l_reg = (void __iomem *)APCS_PLL_L_VAL,
+ .alpha_reg = (void __iomem *)APCS_PLL_ALPHA_VAL,
+ .config_reg = (void __iomem *)APCS_PLL_USER_CTL,
+ .config_ctl_reg = (void __iomem *)APCS_PLL_CONFIG_CTL_LO,
+ .config_ctl_hi_reg = (void __iomem *)APCS_PLL_CONFIG_CTL_HI,
+ .test_ctl_lo_reg = (void __iomem *)APCS_PLL_TEST_CTL_LO,
+ .test_ctl_hi_reg = (void __iomem *)APCS_PLL_TEST_CTL_HI,
+ .status_reg = (void __iomem *)APCS_PLL_MODE,
+ .init_test_ctl = true,
+ .test_ctl_dbg = true,
+ .masks = {
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+ .lock_mask = BIT(31),
+ },
+ .vals = {
+ .config_ctl_val = 0x200D4828,
+ .config_ctl_hi_val = 0x006,
+ .test_ctl_hi_val = 0x00004000,
+ .test_ctl_lo_val = 0x1C000000,
+ },
+ .max_rate = 2054400000UL,
+ .min_rate = 633600000UL,
+ .src_rate = 19200000UL,
+ .base = &virt_bases[APCS_C1_PLL_BASE],
+ .c = {
+ .parent = &xo_a_clk.c,
+ .dbg_name = "apcs_c1_pll",
+ .ops = &clk_ops_variable_rate,
+ VDD_MX_FMAX_MAP2(MIN, 1200000000UL, LOWER, 2400000000UL),
+ CLK_INIT(apcs_c1_pll.c),
+ },
+};
+
+static struct alpha_pll_masks pll_masks_p = {
+ .lock_mask = BIT(31),
+ .update_mask = BIT(22),
+ .output_mask = 0xf,
+ .vco_mask = BM(21, 20) >> 20,
+ .vco_shift = 20,
+ .alpha_en_mask = BIT(24),
+ .cal_l_val_mask = BM(31, 16),
+};
+
+static struct alpha_pll_vco_tbl apcs_cci_pll_vco[] = {
+ VCO(2, 500000000, 1000000000),
+};
+
+static struct alpha_pll_clk apcs_cci_pll = {
+ .masks = &pll_masks_p,
+ .offset = 0x1D0000,
+ .vco_tbl = apcs_cci_pll_vco,
+ .num_vco = ARRAY_SIZE(apcs_cci_pll_vco),
+ .enable_config = 0x8, /* Early output */
+ .slew = true,
+ .config_ctl_val = 0x4001055b,
+ .cal_l_val = 0x27 << 16, /* Mid of VCO mode - 748.8MHz */
+ .base = &virt_bases[APCS_CCI_PLL_BASE],
+ .c = {
+ .parent = &xo_a_clk.c,
+ .rate = 787200000,
+ .dbg_name = "apcs_cci_pll",
+ .ops = &clk_ops_dyna_alpha_pll,
+ /* TODO: FMAX */
+ VDD_MX_FMAX_MAP1(SVS, 1000000000UL),
+ CLK_INIT(apcs_cci_pll.c),
+ },
+};
+
+enum {
+ A53SS_MUX_PERF,
+ A53SS_MUX_PWR,
+ A53SS_MUX_CCI,
+ A53SS_MUX_NUM,
+};
+
+static const char * const pll_names[] = { "c1", "c0", "cci" };
+static const char * const mux_names[] = { "c1", "c0", "cci" };
+
+struct a53_cpu_clk {
+ u32 cpu_reg_mask;
+ cpumask_t cpumask;
+ bool hw_low_power_ctrl;
+ struct pm_qos_request req;
+ struct clk c;
+ struct latency_level latency_lvl;
+ s32 cpu_latency_no_l2_pc_us;
+};
+
+static struct mux_div_clk a53ssmux_perf = {
+ .ops = &rcg_mux_div_ops,
+ .data = {
+ .max_div = 32,
+ .min_div = 2,
+ .is_half_divider = true,
+ },
+ .c = {
+ .dbg_name = "a53ssmux_perf",
+ .ops = &clk_ops_mux_div_clk,
+ CLK_INIT(a53ssmux_perf.c),
+ },
+ .div_mask = BM(4, 0),
+ .src_mask = BM(10, 8) >> 8,
+ .src_shift = 8,
+ MUX_SRC_LIST(
+ { &apcs_c1_pll.c, 5},
+ ),
+};
+
+static struct mux_div_clk a53ssmux_pwr = {
+ .ops = &rcg_mux_div_ops,
+ .data = {
+ .max_div = 32,
+ .min_div = 2,
+ .is_half_divider = true,
+ },
+ .c = {
+ .dbg_name = "a53ssmux_pwr",
+ .ops = &clk_ops_mux_div_clk,
+ CLK_INIT(a53ssmux_pwr.c),
+ },
+ .div_mask = BM(4, 0),
+ .src_mask = BM(10, 8) >> 8,
+ .src_shift = 8,
+ MUX_SRC_LIST(
+ { &apcs_c0_pll.c, 5},
+ ),
+};
+
+static struct mux_div_clk a53ssmux_cci = {
+ .ops = &rcg_mux_div_ops,
+ .data = {
+ .max_div = 32,
+ .min_div = 2,
+ .is_half_divider = true,
+ },
+ .c = {
+ .dbg_name = "a53ssmux_cci",
+ .ops = &clk_ops_mux_div_clk,
+ CLK_INIT(a53ssmux_cci.c),
+ },
+ .div_mask = BM(4, 0),
+ .src_mask = BM(10, 8) >> 8,
+ .src_shift = 8,
+ MUX_SRC_LIST(
+ { &apcs_cci_pll.c, 5},
+ ),
+};
+
+static struct a53_cpu_clk a53_pwr_clk;
+static struct a53_cpu_clk a53_perf_clk;
+static struct a53_cpu_clk a53_cci_clk;
+
+static void do_nothing(void *unused) { }
+
+static inline struct a53_cpu_clk *to_a53_cpu_clk(struct clk *c)
+{
+ return container_of(c, struct a53_cpu_clk, c);
+}
+
+static enum handoff a53_cpu_clk_handoff(struct clk *c)
+{
+ c->rate = clk_get_rate(c->parent);
+ return HANDOFF_DISABLED_CLK;
+}
+
+static long a53_cpu_clk_round_rate(struct clk *c, unsigned long rate)
+{
+ return clk_round_rate(c->parent, rate);
+}
+
+static int a53_cpu_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ int ret = 0;
+ struct a53_cpu_clk *cpuclk = to_a53_cpu_clk(c);
+ bool hw_low_power_ctrl = cpuclk->hw_low_power_ctrl;
+
+ /*
+ * If hardware control of the clock tree is enabled during power
+ * collapse, setup a PM QOS request to prevent power collapse and
+ * wake up one of the CPUs in this clock domain, to ensure software
+ * control while the clock rate is being switched.
+ */
+ if (hw_low_power_ctrl) {
+ memset(&cpuclk->req, 0, sizeof(cpuclk->req));
+ cpumask_copy(&cpuclk->req.cpus_affine,
+ (const struct cpumask *)&cpuclk->cpumask);
+ cpuclk->req.type = PM_QOS_REQ_AFFINE_CORES;
+ pm_qos_add_request(&cpuclk->req, PM_QOS_CPU_DMA_LATENCY,
+ cpuclk->cpu_latency_no_l2_pc_us - 1);
+ smp_call_function_any(&cpuclk->cpumask, do_nothing,
+ NULL, 1);
+ }
+
+ ret = clk_set_rate(c->parent, rate);
+
+ /* Remove PM QOS request */
+ if (hw_low_power_ctrl)
+ pm_qos_remove_request(&cpuclk->req);
+
+ return ret;
+}
+
+static void __iomem *variable_pll_list_registers(struct clk *c, int n,
+ struct clk_register_data **regs, u32 *size)
+{
+ struct pll_clk *pll = to_pll_clk(c);
+ static struct clk_register_data data[] = {
+ {"MODE", 0x0},
+ {"L", 0x8},
+ {"ALPHA", 0x10},
+ {"USER_CTL", 0x18},
+ {"CONFIG_CTL_LO", 0x20},
+ {"CONFIG_CTL_HI", 0x24},
+ {"STATUS", 0x28},
+ };
+ if (n)
+ return ERR_PTR(-EINVAL);
+
+ *regs = data;
+ *size = ARRAY_SIZE(data);
+ return PLL_MODE(pll);
+}
+
+static const struct clk_ops clk_ops_cpu = {
+ .set_rate = a53_cpu_clk_set_rate,
+ .round_rate = a53_cpu_clk_round_rate,
+ .handoff = a53_cpu_clk_handoff,
+};
+
+static struct a53_cpu_clk a53_perf_clk = {
+ .cpu_reg_mask = 0x103,
+ .latency_lvl = {
+ .affinity_level = LPM_AFF_LVL_L2,
+ .reset_level = LPM_RESET_LVL_GDHS,
+ .level_name = "perf",
+ },
+ .cpu_latency_no_l2_pc_us = 280,
+ .c = {
+ .parent = &a53ssmux_perf.c,
+ .ops = &clk_ops_cpu,
+ .vdd_class = &vdd_cpu,
+ .dbg_name = "a53_perf_clk",
+ CLK_INIT(a53_perf_clk.c),
+ },
+};
+
+static struct a53_cpu_clk a53_pwr_clk = {
+ .cpu_reg_mask = 0x3,
+ .latency_lvl = {
+ .affinity_level = LPM_AFF_LVL_L2,
+ .reset_level = LPM_RESET_LVL_GDHS,
+ .level_name = "pwr",
+ },
+ .cpu_latency_no_l2_pc_us = 280,
+ .c = {
+ .parent = &a53ssmux_pwr.c,
+ .ops = &clk_ops_cpu,
+ .vdd_class = &vdd_cpu,
+ .dbg_name = "a53_pwr_clk",
+ CLK_INIT(a53_pwr_clk.c),
+ },
+};
+
+static struct a53_cpu_clk a53_cci_clk = {
+ .c = {
+ .parent = &a53ssmux_cci.c,
+ .ops = &clk_ops_cpu,
+ .vdd_class = &vdd_cpu,
+ .dbg_name = "a53_cci_clk",
+ CLK_INIT(a53_cci_clk.c),
+ },
+};
+
+static void __iomem *meas_base;
+
+static struct measure_clk apc0_m_clk = {
+ .c = {
+ .ops = &clk_ops_empty,
+ .dbg_name = "apc0_m_clk",
+ CLK_INIT(apc0_m_clk.c),
+ },
+};
+
+static struct measure_clk apc1_m_clk = {
+ .c = {
+ .ops = &clk_ops_empty,
+ .dbg_name = "apc1_m_clk",
+ CLK_INIT(apc1_m_clk.c),
+ },
+};
+
+static struct measure_clk cci_m_clk = {
+ .c = {
+ .ops = &clk_ops_empty,
+ .dbg_name = "cci_m_clk",
+ CLK_INIT(cci_m_clk.c),
+ },
+};
+
+static struct mux_clk cpu_debug_ter_mux = {
+ .ops = &mux_reg_ops,
+ .mask = 0x3,
+ .shift = 8,
+ MUX_SRC_LIST(
+ { &apc0_m_clk.c, 0},
+ { &apc1_m_clk.c, 1},
+ { &cci_m_clk.c, 2},
+ ),
+ .base = &meas_base,
+ .c = {
+ .dbg_name = "cpu_debug_ter_mux",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(cpu_debug_ter_mux.c),
+ },
+};
+
+static struct mux_clk cpu_debug_sec_mux = {
+ .ops = &mux_reg_ops,
+ .mask = 0x7,
+ .shift = 12,
+ MUX_SRC_LIST(
+ { &cpu_debug_ter_mux.c, 0},
+ ),
+ MUX_REC_SRC_LIST(
+ &cpu_debug_ter_mux.c,
+ ),
+ .base = &meas_base,
+ .c = {
+ .dbg_name = "cpu_debug_sec_mux",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(cpu_debug_sec_mux.c),
+ },
+};
+
+static struct mux_clk cpu_debug_pri_mux = {
+ .ops = &mux_reg_ops,
+ .mask = 0x3,
+ .shift = 16,
+ MUX_SRC_LIST(
+ { &cpu_debug_sec_mux.c, 0},
+ ),
+ MUX_REC_SRC_LIST(
+ &cpu_debug_sec_mux.c,
+ ),
+ .base = &meas_base,
+ .c = {
+ .dbg_name = "cpu_debug_pri_mux",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(cpu_debug_pri_mux.c),
+ },
+};
+
+static struct clk_lookup a53_cpu_clocks[] = {
+ /* PLLs */
+ CLK_LIST(apcs_c0_pll),
+ CLK_LIST(apcs_c1_pll),
+ CLK_LIST(apcs_cci_pll),
+
+ /* Muxes */
+ CLK_LIST(a53ssmux_pwr),
+ CLK_LIST(a53ssmux_perf),
+ CLK_LIST(a53ssmux_cci),
+
+ /* CPU clocks */
+ CLK_LIST(a53_pwr_clk),
+ CLK_LIST(a53_perf_clk),
+ CLK_LIST(a53_cci_clk),
+
+ /* debug clocks */
+ CLK_LIST(apc0_m_clk),
+ CLK_LIST(apc1_m_clk),
+ CLK_LIST(cci_m_clk),
+ CLK_LIST(cpu_debug_pri_mux),
+};
+
+static struct pll_clk *a53sspll[] = { &apcs_c1_pll, &apcs_c0_pll };
+
+static struct mux_div_clk *a53ssmux[] = { &a53ssmux_perf, &a53ssmux_pwr,
+ &a53ssmux_cci };
+
+static struct a53_cpu_clk *cpuclk[] = { &a53_perf_clk, &a53_pwr_clk,
+ &a53_cci_clk };
+
+static struct clk *logical_cpu_to_clk(int cpu)
+{
+ struct device_node *cpu_node = of_get_cpu_node(cpu, NULL);
+ u32 reg;
+
+ if (cpu_node && !of_property_read_u32(cpu_node, "reg", ®)) {
+ if ((reg | a53_pwr_clk.cpu_reg_mask) ==
+ a53_pwr_clk.cpu_reg_mask)
+ return &a53_pwr_clk.c;
+ if ((reg | a53_perf_clk.cpu_reg_mask) ==
+ a53_perf_clk.cpu_reg_mask)
+ return &a53_perf_clk.c;
+ }
+
+ return NULL;
+}
+
+static int of_get_fmax_vdd_class(struct platform_device *pdev, struct clk *c,
+ char *prop_name)
+{
+ struct device_node *of = pdev->dev.of_node;
+ int prop_len, i;
+ struct clk_vdd_class *vdd = c->vdd_class;
+ u32 *array;
+
+ if (!of_find_property(of, prop_name, &prop_len)) {
+ dev_err(&pdev->dev, "missing %s\n", prop_name);
+ return -EINVAL;
+ }
+
+ prop_len /= sizeof(u32);
+ if (prop_len % 2) {
+ dev_err(&pdev->dev, "bad length %d\n", prop_len);
+ return -EINVAL;
+ }
+
+ prop_len /= 2;
+ vdd->level_votes = devm_kzalloc(&pdev->dev,
+ prop_len * sizeof(*vdd->level_votes),
+ GFP_KERNEL);
+ if (!vdd->level_votes)
+ return -ENOMEM;
+
+ vdd->vdd_uv = devm_kzalloc(&pdev->dev, prop_len * sizeof(int),
+ GFP_KERNEL);
+ if (!vdd->vdd_uv)
+ return -ENOMEM;
+
+ c->fmax = devm_kzalloc(&pdev->dev, prop_len * sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!c->fmax)
+ return -ENOMEM;
+
+ array = devm_kzalloc(&pdev->dev,
+ prop_len * sizeof(u32) * 2, GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ of_property_read_u32_array(of, prop_name, array, prop_len * 2);
+ for (i = 0; i < prop_len; i++) {
+ c->fmax[i] = array[2 * i];
+ vdd->vdd_uv[i] = array[2 * i + 1];
+ }
+
+ devm_kfree(&pdev->dev, array);
+ vdd->num_levels = prop_len;
+ vdd->cur_level = prop_len;
+ vdd->use_max_uV = true;
+ c->num_fmax = prop_len;
+ return 0;
+}
+
+static void get_speed_bin(struct platform_device *pdev, int *bin,
+ int *version)
+{
+ struct resource *res;
+ void __iomem *base;
+ u32 pte_efuse;
+
+ *bin = 0;
+ *version = 0;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+ if (!res) {
+ dev_info(&pdev->dev,
+ "No speed/PVS binning available. Defaulting to 0!\n");
+ return;
+ }
+
+ base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!base) {
+ dev_warn(&pdev->dev,
+ "Unable to read efuse data. Defaulting to 0!\n");
+ return;
+ }
+
+ pte_efuse = readl_relaxed(base);
+ devm_iounmap(&pdev->dev, base);
+
+ *bin = (pte_efuse >> 8) & 0x7;
+
+ dev_info(&pdev->dev, "Speed bin: %d PVS Version: %d\n", *bin,
+ *version);
+}
+
+static int cpu_parse_pll_data(struct platform_device *pdev, int pll_count)
+{
+ int pll_num;
+ struct resource *res;
+ struct clk *c;
+ char pll_name[] = "apcs-xxx-pll-base";
+
+ for (pll_num = 0; pll_num < pll_count; pll_num++) {
+ snprintf(pll_name, ARRAY_SIZE(pll_name), "apcs-%s-pll-base",
+ pll_names[pll_num]);
+
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, pll_name);
+ if (!res) {
+ dev_err(&pdev->dev, "missing %s\n", pll_name);
+ return -EINVAL;
+ }
+
+ if (pll_num < APCS_CCI_PLL_BASE) {
+ a53sspll[pll_num]->base = devm_ioremap(&pdev->dev,
+ res->start, resource_size(res));
+ if (!a53sspll[pll_num]->base) {
+ dev_err(&pdev->dev, "ioremap failed for %s\n",
+ pll_name);
+ return -ENOMEM;
+ }
+ } else {
+ apcs_cci_pll.base = devm_ioremap(&pdev->dev,
+ res->start, resource_size(res));
+ if (!apcs_cci_pll.base) {
+ dev_err(&pdev->dev, "ioremap failed for %s\n",
+ pll_name);
+ return -ENOMEM;
+ }
+ }
+ }
+
+ c = devm_clk_get(&pdev->dev, "xo_a");
+ if (IS_ERR(c)) {
+ if (PTR_ERR(c) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get xo clock\n");
+ return PTR_ERR(c);
+ }
+ xo_a_clk.c.parent = c;
+
+ return 0;
+}
+
+static int cpu_parse_devicetree(struct platform_device *pdev, int mux_id)
+{
+ struct resource *res;
+ char rcg_name[] = "apcs-xxx-rcg-base";
+ char vdd_name[] = "vdd-xxx";
+ struct regulator *regulator;
+
+ snprintf(rcg_name, ARRAY_SIZE(rcg_name), "apcs-%s-rcg-base",
+ mux_names[mux_id]);
+
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, rcg_name);
+ if (!res) {
+ dev_err(&pdev->dev, "missing %s\n", rcg_name);
+ return -EINVAL;
+ }
+
+ a53ssmux[mux_id]->base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!a53ssmux[mux_id]->base) {
+ dev_err(&pdev->dev, "ioremap failed for %s\n", rcg_name);
+ return -ENOMEM;
+ }
+
+ snprintf(vdd_name, ARRAY_SIZE(vdd_name), "vdd-%s", mux_names[mux_id]);
+ regulator = devm_regulator_get(&pdev->dev, vdd_name);
+ if (IS_ERR(regulator)) {
+ if (PTR_ERR(regulator) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "unable to get regulator\n");
+ return PTR_ERR(regulator);
+ }
+
+ cpuclk[mux_id]->c.vdd_class->regulator[0] = regulator;
+
+ return 0;
+}
+
+static int add_opp(struct clk *c, struct device *cpudev, struct device *vregdev,
+ unsigned long max_rate)
+{
+ unsigned long rate = 0;
+ int level;
+ long ret, uv, corner;
+ int j = 1;
+
+ while (1) {
+ rate = c->fmax[j++];
+
+ level = find_vdd_level(c, rate);
+ if (level <= 0) {
+ pr_warn("clock-cpu: no vdd level for %lu.\n", rate);
+ return -EINVAL;
+ }
+
+ corner = c->vdd_class->vdd_uv[level];
+ if (corner < 0)
+ return -EINVAL;
+
+ /* Get actual voltage corresponding to each corner */
+ uv = regulator_list_corner_voltage(c->vdd_class->regulator[0],
+ corner);
+ if (uv < 0) {
+ pr_warn("%s: no uv for corner %ld - err: %ld\n",
+ c->dbg_name, corner, uv);
+ return uv;
+ }
+
+ /*
+ * Populate both CPU and regulator devices with the
+ * freq-to-corner OPP table to maintain backward
+ * compatibility.
+ */
+ ret = dev_pm_opp_add(cpudev, rate, uv);
+ if (ret) {
+ pr_warn("clock-cpu: couldn't add OPP for %lu\n",
+ rate);
+ return ret;
+ }
+
+ ret = dev_pm_opp_add(vregdev, rate, uv);
+ if (ret) {
+ pr_warn("clock-cpu: couldn't add OPP for %lu\n",
+ rate);
+ return ret;
+ }
+
+ if (rate >= max_rate)
+ break;
+ }
+
+ return 0;
+}
+
+static void print_opp_table(int a53_c0_cpu, int a53_c1_cpu)
+{
+ struct dev_pm_opp *oppfmax, *oppfmin;
+ unsigned long apc0_fmax, apc1_fmax, apc0_fmin, apc1_fmin;
+
+ apc0_fmax = a53_pwr_clk.c.fmax[a53_pwr_clk.c.num_fmax - 1];
+ apc0_fmin = a53_pwr_clk.c.fmax[1];
+ apc1_fmax = a53_perf_clk.c.fmax[a53_perf_clk.c.num_fmax - 1];
+ apc1_fmin = a53_perf_clk.c.fmax[1];
+
+ rcu_read_lock();
+ oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c0_cpu),
+ apc0_fmax, true);
+ oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c0_cpu),
+ apc0_fmin, true);
+ /*
+ * One time information during boot. Important to know that this
+ * looks sane since it can eventually make its way to the
+ * scheduler.
+ */
+ pr_info("clock_cpu: a53_c0: OPP voltage for %lu: %ld\n",
+ apc0_fmin, dev_pm_opp_get_voltage(oppfmin));
+ pr_info("clock_cpu: a53_c0: OPP voltage for %lu: %ld\n",
+ apc0_fmax, dev_pm_opp_get_voltage(oppfmax));
+
+ oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c1_cpu),
+ apc1_fmax, true);
+ oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c1_cpu),
+ apc1_fmin, true);
+ pr_info("clock_cpu: a53_c1: OPP voltage for %lu: %lu\n", apc1_fmin,
+ dev_pm_opp_get_voltage(oppfmin));
+ pr_info("clock_cpu: a53_c1: OPP voltage for %lu: %lu\n", apc1_fmax,
+ dev_pm_opp_get_voltage(oppfmax));
+ rcu_read_unlock();
+}
+
+static void populate_opp_table(struct platform_device *pdev)
+{
+ struct platform_device *apc0_dev, *apc1_dev;
+ struct device_node *apc0_node = NULL, *apc1_node;
+ unsigned long apc0_fmax, apc1_fmax;
+ int cpu, a53_c0_cpu = 0, a53_c1_cpu = 0;
+
+ apc0_node = of_parse_phandle(pdev->dev.of_node,
+ "vdd-c0-supply", 0);
+ if (!apc0_node) {
+ pr_err("can't find the apc0 dt node.\n");
+ return;
+ }
+
+ apc1_node = of_parse_phandle(pdev->dev.of_node, "vdd-c1-supply", 0);
+ if (!apc1_node) {
+ pr_err("can't find the apc1 dt node.\n");
+ return;
+ }
+
+ apc0_dev = of_find_device_by_node(apc0_node);
+ if (!apc0_dev) {
+ pr_err("can't find the apc0 device node.\n");
+ return;
+ }
+
+ apc1_dev = of_find_device_by_node(apc1_node);
+ if (!apc1_dev) {
+ pr_err("can't find the apc1 device node.\n");
+ return;
+ }
+
+ apc0_fmax = a53_pwr_clk.c.fmax[a53_pwr_clk.c.num_fmax - 1];
+
+ apc1_fmax = a53_perf_clk.c.fmax[a53_perf_clk.c.num_fmax - 1];
+
+ for_each_possible_cpu(cpu) {
+ if (logical_cpu_to_clk(cpu) == &a53_pwr_clk.c) {
+ a53_c0_cpu = cpu;
+ WARN(add_opp(&a53_pwr_clk.c, get_cpu_device(cpu),
+ &apc0_dev->dev, apc0_fmax),
+ "Failed to add OPP levels for %d\n", cpu);
+ }
+ if (logical_cpu_to_clk(cpu) == &a53_perf_clk.c) {
+ a53_c1_cpu = cpu;
+ WARN(add_opp(&a53_perf_clk.c, get_cpu_device(cpu),
+ &apc1_dev->dev, apc1_fmax),
+ "Failed to add OPP levels for %d\n", cpu);
+ }
+ }
+ /* One time print during bootup */
+ pr_info("clock-cpu: OPP tables populated (cpu %d and %d)",
+ a53_c0_cpu, a53_c1_cpu);
+
+ print_opp_table(a53_c0_cpu, a53_c1_cpu);
+
+}
+
+static int clock_sdm632_pm_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ switch (event) {
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ clk_unprepare(&a53_pwr_clk.c);
+ clk_unprepare(&a53_perf_clk.c);
+ clk_unprepare(&a53_cci_clk.c);
+ break;
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+ clk_prepare(&a53_pwr_clk.c);
+ clk_prepare(&a53_perf_clk.c);
+ clk_prepare(&a53_cci_clk.c);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block clock_sdm632_pm_notifier = {
+ .notifier_call = clock_sdm632_pm_event,
+};
+
+/**
+ * clock_panic_callback() - panic notification callback function.
+ * This function is invoked when a kernel panic occurs.
+ * @nfb: Notifier block pointer
+ * @event: Value passed unmodified to notifier function
+ * @data: Pointer passed unmodified to notifier function
+ *
+ * Return: NOTIFY_OK
+ */
+static int clock_panic_callback(struct notifier_block *nfb,
+ unsigned long event, void *data)
+{
+ unsigned long rate;
+
+ rate = (a53_perf_clk.c.count) ? a53_perf_clk.c.rate : 0;
+ pr_err("%s frequency: %10lu Hz\n", a53_perf_clk.c.dbg_name, rate);
+
+ rate = (a53_pwr_clk.c.count) ? a53_pwr_clk.c.rate : 0;
+ pr_err("%s frequency: %10lu Hz\n", a53_pwr_clk.c.dbg_name, rate);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block clock_panic_notifier = {
+ .notifier_call = clock_panic_callback,
+ .priority = 1,
+};
+
+/* Configure PLL at Nominal frequency */
+static unsigned long pwrcl_early_boot_rate = 1363200000;
+static unsigned long perfcl_early_boot_rate = 1401600000;
+static unsigned long cci_early_boot_rate = 691200000;
+
+static int clock_a53_probe(struct platform_device *pdev)
+{
+ int speed_bin, version, rc, cpu, mux_id;
+ char prop_name[] = "qcom,speedX-bin-vX-XXX";
+ int mux_num = A53SS_MUX_NUM;
+
+ get_speed_bin(pdev, &speed_bin, &version);
+
+ rc = cpu_parse_pll_data(pdev, N_PLL_BASES);
+ if (rc)
+ return rc;
+
+ /* PLL core logic */
+ vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd-mx");
+ if (IS_ERR(vdd_mx.regulator[0])) {
+ dev_err(&pdev->dev, "Get vdd-mx regulator!!!\n");
+ if (PTR_ERR(vdd_mx.regulator[0]) != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "Unable to get vdd-mx regulator!!!\n");
+ return PTR_ERR(vdd_mx.regulator[0]);
+ }
+
+ for (mux_id = 0; mux_id < mux_num; mux_id++) {
+ rc = cpu_parse_devicetree(pdev, mux_id);
+ if (rc)
+ return rc;
+
+ snprintf(prop_name, ARRAY_SIZE(prop_name),
+ "qcom,speed%d-bin-v%d-%s",
+ speed_bin, version, mux_names[mux_id]);
+
+ rc = of_get_fmax_vdd_class(pdev, &cpuclk[mux_id]->c,
+ prop_name);
+ if (rc) {
+ /* Fall back to most conservative PVS table */
+ dev_err(&pdev->dev, "Unable to load voltage plan %s!\n",
+ prop_name);
+
+ snprintf(prop_name, ARRAY_SIZE(prop_name),
+ "qcom,speed0-bin-v0-%s", mux_names[mux_id]);
+ rc = of_get_fmax_vdd_class(pdev, &cpuclk[mux_id]->c,
+ prop_name);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "Unable to load safe voltage plan\n");
+ return rc;
+ }
+ dev_info(&pdev->dev, "Safe voltage plan loaded.\n");
+ }
+ }
+
+ /* Debug MUX */
+ meas_base = devm_ioremap(&pdev->dev, GLB_DIAG, SZ_8);
+ if (!meas_base) {
+ dev_err(&pdev->dev, "Failed to ioremap GLB_DIAG registers\n");
+ return -ENOMEM;
+ }
+
+ rc = of_msm_clock_register(pdev->dev.of_node, a53_cpu_clocks,
+ ARRAY_SIZE(a53_cpu_clocks));
+
+ if (rc) {
+ dev_err(&pdev->dev, "msm_clock_register failed\n");
+ return rc;
+ }
+
+ /* Force to move to PLL configuartion */
+ rc = clk_set_rate(&a53_cci_clk.c, cci_early_boot_rate);
+ if (rc)
+ dev_err(&pdev->dev, "Can't set CCI PLL rate for CCI\n");
+
+ rc = clk_set_rate(&a53_pwr_clk.c, pwrcl_early_boot_rate);
+ if (rc)
+ dev_err(&pdev->dev, "Can't set pwr PLL rate for Cluster-0 %ld\n",
+ pwrcl_early_boot_rate);
+
+ rc = clk_set_rate(&a53_perf_clk.c, perfcl_early_boot_rate);
+ if (rc)
+ dev_err(&pdev->dev, "Can't set perf PLL rate for Cluster-1 %ld\n",
+ perfcl_early_boot_rate);
+
+ rc = clock_rcgwr_init(pdev);
+ if (rc)
+ dev_err(&pdev->dev, "Failed to init RCGwR\n");
+
+ /*
+ * We don't want the CPU clocks to be turned off at late init
+ * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
+ * refcount of these clocks. Any cpufreq/hotplug manager can assume
+ * that the clocks have already been prepared and enabled by the time
+ * they take over.
+ */
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ WARN(clk_prepare_enable(&cpuclk[cpu/4]->c),
+ "Unable to turn on CPU clock");
+ WARN(clk_prepare_enable(&a53_cci_clk.c),
+ "Unable to turn on CCI clock");
+ }
+ put_online_cpus();
+
+ for_each_possible_cpu(cpu) {
+ if (logical_cpu_to_clk(cpu) == &a53_perf_clk.c)
+ cpumask_set_cpu(cpu, &a53_perf_clk.cpumask);
+ if (logical_cpu_to_clk(cpu) == &a53_pwr_clk.c)
+ cpumask_set_cpu(cpu, &a53_pwr_clk.cpumask);
+ }
+
+ a53_pwr_clk.hw_low_power_ctrl = true;
+ a53_perf_clk.hw_low_power_ctrl = true;
+
+ register_pm_notifier(&clock_sdm632_pm_notifier);
+
+ populate_opp_table(pdev);
+
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &clock_panic_notifier);
+
+ return 0;
+}
+
+static const struct of_device_id clock_a53_match_table[] = {
+ {.compatible = "qcom,cpu-clock-sdm632"},
+ {}
+};
+
+static struct platform_driver clock_a53_driver = {
+ .probe = clock_a53_probe,
+ .driver = {
+ .name = "cpu-clock-sdm632",
+ .of_match_table = clock_a53_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init clock_a53_init(void)
+{
+ return platform_driver_register(&clock_a53_driver);
+}
+arch_initcall(clock_a53_init);
+
+static int __init clock_cpu_lpm_get_latency(void)
+{
+ int rc = 0;
+ struct device_node *ofnode = of_find_compatible_node(NULL, NULL,
+ "qcom,cpu-clock-sdm632");
+
+ if (!ofnode)
+ return 0;
+
+ rc = lpm_get_latency(&a53_perf_clk.latency_lvl,
+ &a53_perf_clk.cpu_latency_no_l2_pc_us);
+ if (rc < 0)
+ pr_err("Failed to get the L2 PC value for perf\n");
+
+ rc = lpm_get_latency(&a53_pwr_clk.latency_lvl,
+ &a53_pwr_clk.cpu_latency_no_l2_pc_us);
+ if (rc < 0)
+ pr_err("Failed to get the L2 PC value for pwr\n");
+
+ pr_debug("Latency for pwr/perf cluster %d : %d\n",
+ a53_pwr_clk.cpu_latency_no_l2_pc_us,
+ a53_perf_clk.cpu_latency_no_l2_pc_us);
+
+ return rc;
+}
+late_initcall(clock_cpu_lpm_get_latency);
+
+#define PWR_PLL_BASE 0xb116000
+#define PERF_PLL_BASE 0xb016000
+#define CCI_PLL_BASE 0xb1d0000
+#define APCS_ALIAS1_CMD_RCGR 0xb011050
+#define APCS_ALIAS1_CFG_OFF 0x4
+#define APCS_ALIAS1_CORE_CBCR_OFF 0x8
+#define SRC_SEL 0x4
+#define SRC_DIV 0x1
+
+static int __init cpu_clock_init(void)
+{
+ void __iomem *base;
+ int regval = 0, count;
+ struct device_node *ofnode = of_find_compatible_node(NULL, NULL,
+ "qcom,cpu-clock-sdm632");
+ if (!ofnode)
+ return 0;
+
+ virt_bases[APCS_C0_PLL_BASE] = ioremap_nocache(PWR_PLL_BASE, SZ_1K);
+ virt_bases[APCS_C1_PLL_BASE] = ioremap_nocache(PERF_PLL_BASE, SZ_1K);
+ virt_bases[APCS_CCI_PLL_BASE] = ioremap_nocache(CCI_PLL_BASE, SZ_1K);
+ clk_ops_variable_rate = clk_ops_variable_rate_pll_hwfsm;
+ clk_ops_variable_rate.list_registers = variable_pll_list_registers;
+
+ /* Initialize the PLLs */
+ __variable_rate_pll_init(&apcs_c0_pll.c);
+ __variable_rate_pll_init(&apcs_c1_pll.c);
+ __init_alpha_pll(&apcs_cci_pll.c);
+
+ /* Enable the PLLs */
+ apcs_c0_pll.c.ops->set_rate(&apcs_c0_pll.c, pwrcl_early_boot_rate);
+ clk_ops_variable_rate_pll.enable(&apcs_c0_pll.c);
+
+ apcs_c1_pll.c.ops->set_rate(&apcs_c1_pll.c, perfcl_early_boot_rate);
+ clk_ops_variable_rate_pll.enable(&apcs_c1_pll.c);
+
+ apcs_cci_pll.c.ops->set_rate(&apcs_cci_pll.c, cci_early_boot_rate);
+ clk_ops_dyna_alpha_pll.enable(&apcs_cci_pll.c);
+
+ base = ioremap_nocache(APCS_ALIAS1_CMD_RCGR, SZ_8);
+ regval = readl_relaxed(base);
+
+ /* Source from GPLL0 */
+ regval = (SRC_SEL << 8) | SRC_DIV; /* 0x401 */
+ writel_relaxed(regval, base + APCS_ALIAS1_CFG_OFF);
+ /* Make sure src sel and src div is set before update bit */
+ mb();
+
+ /* update bit */
+ regval = readl_relaxed(base);
+ regval |= BIT(0);
+ writel_relaxed(regval, base);
+ /* Make sure src sel and src div is set before update bit */
+ mb();
+
+ /* Wait for update to take effect */
+ for (count = 500; count > 0; count--) {
+ if (!(readl_relaxed(base)) & BIT(0))
+ break;
+ udelay(1);
+ }
+
+ /* Enable the branch */
+ regval = readl_relaxed(base + APCS_ALIAS1_CORE_CBCR_OFF);
+ regval |= BIT(0);
+ writel_relaxed(regval, base + APCS_ALIAS1_CORE_CBCR_OFF);
+
+ /* Branch enable should be complete */
+ mb();
+ iounmap(base);
+
+ pr_info("CPU clocks configured\n");
+
+ return 0;
+}
+early_initcall(cpu_clock_init);
diff --git a/drivers/clk/msm/clock-gcc-8909.c b/drivers/clk/msm/clock-gcc-8909.c
new file mode 100644
index 0000000..54d8d56
--- /dev/null
+++ b/drivers/clk/msm/clock-gcc-8909.c
@@ -0,0 +1,2919 @@
+/*
+ * Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/clock-pll.h>
+#include <soc/qcom/clock-voter.h>
+
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+
+#include <dt-bindings/clock/msm-clocks-8909.h>
+
+#include "clock.h"
+#include "reset.h"
+
+enum {
+ GCC_BASE,
+ APCS_PLL_BASE,
+ N_BASES,
+};
+
+static void __iomem *virt_bases[N_BASES];
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+
+#define GPLL0_MODE 0x21000
+#define GPLL0_L_VAL 0x21004
+#define GPLL0_ALPHA_VAL 0x21008
+#define GPLL0_ALPHA_VAL_U 0x2100C
+#define GPLL0_USER_CTL 0x21010
+#define GPLL0_CONFIG_CTL 0x21018
+#define GPLL0_STATUS 0x21024
+#define GPLL1_MODE 0x20000
+#define GPLL1_L_VAL 0x20004
+#define GPLL1_M_VAL 0x20008
+#define GPLL1_N_VAL 0x2000C
+#define GPLL1_USER_CTL 0x20010
+#define GPLL1_CONFIG_CTL 0x20014
+#define GPLL1_STATUS 0x2001C
+#define GPLL2_MODE 0x25000
+#define GPLL2_L_VAL 0x25004
+#define GPLL2_ALPHA_VAL 0x25008
+#define GPLL2_ALPHA_VAL_U 0x2500C
+#define GPLL2_USER_CTL 0x25010
+#define GPLL2_CONFIG_CTL 0x25018
+#define GPLL2_STATUS 0x25024
+#define SNOC_QOSGEN 0x2601C
+#define MSS_CFG_AHB_CBCR 0x49000
+#define MSS_Q6_BIMC_AXI_CBCR 0x49004
+#define QPIC_AHB_CBCR 0x3F01C
+#define USB_HS_BCR 0x41000
+#define USB_HS_SYSTEM_CBCR 0x41004
+#define USB_HS_AHB_CBCR 0x41008
+#define USB_HS_SYSTEM_CMD_RCGR 0x41010
+#define USB2A_PHY_SLEEP_CBCR 0x4102C
+#define USB_HS_PHY_CFG_AHB_CBCR 0x41030
+#define USB2_HS_PHY_ONLY_BCR 0x41034
+#define QUSB2_PHY_BCR 0x4103C
+#define SDCC1_APPS_CMD_RCGR 0x42004
+#define SDCC1_APPS_CBCR 0x42018
+#define SDCC1_AHB_CBCR 0x4201C
+#define SDCC2_APPS_CMD_RCGR 0x43004
+#define SDCC2_APPS_CBCR 0x43018
+#define SDCC2_AHB_CBCR 0x4301C
+#define BLSP1_AHB_CBCR 0x01008
+#define BLSP1_QUP1_SPI_APPS_CBCR 0x02004
+#define BLSP1_QUP1_I2C_APPS_CBCR 0x02008
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR 0x0200C
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR 0x03000
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR 0x04000
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR 0x05000
+#define BLSP1_QUP5_I2C_APPS_CMD_RCGR 0x06000
+#define BLSP1_QUP6_I2C_APPS_CMD_RCGR 0x07000
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR 0x02024
+#define BLSP1_UART1_APPS_CBCR 0x0203C
+#define BLSP1_UART1_APPS_CMD_RCGR 0x02044
+#define BLSP1_QUP2_SPI_APPS_CBCR 0x0300C
+#define BLSP1_QUP2_I2C_APPS_CBCR 0x03010
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR 0x03014
+#define BLSP1_UART2_APPS_CBCR 0x0302C
+#define BLSP1_UART2_APPS_CMD_RCGR 0x03034
+#define BLSP1_QUP3_SPI_APPS_CBCR 0x0401C
+#define BLSP1_QUP3_I2C_APPS_CBCR 0x04020
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR 0x04024
+#define BLSP1_QUP4_SPI_APPS_CBCR 0x0501C
+#define BLSP1_QUP4_I2C_APPS_CBCR 0x05020
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR 0x05024
+#define BLSP1_QUP5_SPI_APPS_CBCR 0x0601C
+#define BLSP1_QUP5_I2C_APPS_CBCR 0x06020
+#define BLSP1_QUP5_SPI_APPS_CMD_RCGR 0x06024
+#define BLSP1_QUP6_SPI_APPS_CBCR 0x0701C
+#define BLSP1_QUP6_I2C_APPS_CBCR 0x07020
+#define BLSP1_QUP6_SPI_APPS_CMD_RCGR 0x07024
+#define PDM_AHB_CBCR 0x44004
+#define PDM2_CBCR 0x4400C
+#define PDM2_CMD_RCGR 0x44010
+#define PRNG_AHB_CBCR 0x13004
+#define BOOT_ROM_AHB_CBCR 0x1300C
+#define CRYPTO_CMD_RCGR 0x16004
+#define CRYPTO_CBCR 0x1601C
+#define CRYPTO_AXI_CBCR 0x16020
+#define CRYPTO_AHB_CBCR 0x16024
+#define GCC_XO_DIV4_CBCR 0x30034
+#define GFX_TBU_CBCR 0x12010
+#define VENUS_TBU_CBCR 0x12014
+#define MDP_TBU_CBCR 0x1201C
+#define APSS_TCU_CBCR 0x12018
+#define GFX_TCU_CBCR 0x12020
+#define MSS_TBU_AXI_CBCR 0x12024
+#define MSS_TBU_GSS_AXI_CBCR 0x12028
+#define MSS_TBU_Q6_AXI_CBCR 0x1202C
+#define SMMU_CFG_CBCR 0x12038
+#define VFE_TBU_CBCR 0x1203C
+#define GTCU_AHB_CBCR 0x12044
+#define GTCU_AHB_BRIDGE_CBCR 0x12094
+#define APCS_GPLL_ENA_VOTE 0x45000
+#define APCS_CLOCK_BRANCH_ENA_VOTE 0x45004
+#define APCS_CLOCK_SLEEP_ENA_VOTE 0x45008
+#define APCS_SMMU_CLOCK_BRANCH_ENA_VOTE 0x4500C
+#define APSS_AHB_CMD_RCGR 0x46000
+#define GCC_DEBUG_CLK_CTL 0x74000
+#define CLOCK_FRQ_MEASURE_CTL 0x74004
+#define CLOCK_FRQ_MEASURE_STATUS 0x74008
+#define GCC_PLLTEST_PAD_CFG 0x7400C
+#define GP1_CBCR 0x08000
+#define GP1_CMD_RCGR 0x08004
+#define GP2_CBCR 0x09000
+#define GP2_CMD_RCGR 0x09004
+#define GP3_CBCR 0x0A000
+#define GP3_CMD_RCGR 0x0A004
+#define VCODEC0_CMD_RCGR 0x4C000
+#define VENUS0_VCODEC0_CBCR 0x4C01C
+#define VENUS0_CORE0_VCODEC0_CBCR 0x4C02C
+#define VENUS0_AHB_CBCR 0x4C020
+#define VENUS0_AXI_CBCR 0x4C024
+#define PCLK0_CMD_RCGR 0x4D000
+#define MDP_CMD_RCGR 0x4D014
+#define VSYNC_CMD_RCGR 0x4D02C
+#define BYTE0_CMD_RCGR 0x4D044
+#define ESC0_CMD_RCGR 0x4D05C
+#define MDSS_BCR 0x4D074
+#define MDSS_AHB_CBCR 0x4D07C
+#define MDSS_AXI_CBCR 0x4D080
+#define MDSS_PCLK0_CBCR 0x4D084
+#define MDSS_MDP_CBCR 0x4D088
+#define MDSS_VSYNC_CBCR 0x4D090
+#define MDSS_BYTE0_CBCR 0x4D094
+#define MDSS_ESC0_CBCR 0x4D098
+#define CSI0PHYTIMER_CMD_RCGR 0x4E000
+#define CAMSS_CSI0PHYTIMER_CBCR 0x4E01C
+#define CSI1PHYTIMER_CMD_RCGR 0x4F000
+#define CAMSS_CSI1PHYTIMER_CBCR 0x4F01C
+#define CSI0_CMD_RCGR 0x4E020
+#define CAMSS_CSI0_CBCR 0x4E03C
+#define CAMSS_CSI0_AHB_CBCR 0x4E040
+#define CAMSS_CSI0PHY_CBCR 0x4E048
+#define CAMSS_CSI0RDI_CBCR 0x4E050
+#define CAMSS_CSI0PIX_CBCR 0x4E058
+#define CSI1_CMD_RCGR 0x4F020
+#define CAMSS_CSI1_CBCR 0x4F03C
+#define CAMSS_CSI1_AHB_CBCR 0x4F040
+#define CAMSS_CSI1PHY_CBCR 0x4F048
+#define CAMSS_CSI1RDI_CBCR 0x4F050
+#define CAMSS_CSI1PIX_CBCR 0x4F058
+#define CAMSS_ISPIF_AHB_CBCR 0x50004
+#define CCI_CMD_RCGR 0x51000
+#define CAMSS_CCI_CBCR 0x51018
+#define CAMSS_CCI_AHB_CBCR 0x5101C
+#define MCLK0_CMD_RCGR 0x52000
+#define CAMSS_MCLK0_CBCR 0x52018
+#define MCLK1_CMD_RCGR 0x53000
+#define CAMSS_MCLK1_CBCR 0x53018
+#define CAMSS_GP0_CMD_RCGR 0x54000
+#define CAMSS_GP0_CBCR 0x54018
+#define CAMSS_GP1_CMD_RCGR 0x55000
+#define CAMSS_GP1_CBCR 0x55018
+#define CAMSS_AHB_CBCR 0x5A014
+#define CAMSS_TOP_AHB_CBCR 0x56004
+#define VFE0_CMD_RCGR 0x58000
+#define CAMSS_VFE_BCR 0x58030
+#define CAMSS_VFE0_CBCR 0x58038
+#define CAMSS_VFE_AHB_CBCR 0x58044
+#define CAMSS_VFE_AXI_CBCR 0x58048
+#define CAMSS_CSI_VFE0_CBCR 0x58050
+#define GFX3D_CMD_RCGR 0x59000
+#define OXILI_GFX3D_CBCR 0x59020
+#define OXILI_AHB_CBCR 0x59028
+#define CAMSS_TOP_AHB_CMD_RCGR 0x5A000
+#define BIMC_GFX_CBCR 0x31024
+#define BIMC_GPU_CBCR 0x31040
+
+#define APCS_SH_PLL_MODE 0x00000
+#define APCS_SH_PLL_L_VAL 0x00004
+#define APCS_SH_PLL_M_VAL 0x00008
+#define APCS_SH_PLL_N_VAL 0x0000C
+#define APCS_SH_PLL_USER_CTL 0x00010
+#define APCS_SH_PLL_CONFIG_CTL 0x00014
+#define APCS_SH_PLL_STATUS 0x0001C
+
+/* Mux source select values */
+#define xo_source_val 0
+#define xo_a_source_val 0
+#define gpll0_source_val 1
+#define gpll0_aux_source_val 3
+#define gpll1_e_source_val 3
+#define gpll1_e_gfx3d_source_val 2
+#define gpll2_source_val 3
+#define dsi0_phypll_mm_source_val 1
+
+#define F(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .src_clk = &s##_clk_src.c, \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+ | BVAL(10, 8, s##_source_val), \
+ }
+
+#define F_MDSS(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+ | BVAL(10, 8, s##_mm_source_val), \
+ }
+
+#define F_APCS_PLL(f, l, m, n, pre_div, post_div, vco) \
+ { \
+ .freq_hz = (f), \
+ .l_val = (l), \
+ .m_val = (m), \
+ .n_val = (n), \
+ .pre_div_val = BVAL(12, 12, (pre_div)), \
+ .post_div_val = BVAL(9, 8, (post_div)), \
+ .vco_val = BVAL(29, 28, (vco)), \
+ }
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+
+enum vdd_dig_levels {
+ VDD_DIG_NONE,
+ VDD_DIG_LOWER,
+ VDD_DIG_LOW,
+ VDD_DIG_NOMINAL,
+ VDD_DIG_HIGH,
+ VDD_DIG_NUM
+};
+
+static int vdd_corner[] = {
+ RPM_REGULATOR_CORNER_NONE, /* VDD_DIG_NONE */
+ RPM_REGULATOR_CORNER_SVS_KRAIT, /* VDD_DIG_LOWER SVS */
+ RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_DIG_LOW SVS */
+ RPM_REGULATOR_CORNER_NORMAL, /* VDD_DIG_NOMINAL */
+ RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_DIG_HIGH */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+DEFINE_EXT_CLK(xo_clk_src, NULL);
+DEFINE_EXT_CLK(xo_a_clk_src, NULL);
+DEFINE_EXT_CLK(rpm_debug_clk, NULL);
+DEFINE_EXT_CLK(apss_debug_clk, NULL);
+
+DEFINE_CLK_DUMMY(wcnss_m_clk, 0);
+
+enum vdd_sr2_pll_levels {
+ VDD_SR2_PLL_OFF,
+ VDD_SR2_PLL_SVS,
+ VDD_SR2_PLL_NOM,
+ VDD_SR2_PLL_TUR,
+ VDD_SR2_PLL_NUM,
+};
+
+static int vdd_sr2_levels[] = {
+ 0, RPM_REGULATOR_CORNER_NONE, /* VDD_SR2_PLL_OFF */
+ 1800000, RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_SR2_PLL_SVS */
+ 1800000, RPM_REGULATOR_CORNER_NORMAL, /* VDD_SR2_PLL_NOM */
+ 1800000, RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_SR2_PLL_TUR */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2,
+ vdd_sr2_levels, NULL);
+
+static struct pll_freq_tbl apcs_pll_freq[] = {
+ F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL(1094400000, 57, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL(1190400000, 62, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL(1248000000, 65, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL(1267200000, 66, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL(1305600000, 68, 0x0, 0x1, 0x0, 0x0, 0x0),
+ PLL_F_END
+};
+
+static struct pll_clk a7sspll = {
+ .mode_reg = (void __iomem *)APCS_SH_PLL_MODE,
+ .l_reg = (void __iomem *)APCS_SH_PLL_L_VAL,
+ .m_reg = (void __iomem *)APCS_SH_PLL_M_VAL,
+ .n_reg = (void __iomem *)APCS_SH_PLL_N_VAL,
+ .config_reg = (void __iomem *)APCS_SH_PLL_USER_CTL,
+ .status_reg = (void __iomem *)APCS_SH_PLL_STATUS,
+ .freq_tbl = apcs_pll_freq,
+ .masks = {
+ .vco_mask = BM(29, 28),
+ .pre_div_mask = BIT(12),
+ .post_div_mask = BM(9, 8),
+ .mn_en_mask = BIT(24),
+ .main_output_mask = BIT(0),
+ },
+ .base = &virt_bases[APCS_PLL_BASE],
+ .c = {
+ .parent = &xo_a_clk_src.c,
+ .dbg_name = "a7sspll",
+ .ops = &clk_ops_sr2_pll,
+ .vdd_class = &vdd_sr2_pll,
+ .fmax = (unsigned long [VDD_SR2_PLL_NUM]) {
+ [VDD_SR2_PLL_SVS] = 1000000000,
+ [VDD_SR2_PLL_NOM] = 1900000000,
+ },
+ .num_fmax = VDD_SR2_PLL_NUM,
+ CLK_INIT(a7sspll.c),
+ },
+};
+
+static unsigned int soft_vote_gpll0;
+
+/* PLL_ACTIVE_FLAG bit of GCC_GPLL0_MODE register
+ * gets set from PLL voting FSM.It indicates when
+ * FSM has enabled the PLL and PLL should be locked.
+ */
+static struct pll_vote_clk gpll0_clk_src = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(0),
+ .status_reg = (void __iomem *)GPLL0_MODE,
+ .status_mask = BIT(30),
+ .soft_vote = &soft_vote_gpll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &xo_clk_src.c,
+ .rate = 800000000,
+ .dbg_name = "gpll0_clk_src",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(gpll0_clk_src.c),
+ },
+};
+
+/* Don't vote for xo if using this clock to allow xo shutdown */
+static struct pll_vote_clk gpll0_ao_clk_src = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(0),
+ .status_reg = (void __iomem *)GPLL0_MODE,
+ .status_mask = BIT(30),
+ .soft_vote = &soft_vote_gpll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &xo_a_clk_src.c,
+ .rate = 800000000,
+ .dbg_name = "gpll0_ao_clk_src",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(gpll0_ao_clk_src.c),
+ },
+};
+
+static struct pll_vote_clk gpll1_clk_src = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(1),
+ .status_reg = (void __iomem *)GPLL1_STATUS,
+ .status_mask = BIT(17),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &xo_clk_src.c,
+ .rate = 614400000,
+ .dbg_name = "gpll1_clk_src",
+ .ops = &clk_ops_pll_vote,
+ CLK_INIT(gpll1_clk_src.c),
+ },
+};
+
+DEFINE_EXT_CLK(gpll1_e_clk_src, &gpll1_clk_src.c);
+DEFINE_EXT_CLK(gpll1_e_gfx3d_clk_src, &gpll1_clk_src.c);
+
+/* PLL_ACTIVE_FLAG bit of GCC_GPLL2_MODE register
+ * gets set from PLL voting FSM.It indicates when
+ * FSM has enabled the PLL and PLL should be locked.
+ */
+static struct pll_vote_clk gpll2_clk_src = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(3),
+ .status_reg = (void __iomem *)GPLL2_MODE,
+ .status_mask = BIT(30),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &xo_clk_src.c,
+ .rate = 792000000,
+ .dbg_name = "gpll2_clk_src",
+ .ops = &clk_ops_pll_vote,
+ CLK_INIT(gpll2_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_apss_ahb_clk[] = {
+ F( 19200000, xo_a, 1, 0, 0),
+ F( 50000000, gpll0, 16, 0, 0),
+ F( 100000000, gpll0, 8, 0, 0),
+ F_END
+};
+
+static struct rcg_clk apss_ahb_clk_src = {
+ .cmd_rcgr_reg = APSS_AHB_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_apss_ahb_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "apss_ahb_clk_src",
+ .ops = &clk_ops_rcg,
+ CLK_INIT(apss_ahb_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_top_ahb_clk[] = {
+ F( 40000000, gpll0, 10, 1, 2),
+ F( 80000000, gpll0, 10, 0, 0),
+ F_END
+};
+
+static struct rcg_clk camss_top_ahb_clk_src = {
+ .cmd_rcgr_reg = CAMSS_TOP_AHB_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_camss_top_ahb_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "camss_top_ahb_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 40000000, NOMINAL, 80000000),
+ CLK_INIT(camss_top_ahb_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_csi0_1_clk[] = {
+ F( 100000000, gpll0, 8, 0, 0),
+ F( 200000000, gpll0, 4, 0, 0),
+ F_END
+};
+
+static struct rcg_clk csi0_clk_src = {
+ .cmd_rcgr_reg = CSI0_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_camss_csi0_1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "csi0_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+ CLK_INIT(csi0_clk_src.c),
+ },
+};
+
+static struct rcg_clk csi1_clk_src = {
+ .cmd_rcgr_reg = CSI1_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_camss_csi0_1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "csi1_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+ CLK_INIT(csi1_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_vfe0_clk[] = {
+ F( 50000000, gpll0, 16, 0, 0),
+ F( 80000000, gpll0, 10, 0, 0),
+ F( 100000000, gpll0, 8, 0, 0),
+ F( 133330000, gpll0, 6, 0, 0),
+ F( 160000000, gpll0, 5, 0, 0),
+ F( 177780000, gpll0, 4.5, 0, 0),
+ F( 200000000, gpll0, 4, 0, 0),
+ F( 266670000, gpll0, 3, 0, 0),
+ F( 320000000, gpll0, 2.5, 0, 0),
+ F_END
+};
+
+static struct rcg_clk vfe0_clk_src = {
+ .cmd_rcgr_reg = VFE0_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_camss_vfe0_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "vfe0_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP3(LOWER, 133330000, NOMINAL, 266670000, HIGH,
+ 320000000),
+ CLK_INIT(vfe0_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_venus0_vcodec0_clk[] = {
+ F( 133330000, gpll0, 6, 0, 0),
+ F( 266670000, gpll0, 3, 0, 0),
+ F( 307200000, gpll1_e, 4, 0, 0),
+ F_END
+};
+
+static struct rcg_clk vcodec0_clk_src = {
+ .cmd_rcgr_reg = VCODEC0_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_venus0_vcodec0_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "vcodec0_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 133330000, NOMINAL, 266670000, HIGH,
+ 307200000),
+ CLK_INIT(vcodec0_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_i2c_apps_clk[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F( 50000000, gpll0, 16, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup1_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+ CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_spi_apps_clk[] = {
+ F( 960000, xo, 10, 1, 2),
+ F( 4800000, xo, 4, 0, 0),
+ F( 9600000, xo, 2, 0, 0),
+ F( 16000000, gpll0, 10, 1, 5),
+ F( 19200000, xo, 1, 0, 0),
+ F( 25000000, gpll0, 16, 1, 2),
+ F( 50000000, gpll0, 16, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup1_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup2_spi_apps_clk[] = {
+ F( 960000, xo, 10, 1, 2),
+ F( 4800000, xo, 4, 0, 0),
+ F( 8000000, gpll0, 10, 1, 10),
+ F( 9600000, xo, 2, 0, 0),
+ F( 16000000, gpll0, 10, 1, 5),
+ F( 19200000, xo, 1, 0, 0),
+ F( 25000000, gpll0, 16, 1, 2),
+ F( 50000000, gpll0, 16, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup2_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+ CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup2_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup2_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup3_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+ CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup3_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup4_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+ CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup4_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup5_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP5_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup5_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+ CLK_INIT(blsp1_qup5_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup5_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP5_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup5_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup5_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup6_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP6_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup6_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+ CLK_INIT(blsp1_qup6_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup6_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP6_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup6_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup6_spi_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_uart1_2_apps_clk[] = {
+ F( 3686400, gpll0, 1, 72, 15625),
+ F( 7372800, gpll0, 1, 144, 15625),
+ F( 14745600, gpll0, 1, 288, 15625),
+ F( 16000000, gpll0, 10, 1, 5),
+ F( 19200000, xo, 1, 0, 0),
+ F( 24000000, gpll0, 1, 3, 100),
+ F( 25000000, gpll0, 16, 1, 2),
+ F( 32000000, gpll0, 1, 1, 25),
+ F( 40000000, gpll0, 1, 1, 20),
+ F( 46400000, gpll0, 1, 29, 500),
+ F( 48000000, gpll0, 1, 3, 50),
+ F( 51200000, gpll0, 1, 8, 125),
+ F( 56000000, gpll0, 1, 7, 100),
+ F( 58982400, gpll0, 1, 1152, 15625),
+ F( 60000000, gpll0, 1, 3, 40),
+ F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART1_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_2_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart1_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 32000000, NOMINAL, 64000000),
+ CLK_INIT(blsp1_uart1_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART2_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_2_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart2_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 32000000, NOMINAL, 64000000),
+ CLK_INIT(blsp1_uart2_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_gp0_1_clk[] = {
+ F( 100000000, gpll0, 8, 0, 0),
+ F( 200000000, gpll0, 4, 0, 0),
+ F_END
+};
+
+static struct rcg_clk camss_gp0_clk_src = {
+ .cmd_rcgr_reg = CAMSS_GP0_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_camss_gp0_1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "camss_gp0_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+ CLK_INIT(camss_gp0_clk_src.c),
+ },
+};
+
+static struct rcg_clk camss_gp1_clk_src = {
+ .cmd_rcgr_reg = CAMSS_GP1_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_camss_gp0_1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "camss_gp1_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+ CLK_INIT(camss_gp1_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_mclk0_1_clk[] = {
+ F( 24000000, gpll2, 1, 1, 33),
+ F( 66670000, gpll0, 12, 0, 0),
+ F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_mclkm_clk[] = {
+ F( 24000000, gpll2, 2, 1, 19),
+ F( 66670000, gpll0, 12, 0, 0),
+ F_END
+};
+
+static unsigned long mclk0_1_fmax[VDD_DIG_NUM] = {
+ 0, 0, 0, 66670000, 0,
+};
+
+static struct rcg_clk mclk0_clk_src = {
+ .cmd_rcgr_reg = MCLK0_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_camss_mclk0_1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "mclk0_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP1(LOWER, 66670000),
+ CLK_INIT(mclk0_clk_src.c),
+ },
+};
+
+static struct rcg_clk mclk1_clk_src = {
+ .cmd_rcgr_reg = MCLK1_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_camss_mclk0_1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "mclk1_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP1(LOWER, 66670000),
+ CLK_INIT(mclk1_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_csi0_1phytimer_clk[] = {
+ F( 100000000, gpll0, 8, 0, 0),
+ F( 200000000, gpll0, 4, 0, 0),
+ F_END
+};
+
+static struct rcg_clk csi0phytimer_clk_src = {
+ .cmd_rcgr_reg = CSI0PHYTIMER_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_camss_csi0_1phytimer_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "csi0phytimer_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+ CLK_INIT(csi0phytimer_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_crypto_clk[] = {
+ F( 50000000, gpll0, 16, 0, 0),
+ F( 80000000, gpll0, 10, 0, 0),
+ F( 100000000, gpll0, 8, 0, 0),
+ F( 160000000, gpll0, 5, 0, 0),
+ F_END
+};
+
+static struct rcg_clk crypto_clk_src = {
+ .cmd_rcgr_reg = CRYPTO_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_crypto_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "crypto_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 80000000, NOMINAL, 160000000),
+ CLK_INIT(crypto_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_gp1_3_clk[] = {
+ F( 150000, xo, 1, 1, 128),
+ F( 19200000, xo, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk gp1_clk_src = {
+ .cmd_rcgr_reg = GP1_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_gp1_3_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gp1_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+ CLK_INIT(gp1_clk_src.c),
+ },
+};
+
+static struct rcg_clk gp2_clk_src = {
+ .cmd_rcgr_reg = GP2_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_gp1_3_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gp2_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+ CLK_INIT(gp2_clk_src.c),
+ },
+};
+
+static struct rcg_clk gp3_clk_src = {
+ .cmd_rcgr_reg = GP3_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_gp1_3_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gp3_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+ CLK_INIT(gp3_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_byte0_clk[] = {
+ {
+ .div_src_val = BVAL(10, 8, dsi0_phypll_mm_source_val),
+ },
+};
+
+static struct rcg_clk byte0_clk_src = {
+ .cmd_rcgr_reg = BYTE0_CMD_RCGR,
+ .current_freq = ftbl_gcc_mdss_byte0_clk,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "byte0_clk_src",
+ .ops = &clk_ops_byte,
+ VDD_DIG_FMAX_MAP1(LOWER, 125000000),
+ CLK_INIT(byte0_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_esc0_clk[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk esc0_clk_src = {
+ .cmd_rcgr_reg = ESC0_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_mdss_esc0_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "esc0_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+ CLK_INIT(esc0_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_mdp_clk[] = {
+ F( 50000000, gpll0, 16, 0, 0),
+ F( 80000000, gpll0, 10, 0, 0),
+ F( 100000000, gpll0, 8, 0, 0),
+ F( 160000000, gpll0, 5, 0, 0),
+ F( 177780000, gpll0, 4.5, 0, 0),
+ F( 200000000, gpll0, 4, 0, 0),
+ F( 266670000, gpll0, 3, 0, 0),
+ F( 307200000, gpll1_e, 4, 0, 0),
+ F_END
+};
+
+static struct rcg_clk mdp_clk_src = {
+ .cmd_rcgr_reg = MDP_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_mdss_mdp_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "mdp_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP3(LOWER, 160000000, LOW, 200000000, NOMINAL,
+ 307200000),
+ CLK_INIT(mdp_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_pclk0_clk[] = {
+ {
+ .div_src_val = BVAL(10, 8, dsi0_phypll_mm_source_val)
+ | BVAL(4, 0, 0),
+ },
+};
+
+static struct rcg_clk pclk0_clk_src = {
+ .cmd_rcgr_reg = PCLK0_CMD_RCGR,
+ .current_freq = ftbl_gcc_mdss_pclk0_clk,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "pclk0_clk_src",
+ .ops = &clk_ops_pixel,
+ VDD_DIG_FMAX_MAP1(LOWER, 83333333.33),
+ CLK_INIT(pclk0_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_vsync_clk[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk vsync_clk_src = {
+ .cmd_rcgr_reg = VSYNC_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_mdss_vsync_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "vsync_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+ CLK_INIT(vsync_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F( 50000000, gpll0, 16, 0, 0),
+ F( 80000000, gpll0, 10, 0, 0),
+ F( 100000000, gpll0, 8, 0, 0),
+ F( 160000000, gpll0, 5, 0, 0),
+ F( 177780000, gpll0, 4.5, 0, 0),
+ F( 200000000, gpll0, 4, 0, 0),
+ F( 266670000, gpll0, 3, 0, 0),
+ F( 307200000, gpll1_e_gfx3d, 4, 0, 0),
+ F( 409600000, gpll1_e_gfx3d, 3, 0, 0),
+ F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_465_clk[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F( 50000000, gpll0, 16, 0, 0),
+ F( 80000000, gpll0, 10, 0, 0),
+ F( 100000000, gpll0, 8, 0, 0),
+ F( 160000000, gpll0, 5, 0, 0),
+ F( 177780000, gpll0, 4.5, 0, 0),
+ F( 200000000, gpll0, 4, 0, 0),
+ F( 266670000, gpll0, 3, 0, 0),
+ F( 307200000, gpll1_e_gfx3d, 4, 0, 0),
+ F( 409600000, gpll1_e_gfx3d, 3, 0, 0),
+ F( 456000000, gpll2, 2, 0, 0),
+ F_END
+};
+
+static struct rcg_clk gfx3d_clk_src = {
+ .cmd_rcgr_reg = GFX3D_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_oxili_gfx3d_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gfx3d_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP3(LOWER, 200000000, NOMINAL, 307200000, HIGH,
+ 409600000),
+ CLK_INIT(gfx3d_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_pdm2_clk[] = {
+ F( 64000000, gpll0, 12.5, 0, 0),
+ F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+ .cmd_rcgr_reg = PDM2_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_pdm2_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "pdm2_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 64000000),
+ CLK_INIT(pdm2_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc1_2_apps_clk[] = {
+ F( 144000, xo, 16, 3, 25),
+ F( 400000, xo, 12, 1, 4),
+ F( 20000000, gpll0, 10, 1, 4),
+ F( 25000000, gpll0, 16, 1, 2),
+ F( 50000000, gpll0, 16, 0, 0),
+ F( 100000000, gpll0, 8, 0, 0),
+ F( 177770000, gpll0, 4.5, 0, 0),
+ F( 200000000, gpll0, 4, 0, 0),
+ F_END
+};
+
+static struct rcg_clk sdcc1_apps_clk_src = {
+ .cmd_rcgr_reg = SDCC1_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "sdcc1_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 50000000, NOMINAL, 200000000),
+ CLK_INIT(sdcc1_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+ .cmd_rcgr_reg = SDCC2_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "sdcc2_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 50000000, NOMINAL, 200000000),
+ CLK_INIT(sdcc2_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
+ F( 57140000, gpll0, 14, 0, 0),
+ F( 80000000, gpll0, 10, 0, 0),
+ F( 100000000, gpll0, 8, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+ .cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_usb_hs_system_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb_hs_system_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOW, 57140000, NOMINAL, 100000000),
+ CLK_INIT(usb_hs_system_clk_src.c),
+ },
+};
+
+static struct branch_clk gcc_bimc_gpu_clk = {
+ .cbcr_reg = BIMC_GPU_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_bimc_gpu_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_bimc_gpu_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+ .cbcr_reg = BLSP1_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(10),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_blsp1_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+ .parent = &blsp1_qup1_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+ .parent = &blsp1_qup1_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+ .parent = &blsp1_qup2_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+ .parent = &blsp1_qup2_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+ .parent = &blsp1_qup3_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+ .parent = &blsp1_qup3_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+ .parent = &blsp1_qup4_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+ .parent = &blsp1_qup4_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup5_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP5_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup5_i2c_apps_clk",
+ .parent = &blsp1_qup5_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup5_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup5_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP5_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup5_spi_apps_clk",
+ .parent = &blsp1_qup5_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup5_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup6_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP6_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup6_i2c_apps_clk",
+ .parent = &blsp1_qup6_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup6_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup6_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP6_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup6_spi_apps_clk",
+ .parent = &blsp1_qup6_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup6_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+ .cbcr_reg = BLSP1_UART1_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart1_apps_clk",
+ .parent = &blsp1_uart1_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+ .cbcr_reg = BLSP1_UART2_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart2_apps_clk",
+ .parent = &blsp1_uart2_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+ .cbcr_reg = BOOT_ROM_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(7),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_boot_rom_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_csi0_ahb_clk = {
+ .cbcr_reg = CAMSS_CSI0_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_csi0_ahb_clk",
+ .parent = &camss_top_ahb_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_csi0_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_csi0_clk = {
+ .cbcr_reg = CAMSS_CSI0_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_csi0_clk",
+ .parent = &csi0_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_csi0_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_csi0phy_clk = {
+ .cbcr_reg = CAMSS_CSI0PHY_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_csi0phy_clk",
+ .parent = &csi0_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_csi0phy_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_csi0pix_clk = {
+ .cbcr_reg = CAMSS_CSI0PIX_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_csi0pix_clk",
+ .parent = &csi0_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_csi0pix_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_csi0rdi_clk = {
+ .cbcr_reg = CAMSS_CSI0RDI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_csi0rdi_clk",
+ .parent = &csi0_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_csi0rdi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_csi1_ahb_clk = {
+ .cbcr_reg = CAMSS_CSI1_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_csi1_ahb_clk",
+ .parent = &camss_top_ahb_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_csi1_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_csi1_clk = {
+ .cbcr_reg = CAMSS_CSI1_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_csi1_clk",
+ .parent = &csi1_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_csi1_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_csi1phy_clk = {
+ .cbcr_reg = CAMSS_CSI1PHY_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_csi1phy_clk",
+ .parent = &csi1_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_csi1phy_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_csi1pix_clk = {
+ .cbcr_reg = CAMSS_CSI1PIX_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_csi1pix_clk",
+ .parent = &csi1_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_csi1pix_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_csi1rdi_clk = {
+ .cbcr_reg = CAMSS_CSI1RDI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_csi1rdi_clk",
+ .parent = &csi1_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_csi1rdi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_csi_vfe0_clk = {
+ .cbcr_reg = CAMSS_CSI_VFE0_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_csi_vfe0_clk",
+ .parent = &vfe0_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_csi_vfe0_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_gp0_clk = {
+ .cbcr_reg = CAMSS_GP0_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_gp0_clk",
+ .parent = &camss_gp0_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_gp0_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_gp1_clk = {
+ .cbcr_reg = CAMSS_GP1_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_gp1_clk",
+ .parent = &camss_gp1_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_gp1_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_ispif_ahb_clk = {
+ .cbcr_reg = CAMSS_ISPIF_AHB_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_ispif_ahb_clk",
+ .parent = &camss_top_ahb_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_ispif_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_mclk0_clk = {
+ .cbcr_reg = CAMSS_MCLK0_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_mclk0_clk",
+ .parent = &mclk0_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_mclk0_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_mclk1_clk = {
+ .cbcr_reg = CAMSS_MCLK1_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_mclk1_clk",
+ .parent = &mclk1_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_mclk1_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_csi0phytimer_clk = {
+ .cbcr_reg = CAMSS_CSI0PHYTIMER_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_csi0phytimer_clk",
+ .parent = &csi0phytimer_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_csi0phytimer_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_ahb_clk = {
+ .cbcr_reg = CAMSS_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_top_ahb_clk = {
+ .cbcr_reg = CAMSS_TOP_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_top_ahb_clk",
+ .parent = &camss_top_ahb_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_top_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_vfe0_clk = {
+ .cbcr_reg = CAMSS_VFE0_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_vfe0_clk",
+ .parent = &vfe0_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_vfe0_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_vfe_ahb_clk = {
+ .cbcr_reg = CAMSS_VFE_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_vfe_ahb_clk",
+ .parent = &camss_top_ahb_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_vfe_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_camss_vfe_axi_clk = {
+ .cbcr_reg = CAMSS_VFE_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_camss_vfe_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_camss_vfe_axi_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_crypto_ahb_clk = {
+ .cbcr_reg = CRYPTO_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(0),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_crypto_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_crypto_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_crypto_axi_clk = {
+ .cbcr_reg = CRYPTO_AXI_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(1),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_crypto_axi_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_crypto_axi_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_crypto_clk = {
+ .cbcr_reg = CRYPTO_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(2),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_crypto_clk",
+ .parent = &crypto_clk_src.c,
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_crypto_clk.c),
+ },
+};
+
+static struct branch_clk gcc_gp1_clk = {
+ .cbcr_reg = GP1_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_gp1_clk",
+ .parent = &gp1_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_gp1_clk.c),
+ },
+};
+
+static struct branch_clk gcc_gp2_clk = {
+ .cbcr_reg = GP2_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_gp2_clk",
+ .parent = &gp2_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_gp2_clk.c),
+ },
+};
+
+static struct branch_clk gcc_gp3_clk = {
+ .cbcr_reg = GP3_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_gp3_clk",
+ .parent = &gp3_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_gp3_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mdss_ahb_clk = {
+ .cbcr_reg = MDSS_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mdss_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mdss_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mdss_axi_clk = {
+ .cbcr_reg = MDSS_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mdss_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mdss_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mdss_byte0_clk = {
+ .cbcr_reg = MDSS_BYTE0_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mdss_byte0_clk",
+ .parent = &byte0_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mdss_byte0_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mdss_esc0_clk = {
+ .cbcr_reg = MDSS_ESC0_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mdss_esc0_clk",
+ .parent = &esc0_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mdss_esc0_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mdss_mdp_clk = {
+ .cbcr_reg = MDSS_MDP_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mdss_mdp_clk",
+ .parent = &mdp_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mdss_mdp_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mdss_pclk0_clk = {
+ .cbcr_reg = MDSS_PCLK0_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mdss_pclk0_clk",
+ .parent = &pclk0_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mdss_pclk0_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mdss_vsync_clk = {
+ .cbcr_reg = MDSS_VSYNC_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mdss_vsync_clk",
+ .parent = &vsync_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mdss_vsync_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+ .cbcr_reg = MSS_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mss_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+ .cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mss_q6_bimc_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_bimc_gfx_clk = {
+ .cbcr_reg = BIMC_GFX_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_bimc_gfx_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_bimc_gfx_clk.c),
+ },
+};
+
+static struct branch_clk gcc_oxili_ahb_clk = {
+ .cbcr_reg = OXILI_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_oxili_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_oxili_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_oxili_gfx3d_clk = {
+ .cbcr_reg = OXILI_GFX3D_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_oxili_gfx3d_clk",
+ .parent = &gfx3d_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_oxili_gfx3d_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+ .cbcr_reg = PDM2_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_pdm2_clk",
+ .parent = &pdm2_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pdm2_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+ .cbcr_reg = PDM_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_pdm_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pdm_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+ .cbcr_reg = PRNG_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(8),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_prng_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_prng_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc1_ahb_clk = {
+ .cbcr_reg = SDCC1_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc1_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc1_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc1_apps_clk = {
+ .cbcr_reg = SDCC1_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc1_apps_clk",
+ .parent = &sdcc1_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc1_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+ .cbcr_reg = SDCC2_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc2_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc2_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+ .cbcr_reg = SDCC2_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc2_apps_clk",
+ .parent = &sdcc2_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc2_apps_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_apss_tcu_clk = {
+ .cbcr_reg = APSS_TCU_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(1),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_apss_tcu_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_apss_tcu_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_gfx_tbu_clk = {
+ .cbcr_reg = GFX_TBU_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(3),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_gfx_tbu_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_gfx_tbu_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_gfx_tcu_clk = {
+ .cbcr_reg = GFX_TCU_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(2),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_gfx_tcu_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_gfx_tcu_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_mdp_tbu_clk = {
+ .cbcr_reg = MDP_TBU_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(4),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mdp_tbu_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_mdp_tbu_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_smmu_cfg_clk = {
+ .cbcr_reg = SMMU_CFG_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(12),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_smmu_cfg_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_smmu_cfg_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_venus_tbu_clk = {
+ .cbcr_reg = VENUS_TBU_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(5),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_venus_tbu_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_venus_tbu_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_vfe_tbu_clk = {
+ .cbcr_reg = VFE_TBU_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(9),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_vfe_tbu_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_vfe_tbu_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_gtcu_ahb_clk = {
+ .cbcr_reg = GTCU_AHB_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(13),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_gtcu_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_gtcu_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb2a_phy_sleep_clk = {
+ .cbcr_reg = USB2A_PHY_SLEEP_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb2a_phy_sleep_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb2a_phy_sleep_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hs_phy_cfg_ahb_clk = {
+ .cbcr_reg = USB_HS_PHY_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hs_phy_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hs_phy_cfg_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+ .cbcr_reg = USB_HS_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hs_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hs_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+ .cbcr_reg = USB_HS_SYSTEM_CBCR,
+ .bcr_reg = USB_HS_BCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hs_system_clk",
+ .parent = &usb_hs_system_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hs_system_clk.c),
+ },
+};
+
+static struct reset_clk gcc_usb2_hs_phy_only_clk = {
+ .reset_reg = USB2_HS_PHY_ONLY_BCR,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb2_hs_phy_only_clk",
+ .ops = &clk_ops_rst,
+ CLK_INIT(gcc_usb2_hs_phy_only_clk.c),
+ },
+};
+
+static struct reset_clk gcc_qusb2_phy_clk = {
+ .reset_reg = QUSB2_PHY_BCR,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_qusb2_phy_clk",
+ .ops = &clk_ops_rst,
+ CLK_INIT(gcc_qusb2_phy_clk.c),
+ },
+};
+
+static struct branch_clk gcc_venus0_ahb_clk = {
+ .cbcr_reg = VENUS0_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_venus0_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_venus0_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_venus0_axi_clk = {
+ .cbcr_reg = VENUS0_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_venus0_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_venus0_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_venus0_core0_vcodec0_clk = {
+ .cbcr_reg = VENUS0_CORE0_VCODEC0_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_venus0_core0_vcodec0_clk",
+ .parent = &vcodec0_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_venus0_core0_vcodec0_clk.c),
+ },
+};
+
+static struct branch_clk gcc_venus0_vcodec0_clk = {
+ .cbcr_reg = VENUS0_VCODEC0_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_venus0_vcodec0_clk",
+ .parent = &vcodec0_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_venus0_vcodec0_clk.c),
+ },
+};
+
+static struct gate_clk gcc_snoc_qosgen_clk = {
+ .en_mask = BIT(0),
+ .en_reg = SNOC_QOSGEN,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_snoc_qosgen_clk",
+ .ops = &clk_ops_gate,
+ .flags = CLKFLAG_SKIP_HANDOFF,
+ CLK_INIT(gcc_snoc_qosgen_clk.c),
+ },
+};
+
+static struct mux_clk gcc_debug_mux;
+static struct clk_ops clk_ops_debug_mux;
+
+static struct measure_clk apc0_m_clk = {
+ .c = {
+ .ops = &clk_ops_empty,
+ .dbg_name = "apc0_m_clk",
+ CLK_INIT(apc0_m_clk.c),
+ },
+};
+
+static struct measure_clk apc1_m_clk = {
+ .c = {
+ .ops = &clk_ops_empty,
+ .dbg_name = "apc1_m_clk",
+ CLK_INIT(apc1_m_clk.c),
+ },
+};
+
+static struct measure_clk apc2_m_clk = {
+ .c = {
+ .ops = &clk_ops_empty,
+ .dbg_name = "apc2_m_clk",
+ CLK_INIT(apc2_m_clk.c),
+ },
+};
+
+static struct measure_clk apc3_m_clk = {
+ .c = {
+ .ops = &clk_ops_empty,
+ .dbg_name = "apc3_m_clk",
+ CLK_INIT(apc3_m_clk.c),
+ },
+};
+
+static struct measure_clk l2_m_clk = {
+ .c = {
+ .ops = &clk_ops_empty,
+ .dbg_name = "l2_m_clk",
+ CLK_INIT(l2_m_clk.c),
+ },
+};
+
+static void __iomem *meas_base;
+
+static struct mux_clk apss_debug_ter_mux = {
+ .ops = &mux_reg_ops,
+ .mask = 0x3,
+ .shift = 8,
+ MUX_SRC_LIST(
+ {&apc0_m_clk.c, 0},
+ {&apc1_m_clk.c, 1},
+ {&apc2_m_clk.c, 2},
+ {&apc3_m_clk.c, 3},
+ ),
+ .base = &meas_base,
+ .c = {
+ .dbg_name = "apss_debug_ter_mux",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(apss_debug_ter_mux.c),
+ },
+};
+
+static struct mux_clk apss_debug_sec_mux = {
+ .ops = &mux_reg_ops,
+ .mask = 0x7,
+ .shift = 12,
+ MUX_SRC_LIST(
+ {&apss_debug_ter_mux.c, 0},
+ {&l2_m_clk.c, 1},
+ ),
+ MUX_REC_SRC_LIST(
+ &apss_debug_ter_mux.c,
+ ),
+ .base = &meas_base,
+ .c = {
+ .dbg_name = "apss_debug_sec_mux",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(apss_debug_sec_mux.c),
+ },
+};
+
+static struct mux_clk apss_debug_pri_mux = {
+ .ops = &mux_reg_ops,
+ .mask = 0x3,
+ .shift = 16,
+ MUX_SRC_LIST(
+ {&apss_debug_sec_mux.c, 0},
+ ),
+ MUX_REC_SRC_LIST(
+ &apss_debug_sec_mux.c,
+ ),
+ .base = &meas_base,
+ .c = {
+ .dbg_name = "apss_debug_pri_mux",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(apss_debug_pri_mux.c),
+ },
+};
+
+static struct measure_clk_data debug_mux_priv = {
+ .cxo = &xo_clk_src.c,
+ .plltest_reg = GCC_PLLTEST_PAD_CFG,
+ .plltest_val = 0x51A00,
+ .xo_div4_cbcr = GCC_XO_DIV4_CBCR,
+ .ctl_reg = CLOCK_FRQ_MEASURE_CTL,
+ .status_reg = CLOCK_FRQ_MEASURE_STATUS,
+ .base = &virt_bases[GCC_BASE],
+};
+
+static int gcc_set_mux_sel(struct mux_clk *clk, int sel)
+{
+ u32 regval;
+
+ regval = readl_relaxed(GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+ regval &= 0x1FF;
+ writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+ if (sel == 0xFFFF)
+ return 0;
+
+ mux_reg_ops.set_mux_sel(clk, sel);
+
+ return 0;
+};
+
+static struct clk_mux_ops gcc_debug_mux_ops;
+static struct mux_clk gcc_debug_mux = {
+ .priv = &debug_mux_priv,
+ .ops = &gcc_debug_mux_ops,
+ .offset = GCC_DEBUG_CLK_CTL,
+ .mask = 0x1FF,
+ .en_offset = GCC_DEBUG_CLK_CTL,
+ .en_mask = BIT(16),
+ .base = &virt_bases[GCC_BASE],
+ MUX_REC_SRC_LIST(
+ &rpm_debug_clk.c,
+ &apss_debug_pri_mux.c,
+ ),
+ MUX_SRC_LIST(
+ { &rpm_debug_clk.c, 0xFFFF},
+ { &apss_debug_pri_mux.c, 0x016A},
+ { &gcc_gp1_clk.c, 0x0010 },
+ { &gcc_gp2_clk.c, 0x0011 },
+ { &gcc_gp3_clk.c, 0x0012 },
+ { &gcc_bimc_gfx_clk.c, 0x002d },
+ { &gcc_mss_cfg_ahb_clk.c, 0x0030 },
+ { &gcc_mss_q6_bimc_axi_clk.c, 0x0031 },
+ { &gcc_apss_tcu_clk.c, 0x0050 },
+ { &gcc_mdp_tbu_clk.c, 0x0051 },
+ { &gcc_gfx_tbu_clk.c, 0x0052 },
+ { &gcc_gfx_tcu_clk.c, 0x0053 },
+ { &gcc_venus_tbu_clk.c, 0x0054 },
+ { &gcc_gtcu_ahb_clk.c, 0x0058 },
+ { &gcc_vfe_tbu_clk.c, 0x005a },
+ { &gcc_smmu_cfg_clk.c, 0x005b },
+ { &gcc_usb_hs_system_clk.c, 0x0060 },
+ { &gcc_usb_hs_ahb_clk.c, 0x0061 },
+ { &gcc_usb2a_phy_sleep_clk.c, 0x0063 },
+ { &gcc_usb_hs_phy_cfg_ahb_clk.c, 0x0064 },
+ { &gcc_sdcc1_apps_clk.c, 0x0068 },
+ { &gcc_sdcc1_ahb_clk.c, 0x0069 },
+ { &gcc_sdcc2_apps_clk.c, 0x0070 },
+ { &gcc_sdcc2_ahb_clk.c, 0x0071 },
+ { &gcc_blsp1_ahb_clk.c, 0x0088 },
+ { &gcc_blsp1_qup1_spi_apps_clk.c, 0x008a },
+ { &gcc_blsp1_qup1_i2c_apps_clk.c, 0x008b },
+ { &gcc_blsp1_uart1_apps_clk.c, 0x008c },
+ { &gcc_blsp1_qup2_spi_apps_clk.c, 0x008e },
+ { &gcc_blsp1_qup2_i2c_apps_clk.c, 0x0090 },
+ { &gcc_blsp1_uart2_apps_clk.c, 0x0091 },
+ { &gcc_blsp1_qup3_spi_apps_clk.c, 0x0093 },
+ { &gcc_blsp1_qup3_i2c_apps_clk.c, 0x0094 },
+ { &gcc_blsp1_qup4_spi_apps_clk.c, 0x0098 },
+ { &gcc_blsp1_qup4_i2c_apps_clk.c, 0x0099 },
+ { &gcc_blsp1_qup5_spi_apps_clk.c, 0x009c },
+ { &gcc_blsp1_qup5_i2c_apps_clk.c, 0x009d },
+ { &gcc_blsp1_qup6_spi_apps_clk.c, 0x00a1 },
+ { &gcc_blsp1_qup6_i2c_apps_clk.c, 0x00a2 },
+ { &gcc_camss_top_ahb_clk.c, 0x00a8 },
+ { &gcc_camss_ahb_clk.c, 0x00a9 },
+ { &gcc_camss_gp0_clk.c, 0x00ab },
+ { &gcc_camss_gp1_clk.c, 0x00ac },
+ { &gcc_camss_mclk0_clk.c, 0x00ad },
+ { &gcc_camss_mclk1_clk.c, 0x00ae },
+ { &gcc_camss_csi0phytimer_clk.c, 0x00b1 },
+ { &gcc_camss_vfe0_clk.c, 0x00b8 },
+ { &gcc_camss_vfe_ahb_clk.c, 0x00bb },
+ { &gcc_camss_vfe_axi_clk.c, 0x00bc },
+ { &gcc_camss_csi_vfe0_clk.c, 0x00bf },
+ { &gcc_camss_csi0_clk.c, 0x00c0 },
+ { &gcc_camss_csi0_ahb_clk.c, 0x00c1 },
+ { &gcc_camss_csi0phy_clk.c, 0x00c2 },
+ { &gcc_camss_csi0rdi_clk.c, 0x00c3 },
+ { &gcc_camss_csi0pix_clk.c, 0x00c4 },
+ { &gcc_camss_csi1_clk.c, 0x00c5 },
+ { &gcc_camss_csi1_ahb_clk.c, 0x00c6 },
+ { &gcc_camss_csi1phy_clk.c, 0x00c7 },
+ { &gcc_pdm_ahb_clk.c, 0x00d0 },
+ { &gcc_pdm2_clk.c, 0x00d2 },
+ { &gcc_prng_ahb_clk.c, 0x00d8 },
+ { &gcc_camss_csi1rdi_clk.c, 0x00e0 },
+ { &gcc_camss_csi1pix_clk.c, 0x00e1 },
+ { &gcc_camss_ispif_ahb_clk.c, 0x00e2 },
+ { &gcc_venus0_core0_vcodec0_clk.c, 0x00ee },
+ { &gcc_boot_rom_ahb_clk.c, 0x00f8 },
+ { &gcc_crypto_clk.c, 0x0138 },
+ { &gcc_crypto_axi_clk.c, 0x0139 },
+ { &gcc_crypto_ahb_clk.c, 0x013a },
+ { &gcc_bimc_gpu_clk.c, 0x0157 },
+ { &gcc_oxili_gfx3d_clk.c, 0x01ea },
+ { &gcc_oxili_ahb_clk.c, 0x01eb },
+ { &gcc_venus0_vcodec0_clk.c, 0x01f1 },
+ { &gcc_venus0_axi_clk.c, 0x01f2 },
+ { &gcc_venus0_ahb_clk.c, 0x01f3 },
+ { &gcc_mdss_ahb_clk.c, 0x01f6 },
+ { &gcc_mdss_axi_clk.c, 0x01f7 },
+ { &gcc_mdss_pclk0_clk.c, 0x01f8 },
+ { &gcc_mdss_mdp_clk.c, 0x01f9 },
+ { &gcc_mdss_vsync_clk.c, 0x01fb },
+ { &gcc_mdss_byte0_clk.c, 0x01fc },
+ { &gcc_mdss_esc0_clk.c, 0x01fd },
+ { &wcnss_m_clk.c, 0x0198},
+ ),
+ .c = {
+ .dbg_name = "gcc_debug_mux",
+ .ops = &clk_ops_debug_mux,
+ .flags = CLKFLAG_NO_RATE_CACHE | CLKFLAG_MEASURE,
+ CLK_INIT(gcc_debug_mux.c),
+ },
+};
+
+/* Clock lookup */
+static struct clk_lookup msm_clocks_lookup[] = {
+ /* PLLs */
+ CLK_LIST(gpll0_clk_src),
+ CLK_LIST(gpll0_ao_clk_src),
+ CLK_LIST(gpll1_clk_src),
+ CLK_LIST(gpll2_clk_src),
+ CLK_LIST(a7sspll),
+
+ /* RCGs */
+ CLK_LIST(apss_ahb_clk_src),
+ CLK_LIST(camss_top_ahb_clk_src),
+ CLK_LIST(csi0_clk_src),
+ CLK_LIST(csi1_clk_src),
+ CLK_LIST(vfe0_clk_src),
+ CLK_LIST(mdp_clk_src),
+ CLK_LIST(gfx3d_clk_src),
+ CLK_LIST(blsp1_qup1_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup1_spi_apps_clk_src),
+ CLK_LIST(blsp1_qup2_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup2_spi_apps_clk_src),
+ CLK_LIST(blsp1_qup3_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup3_spi_apps_clk_src),
+ CLK_LIST(blsp1_qup4_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup4_spi_apps_clk_src),
+ CLK_LIST(blsp1_qup5_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup5_spi_apps_clk_src),
+ CLK_LIST(blsp1_qup6_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup6_spi_apps_clk_src),
+ CLK_LIST(blsp1_uart1_apps_clk_src),
+ CLK_LIST(blsp1_uart2_apps_clk_src),
+ CLK_LIST(camss_gp0_clk_src),
+ CLK_LIST(camss_gp1_clk_src),
+ CLK_LIST(mclk0_clk_src),
+ CLK_LIST(mclk1_clk_src),
+ CLK_LIST(csi0phytimer_clk_src),
+ CLK_LIST(gp1_clk_src),
+ CLK_LIST(gp2_clk_src),
+ CLK_LIST(gp3_clk_src),
+ CLK_LIST(esc0_clk_src),
+ CLK_LIST(vsync_clk_src),
+ CLK_LIST(pdm2_clk_src),
+ CLK_LIST(sdcc1_apps_clk_src),
+ CLK_LIST(sdcc2_apps_clk_src),
+ CLK_LIST(usb_hs_system_clk_src),
+ CLK_LIST(vcodec0_clk_src),
+
+ /* Voteable Clocks */
+ CLK_LIST(gcc_blsp1_ahb_clk),
+ CLK_LIST(gcc_boot_rom_ahb_clk),
+ CLK_LIST(gcc_prng_ahb_clk),
+ CLK_LIST(gcc_apss_tcu_clk),
+ CLK_LIST(gcc_gfx_tbu_clk),
+ CLK_LIST(gcc_gfx_tcu_clk),
+ CLK_LIST(gcc_mdp_tbu_clk),
+ CLK_LIST(gcc_gtcu_ahb_clk),
+ CLK_LIST(gcc_smmu_cfg_clk),
+ CLK_LIST(gcc_venus_tbu_clk),
+ CLK_LIST(gcc_vfe_tbu_clk),
+
+ /* Branches */
+ CLK_LIST(gcc_blsp1_qup1_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup1_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_qup2_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup2_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_qup3_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup3_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_qup4_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup4_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_qup5_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup5_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_qup6_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup6_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_uart1_apps_clk),
+ CLK_LIST(gcc_blsp1_uart2_apps_clk),
+ CLK_LIST(gcc_camss_csi0_ahb_clk),
+ CLK_LIST(gcc_camss_csi0_clk),
+ CLK_LIST(gcc_camss_csi0phy_clk),
+ CLK_LIST(gcc_camss_csi0pix_clk),
+ CLK_LIST(gcc_camss_csi0rdi_clk),
+ CLK_LIST(gcc_camss_csi1_ahb_clk),
+ CLK_LIST(gcc_camss_csi1_clk),
+ CLK_LIST(gcc_camss_csi1phy_clk),
+ CLK_LIST(gcc_camss_csi1pix_clk),
+ CLK_LIST(gcc_camss_csi1rdi_clk),
+ CLK_LIST(gcc_camss_csi_vfe0_clk),
+ CLK_LIST(gcc_camss_gp0_clk),
+ CLK_LIST(gcc_camss_gp1_clk),
+ CLK_LIST(gcc_camss_ispif_ahb_clk),
+ CLK_LIST(gcc_camss_mclk0_clk),
+ CLK_LIST(gcc_camss_mclk1_clk),
+ CLK_LIST(gcc_camss_csi0phytimer_clk),
+ CLK_LIST(gcc_camss_ahb_clk),
+ CLK_LIST(gcc_camss_top_ahb_clk),
+ CLK_LIST(gcc_camss_vfe0_clk),
+ CLK_LIST(gcc_camss_vfe_ahb_clk),
+ CLK_LIST(gcc_camss_vfe_axi_clk),
+ CLK_LIST(gcc_gp1_clk),
+ CLK_LIST(gcc_gp2_clk),
+ CLK_LIST(gcc_gp3_clk),
+ CLK_LIST(gcc_mdss_ahb_clk),
+ CLK_LIST(gcc_mdss_axi_clk),
+ CLK_LIST(gcc_mdss_esc0_clk),
+ CLK_LIST(gcc_mdss_mdp_clk),
+ CLK_LIST(gcc_mdss_vsync_clk),
+ CLK_LIST(gcc_mss_cfg_ahb_clk),
+ CLK_LIST(gcc_mss_q6_bimc_axi_clk),
+ CLK_LIST(gcc_oxili_ahb_clk),
+ CLK_LIST(gcc_oxili_gfx3d_clk),
+ CLK_LIST(gcc_pdm2_clk),
+ CLK_LIST(gcc_pdm_ahb_clk),
+ CLK_LIST(gcc_sdcc1_ahb_clk),
+ CLK_LIST(gcc_sdcc1_apps_clk),
+ CLK_LIST(gcc_sdcc2_ahb_clk),
+ CLK_LIST(gcc_sdcc2_apps_clk),
+ CLK_LIST(gcc_usb2a_phy_sleep_clk),
+ CLK_LIST(gcc_usb_hs_ahb_clk),
+ CLK_LIST(gcc_usb_hs_system_clk),
+ CLK_LIST(gcc_venus0_ahb_clk),
+ CLK_LIST(gcc_venus0_axi_clk),
+ CLK_LIST(gcc_venus0_vcodec0_clk),
+ CLK_LIST(gcc_bimc_gfx_clk),
+ CLK_LIST(gcc_bimc_gpu_clk),
+ CLK_LIST(gcc_venus0_core0_vcodec0_clk),
+ CLK_LIST(gcc_usb_hs_phy_cfg_ahb_clk),
+ CLK_LIST(wcnss_m_clk),
+
+ /* Crypto clocks */
+ CLK_LIST(gcc_crypto_clk),
+ CLK_LIST(gcc_crypto_ahb_clk),
+ CLK_LIST(gcc_crypto_axi_clk),
+ CLK_LIST(crypto_clk_src),
+
+ /* Reset clocks */
+ CLK_LIST(gcc_usb2_hs_phy_only_clk),
+ CLK_LIST(gcc_qusb2_phy_clk),
+
+ /* QoS Reference clock */
+ CLK_LIST(gcc_snoc_qosgen_clk),
+};
+
+static const struct msm_reset_map gcc_8909_resets[] = {
+ [GCC_USB_HS_BCR] = {0x41000},
+ [GCC_USB2_HS_PHY_ONLY_BCR] = {0x41034},
+ [GCC_QUSB2_PHY_BCR] = {0x4103C},
+};
+
+static int add_dev_opp(struct clk *c, struct device *dev,
+ unsigned long max_rate)
+{
+ unsigned long rate = 0;
+ int level;
+ long ret;
+
+ while (1) {
+ ret = clk_round_rate(c, rate + 1);
+ if (ret < 0) {
+ pr_warn("round_rate failed at %lu\n", rate);
+ return ret;
+ }
+ rate = ret;
+ level = find_vdd_level(c, rate);
+ if (level <= 0) {
+ pr_warn("no uv for %lu.\n", rate);
+ return -EINVAL;
+ }
+ ret = dev_pm_opp_add(dev, rate, c->vdd_class->vdd_uv[level]);
+ if (ret) {
+ pr_warn("failed to add OPP for %lu\n", rate);
+ return ret;
+ }
+ if (rate >= max_rate)
+ break;
+ }
+ return 0;
+}
+
+static void register_opp_for_dev(struct platform_device *pdev)
+{
+ struct clk *opp_clk, *opp_clk_src;
+ unsigned long dev_fmax;
+
+ opp_clk = clk_get(&pdev->dev, "core_clk");
+ if (IS_ERR(opp_clk)) {
+ pr_err("Error getting core clk: %lu\n", PTR_ERR(opp_clk));
+ return;
+ }
+ opp_clk_src = opp_clk;
+ if (opp_clk->num_fmax <= 0) {
+ if (opp_clk->parent && opp_clk->parent->num_fmax > 0)
+ opp_clk_src = opp_clk->parent;
+ else
+ return;
+ }
+
+ dev_fmax = opp_clk_src->fmax[opp_clk_src->num_fmax - 1];
+ WARN(add_dev_opp(opp_clk_src, &pdev->dev, dev_fmax),
+ "Failed to add OPP levels for dev\n");
+}
+
+static void gcc_gfx3d_fmax(struct platform_device *pdev)
+{
+ void __iomem *base;
+ u32 pte_efuse, bin, shift = 2, mask = 0x7;
+
+ base = devm_ioremap(&pdev->dev, 0x0005c00c, 0x8);
+ if (IS_ERR(base)) {
+ pr_err("Failed to map raw base address\n");
+ return;
+ }
+
+ pte_efuse = readl_relaxed(base);
+ devm_iounmap(&pdev->dev, base);
+ bin = (pte_efuse >> shift) & mask;
+ if (bin != 0)
+ return;
+
+ pr_debug("%s, bin: %d\n", __func__, bin);
+
+ gpll2_clk_src.c.rate = 912000000;
+
+ gfx3d_clk_src.c.fmax[VDD_DIG_HIGH] = 456000000;
+ gfx3d_clk_src.freq_tbl = ftbl_gcc_oxili_gfx3d_465_clk;
+
+ mclk0_clk_src.freq_tbl = ftbl_gcc_camss_mclkm_clk;
+ mclk0_clk_src.c.fmax = mclk0_1_fmax;
+ mclk1_clk_src.freq_tbl = ftbl_gcc_camss_mclkm_clk;
+ mclk1_clk_src.c.fmax = mclk0_1_fmax;
+}
+
+static int msm_gcc_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct clk *xo_gcc;
+ int ret, node = 0;
+ u32 regval;
+ struct device_node *opp_dev_node = NULL;
+ struct platform_device *opp_dev = NULL;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+ if (!res) {
+ dev_err(&pdev->dev, "Register base not defined\n");
+ return -ENOMEM;
+ }
+
+ virt_bases[GCC_BASE] = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!virt_bases[GCC_BASE]) {
+ dev_err(&pdev->dev, "Failed to ioremap CC registers\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_base");
+ if (!res) {
+ dev_err(&pdev->dev, "APCS PLL Register base not defined\n");
+ return -ENOMEM;
+ }
+
+ virt_bases[APCS_PLL_BASE] = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!virt_bases[APCS_PLL_BASE]) {
+ dev_err(&pdev->dev, "Failed to ioremap APCS PLL registers\n");
+ return -ENOMEM;
+ }
+
+ vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig");
+ if (IS_ERR(vdd_dig.regulator[0])) {
+ if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_dig regulator!!!\n");
+ return PTR_ERR(vdd_dig.regulator[0]);
+ }
+
+ vdd_sr2_pll.regulator[0] = devm_regulator_get(&pdev->dev,
+ "vdd_sr2_pll");
+ if (IS_ERR(vdd_sr2_pll.regulator[0])) {
+ if (!(PTR_ERR(vdd_sr2_pll.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_sr2_pll regulator!!!\n");
+ return PTR_ERR(vdd_sr2_pll.regulator[0]);
+ }
+
+ vdd_sr2_pll.regulator[1] = devm_regulator_get(&pdev->dev,
+ "vdd_sr2_dig");
+ if (IS_ERR(vdd_sr2_pll.regulator[1])) {
+ if (!(PTR_ERR(vdd_sr2_pll.regulator[1]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_sr2_dig regulator!!!\n");
+ return PTR_ERR(vdd_sr2_pll.regulator[1]);
+ }
+
+ xo_gcc = xo_clk_src.c.parent = devm_clk_get(&pdev->dev, "xo");
+ if (IS_ERR(xo_gcc)) {
+ if (!(PTR_ERR(xo_gcc) == -EPROBE_DEFER))
+ dev_err(&pdev->dev, "Unable to get XO clock!!!\n");
+ return PTR_ERR(xo_gcc);
+ }
+
+ /*Vote for GPLL0 to turn on. Needed by acpuclock. */
+ regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+ regval |= BIT(0);
+ writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+
+ xo_a_clk_src.c.parent = clk_get(&pdev->dev, "xo_a");
+ if (IS_ERR(xo_a_clk_src.c.parent)) {
+ if (!(PTR_ERR(xo_a_clk_src.c.parent) == -EPROBE_DEFER))
+ dev_err(&pdev->dev, "Unable to get xo_a clock!!!\n");
+ return PTR_ERR(xo_a_clk_src.c.parent);
+ }
+
+ gcc_gfx3d_fmax(pdev);
+
+ ret = of_msm_clock_register(pdev->dev.of_node,
+ msm_clocks_lookup,
+ ARRAY_SIZE(msm_clocks_lookup));
+ if (ret)
+ return ret;
+
+ clk_set_rate(&apss_ahb_clk_src.c, 19200000);
+ clk_prepare_enable(&apss_ahb_clk_src.c);
+
+ opp_dev_node = of_parse_phandle(pdev->dev.of_node, "qcom,dev-opp-list",
+ node);
+ while (opp_dev_node) {
+ opp_dev = of_find_device_by_node(opp_dev_node);
+ if (!opp_dev) {
+ pr_err("cant find device for node\n");
+ return -EINVAL;
+ }
+ register_opp_for_dev(opp_dev);
+ node++;
+ opp_dev_node = of_parse_phandle(pdev->dev.of_node,
+ "qcom,dev-opp-list", node);
+ }
+
+ msm_reset_controller_register(pdev, gcc_8909_resets,
+ ARRAY_SIZE(gcc_8909_resets),
+ virt_bases[GCC_BASE]);
+
+ dev_info(&pdev->dev, "Registered GCC clocks\n");
+
+ return 0;
+}
+
+static const struct of_device_id msm_clock_gcc_match_table[] = {
+ { .compatible = "qcom,gcc-8909" },
+ {},
+};
+
+static struct platform_driver msm_clock_gcc_driver = {
+ .probe = msm_gcc_probe,
+ .driver = {
+ .name = "qcom,gcc-8909",
+ .of_match_table = msm_clock_gcc_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_gcc_init(void)
+{
+ return platform_driver_register(&msm_clock_gcc_driver);
+}
+arch_initcall(msm_gcc_init);
+
+static struct clk_lookup msm_clocks_measure[] = {
+ CLK_LOOKUP_OF("measure", gcc_debug_mux, "debug"),
+ CLK_LIST(apss_debug_pri_mux),
+ CLK_LIST(apc0_m_clk),
+ CLK_LIST(apc1_m_clk),
+ CLK_LIST(apc2_m_clk),
+ CLK_LIST(apc3_m_clk),
+ CLK_LIST(l2_m_clk),
+};
+
+static int msm_clock_debug_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "meas");
+ if (!res) {
+ dev_err(&pdev->dev, "GLB clock diag base not defined.\n");
+ return -EINVAL;
+ }
+
+ meas_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!meas_base) {
+ dev_err(&pdev->dev, "Unable to map GLB clock diag base.\n");
+ return -ENOMEM;
+ }
+
+ clk_ops_debug_mux = clk_ops_gen_mux;
+ clk_ops_debug_mux.get_rate = measure_get_rate;
+
+ gcc_debug_mux_ops = mux_reg_ops;
+ gcc_debug_mux_ops.set_mux_sel = gcc_set_mux_sel;
+
+ rpm_debug_clk.c.parent = clk_get(&pdev->dev, "rpm_debug_mux");
+ if (IS_ERR(rpm_debug_clk.c.parent)) {
+ dev_err(&pdev->dev, "Failed to get RPM debug Mux\n");
+ return PTR_ERR(rpm_debug_clk.c.parent);
+ }
+
+ ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_measure,
+ ARRAY_SIZE(msm_clocks_measure));
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register debug Mux\n");
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "Registered Debug Mux successfully\n");
+ return ret;
+}
+
+static const struct of_device_id msm_clock_debug_match_table[] = {
+ { .compatible = "qcom,cc-debug-8909" },
+ {}
+};
+
+static struct platform_driver msm_clock_debug_driver = {
+ .probe = msm_clock_debug_probe,
+ .driver = {
+ .name = "qcom,cc-debug-8909",
+ .of_match_table = msm_clock_debug_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_clock_debug_init(void)
+{
+ return platform_driver_register(&msm_clock_debug_driver);
+}
+late_initcall(msm_clock_debug_init);
+
+/* MDSS DSI_PHY_PLL */
+static struct clk_lookup msm_clocks_gcc_mdss[] = {
+ CLK_LIST(byte0_clk_src),
+ CLK_LIST(pclk0_clk_src),
+ CLK_LIST(gcc_mdss_pclk0_clk),
+ CLK_LIST(gcc_mdss_byte0_clk),
+};
+
+static int msm_gcc_mdss_probe(struct platform_device *pdev)
+{
+ int counter = 0, ret = 0;
+
+ pclk0_clk_src.c.parent = devm_clk_get(&pdev->dev, "pclk0_src");
+ if (IS_ERR(pclk0_clk_src.c.parent)) {
+ dev_err(&pdev->dev, "Failed to get pclk0 source.\n");
+ return PTR_ERR(pclk0_clk_src.c.parent);
+ }
+
+ for (counter = 0; counter < (sizeof(ftbl_gcc_mdss_pclk0_clk)/
+ sizeof(struct clk_freq_tbl)); counter++)
+ ftbl_gcc_mdss_pclk0_clk[counter].src_clk =
+ pclk0_clk_src.c.parent;
+
+ byte0_clk_src.c.parent = devm_clk_get(&pdev->dev, "byte0_src");
+ if (IS_ERR(byte0_clk_src.c.parent)) {
+ dev_err(&pdev->dev, "Failed to get byte0 source.\n");
+ devm_clk_put(&pdev->dev, pclk0_clk_src.c.parent);
+ return PTR_ERR(byte0_clk_src.c.parent);
+ }
+
+ for (counter = 0; counter < (sizeof(ftbl_gcc_mdss_byte0_clk)/
+ sizeof(struct clk_freq_tbl)); counter++)
+ ftbl_gcc_mdss_byte0_clk[counter].src_clk =
+ byte0_clk_src.c.parent;
+
+ ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_gcc_mdss,
+ ARRAY_SIZE(msm_clocks_gcc_mdss));
+ if (ret)
+ return ret;
+
+ dev_info(&pdev->dev, "Registered GCC MDSS clocks.\n");
+
+ return ret;
+}
+
+static const struct of_device_id msm_clock_mdss_match_table[] = {
+ { .compatible = "qcom,gcc-mdss-8909" },
+ {}
+};
+
+static struct platform_driver msm_clock_gcc_mdss_driver = {
+ .probe = msm_gcc_mdss_probe,
+ .driver = {
+ .name = "gcc-mdss-8909",
+ .of_match_table = msm_clock_mdss_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_gcc_mdss_init(void)
+{
+ return platform_driver_register(&msm_clock_gcc_mdss_driver);
+}
+fs_initcall_sync(msm_gcc_mdss_init);
diff --git a/drivers/clk/msm/clock-gcc-mdm9607.c b/drivers/clk/msm/clock-gcc-mdm9607.c
new file mode 100644
index 0000000..3900b08
--- /dev/null
+++ b/drivers/clk/msm/clock-gcc-mdm9607.c
@@ -0,0 +1,1954 @@
+/*
+ * 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/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/clock-pll.h>
+#include <soc/qcom/clock-alpha-pll.h>
+#include <soc/qcom/clock-voter.h>
+#include <soc/qcom/clock-rpm.h>
+#include <soc/qcom/rpm-smd.h>
+
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+
+#include <dt-bindings/clock/mdm-clocks-9607.h>
+#include <dt-bindings/clock/mdm-clocks-hwio-9607.h>
+
+#include "clock.h"
+
+enum {
+ GCC_BASE,
+ DEBUG_BASE,
+ APCS_PLL_BASE,
+ N_BASES,
+};
+
+static void __iomem *virt_bases[N_BASES];
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+
+DEFINE_CLK_RPM_SMD_BRANCH(xo_clk_src, xo_a_clk_src,
+ RPM_MISC_CLK_TYPE, XO_ID, 19200000);
+
+DEFINE_CLK_RPM_SMD(pcnoc_clk, pcnoc_a_clk, RPM_BUS_CLK_TYPE, PCNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
+DEFINE_CLK_RPM_SMD(qpic_clk, qpic_a_clk, RPM_QPIC_CLK_TYPE, QPIC_ID, NULL);
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk1, bb_clk1_a, BB_CLK1_ID);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk1_pin, bb_clk1_a_pin, BB_CLK1_ID);
+
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_usb_clk, &bimc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_usb_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_keepalive_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_msmbus_clk, &pcnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_msmbus_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_usb_clk, &pcnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_usb_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_BRANCH_VOTER(xo_lpm_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_otg_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_mss_clk, &xo_clk_src.c);
+
+#define F_APCS_STROMER_PLL(f, l, m, pre_div, post_div, vco) \
+ { \
+ .freq_hz = (f), \
+ .l_val = (l), \
+ .a_val = (m), \
+ .pre_div_val = BVAL(14, 12, (pre_div)), \
+ .post_div_val = BVAL(11, 8, (post_div)), \
+ .vco_val = BVAL(21, 20, (vco)), \
+ }
+
+static DEFINE_VDD_REGULATORS(vdd_stromer_pll, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+static struct alpha_pll_masks pll_masks_p = {
+ .lock_mask = BIT(31),
+ .active_mask = BIT(30),
+ .vco_mask = BM(21, 20) >> 20,
+ .vco_shift = 20,
+ .alpha_en_mask = BIT(24),
+ .output_mask = 0xf,
+ .update_mask = BIT(22),
+ .post_div_mask = BM(11, 8),
+};
+
+static struct alpha_pll_vco_tbl p_vco[] = {
+ VCO(0, 700000000, 1400000000),
+};
+
+static struct alpha_pll_clk a7sspll = {
+ .masks = &pll_masks_p,
+ .vco_tbl = p_vco,
+ .num_vco = ARRAY_SIZE(p_vco),
+ .base = &virt_bases[APCS_PLL_BASE],
+ .offset = APCS_MODE,
+ .slew = true,
+ .enable_config = 1,
+ .post_div_config = 0,
+ .c = {
+ .parent = &xo_a_clk_src.c,
+ .dbg_name = "a7sspll",
+ .ops = &clk_ops_dyna_alpha_pll,
+ VDD_STROMER_FMAX_MAP1(LOW, 1400000000),
+ CLK_INIT(a7sspll.c),
+ },
+};
+
+static unsigned int soft_vote_gpll0;
+
+static struct pll_vote_clk gpll0_clk_src = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(0),
+ .status_reg = (void __iomem *)GPLL0_MODE,
+ .status_mask = BIT(30),
+ .base = &virt_bases[GCC_BASE],
+ .soft_vote = &soft_vote_gpll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+ .c = {
+ .parent = &xo_clk_src.c,
+ .rate = 800000000,
+ .dbg_name = "gpll0_clk_src",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(gpll0_clk_src.c),
+ },
+};
+
+static struct pll_vote_clk gpll0_ao_clk_src = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(0),
+ .status_reg = (void __iomem *)GPLL0_MODE,
+ .status_mask = BIT(30),
+ .soft_vote = &soft_vote_gpll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &xo_a_clk_src.c,
+ .rate = 800000000,
+ .dbg_name = "gpll0_ao_clk_src",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(gpll0_ao_clk_src.c),
+ },
+};
+
+static struct pll_vote_clk gpll2_clk_src = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(3),
+ .status_reg = (void __iomem *)GPLL2_MODE,
+ .status_mask = BIT(30),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &xo_clk_src.c,
+ .rate = 480000000,
+ .dbg_name = "gpll2_clk_src",
+ .ops = &clk_ops_pll_vote,
+ CLK_INIT(gpll2_clk_src.c),
+ },
+};
+
+static struct pll_vote_clk gpll1_clk_src = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(1),
+ .status_reg = (void __iomem *)GPLL1_STATUS,
+ .status_mask = BIT(17),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &xo_clk_src.c,
+ .rate = 614400000,
+ .dbg_name = "gpll1_clk_src",
+ .ops = &clk_ops_pll_vote,
+ CLK_INIT(gpll1_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_apss_ahb_clk_src[] = {
+ F( 19200000, xo_a, 1, 0, 0),
+ F( 50000000, gpll0, 16, 0, 0),
+ F( 100000000, gpll0, 8, 0, 0),
+ F_END
+};
+
+static struct rcg_clk apss_ahb_clk_src = {
+ .cmd_rcgr_reg = APSS_AHB_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_apss_ahb_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "apss_ahb_clk_src",
+ .ops = &clk_ops_rcg,
+ CLK_INIT(apss_ahb_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_emac_0_125m_clk_src[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F_EXT( 25000000, emac_0_125m_clk, 5, 0, 0),
+ F_EXT( 125000000, emac_0_125m_clk, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk emac_0_125m_clk_src = {
+ .cmd_rcgr_reg = EMAC_0_125M_CMD_RCGR,
+ .current_freq = ftbl_emac_0_125m_clk_src,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_emac_0_125m_clk_src,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "emac_0_125m_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 125000000),
+ CLK_INIT(emac_0_125m_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_emac_0_sys_25m_clk_src[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F_EXT( 25000000, emac_0_125m_clk, 5, 0, 0),
+ F_EXT( 125000000, emac_0_125m_clk, 1, 0, 0),
+ F_END
+};
+static struct rcg_clk emac_0_sys_25m_clk_src = {
+ .cmd_rcgr_reg = EMAC_0_SYS_25M_CMD_RCGR,
+ .current_freq = ftbl_emac_0_sys_25m_clk_src,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_emac_0_sys_25m_clk_src,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "emac_0_sys_25m_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 125000000),
+ CLK_INIT(emac_0_sys_25m_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_emac_0_tx_clk_src[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F_EXT( 125000000, emac_0_tx_clk, 1, 0, 0),
+ F_END
+};
+static struct rcg_clk emac_0_tx_clk_src = {
+ .cmd_rcgr_reg = EMAC_0_TX_CMD_RCGR,
+ .current_freq = ftbl_emac_0_tx_clk_src,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_emac_0_tx_clk_src,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "emac_0_tx_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 125000000),
+ CLK_INIT(emac_0_tx_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp_i2c_apps_clk_src[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F( 50000000, gpll0, 16, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup1_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+ CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
+ F( 960000, xo, 10, 1, 2),
+ F( 4800000, xo, 4, 0, 0),
+ F( 9600000, xo, 2, 0, 0),
+ F( 16000000, gpll0, 10, 1, 5),
+ F( 19200000, xo, 1, 0, 0),
+ F( 25000000, gpll0, 16, 1, 2),
+ F( 50000000, gpll0, 16, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup1_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup2_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+ CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup2_spi_apps_clk_src[] = {
+ F( 960000, xo, 10, 1, 2),
+ F( 4800000, xo, 4, 0, 0),
+ F( 9600000, xo, 2, 0, 0),
+ F( 16000000, gpll0, 10, 1, 5),
+ F( 19200000, xo, 1, 0, 0),
+ F( 25000000, gpll0, 16, 1, 2),
+ F( 50000000, gpll0, 16, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp1_qup2_spi_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup2_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup3_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+ CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup3_spi_apps_clk_src[] = {
+ F( 960000, xo, 10, 1, 2),
+ F( 4800000, xo, 4, 0, 0),
+ F( 9600000, xo, 2, 0, 0),
+ F( 16000000, gpll0, 10, 1, 5),
+ F( 18180000, gpll0, 1, 1, 44),
+ F( 19200000, xo, 1, 0, 0),
+ F( 25000000, gpll0, 16, 1, 2),
+ F( 36360000, gpll0, 1, 1, 22),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp1_qup3_spi_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup3_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 18180000, NOMINAL, 36360000),
+ CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup4_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+ CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup4_spi_apps_clk_src[] = {
+ F( 960000, xo, 10, 1, 2),
+ F( 4800000, xo, 4, 0, 0),
+ F( 9600000, xo, 2, 0, 0),
+ F( 16000000, gpll0, 10, 1, 5),
+ F( 19200000, xo, 1, 0, 0),
+ F( 25000000, gpll0, 16, 1, 2),
+ F( 50000000, gpll0, 16, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp1_qup4_spi_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup4_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup5_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP5_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup5_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+ CLK_INIT(blsp1_qup5_i2c_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup5_spi_apps_clk_src[] = {
+ F( 960000, xo, 10, 1, 2),
+ F( 4800000, xo, 4, 0, 0),
+ F( 9600000, xo, 2, 0, 0),
+ F( 16000000, gpll0, 10, 1, 5),
+ F( 19200000, xo, 1, 0, 0),
+ F( 25000000, gpll0, 16, 1, 2),
+ F( 50000000, gpll0, 16, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup5_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP5_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp1_qup5_spi_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup5_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup5_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup6_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP6_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup6_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+ CLK_INIT(blsp1_qup6_i2c_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup6_spi_apps_clk_src[] = {
+ F( 960000, xo, 10, 1, 2),
+ F( 4800000, xo, 4, 0, 0),
+ F( 9600000, xo, 2, 0, 0),
+ F( 16000000, gpll0, 10, 1, 5),
+ F( 19200000, xo, 1, 0, 0),
+ F( 25000000, gpll0, 16, 1, 2),
+ F( 50000000, gpll0, 16, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup6_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP6_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp1_qup6_spi_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup6_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup6_spi_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp_uart_apps_clk_src[] = {
+ F( 3686400, gpll0, 1, 72, 15625),
+ F( 7372800, gpll0, 1, 144, 15625),
+ F( 14745600, gpll0, 1, 288, 15625),
+ F( 16000000, gpll0, 10, 1, 5),
+ F( 19200000, xo, 1, 0, 0),
+ F( 24000000, gpll0, 1, 3, 100),
+ F( 25000000, gpll0, 16, 1, 2),
+ F( 32000000, gpll0, 1, 1, 25),
+ F( 40000000, gpll0, 1, 1, 20),
+ F( 46400000, gpll0, 1, 29, 500),
+ F( 48000000, gpll0, 1, 3, 50),
+ F( 51200000, gpll0, 1, 8, 125),
+ F( 56000000, gpll0, 1, 7, 100),
+ F( 58982400, gpll0, 1, 1152, 15625),
+ F( 60000000, gpll0, 1, 3, 40),
+ F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART1_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp_uart_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart1_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 48480000, NOMINAL, 64000000),
+ CLK_INIT(blsp1_uart1_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART2_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp_uart_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart2_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 48480000, NOMINAL, 64000000),
+ CLK_INIT(blsp1_uart2_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart3_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART3_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp_uart_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart3_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 48480000, NOMINAL, 64000000),
+ CLK_INIT(blsp1_uart3_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart4_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART4_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp_uart_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart4_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 48480000, NOMINAL, 64000000),
+ CLK_INIT(blsp1_uart4_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart5_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART5_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp_uart_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart5_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 48480000, NOMINAL, 64000000),
+ CLK_INIT(blsp1_uart5_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart6_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART6_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp_uart_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart6_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOWER, 48480000, NOMINAL, 64000000),
+ CLK_INIT(blsp1_uart6_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_crypto_clk_src[] = {
+ F( 50000000, gpll0, 16, 0, 0),
+ F( 80000000, gpll0, 10, 0, 0),
+ F( 100000000, gpll0, 8, 0, 0),
+ F( 160000000, gpll0, 5, 0, 0),
+ F_END
+};
+
+static struct rcg_clk crypto_clk_src = {
+ .cmd_rcgr_reg = CRYPTO_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_crypto_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "crypto_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 80000000, NOMINAL, 160000000),
+ CLK_INIT(crypto_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gp_clk_src[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk gp1_clk_src = {
+ .cmd_rcgr_reg = GP1_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gp_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gp1_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+ CLK_INIT(gp1_clk_src.c),
+ },
+};
+
+static struct rcg_clk gp2_clk_src = {
+ .cmd_rcgr_reg = GP2_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gp_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gp2_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+ CLK_INIT(gp2_clk_src.c),
+ },
+};
+
+static struct rcg_clk gp3_clk_src = {
+ .cmd_rcgr_reg = GP3_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gp_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gp3_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+ CLK_INIT(gp3_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_pdm2_clk_src[] = {
+ F( 64000000, gpll0, 12.5, 0, 0),
+ F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+ .cmd_rcgr_reg = PDM2_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_pdm2_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "pdm2_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 64000000),
+ CLK_INIT(pdm2_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_sdcc_apps_clk[] = {
+ F( 144000, xo, 16, 3, 25),
+ F( 400000, xo, 12, 1, 4),
+ F( 20000000, gpll0, 10, 1, 4),
+ F( 25000000, gpll0, 16, 1, 2),
+ F( 50000000, gpll0, 16, 0, 0),
+ F( 100000000, gpll0, 8, 0, 0),
+ F( 177777778, gpll0, 4.5, 0, 0),
+ F( 200000000, gpll0, 4, 0, 0),
+ F_END
+};
+
+static struct rcg_clk sdcc1_apps_clk_src = {
+ .cmd_rcgr_reg = SDCC1_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_sdcc_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "sdcc1_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 50000000, NOMINAL, 200000000),
+ CLK_INIT(sdcc1_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+ .cmd_rcgr_reg = SDCC2_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_sdcc_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "sdcc2_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 50000000, NOMINAL, 200000000),
+ CLK_INIT(sdcc2_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_usb_hs_system_clk_src[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F( 57140000, gpll0, 14, 0, 0),
+ F( 69565000, gpll0, 11.5, 0, 0),
+ F( 133330000, gpll0, 6, 0, 0),
+ F( 177778000, gpll0, 4.5, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+ .cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_usb_hs_system_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb_hs_system_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP3(LOWER, 69570000, NOMINAL, 133330000,
+ HIGH, 177780000),
+ CLK_INIT(usb_hs_system_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_usb_hsic_clk_src[] = {
+ F( 480000000, gpll2, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb_hsic_clk_src = {
+ .cmd_rcgr_reg = USB_HSIC_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_usb_hsic_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb_hsic_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 480000000),
+ CLK_INIT(usb_hsic_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_usb_hsic_io_cal_clk_src[] = {
+ F( 9600000, xo, 2, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb_hsic_io_cal_clk_src = {
+ .cmd_rcgr_reg = USB_HSIC_IO_CAL_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_usb_hsic_io_cal_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb_hsic_io_cal_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 9600000),
+ CLK_INIT(usb_hsic_io_cal_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_usb_hsic_system_clk_src[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F( 57140000, gpll0, 14, 0, 0),
+ F( 133330000, gpll0, 6, 0, 0),
+ F( 177778000, gpll0, 4.5, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb_hsic_system_clk_src = {
+ .cmd_rcgr_reg = USB_HSIC_SYSTEM_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_usb_hsic_system_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb_hsic_system_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP3(LOWER, 57140000, NOMINAL, 133330000,
+ HIGH, 177778000),
+ CLK_INIT(usb_hsic_system_clk_src.c),
+ },
+};
+
+static struct local_vote_clk gcc_apss_ahb_clk = {
+ .cbcr_reg = APSS_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(14),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_apss_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_apss_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_apss_axi_clk = {
+ .cbcr_reg = APSS_AXI_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(13),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_apss_axi_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_apss_axi_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+ .cbcr_reg = BLSP1_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(10),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_blsp1_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+ .cbcr_reg = BOOT_ROM_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(7),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_boot_rom_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_crypto_ahb_clk = {
+ .cbcr_reg = CRYPTO_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(0),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_crypto_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_crypto_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_crypto_axi_clk = {
+ .cbcr_reg = CRYPTO_AXI_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(1),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_crypto_axi_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_crypto_axi_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_crypto_clk = {
+ .cbcr_reg = CRYPTO_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(2),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_crypto_clk",
+ .parent = &crypto_clk_src.c,
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_crypto_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_apss_tcu_clk = {
+ .cbcr_reg = APSS_TCU_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(1),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_apss_tcu_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_apss_tcu_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+ .cbcr_reg = PRNG_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(8),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_prng_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_prng_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_smmu_cfg_clk = {
+ .cbcr_reg = SMMU_CFG_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(12),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_smmu_cfg_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_smmu_cfg_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_qdss_dap_clk = {
+ .cbcr_reg = QDSS_DAP_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(19),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_qdss_dap_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_qdss_dap_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+ .parent = &blsp1_qup1_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+ .parent = &blsp1_qup1_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+ .parent = &blsp1_qup2_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+ .parent = &blsp1_qup2_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+ .parent = &blsp1_qup3_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+ .parent = &blsp1_qup3_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+ .parent = &blsp1_qup4_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+ .parent = &blsp1_qup4_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup5_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP5_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup5_i2c_apps_clk",
+ .parent = &blsp1_qup5_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup5_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup5_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP5_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup5_spi_apps_clk",
+ .parent = &blsp1_qup5_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup5_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup6_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP6_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup6_i2c_apps_clk",
+ .parent = &blsp1_qup6_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup6_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup6_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP6_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup6_spi_apps_clk",
+ .parent = &blsp1_qup6_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup6_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+ .cbcr_reg = BLSP1_UART1_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart1_apps_clk",
+ .parent = &blsp1_uart1_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+ .cbcr_reg = BLSP1_UART2_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart2_apps_clk",
+ .parent = &blsp1_uart2_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart3_apps_clk = {
+ .cbcr_reg = BLSP1_UART3_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart3_apps_clk",
+ .parent = &blsp1_uart3_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart3_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart4_apps_clk = {
+ .cbcr_reg = BLSP1_UART4_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart4_apps_clk",
+ .parent = &blsp1_uart4_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart4_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart5_apps_clk = {
+ .cbcr_reg = BLSP1_UART5_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart5_apps_clk",
+ .parent = &blsp1_uart5_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart5_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart6_apps_clk = {
+ .cbcr_reg = BLSP1_UART6_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart6_apps_clk",
+ .parent = &blsp1_uart6_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart6_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_gp1_clk = {
+ .cbcr_reg = GP1_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_gp1_clk",
+ .parent = &gp1_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_gp1_clk.c),
+ },
+};
+
+static struct branch_clk gcc_gp2_clk = {
+ .cbcr_reg = GP2_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_gp2_clk",
+ .parent = &gp2_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_gp2_clk.c),
+ },
+};
+
+static struct branch_clk gcc_gp3_clk = {
+ .cbcr_reg = GP3_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_gp3_clk",
+ .parent = &gp3_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_gp3_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+ .cbcr_reg = MSS_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mss_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+ .cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mss_q6_bimc_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+ .cbcr_reg = PDM2_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_pdm2_clk",
+ .parent = &pdm2_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pdm2_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+ .cbcr_reg = PDM_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_pdm_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pdm_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc1_ahb_clk = {
+ .cbcr_reg = SDCC1_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc1_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc1_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc1_apps_clk = {
+ .cbcr_reg = SDCC1_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc1_apps_clk",
+ .parent = &sdcc1_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc1_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+ .cbcr_reg = SDCC2_AHB_CBCR,
+ .has_sibling = 1,
+ .toggle_memory = true,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc2_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc2_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+ .cbcr_reg = SDCC2_APPS_CBCR,
+ .has_sibling = 0,
+ .toggle_memory = true,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc2_apps_clk",
+ .parent = &sdcc2_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc2_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_emac_0_125m_clk = {
+ .cbcr_reg = EMAC_0_125M_CBCR,
+ .has_sibling = 0,
+ .toggle_memory = true,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_emac_0_125m_clk",
+ .parent = &emac_0_125m_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_emac_0_125m_clk.c),
+ },
+};
+
+static struct branch_clk gcc_emac_0_ahb_clk = {
+ .cbcr_reg = EMAC_0_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_emac_0_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_emac_0_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_emac_0_axi_clk = {
+ .cbcr_reg = EMAC_0_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_emac_0_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_emac_0_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_emac_0_sys_25m_clk = {
+ .cbcr_reg = EMAC_0_SYS_25M_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_emac_0_sys_25m_clk",
+ .parent = &emac_0_sys_25m_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_emac_0_sys_25m_clk.c),
+ },
+};
+
+static struct branch_clk gcc_emac_0_sys_clk = {
+ .cbcr_reg = EMAC_0_SYS_CBCR,
+ .has_sibling = 1,
+ .toggle_memory = true,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_emac_0_sys_clk",
+ .parent = &emac_0_125m_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_emac_0_sys_clk.c),
+ },
+};
+
+static struct branch_clk gcc_emac_0_tx_clk = {
+ .cbcr_reg = EMAC_0_TX_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_emac_0_tx_clk",
+ .parent = &emac_0_tx_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_emac_0_tx_clk.c),
+ },
+};
+
+static struct gate_clk gcc_emac_0_rx_clk = {
+ .en_reg = EMAC_0_RX_CBCR,
+ .en_mask = BIT(0),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_emac_0_rx_clk",
+ .ops = &clk_ops_gate,
+ CLK_INIT(gcc_emac_0_rx_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb2a_phy_sleep_clk = {
+ .cbcr_reg = USB2A_PHY_SLEEP_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb2a_phy_sleep_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb2a_phy_sleep_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hs_phy_cfg_ahb_clk = {
+ .cbcr_reg = USB_HS_PHY_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hs_phy_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hs_phy_cfg_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+ .cbcr_reg = USB_HS_AHB_CBCR,
+ .has_sibling = 1,
+ .toggle_memory = true,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hs_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hs_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+ .cbcr_reg = USB_HS_SYSTEM_CBCR,
+ .bcr_reg = USB_HS_BCR,
+ .has_sibling = 0,
+ .toggle_memory = true,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hs_system_clk",
+ .parent = &usb_hs_system_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hs_system_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hsic_ahb_clk = {
+ .cbcr_reg = USB_HSIC_AHB_CBCR,
+ .has_sibling = 1,
+ .toggle_memory = true,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hsic_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hsic_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hsic_clk = {
+ .cbcr_reg = USB_HSIC_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hsic_clk",
+ .parent = &usb_hsic_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hsic_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hsic_io_cal_clk = {
+ .cbcr_reg = USB_HSIC_IO_CAL_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hsic_io_cal_clk",
+ .parent = &usb_hsic_io_cal_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hsic_io_cal_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hsic_io_cal_sleep_clk = {
+ .cbcr_reg = USB_HSIC_IO_CAL_SLEEP_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hsic_io_cal_sleep_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hsic_io_cal_sleep_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hsic_system_clk = {
+ .cbcr_reg = USB_HSIC_SYSTEM_CBCR,
+ .bcr_reg = USB_HS_HSIC_BCR,
+ .toggle_memory = true,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hsic_system_clk",
+ .parent = &usb_hsic_system_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hsic_system_clk.c),
+ },
+};
+
+static struct reset_clk gcc_usb2_hs_phy_only_clk = {
+ .reset_reg = USB2_HS_PHY_ONLY_BCR,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb2_hs_phy_only_clk",
+ .ops = &clk_ops_rst,
+ CLK_INIT(gcc_usb2_hs_phy_only_clk.c),
+ },
+};
+
+static struct reset_clk gcc_qusb2_phy_clk = {
+ .reset_reg = QUSB2_PHY_BCR,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_qusb2_phy_clk",
+ .ops = &clk_ops_rst,
+ CLK_INIT(gcc_qusb2_phy_clk.c),
+ },
+};
+
+static struct measure_clk apc0_m_clk = {
+ .c = {
+ .ops = &clk_ops_empty,
+ .dbg_name = "apc0_m_clk",
+ CLK_INIT(apc0_m_clk.c),
+ },
+};
+
+static struct measure_clk l2_m_clk = {
+ .c = {
+ .ops = &clk_ops_empty,
+ .dbg_name = "l2_m_clk",
+ CLK_INIT(l2_m_clk.c),
+ },
+};
+
+static void __iomem *meas_base;
+
+static struct mux_clk apss_debug_pri_mux = {
+ .ops = &mux_reg_ops,
+ .mask = 0x7,
+ .shift = 3,
+ MUX_SRC_LIST(
+ {&apc0_m_clk.c, 3},
+ {&l2_m_clk.c, 2},
+ ),
+ .base = &meas_base,
+ .c = {
+ .dbg_name = "apss_debug_pri_mux",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(apss_debug_pri_mux.c),
+ },
+};
+
+static int gcc_set_mux_sel(struct mux_clk *clk, int sel)
+{
+ u32 regval;
+
+ regval = readl_relaxed(GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+ regval &= 0x1FF;
+ writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+ if (sel == 0xFFFF)
+ return 0;
+ mux_reg_ops.set_mux_sel(clk, sel);
+
+ return 0;
+}
+
+static struct measure_clk_data debug_mux_priv = {
+ .cxo = &xo_clk_src.c,
+ .plltest_reg = PLLTEST_PAD_CFG,
+ .plltest_val = 0x51A00,
+ .xo_div4_cbcr = GCC_XO_DIV4_CBCR,
+ .ctl_reg = CLOCK_FRQ_MEASURE_CTL,
+ .status_reg = CLOCK_FRQ_MEASURE_STATUS,
+ .base = &virt_bases[DEBUG_BASE],
+};
+static struct clk_ops clk_ops_debug_mux;
+static struct clk_mux_ops gcc_debug_mux_ops;
+static struct mux_clk gcc_debug_mux = {
+ .priv = &debug_mux_priv,
+ .ops = &gcc_debug_mux_ops,
+ .offset = GCC_DEBUG_CLK_CTL,
+ .mask = 0x1FF,
+ .en_offset = GCC_DEBUG_CLK_CTL,
+ .en_mask = BIT(16),
+ .base = &virt_bases[DEBUG_BASE],
+ MUX_SRC_LIST(
+ { &pcnoc_clk.c, 0x0008 },
+ { &bimc_clk.c, 0x155 },
+ { &gcc_gp1_clk.c, 0x0010 },
+ { &gcc_gp2_clk.c, 0x0011 },
+ { &gcc_gp3_clk.c, 0x0012 },
+ { &gcc_mss_cfg_ahb_clk.c, 0x0030 },
+ { &gcc_mss_q6_bimc_axi_clk.c, 0x0031 },
+ { &gcc_qdss_dap_clk.c, 0x0049 },
+ { &gcc_apss_tcu_clk.c, 0x0050 },
+ { &gcc_smmu_cfg_clk.c, 0x005b },
+ { &gcc_usb_hs_system_clk.c, 0x0060 },
+ { &gcc_usb_hs_ahb_clk.c, 0x0061 },
+ { &gcc_usb2a_phy_sleep_clk.c, 0x0063 },
+ { &gcc_usb_hs_phy_cfg_ahb_clk.c, 0x0064 },
+ { &gcc_sdcc1_apps_clk.c, 0x0068 },
+ { &gcc_sdcc1_ahb_clk.c, 0x0069 },
+ { &gcc_sdcc2_apps_clk.c, 0x0070 },
+ { &gcc_sdcc2_ahb_clk.c, 0x0071 },
+ { &gcc_blsp1_ahb_clk.c, 0x0088 },
+ { &gcc_blsp1_qup1_spi_apps_clk.c, 0x008a },
+ { &gcc_blsp1_qup1_i2c_apps_clk.c, 0x008b },
+ { &gcc_blsp1_uart1_apps_clk.c, 0x008c },
+ { &gcc_blsp1_qup2_spi_apps_clk.c, 0x008e },
+ { &gcc_blsp1_qup2_i2c_apps_clk.c, 0x0090 },
+ { &gcc_blsp1_uart2_apps_clk.c, 0x0091 },
+ { &gcc_blsp1_qup3_spi_apps_clk.c, 0x0093 },
+ { &gcc_blsp1_qup3_i2c_apps_clk.c, 0x0094 },
+ { &gcc_blsp1_uart3_apps_clk.c, 0x0095 },
+ { &gcc_blsp1_qup4_spi_apps_clk.c, 0x0098 },
+ { &gcc_blsp1_qup4_i2c_apps_clk.c, 0x0099 },
+ { &gcc_blsp1_uart4_apps_clk.c, 0x009a },
+ { &gcc_blsp1_qup5_spi_apps_clk.c, 0x009c },
+ { &gcc_blsp1_qup5_i2c_apps_clk.c, 0x009d },
+ { &gcc_blsp1_uart5_apps_clk.c, 0x009e },
+ { &gcc_blsp1_qup6_spi_apps_clk.c, 0x00a1 },
+ { &gcc_blsp1_qup6_i2c_apps_clk.c, 0x00a2 },
+ { &gcc_blsp1_uart6_apps_clk.c, 0x00a3 },
+ { &gcc_pdm_ahb_clk.c, 0x00d0 },
+ { &gcc_pdm2_clk.c, 0x00d2 },
+ { &gcc_prng_ahb_clk.c, 0x00d8 },
+ { &gcc_boot_rom_ahb_clk.c, 0x00f8 },
+ { &gcc_crypto_clk.c, 0x0138 },
+ { &gcc_crypto_axi_clk.c, 0x0139 },
+ { &gcc_crypto_ahb_clk.c, 0x013a },
+ { &gcc_apss_ahb_clk.c, 0x0168 },
+ { &gcc_apss_axi_clk.c, 0x0169 },
+ { &gcc_usb_hsic_ahb_clk.c, 0x0198 },
+ { &gcc_usb_hsic_system_clk.c, 0x0199 },
+ { &gcc_usb_hsic_clk.c, 0x019a },
+ { &gcc_usb_hsic_io_cal_clk.c, 0x019b },
+ { &gcc_usb_hsic_io_cal_sleep_clk.c, 0x019c },
+ { &gcc_emac_0_axi_clk.c, 0x01b8 },
+ { &gcc_emac_0_ahb_clk.c, 0x01b9 },
+ { &gcc_emac_0_sys_25m_clk.c, 0x01ba },
+ { &gcc_emac_0_tx_clk.c, 0x01bb },
+ { &gcc_emac_0_125m_clk.c, 0x01bc },
+ { &gcc_emac_0_rx_clk.c, 0x01bd },
+ { &gcc_emac_0_sys_clk.c, 0x01be },
+ ),
+ .c = {
+ .dbg_name = "gcc_debug_mux",
+ .ops = &clk_ops_debug_mux,
+ .flags = CLKFLAG_NO_RATE_CACHE | CLKFLAG_MEASURE,
+ CLK_INIT(gcc_debug_mux.c),
+ },
+};
+/* Clock lookup */
+static struct clk_lookup msm_clocks_lookup[] = {
+ CLK_LIST(gpll0_clk_src),
+ CLK_LIST(gpll0_ao_clk_src),
+ CLK_LIST(gpll2_clk_src),
+ CLK_LIST(gpll1_clk_src),
+ CLK_LIST(a7sspll),
+
+ CLK_LIST(pcnoc_clk),
+ CLK_LIST(pcnoc_a_clk),
+ CLK_LIST(pcnoc_msmbus_clk),
+ CLK_LIST(pcnoc_msmbus_a_clk),
+ CLK_LIST(pcnoc_keepalive_a_clk),
+ CLK_LIST(pcnoc_usb_clk),
+ CLK_LIST(pcnoc_usb_a_clk),
+ CLK_LIST(bimc_clk),
+ CLK_LIST(bimc_a_clk),
+ CLK_LIST(bimc_msmbus_clk),
+ CLK_LIST(bimc_msmbus_a_clk),
+ CLK_LIST(bimc_usb_clk),
+ CLK_LIST(bimc_usb_a_clk),
+ CLK_LIST(qdss_clk),
+ CLK_LIST(qdss_a_clk),
+ CLK_LIST(qpic_clk),
+ CLK_LIST(qpic_a_clk),
+ CLK_LIST(xo_clk_src),
+ CLK_LIST(xo_a_clk_src),
+ CLK_LIST(xo_otg_clk),
+ CLK_LIST(xo_lpm_clk),
+ CLK_LIST(xo_pil_mss_clk),
+
+ CLK_LIST(bb_clk1),
+ CLK_LIST(bb_clk1_pin),
+
+ CLK_LIST(gcc_apss_ahb_clk),
+ CLK_LIST(gcc_apss_axi_clk),
+ CLK_LIST(gcc_blsp1_ahb_clk),
+ CLK_LIST(gcc_boot_rom_ahb_clk),
+ CLK_LIST(gcc_crypto_ahb_clk),
+ CLK_LIST(gcc_crypto_axi_clk),
+ CLK_LIST(gcc_crypto_clk),
+ CLK_LIST(gcc_prng_ahb_clk),
+ CLK_LIST(gcc_apss_tcu_clk),
+ CLK_LIST(gcc_qdss_dap_clk),
+ CLK_LIST(gcc_smmu_cfg_clk),
+ CLK_LIST(apss_ahb_clk_src),
+ CLK_LIST(emac_0_125m_clk_src),
+ CLK_LIST(blsp1_qup1_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup1_spi_apps_clk_src),
+ CLK_LIST(blsp1_qup2_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup2_spi_apps_clk_src),
+ CLK_LIST(blsp1_qup3_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup3_spi_apps_clk_src),
+ CLK_LIST(blsp1_qup4_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup4_spi_apps_clk_src),
+ CLK_LIST(blsp1_qup5_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup5_spi_apps_clk_src),
+ CLK_LIST(blsp1_qup6_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup6_spi_apps_clk_src),
+ CLK_LIST(blsp1_uart1_apps_clk_src),
+ CLK_LIST(blsp1_uart2_apps_clk_src),
+ CLK_LIST(blsp1_uart3_apps_clk_src),
+ CLK_LIST(blsp1_uart4_apps_clk_src),
+ CLK_LIST(blsp1_uart5_apps_clk_src),
+ CLK_LIST(blsp1_uart6_apps_clk_src),
+ CLK_LIST(crypto_clk_src),
+ CLK_LIST(gp1_clk_src),
+ CLK_LIST(gp2_clk_src),
+ CLK_LIST(gp3_clk_src),
+ CLK_LIST(pdm2_clk_src),
+ CLK_LIST(sdcc1_apps_clk_src),
+ CLK_LIST(sdcc2_apps_clk_src),
+ CLK_LIST(emac_0_sys_25m_clk_src),
+ CLK_LIST(emac_0_tx_clk_src),
+ CLK_LIST(usb_hs_system_clk_src),
+ CLK_LIST(usb_hsic_clk_src),
+ CLK_LIST(usb_hsic_io_cal_clk_src),
+ CLK_LIST(usb_hsic_system_clk_src),
+ CLK_LIST(gcc_blsp1_qup1_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup1_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_qup2_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup2_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_qup3_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup3_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_qup4_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup4_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_qup5_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup5_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_qup6_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup6_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_uart1_apps_clk),
+ CLK_LIST(gcc_blsp1_uart2_apps_clk),
+ CLK_LIST(gcc_blsp1_uart3_apps_clk),
+ CLK_LIST(gcc_blsp1_uart4_apps_clk),
+ CLK_LIST(gcc_blsp1_uart5_apps_clk),
+ CLK_LIST(gcc_blsp1_uart6_apps_clk),
+ CLK_LIST(gcc_gp1_clk),
+ CLK_LIST(gcc_gp2_clk),
+ CLK_LIST(gcc_gp3_clk),
+ CLK_LIST(gcc_mss_cfg_ahb_clk),
+ CLK_LIST(gcc_mss_q6_bimc_axi_clk),
+ CLK_LIST(gcc_pdm2_clk),
+ CLK_LIST(gcc_pdm_ahb_clk),
+ CLK_LIST(gcc_sdcc1_ahb_clk),
+ CLK_LIST(gcc_sdcc1_apps_clk),
+ CLK_LIST(gcc_sdcc2_ahb_clk),
+ CLK_LIST(gcc_sdcc2_apps_clk),
+ CLK_LIST(gcc_emac_0_125m_clk),
+ CLK_LIST(gcc_emac_0_ahb_clk),
+ CLK_LIST(gcc_emac_0_axi_clk),
+ CLK_LIST(gcc_emac_0_sys_25m_clk),
+ CLK_LIST(gcc_emac_0_sys_clk),
+ CLK_LIST(gcc_emac_0_tx_clk),
+ CLK_LIST(gcc_emac_0_rx_clk),
+ CLK_LIST(gcc_usb2a_phy_sleep_clk),
+ CLK_LIST(gcc_usb_hs_phy_cfg_ahb_clk),
+ CLK_LIST(gcc_usb_hs_ahb_clk),
+ CLK_LIST(gcc_usb_hs_system_clk),
+ CLK_LIST(gcc_usb_hsic_ahb_clk),
+ CLK_LIST(gcc_usb_hsic_clk),
+ CLK_LIST(gcc_usb_hsic_io_cal_clk),
+ CLK_LIST(gcc_usb_hsic_io_cal_sleep_clk),
+ CLK_LIST(gcc_usb_hsic_system_clk),
+ CLK_LIST(gcc_usb2_hs_phy_only_clk),
+ CLK_LIST(gcc_qusb2_phy_clk),
+};
+
+static int msm_gcc_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret;
+ u32 regval;
+
+ ret = vote_bimc(&bimc_clk, INT_MAX);
+ if (ret < 0)
+ return ret;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+ if (!res) {
+ dev_err(&pdev->dev, "Register base not defined\n");
+ return -ENOMEM;
+ }
+
+ virt_bases[GCC_BASE] = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!virt_bases[GCC_BASE]) {
+ dev_err(&pdev->dev, "Failed to ioremap CC registers\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_base");
+ if (!res) {
+ dev_err(&pdev->dev, "APCS PLL Register base not defined\n");
+ return -ENOMEM;
+ }
+
+ virt_bases[APCS_PLL_BASE] = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!virt_bases[APCS_PLL_BASE]) {
+ dev_err(&pdev->dev, "Failed to ioremap APCS PLL registers\n");
+ return -ENOMEM;
+ }
+
+ vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig");
+ if (IS_ERR(vdd_dig.regulator[0])) {
+ if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_dig regulator!!!\n");
+ return PTR_ERR(vdd_dig.regulator[0]);
+ }
+
+ vdd_stromer_pll.regulator[0] = devm_regulator_get(&pdev->dev,
+ "vdd_stromer_dig");
+ if (IS_ERR(vdd_stromer_pll.regulator[0])) {
+ if (!(PTR_ERR(vdd_stromer_pll.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_stromer_dig regulator!!!\n");
+ return PTR_ERR(vdd_stromer_pll.regulator[0]);
+ }
+
+ /*Vote for GPLL0 to turn on. Needed by acpuclock. */
+ regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+ regval |= BIT(0);
+ writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+
+ ret = of_msm_clock_register(pdev->dev.of_node,
+ msm_clocks_lookup,
+ ARRAY_SIZE(msm_clocks_lookup));
+ if (ret)
+ return ret;
+
+ ret = enable_rpm_scaling();
+ if (ret)
+ return ret;
+
+ clk_set_rate(&apss_ahb_clk_src.c, 19200000);
+ clk_prepare_enable(&apss_ahb_clk_src.c);
+ /*
+ * Hold an active set vote for PCNOC AHB source. Sleep set
+ * vote is 0.
+ */
+ clk_set_rate(&pcnoc_keepalive_a_clk.c, 19200000);
+ clk_prepare_enable(&pcnoc_keepalive_a_clk.c);
+
+ clk_prepare_enable(&xo_a_clk_src.c);
+
+ dev_info(&pdev->dev, "Registered GCC clocks\n");
+
+ return 0;
+}
+
+static const struct of_device_id msm_clock_gcc_match_table[] = {
+ { .compatible = "qcom,gcc-mdm9607" },
+ {},
+};
+
+static struct platform_driver msm_clock_gcc_driver = {
+ .probe = msm_gcc_probe,
+ .driver = {
+ .name = "qcom,gcc-mdm9607",
+ .of_match_table = msm_clock_gcc_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_gcc_init(void)
+{
+ return platform_driver_register(&msm_clock_gcc_driver);
+}
+arch_initcall(msm_gcc_init);
+
+static struct clk_lookup msm_clocks_measure[] = {
+ CLK_LOOKUP_OF("measure", gcc_debug_mux, "debug"),
+ CLK_LIST(apss_debug_pri_mux),
+ CLK_LIST(apc0_m_clk),
+ CLK_LIST(l2_m_clk),
+};
+
+static int msm_clock_debug_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *res;
+
+ clk_ops_debug_mux = clk_ops_gen_mux;
+ clk_ops_debug_mux.get_rate = measure_get_rate;
+
+ gcc_debug_mux_ops = mux_reg_ops;
+ gcc_debug_mux_ops.set_mux_sel = gcc_set_mux_sel;
+
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+ if (!res) {
+ dev_err(&pdev->dev, "Register base not defined\n");
+ return -ENOMEM;
+ }
+
+ virt_bases[DEBUG_BASE] = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!virt_bases[DEBUG_BASE]) {
+ dev_err(&pdev->dev, "Failed to ioremap debug cc registers\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "meas");
+ if (!res) {
+ dev_err(&pdev->dev, "GLB clock diag base not defined.\n");
+ return -EINVAL;
+ }
+
+ meas_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!meas_base) {
+ dev_err(&pdev->dev, "Unable to map GLB clock diag base.\n");
+ return -ENOMEM;
+ }
+
+ ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_measure,
+ ARRAY_SIZE(msm_clocks_measure));
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register debug Mux\n");
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "Registered Debug Mux successfully\n");
+ return ret;
+}
+
+static const struct of_device_id msm_clock_debug_match_table[] = {
+ { .compatible = "qcom,cc-debug-mdm9607" },
+ {}
+};
+
+static struct platform_driver msm_clock_debug_driver = {
+ .probe = msm_clock_debug_probe,
+ .driver = {
+ .name = "qcom,cc-debug-mdm9607",
+ .of_match_table = msm_clock_debug_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_clock_debug_init(void)
+{
+ return platform_driver_register(&msm_clock_debug_driver);
+}
+
+late_initcall(msm_clock_debug_init);
diff --git a/drivers/clk/msm/clock-gcc-mdm9650.c b/drivers/clk/msm/clock-gcc-mdm9650.c
new file mode 100644
index 0000000..ea351a1
--- /dev/null
+++ b/drivers/clk/msm/clock-gcc-mdm9650.c
@@ -0,0 +1,1862 @@
+/*
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <dt-bindings/clock/mdm-clocks-9650.h>
+#include <soc/qcom/clock-rpm.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/clock-voter.h>
+#include <soc/qcom/clock-pll.h>
+#include <soc/qcom/clock-alpha-pll.h>
+#include <soc/qcom/rpm-smd.h>
+
+#include "vdd-level-9650.h"
+
+#define RPM_MISC_CLK_TYPE 0x306b6c63
+#define RPM_BUS_CLK_TYPE 0x316b6c63
+#define RPM_MEM_CLK_TYPE 0x326b6c63
+#define RPM_IPA_CLK_TYPE 0x617069
+#define RPM_CE_CLK_TYPE 0x6563
+#define RPM_QPIC_CLK_TYPE 0x63697071
+
+#define RPM_SMD_KEY_ENABLE 0x62616E45
+
+#define CXO_CLK_SRC_ID 0x0
+#define QDSS_CLK_ID 0x1
+#define PCNOC_CLK_ID 0x0
+#define SNOC_CLK_ID 0x1
+#define BIMC_CLK_ID 0x0
+#define IPA_CLK_ID 0x0
+#define QPIC_CLK_ID 0x0
+#define CE_CLK_ID 0x0
+#define XO_ID 0x0
+#define MSS_CFG_AHB_CLK_ID 0x0
+
+#define RF_CLK1_ID 0x4
+#define RF_CLK2_ID 0x5
+#define RF_CLK3_ID 0x6
+#define LN_BB_CLK_ID 0x8
+#define DIV_CLK1_ID 0xb
+
+#define RF_CLK1_PIN_ID 0x4
+#define RF_CLK2_PIN_ID 0x5
+#define RF_CLK3_PIN_ID 0x6
+
+static void __iomem *virt_base;
+static void __iomem *virt_dbgbase;
+static void __iomem *virt_apcsbase;
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_base + (x))
+
+#define xo_source_val 0
+#define xo_a_clk_source_val 0
+#define gpll0_out_main_cgc_source_val 1
+#define gpll0_ao_out_main_cgc_source_val 1
+#define gpll0_out_main_div2_cgc_source_val 2
+
+#define FIXDIV(div) (div ? (2 * (div) - 1) : (0))
+
+#define F(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .src_clk = &s.c, \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)FIXDIV(div)) \
+ | BVAL(10, 8, s##_source_val), \
+ }
+
+#define F_EXT(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)FIXDIV(div)) \
+ | BVAL(10, 8, s##_source_val), \
+ }
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
+static DEFINE_VDD_REGULATORS(vdd_dig_ao, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+#define GPLL0_MODE (0x21000)
+#define MSS_Q6_BIMC_AXI_CBCR (0x49004)
+#define QUSB2A_PHY_BCR (0x41028)
+#define SDCC1_APPS_CMD_RCGR (0x42004)
+#define SDCC1_APPS_CBCR (0x42018)
+#define SDCC1_AHB_CBCR (0x4201C)
+#define BLSP1_AHB_CBCR (0x1008)
+#define BLSP1_QUP1_SPI_APPS_CBCR (0x2004)
+#define BLSP1_QUP1_I2C_APPS_CBCR (0x2008)
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR (0x200C)
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR (0x3000)
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR (0x4000)
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR (0x5000)
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR (0x2024)
+#define BLSP1_UART1_APPS_CBCR (0x203C)
+#define BLSP1_UART1_APPS_CMD_RCGR (0x2044)
+#define BLSP1_QUP2_SPI_APPS_CBCR (0x300C)
+#define BLSP1_QUP2_I2C_APPS_CBCR (0x3010)
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR (0x3014)
+#define BLSP1_UART2_APPS_CBCR (0x302C)
+#define BLSP1_UART2_APPS_CMD_RCGR (0x3034)
+#define BLSP1_QUP3_SPI_APPS_CBCR (0x401C)
+#define BLSP1_QUP3_I2C_APPS_CBCR (0x4020)
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR (0x4024)
+#define BLSP1_UART3_APPS_CBCR (0x403C)
+#define BLSP1_UART3_APPS_CMD_RCGR (0x4044)
+#define BLSP1_QUP4_SPI_APPS_CBCR (0x501C)
+#define BLSP1_QUP4_I2C_APPS_CBCR (0x5020)
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR (0x5024)
+#define BLSP1_UART4_APPS_CBCR (0x503C)
+#define BLSP1_UART4_APPS_CMD_RCGR (0x5044)
+#define PDM_AHB_CBCR (0x44004)
+#define PDM2_CBCR (0x4400C)
+#define PDM2_CMD_RCGR (0x44010)
+#define PRNG_AHB_CBCR (0x13004)
+#define BOOT_ROM_AHB_CBCR (0x1300C)
+#define RPM_MISC (0x2D028)
+#define GCC_XO_CMD_RCGR (0x30018)
+#define GCC_XO_DIV4_CBCR (0x30034)
+#define APSS_TCU_CBCR (0x12018)
+#define SMMU_CFG_CBCR (0x12038)
+#define APCS_GPLL_ENA_VOTE (0x45000)
+#define APCS_CLOCK_BRANCH_ENA_VOTE (0x45004)
+#define APCS_SMMU_CLOCK_BRANCH_ENA_VOTE (0x4500C)
+#define APSS_AHB_CMD_RCGR (0x46000)
+#define GCC_DEBUG_CLK_CTL (0x74000)
+#define CLOCK_FRQ_MEASURE_CTL (0x74004)
+#define CLOCK_FRQ_MEASURE_STATUS (0x74008)
+#define PLLTEST_PAD_CFG (0x7400C)
+#define GP1_CBCR (0x8000)
+#define GP1_CMD_RCGR (0x8004)
+#define GP2_CBCR (0x9000)
+#define GP2_CMD_RCGR (0x9004)
+#define GP3_CBCR (0xA000)
+#define GP3_CMD_RCGR (0xA004)
+#define PCIE_CFG_AHB_CBCR (0x5D008)
+#define PCIE_PIPE_CBCR (0x5D00C)
+#define PCIE_AXI_CBCR (0x5D010)
+#define PCIE_SLEEP_CBCR (0x5D014)
+#define PCIE_AXI_MSTR_CBCR (0x5D018)
+#define PCIE_AUX_CMD_RCGR (0x5D030)
+#define PCIEPHY_PHY_BCR (0x5D048)
+#define PCIE_REF_CLK_EN (0x5D04C)
+#define PCIE_PHY_BCR (0x5D050)
+#define USB_SS_REF_CLK_EN (0x5E07C)
+#define USB_PHY_CFG_AHB_CBCR (0x5E080)
+#define SYS_NOC_USB3_AXI_CBCR (0x5E084)
+#define USB_30_BCR (0x5E070)
+#define USB30_MASTER_CBCR (0x5E000)
+#define USB30_SLEEP_CBCR (0x5E004)
+#define USB30_MOCK_UTMI_CBCR (0x5E008)
+#define USB30_MASTER_CMD_RCGR (0x5E00C)
+#define USB30_MOCK_UTMI_CMD_RCGR (0x5E020)
+#define USB3_PHY_BCR (0x5E034)
+#define USB3PHY_PHY_BCR (0x5E03C)
+#define USB3_PIPE_CBCR (0x5E040)
+#define USB3_AUX_CBCR (0x5E044)
+#define USB3_AUX_CMD_RCGR (0x5E05C)
+#define USB3_AXI_TBU_CBCR (0x12060)
+#define PCIE_AXI_TBU_CBCR (0x12064)
+#define QUSB_REF_CLK_EN (0x41030)
+#define DCC_CBCR (0x77004)
+#define MSS_CFG_AHB_CBCR (0x49000)
+
+/* sdx20 */
+#define PCIE_AUX_CBCR (0x5D024)
+#define PCIE_AUX_PHY_CMD_RCGR (0x5D030)
+#define PCIE_BCR (0x5D004)
+#define PCIE_AUX_CLK_SEL (0x5D028)
+
+DEFINE_CLK_RPM_SMD_BRANCH(xo, xo_a_clk, RPM_MISC_CLK_TYPE,
+ XO_ID, 19200000);
+
+DEFINE_CLK_RPM_SMD(ce_clk, ce_a_clk, RPM_CE_CLK_TYPE,
+ CE_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(pcnoc_clk, pcnoc_a_clk, RPM_BUS_CLK_TYPE,
+ PCNOC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE,
+ BIMC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE,
+ SNOC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(ipa_clk, ipa_a_clk, RPM_IPA_CLK_TYPE,
+ IPA_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(qpic_clk, qpic_a_clk, RPM_QPIC_CLK_TYPE,
+ QPIC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE,
+ QDSS_CLK_ID);
+
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(mcd_ce_clk, &ce_clk.c, 85710000);
+static DEFINE_CLK_VOTER(pcnoc_keepalive_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_msmbus_clk, &pcnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_msmbus_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_pm_clk, &pcnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_sps_clk, &pcnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(qcedev_ce_clk, &ce_clk.c, 85710000);
+static DEFINE_CLK_VOTER(qcrypto_ce_clk, &ce_clk.c, 85710000);
+static DEFINE_CLK_VOTER(qseecom_ce_clk, &ce_clk.c, 85710000);
+static DEFINE_CLK_VOTER(scm_ce_clk, &ce_clk.c, 85710000);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_BRANCH_VOTER(cxo_dwc3_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpm_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_otg_clk, &xo.c);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk1, div_clk1_ao, DIV_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(ln_bb_clk, ln_bb_a_clk, LN_BB_CLK_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk1, rf_clk1_ao, RF_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk2, rf_clk2_ao, RF_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk3, rf_clk3_ao, RF_CLK3_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(rf_clk1_pin, rf_clk1_pin_ao,
+ RF_CLK1_PIN_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(rf_clk2_pin, rf_clk2_pin_ao,
+ RF_CLK2_PIN_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(rf_clk3_pin, rf_clk3_pin_ao,
+ RF_CLK3_PIN_ID);
+
+static struct alpha_pll_masks alpha_pll_masks_20nm_p = {
+ .lock_mask = BIT(31),
+ .update_mask = BIT(22),
+ .vco_mask = BM(21, 20) >> 20,
+ .vco_shift = 20,
+ .alpha_en_mask = BIT(24),
+};
+
+static struct alpha_pll_vco_tbl alpha_pll_vco_20nm_p[] = {
+ VCO(3, 250000000, 500000000),
+ VCO(2, 500000000, 1000000000),
+ VCO(1, 1000000000, 1500000000),
+ VCO(0, 1500000000, 2000000000),
+};
+
+static struct alpha_pll_clk a7pll_clk = {
+ .masks = &alpha_pll_masks_20nm_p,
+ .base = &virt_apcsbase,
+ .vco_tbl = alpha_pll_vco_20nm_p,
+ .num_vco = ARRAY_SIZE(alpha_pll_vco_20nm_p),
+ .c = {
+ .parent = &xo_a_clk.c,
+ .dbg_name = "a7pll_clk",
+ .ops = &clk_ops_alpha_pll,
+ VDD_DIG_FMAX_MAP2_AO(LOW, 1000000000, NOMINAL, 2000000000),
+ CLK_INIT(a7pll_clk.c),
+ },
+};
+
+static unsigned int soft_vote_gpll0;
+
+static struct pll_vote_clk gpll0 = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(0),
+ .status_reg = (void __iomem *)GPLL0_MODE,
+ .status_mask = BIT(30),
+ .soft_vote = &soft_vote_gpll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+ .base = &virt_base,
+ .c = {
+ .rate = 600000000,
+ .parent = &xo.c,
+ .dbg_name = "gpll0",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(gpll0.c),
+ },
+};
+
+static struct pll_vote_clk gpll0_ao = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(0),
+ .status_reg = (void __iomem *)GPLL0_MODE,
+ .status_mask = BIT(30),
+ .soft_vote = &soft_vote_gpll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+ .base = &virt_base,
+ .c = {
+ .rate = 600000000,
+ .parent = &xo_a_clk.c,
+ .dbg_name = "gpll0_ao",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(gpll0_ao.c),
+ },
+};
+
+DEFINE_EXT_CLK(gpll0_out_main_cgc, &gpll0.c);
+DEFINE_EXT_CLK(gpll0_ao_out_main_cgc, &gpll0_ao.c);
+
+DEFINE_FIXED_DIV_CLK(gpll0_out_main_div2_cgc, 2, &gpll0.c);
+
+static struct gate_clk gpll0_out_msscc = {
+ .en_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(18),
+ .delay_us = 1,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gpll0_out_msscc",
+ .ops = &clk_ops_gate,
+ CLK_INIT(gpll0_out_msscc.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_apss_ahb_clk_src[] = {
+ F( 19200000, xo_a_clk, 1, 0, 0),
+ F( 50000000, gpll0_ao_out_main_cgc, 12, 0, 0),
+ F( 100000000, gpll0_ao_out_main_cgc, 6, 0, 0),
+ F( 133333333, gpll0_ao_out_main_cgc, 4.5, 0, 0),
+ F_END
+};
+
+static struct rcg_clk apss_ahb_clk_src = {
+ .cmd_rcgr_reg = APSS_AHB_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_apss_ahb_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "apss_ahb_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP4(LOWER, 19200000, LOW, 50000000,
+ NOMINAL, 100000000, HIGH, 133333333),
+ CLK_INIT(apss_ahb_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_usb30_master_clk_src[] = {
+ F( 60000000, gpll0_out_main_div2_cgc, 5, 0, 0),
+ F( 120000000, gpll0_out_main_cgc, 5, 0, 0),
+ F( 171430000, gpll0_out_main_cgc, 3.5, 0, 0),
+ F( 200000000, gpll0_out_main_cgc, 3, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb30_master_clk_src = {
+ .cmd_rcgr_reg = USB30_MASTER_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_usb30_master_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "usb30_master_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP4(LOWER, 60000000, LOW, 120000000,
+ NOMINAL, 171430000, HIGH, 200000000),
+ CLK_INIT(usb30_master_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp_i2c_apps_clk_src[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F( 50000000, gpll0_out_main_cgc, 12, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "blsp1_qup1_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
+ CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
+ F( 960000, xo, 10, 1, 2),
+ F( 4800000, xo, 4, 0, 0),
+ F( 9600000, xo, 2, 0, 0),
+ F( 15000000, gpll0_out_main_cgc, 10, 1, 4),
+ F( 19200000, xo, 1, 0, 0),
+ F( 24000000, gpll0_out_main_cgc, 12.5, 1, 2),
+ F( 25000000, gpll0_out_main_cgc, 12, 1, 2),
+ F( 50000000, gpll0_out_main_cgc, 12, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "blsp1_qup1_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 12500000, LOW, 25000000,
+ NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "blsp1_qup2_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+ CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup2_spi_apps_clk_src[] = {
+ F( 960000, xo, 10, 1, 2),
+ F( 4800000, xo, 4, 0, 0),
+ F( 9600000, xo, 2, 0, 0),
+ F( 15000000, gpll0_out_main_cgc, 10, 1, 4),
+ F( 19200000, xo, 1, 0, 0),
+ F( 24000000, gpll0_out_main_cgc, 12.5, 1, 2),
+ F( 25000000, gpll0_out_main_cgc, 12, 1, 2),
+ F( 50000000, gpll0_out_main_cgc, 12, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp1_qup2_spi_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "blsp1_qup2_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 12500000, LOW, 25000000,
+ NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "blsp1_qup3_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+ CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup3_spi_apps_clk_src[] = {
+ F( 960000, xo, 10, 1, 2),
+ F( 4800000, xo, 4, 0, 0),
+ F( 9600000, xo, 2, 0, 0),
+ F( 15000000, gpll0_out_main_cgc, 10, 1, 4),
+ F( 19200000, xo, 1, 0, 0),
+ F( 24000000, gpll0_out_main_cgc, 12.5, 1, 2),
+ F( 25000000, gpll0_out_main_cgc, 12, 1, 2),
+ F( 50000000, gpll0_out_main_cgc, 12, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp1_qup3_spi_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "blsp1_qup3_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 12500000, LOW, 25000000,
+ NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "blsp1_qup4_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+ CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup4_spi_apps_clk_src[] = {
+ F( 960000, xo, 10, 1, 2),
+ F( 4800000, xo, 4, 0, 0),
+ F( 9600000, xo, 2, 0, 0),
+ F( 15000000, gpll0_out_main_cgc, 10, 1, 4),
+ F( 19200000, xo, 1, 0, 0),
+ F( 24000000, gpll0_out_main_cgc, 12.5, 1, 2),
+ F( 25000000, gpll0_out_main_cgc, 12, 1, 2),
+ F( 50000000, gpll0_out_main_cgc, 12, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp1_qup4_spi_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "blsp1_qup4_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 12500000, LOW, 25000000,
+ NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_blsp_uart_apps_clk_src[] = {
+ F( 3686400, gpll0_out_main_div2_cgc, 1, 192, 15625),
+ F( 7372800, gpll0_out_main_div2_cgc, 1, 384, 15625),
+ F( 14745600, gpll0_out_main_div2_cgc, 1, 768, 15625),
+ F( 16000000, gpll0_out_main_div2_cgc, 1, 4, 75),
+ F( 19200000, xo, 1, 0, 0),
+ F( 24000000, gpll0_out_main_cgc, 5, 1, 5),
+ F( 32000000, gpll0_out_main_cgc, 1, 4, 75),
+ F( 40000000, gpll0_out_main_cgc, 15, 0, 0),
+ F( 46400000, gpll0_out_main_cgc, 1, 29, 375),
+ F( 48000000, gpll0_out_main_cgc, 12.5, 0, 0),
+ F( 51200000, gpll0_out_main_cgc, 1, 32, 375),
+ F( 56000000, gpll0_out_main_cgc, 1, 7, 75),
+ F( 58982400, gpll0_out_main_cgc, 1, 1536, 15625),
+ F( 60000000, gpll0_out_main_cgc, 10, 0, 0),
+ F( 63157895, gpll0_out_main_cgc, 9.5, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART1_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp_uart_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "blsp1_uart1_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 48000000,
+ NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart1_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART2_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp_uart_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "blsp1_uart2_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 48000000,
+ NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart2_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart3_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART3_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp_uart_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "blsp1_uart3_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 48000000,
+ NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart3_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart4_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART4_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_blsp_uart_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "blsp1_uart4_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 48000000,
+ NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart4_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gp_clk_src[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F( 50000000, gpll0_out_main_div2_cgc, 6, 0, 0),
+ F( 100000000, gpll0_out_main_cgc, 6, 0, 0),
+ F( 200000000, gpll0_out_main_cgc, 3, 0, 0),
+ F_END
+};
+
+static struct rcg_clk gp1_clk_src = {
+ .cmd_rcgr_reg = GP1_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gp_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gp1_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000,
+ NOMINAL, 200000000),
+ CLK_INIT(gp1_clk_src.c),
+ },
+};
+
+static struct rcg_clk gp2_clk_src = {
+ .cmd_rcgr_reg = GP2_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gp_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gp2_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000,
+ NOMINAL, 200000000),
+ CLK_INIT(gp2_clk_src.c),
+ },
+};
+
+static struct rcg_clk gp3_clk_src = {
+ .cmd_rcgr_reg = GP3_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gp_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gp3_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000,
+ NOMINAL, 200000000),
+ CLK_INIT(gp3_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_pcie_aux_clk_src[] = {
+ F( 1000000, xo, 1, 5, 96),
+ F( 19200000, xo, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk pcie_aux_clk_src = {
+ .cmd_rcgr_reg = PCIE_AUX_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_pcie_aux_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "pcie_aux_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+ CLK_INIT(pcie_aux_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_pdm2_clk_src[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F( 60000000, gpll0_out_main_cgc, 10, 0, 0),
+ F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+ .cmd_rcgr_reg = PDM2_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_pdm2_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "pdm2_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 60000000),
+ CLK_INIT(pdm2_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_sdcc1_apps_clk_src[] = {
+ F( 144000, xo, 16, 3, 25),
+ F( 400000, xo, 12, 1, 4),
+ F( 20000000, gpll0_out_main_div2_cgc, 15, 0, 0),
+ F( 25000000, gpll0_out_main_div2_cgc, 12, 0, 0),
+ F( 50000000, gpll0_out_main_div2_cgc, 6, 0, 0),
+ F( 100000000, gpll0_out_main_cgc, 6, 0, 0),
+ F( 200000000, gpll0_out_main_cgc, 3, 0, 0),
+ F_END
+};
+
+static struct rcg_clk sdcc1_apps_clk_src = {
+ .cmd_rcgr_reg = SDCC1_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_sdcc1_apps_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "sdcc1_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000,
+ NOMINAL, 200000000),
+ CLK_INIT(sdcc1_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_usb30_mock_utmi_clk_src[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F( 30000000, gpll0_out_main_div2_cgc, 10, 0, 0),
+ F( 60000000, gpll0_out_main_cgc, 10, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb30_mock_utmi_clk_src = {
+ .cmd_rcgr_reg = USB30_MOCK_UTMI_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_usb30_mock_utmi_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "usb30_mock_utmi_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOWER, 30000000, LOW, 60000000),
+ CLK_INIT(usb30_mock_utmi_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_usb3_aux_clk_src[] = {
+ F( 1000000, xo, 1, 5, 96),
+ F_END
+};
+
+static struct rcg_clk usb3_aux_clk_src = {
+ .cmd_rcgr_reg = USB3_AUX_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_usb3_aux_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "usb3_aux_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+ CLK_INIT(usb3_aux_clk_src.c),
+ },
+};
+
+static struct reset_clk gcc_pcie_phy_reset = {
+ .reset_reg = PCIE_PHY_BCR,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_pcie_phy_reset",
+ .ops = &clk_ops_rst,
+ CLK_INIT(gcc_pcie_phy_reset.c),
+ },
+};
+
+static struct reset_clk gcc_qusb2a_phy_reset = {
+ .reset_reg = QUSB2A_PHY_BCR,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_qusb2a_phy_reset",
+ .ops = &clk_ops_rst,
+ CLK_INIT(gcc_qusb2a_phy_reset.c),
+ },
+};
+
+static struct reset_clk gcc_usb3phy_phy_reset = {
+ .reset_reg = USB3PHY_PHY_BCR,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_usb3phy_phy_reset",
+ .ops = &clk_ops_rst,
+ CLK_INIT(gcc_usb3phy_phy_reset.c),
+ },
+};
+
+static struct reset_clk gcc_usb3_phy_reset = {
+ .reset_reg = USB3_PHY_BCR,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_usb3_phy_reset",
+ .ops = &clk_ops_rst,
+ CLK_INIT(gcc_usb3_phy_reset.c),
+ },
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+ .cbcr_reg = BLSP1_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(10),
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_blsp1_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_blsp1_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+ .parent = &blsp1_qup1_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+ .parent = &blsp1_qup1_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+ .parent = &blsp1_qup2_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+ .parent = &blsp1_qup2_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+ .parent = &blsp1_qup3_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+ .parent = &blsp1_qup3_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+ .parent = &blsp1_qup4_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+ .parent = &blsp1_qup4_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+ .cbcr_reg = BLSP1_UART1_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_blsp1_uart1_apps_clk",
+ .parent = &blsp1_uart1_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+ .cbcr_reg = BLSP1_UART2_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_blsp1_uart2_apps_clk",
+ .parent = &blsp1_uart2_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart3_apps_clk = {
+ .cbcr_reg = BLSP1_UART3_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_blsp1_uart3_apps_clk",
+ .parent = &blsp1_uart3_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart3_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart4_apps_clk = {
+ .cbcr_reg = BLSP1_UART4_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_blsp1_uart4_apps_clk",
+ .parent = &blsp1_uart4_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart4_apps_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+ .cbcr_reg = BOOT_ROM_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(7),
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_boot_rom_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_dcc_clk = {
+ .cbcr_reg = DCC_CBCR,
+ .has_sibling = 1,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_dcc_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_dcc_clk.c),
+ },
+};
+
+static struct branch_clk gcc_gp1_clk = {
+ .cbcr_reg = GP1_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_gp1_clk",
+ .parent = &gp1_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_gp1_clk.c),
+ },
+};
+
+static struct branch_clk gcc_gp2_clk = {
+ .cbcr_reg = GP2_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_gp2_clk",
+ .parent = &gp2_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_gp2_clk.c),
+ },
+};
+
+static struct branch_clk gcc_gp3_clk = {
+ .cbcr_reg = GP3_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_gp3_clk",
+ .parent = &gp3_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_gp3_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+ .cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_mss_q6_bimc_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pcie_axi_clk = {
+ .cbcr_reg = PCIE_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_pcie_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pcie_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pcie_axi_mstr_clk = {
+ .cbcr_reg = PCIE_AXI_MSTR_CBCR,
+ .has_sibling = 1,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_pcie_axi_mstr_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pcie_axi_mstr_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pcie_cfg_ahb_clk = {
+ .cbcr_reg = PCIE_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_pcie_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pcie_cfg_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pcie_pipe_clk = {
+ .cbcr_reg = PCIE_PIPE_CBCR,
+ .bcr_reg = PCIEPHY_PHY_BCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .halt_check = DELAY,
+ .c = {
+ .dbg_name = "gcc_pcie_pipe_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pcie_pipe_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pcie_sleep_clk = {
+ .cbcr_reg = PCIE_SLEEP_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_pcie_sleep_clk",
+ .parent = &pcie_aux_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pcie_sleep_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+ .cbcr_reg = PDM2_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_pdm2_clk",
+ .parent = &pdm2_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pdm2_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+ .cbcr_reg = PDM_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_pdm_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pdm_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+ .cbcr_reg = PRNG_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(8),
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_prng_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_prng_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc1_ahb_clk = {
+ .cbcr_reg = SDCC1_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_sdcc1_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc1_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc1_apps_clk = {
+ .cbcr_reg = SDCC1_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_sdcc1_apps_clk",
+ .parent = &sdcc1_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc1_apps_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_apss_tcu_clk = {
+ .cbcr_reg = APSS_TCU_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(1),
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_apss_tcu_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_apss_tcu_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_pcie_axi_tbu_clk = {
+ .cbcr_reg = PCIE_AXI_TBU_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(16),
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_pcie_axi_tbu_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_pcie_axi_tbu_clk.c),
+ },
+};
+
+static struct gate_clk gcc_pcie_ref_clk = {
+ .en_reg = PCIE_REF_CLK_EN,
+ .en_mask = BIT(0),
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_pcie_ref_clk",
+ .ops = &clk_ops_gate,
+ CLK_INIT(gcc_pcie_ref_clk.c),
+ },
+};
+
+static struct gate_clk gcc_usb_ss_ref_clk = {
+ .en_reg = USB_SS_REF_CLK_EN,
+ .en_mask = BIT(0),
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_usb_ss_ref_clk",
+ .ops = &clk_ops_gate,
+ CLK_INIT(gcc_usb_ss_ref_clk.c),
+ },
+};
+
+static struct gate_clk gcc_qusb_ref_clk = {
+ .en_reg = QUSB_REF_CLK_EN,
+ .en_mask = BIT(0),
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_qusb_ref_clk",
+ .ops = &clk_ops_gate,
+ CLK_INIT(gcc_qusb_ref_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_smmu_cfg_clk = {
+ .cbcr_reg = SMMU_CFG_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(12),
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_smmu_cfg_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_smmu_cfg_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_usb3_axi_tbu_clk = {
+ .cbcr_reg = USB3_AXI_TBU_CBCR,
+ .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(15),
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_usb3_axi_tbu_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_usb3_axi_tbu_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sys_noc_usb3_axi_clk = {
+ .cbcr_reg = SYS_NOC_USB3_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_sys_noc_usb3_axi_clk",
+ .parent = &usb30_master_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sys_noc_usb3_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb30_master_clk = {
+ .cbcr_reg = USB30_MASTER_CBCR,
+ .bcr_reg = USB_30_BCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_usb30_master_clk",
+ .parent = &usb30_master_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb30_master_clk.c),
+ .depends = &gcc_sys_noc_usb3_axi_clk.c,
+ },
+};
+
+static struct branch_clk gcc_usb30_mock_utmi_clk = {
+ .cbcr_reg = USB30_MOCK_UTMI_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_usb30_mock_utmi_clk",
+ .parent = &usb30_mock_utmi_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb30_mock_utmi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb30_sleep_clk = {
+ .cbcr_reg = USB30_SLEEP_CBCR,
+ .has_sibling = 1,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_usb30_sleep_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb30_sleep_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb3_aux_clk = {
+ .cbcr_reg = USB3_AUX_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_usb3_aux_clk",
+ .parent = &usb3_aux_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb3_aux_clk.c),
+ },
+};
+
+static struct gate_clk gcc_usb3_pipe_clk = {
+ .en_reg = USB3_PIPE_CBCR,
+ .en_mask = BIT(0),
+ .delay_us = 50,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_usb3_pipe_clk",
+ .ops = &clk_ops_gate,
+ CLK_INIT(gcc_usb3_pipe_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_phy_cfg_ahb_clk = {
+ .cbcr_reg = USB_PHY_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_usb_phy_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_phy_cfg_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+ .cbcr_reg = MSS_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "gcc_mss_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+ },
+};
+
+static struct mux_clk gcc_debug_mux;
+static struct clk_ops clk_ops_debug_mux;
+static struct clk_mux_ops gcc_debug_mux_ops;
+static struct branch_clk gcc_pcie_aux_clk;
+
+static struct measure_clk_data debug_mux_priv = {
+ .cxo = &xo.c,
+ .plltest_reg = PLLTEST_PAD_CFG,
+ .plltest_val = 0x51A00,
+ .xo_div4_cbcr = GCC_XO_DIV4_CBCR,
+ .ctl_reg = CLOCK_FRQ_MEASURE_CTL,
+ .status_reg = CLOCK_FRQ_MEASURE_STATUS,
+ .base = &virt_base,
+};
+
+static struct mux_clk gcc_debug_mux = {
+ .priv = &debug_mux_priv,
+ .ops = &gcc_debug_mux_ops,
+ .en_mask = BIT(16),
+ .mask = 0x3FF,
+ .base = &virt_dbgbase,
+ MUX_REC_SRC_LIST(
+ ),
+ MUX_SRC_LIST(
+ { &snoc_clk.c, 0x0000 },
+ { &gcc_sys_noc_usb3_axi_clk.c, 0x0001 },
+ { &pcnoc_clk.c, 0x0008 },
+ { &gcc_mss_cfg_ahb_clk.c, 0x0030 },
+ { &qdss_clk.c, 0x0042 },
+ { &gcc_apss_tcu_clk.c, 0x0050 },
+ { &gcc_smmu_cfg_clk.c, 0x005b },
+ { &gcc_sdcc1_apps_clk.c, 0x0068 },
+ { &gcc_sdcc1_ahb_clk.c, 0x0069 },
+ { &gcc_blsp1_ahb_clk.c, 0x0088 },
+ { &gcc_blsp1_qup1_spi_apps_clk.c, 0x008a },
+ { &gcc_blsp1_qup1_i2c_apps_clk.c, 0x008b },
+ { &gcc_blsp1_uart1_apps_clk.c, 0x008c },
+ { &gcc_blsp1_qup2_spi_apps_clk.c, 0x008e },
+ { &gcc_blsp1_qup2_i2c_apps_clk.c, 0x0090 },
+ { &gcc_blsp1_uart2_apps_clk.c, 0x0091 },
+ { &gcc_blsp1_qup3_spi_apps_clk.c, 0x0093 },
+ { &gcc_blsp1_qup3_i2c_apps_clk.c, 0x0094 },
+ { &gcc_blsp1_uart3_apps_clk.c, 0x0095 },
+ { &gcc_blsp1_qup4_spi_apps_clk.c, 0x0098 },
+ { &gcc_blsp1_qup4_i2c_apps_clk.c, 0x0099 },
+ { &gcc_blsp1_uart4_apps_clk.c, 0x009a },
+ { &gcc_pdm_ahb_clk.c, 0x00d0 },
+ { &gcc_pdm2_clk.c, 0x00d2 },
+ { &gcc_prng_ahb_clk.c, 0x00d8 },
+ { &gcc_boot_rom_ahb_clk.c, 0x00f8 },
+ { &ce_clk.c, 0x0138 },
+ { &bimc_clk.c, 0x0155 },
+ { &gcc_usb3_axi_tbu_clk.c, 0x0203 },
+ { &gcc_pcie_axi_tbu_clk.c, 0x0204 },
+ { &ipa_clk.c, 0x0218 },
+ { &qpic_clk.c, 0x0220 },
+ { &gcc_usb30_master_clk.c, 0x0230 },
+ { &gcc_usb30_sleep_clk.c, 0x0231 },
+ { &gcc_usb30_mock_utmi_clk.c, 0x0232 },
+ { &gcc_usb_phy_cfg_ahb_clk.c, 0x0233 },
+ { &gcc_usb3_pipe_clk.c, 0x0234 },
+ { &gcc_usb3_aux_clk.c, 0x0235 },
+ { &gcc_pcie_cfg_ahb_clk.c, 0x0238 },
+ { &gcc_pcie_pipe_clk.c, 0x0239 },
+ { &gcc_pcie_axi_clk.c, 0x023a },
+ { &gcc_pcie_sleep_clk.c, 0x023b },
+ { &gcc_pcie_axi_mstr_clk.c, 0x023c },
+ { &gcc_dcc_clk.c, 0x0278 },
+ {&gcc_pcie_aux_clk.c, 0x023d },
+ ),
+ .c = {
+ .dbg_name = "gcc_debug_mux",
+ .ops = &clk_ops_debug_mux,
+ .flags = CLKFLAG_NO_RATE_CACHE | CLKFLAG_MEASURE,
+ CLK_INIT(gcc_debug_mux.c),
+ },
+};
+
+static struct clk_lookup msm_clocks_rpm_9650[] = {
+ CLK_LIST(xo),
+ CLK_LIST(xo_a_clk),
+ CLK_LIST(ce_clk),
+ CLK_LIST(ce_a_clk),
+ CLK_LIST(pcnoc_clk),
+ CLK_LIST(pcnoc_a_clk),
+ CLK_LIST(bimc_clk),
+ CLK_LIST(bimc_a_clk),
+ CLK_LIST(snoc_clk),
+ CLK_LIST(snoc_a_clk),
+ CLK_LIST(ipa_clk),
+ CLK_LIST(ipa_a_clk),
+ CLK_LIST(qpic_clk),
+ CLK_LIST(qpic_a_clk),
+ CLK_LIST(qdss_clk),
+ CLK_LIST(qdss_a_clk),
+ CLK_LIST(bimc_msmbus_clk),
+ CLK_LIST(bimc_msmbus_a_clk),
+ CLK_LIST(mcd_ce_clk),
+ CLK_LIST(pcnoc_keepalive_a_clk),
+ CLK_LIST(pcnoc_msmbus_clk),
+ CLK_LIST(pcnoc_msmbus_a_clk),
+ CLK_LIST(pcnoc_pm_clk),
+ CLK_LIST(pcnoc_sps_clk),
+ CLK_LIST(qcedev_ce_clk),
+ CLK_LIST(qcrypto_ce_clk),
+ CLK_LIST(qseecom_ce_clk),
+ CLK_LIST(scm_ce_clk),
+ CLK_LIST(snoc_msmbus_clk),
+ CLK_LIST(snoc_msmbus_a_clk),
+ CLK_LIST(cxo_dwc3_clk),
+ CLK_LIST(cxo_lpm_clk),
+ CLK_LIST(cxo_otg_clk),
+ CLK_LIST(div_clk1),
+ CLK_LIST(div_clk1_ao),
+ CLK_LIST(ln_bb_clk),
+ CLK_LIST(ln_bb_a_clk),
+ CLK_LIST(rf_clk1),
+ CLK_LIST(rf_clk1_ao),
+ CLK_LIST(rf_clk2),
+ CLK_LIST(rf_clk2_ao),
+ CLK_LIST(rf_clk3),
+ CLK_LIST(rf_clk3_ao),
+ CLK_LIST(rf_clk1_pin),
+ CLK_LIST(rf_clk1_pin_ao),
+ CLK_LIST(rf_clk2_pin),
+ CLK_LIST(rf_clk2_pin_ao),
+ CLK_LIST(rf_clk3_pin),
+ CLK_LIST(rf_clk3_pin_ao),
+};
+
+static struct clk_lookup msm_clocks_gcc_9650[] = {
+ CLK_LIST(gpll0),
+ CLK_LIST(gpll0_ao),
+ CLK_LIST(gpll0_out_main_cgc),
+ CLK_LIST(gpll0_out_main_div2_cgc),
+ CLK_LIST(gpll0_out_msscc),
+ CLK_LIST(apss_ahb_clk_src),
+ CLK_LIST(usb30_master_clk_src),
+ CLK_LIST(blsp1_qup1_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup1_spi_apps_clk_src),
+ CLK_LIST(blsp1_qup2_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup2_spi_apps_clk_src),
+ CLK_LIST(blsp1_qup3_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup3_spi_apps_clk_src),
+ CLK_LIST(blsp1_qup4_i2c_apps_clk_src),
+ CLK_LIST(blsp1_qup4_spi_apps_clk_src),
+ CLK_LIST(blsp1_uart1_apps_clk_src),
+ CLK_LIST(blsp1_uart2_apps_clk_src),
+ CLK_LIST(blsp1_uart3_apps_clk_src),
+ CLK_LIST(blsp1_uart4_apps_clk_src),
+ CLK_LIST(gp1_clk_src),
+ CLK_LIST(gp2_clk_src),
+ CLK_LIST(gp3_clk_src),
+ CLK_LIST(pcie_aux_clk_src),
+ CLK_LIST(pdm2_clk_src),
+ CLK_LIST(sdcc1_apps_clk_src),
+ CLK_LIST(usb30_mock_utmi_clk_src),
+ CLK_LIST(usb3_aux_clk_src),
+ CLK_LIST(gcc_pcie_phy_reset),
+ CLK_LIST(gcc_qusb2a_phy_reset),
+ CLK_LIST(gcc_usb3phy_phy_reset),
+ CLK_LIST(gcc_usb3_phy_reset),
+ CLK_LIST(gcc_blsp1_ahb_clk),
+ CLK_LIST(gcc_blsp1_qup1_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup1_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_qup2_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup2_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_qup3_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup3_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_qup4_i2c_apps_clk),
+ CLK_LIST(gcc_blsp1_qup4_spi_apps_clk),
+ CLK_LIST(gcc_blsp1_uart1_apps_clk),
+ CLK_LIST(gcc_blsp1_uart2_apps_clk),
+ CLK_LIST(gcc_blsp1_uart3_apps_clk),
+ CLK_LIST(gcc_blsp1_uart4_apps_clk),
+ CLK_LIST(gcc_boot_rom_ahb_clk),
+ CLK_LIST(gcc_dcc_clk),
+ CLK_LIST(gcc_gp1_clk),
+ CLK_LIST(gcc_gp2_clk),
+ CLK_LIST(gcc_gp3_clk),
+ CLK_LIST(gcc_mss_q6_bimc_axi_clk),
+ CLK_LIST(gcc_pcie_axi_clk),
+ CLK_LIST(gcc_pcie_axi_mstr_clk),
+ CLK_LIST(gcc_pcie_cfg_ahb_clk),
+ CLK_LIST(gcc_pcie_pipe_clk),
+ CLK_LIST(gcc_pcie_sleep_clk),
+ CLK_LIST(gcc_pdm2_clk),
+ CLK_LIST(gcc_pdm_ahb_clk),
+ CLK_LIST(gcc_prng_ahb_clk),
+ CLK_LIST(gcc_sdcc1_ahb_clk),
+ CLK_LIST(gcc_sdcc1_apps_clk),
+ CLK_LIST(gcc_apss_tcu_clk),
+ CLK_LIST(gcc_pcie_axi_tbu_clk),
+ CLK_LIST(gcc_pcie_ref_clk),
+ CLK_LIST(gcc_usb_ss_ref_clk),
+ CLK_LIST(gcc_qusb_ref_clk),
+ CLK_LIST(gcc_smmu_cfg_clk),
+ CLK_LIST(gcc_usb3_axi_tbu_clk),
+ CLK_LIST(gcc_sys_noc_usb3_axi_clk),
+ CLK_LIST(gcc_usb30_master_clk),
+ CLK_LIST(gcc_usb30_mock_utmi_clk),
+ CLK_LIST(gcc_usb30_sleep_clk),
+ CLK_LIST(gcc_usb3_aux_clk),
+ CLK_LIST(gcc_usb3_pipe_clk),
+ CLK_LIST(gcc_usb_phy_cfg_ahb_clk),
+ CLK_LIST(gcc_mss_cfg_ahb_clk),
+ CLK_LIST(a7pll_clk),
+};
+
+/* sdx20 */
+/* Fractional Val offset from PLL base */
+#define APCS_CPU_PLL_FRAC_OFF 0x40
+
+static int set_pcie_aux_mux_sel(struct mux_clk *clk, int sel);
+static int get_pcie_aux_mux_sel(struct mux_clk *clk);
+
+static struct alpha_pll_masks fabia_pll_masks_p = {
+ .lock_mask = BIT(31),
+ .active_mask = BIT(30),
+ .update_mask = BIT(22),
+ .output_mask = 0xf,
+};
+
+static struct alpha_pll_vco_tbl fabia_pll_vco_p[] = {
+ VCO(0, 250000000, 2000000000),
+ VCO(1, 125000000, 1000000000),
+};
+
+static struct rcg_clk pcie_aux_phy_clk_src = {
+ .cmd_rcgr_reg = PCIE_AUX_PHY_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_pcie_aux_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "pcie_aux_phy_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+ CLK_INIT(pcie_aux_phy_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_apss_ahb_clk_src_sdx20[] = {
+ F( 50000000, gpll0_ao_out_main_cgc, 12, 0, 0),
+ F( 100000000, gpll0_ao_out_main_cgc, 6, 0, 0),
+ F( 133333333, gpll0_ao_out_main_cgc, 4.5, 0, 0),
+ F_END
+};
+
+static struct clk_freq_tbl ftbl_usb30_mock_utmi_clk_src_sdx20[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F_END
+};
+
+DEFINE_CLK_DUMMY(pcie20_phy_aux_clk, 16600000);
+
+static struct clk_mux_ops pcie_aux_mux_ops = {
+ .set_mux_sel = set_pcie_aux_mux_sel,
+ .get_mux_sel = get_pcie_aux_mux_sel
+};
+
+static struct mux_clk pcie_aux_mux_clk = {
+ .num_parents = 2,
+ .offset = PCIE_AUX_CLK_SEL,
+ .parents = (struct clk_src[]) {
+ {&pcie20_phy_aux_clk.c, 0},
+ {&xo.c, 2},
+ },
+ .ops = &pcie_aux_mux_ops,
+ .mask = 0x3,
+ .shift = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "pcie_aux_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(pcie_aux_mux_clk.c),
+ }
+};
+
+static struct branch_clk gcc_pcie_aux_clk = {
+ .cbcr_reg = PCIE_AUX_CBCR,
+ .bcr_reg = PCIE_BCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .parent = &pcie_aux_mux_clk.c,
+ .dbg_name = "gcc_pcie_aux_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pcie_aux_clk.c),
+ },
+};
+
+static struct clk_lookup msm_clocks_gcc_sdx20[] = {
+ CLK_LIST(gcc_pcie_aux_clk),
+ CLK_LIST(pcie_aux_phy_clk_src),
+ CLK_LIST(pcie20_phy_aux_clk),
+ CLK_LIST(pcie_aux_mux_clk),
+};
+
+static int set_pcie_aux_mux_sel(struct mux_clk *clk, int sel)
+{
+ u32 regval;
+
+ regval = readl_relaxed(*clk->base + clk->offset);
+ regval &= ~(clk->mask << clk->shift);
+ regval |= (sel & clk->mask) << clk->shift;
+ writel_relaxed(regval, *clk->base + clk->offset);
+
+ return 0;
+}
+
+static int get_pcie_aux_mux_sel(struct mux_clk *clk)
+{
+ u32 regval;
+
+ regval = readl_relaxed(*clk->base + clk->offset);
+ return (regval >> clk->shift) & clk->mask;
+}
+
+static void msm_clocks_gcc_sdx20_fixup(void)
+{
+ gcc_pcie_sleep_clk.c.parent = &pcie_aux_phy_clk_src.c;
+
+ a7pll_clk.fabia_frac_offset = APCS_CPU_PLL_FRAC_OFF;
+ a7pll_clk.masks = &fabia_pll_masks_p;
+ a7pll_clk.vco_tbl = fabia_pll_vco_p;
+ a7pll_clk.num_vco = ARRAY_SIZE(fabia_pll_vco_p);
+ a7pll_clk.c.ops = &clk_ops_fabia_alpha_pll;
+ a7pll_clk.is_fabia = true;
+
+ apss_ahb_clk_src.freq_tbl = ftbl_apss_ahb_clk_src_sdx20;
+ usb30_mock_utmi_clk_src.freq_tbl =
+ ftbl_usb30_mock_utmi_clk_src_sdx20;
+
+ sdcc1_apps_clk_src.c.fmax[VDD_DIG_MIN] = 25000000;
+ sdcc1_apps_clk_src.c.fmax[VDD_DIG_LOWER] = 50000000;
+ sdcc1_apps_clk_src.c.fmax[VDD_DIG_LOW] = 1000000000;
+ sdcc1_apps_clk_src.c.fmax[VDD_DIG_NOMINAL] = 2000000000;
+
+ blsp1_qup1_spi_apps_clk_src.c.fmax[VDD_DIG_MIN] = 6250000;
+ blsp1_qup1_spi_apps_clk_src.c.fmax[VDD_DIG_MIN] = 6250000;
+ blsp1_qup2_i2c_apps_clk_src.c.fmax[VDD_DIG_MIN] = 9600000;
+ blsp1_qup2_spi_apps_clk_src.c.fmax[VDD_DIG_MIN] = 6250000;
+ blsp1_qup3_i2c_apps_clk_src.c.fmax[VDD_DIG_MIN] = 9600000;
+ blsp1_qup3_spi_apps_clk_src.c.fmax[VDD_DIG_MIN] = 6250000;
+
+ pcie_aux_clk_src.c.ops = &clk_ops_dummy;
+}
+
+static int msm_gcc_9650_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret;
+ bool for_sdx20 = false;
+
+ ret = vote_bimc(&bimc_clk, INT_MAX);
+ if (ret < 0)
+ return ret;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get CC base.\n");
+ return -EINVAL;
+ }
+ virt_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!virt_base) {
+ dev_err(&pdev->dev, "Failed to map in CC registers.\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_base");
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get APCS base.\n");
+ return -EINVAL;
+ }
+ virt_apcsbase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!virt_apcsbase) {
+ dev_err(&pdev->dev, "Failed to map in APCS registers.\n");
+ return -ENOMEM;
+ }
+
+ vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig");
+ if (IS_ERR(vdd_dig.regulator[0])) {
+ if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev, "Unable to get vdd_dig regulator!");
+ return PTR_ERR(vdd_dig.regulator[0]);
+ }
+
+ vdd_dig_ao.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig_ao");
+ if (IS_ERR(vdd_dig_ao.regulator[0])) {
+ if (!(PTR_ERR(vdd_dig_ao.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev, "Unable to get vdd_dig_ao regulator!");
+ return PTR_ERR(vdd_dig_ao.regulator[0]);
+ }
+
+ ret = of_msm_clock_register(pdev->dev.of_node,
+ msm_clocks_rpm_9650,
+ ARRAY_SIZE(msm_clocks_rpm_9650));
+ if (ret)
+ return ret;
+
+ if (of_device_is_compatible(pdev->dev.of_node, "qcom,gcc-9650")) {
+ vdd_dig.use_max_uV = true;
+ vdd_dig_ao.use_max_uV = true;
+ }
+
+ for_sdx20 = of_device_is_compatible(pdev->dev.of_node,
+ "qcom,gcc-sdx20");
+
+ ret = enable_rpm_scaling();
+ if (ret < 0)
+ return ret;
+
+ dev_info(&pdev->dev, "Registered RPM clocks.\n");
+
+ /*
+ * Update for sdx20 clocks.
+ */
+ if (for_sdx20)
+ msm_clocks_gcc_sdx20_fixup();
+
+ ret = of_msm_clock_register(pdev->dev.of_node,
+ msm_clocks_gcc_9650,
+ ARRAY_SIZE(msm_clocks_gcc_9650));
+ if (ret)
+ return ret;
+
+ /*
+ * Register sdx20 clocks.
+ */
+ if (for_sdx20)
+ ret = of_msm_clock_register(pdev->dev.of_node,
+ msm_clocks_gcc_sdx20,
+ ARRAY_SIZE(msm_clocks_gcc_sdx20));
+ if (ret)
+ return ret;
+
+ /*
+ * Hold an active set vote for the PCNOC AHB source.
+ * Sleep set vote is 0.
+ */
+ clk_set_rate(&pcnoc_keepalive_a_clk.c, 19200000);
+ clk_prepare_enable(&pcnoc_keepalive_a_clk.c);
+
+ clk_prepare_enable(&xo_a_clk.c);
+
+ dev_info(&pdev->dev, "Registered GCC clocks.\n");
+
+ return 0;
+}
+
+static const struct of_device_id msm_clock_gcc_match_table[] = {
+ { .compatible = "qcom,gcc-9650" },
+ { .compatible = "qcom,gcc-sdx20" },
+ {}
+};
+
+static struct platform_driver msm_clock_gcc_driver = {
+ .probe = msm_gcc_9650_probe,
+ .driver = {
+ .name = "qcom,gcc-9650",
+ .of_match_table = msm_clock_gcc_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init msm_gcc_9650_init(void)
+{
+ return platform_driver_register(&msm_clock_gcc_driver);
+}
+arch_initcall(msm_gcc_9650_init);
+
+/* ======== Clock Debug Controller ======== */
+static struct clk_lookup msm_clocks_measure_9650[] = {
+ CLK_LOOKUP_OF("measure", gcc_debug_mux, "debug"),
+};
+
+static const struct of_device_id msm_clock_debug_match_table[] = {
+ { .compatible = "qcom,cc-debug-9650" },
+ {}
+};
+
+static int msm_clock_debug_9650_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret;
+
+ clk_ops_debug_mux = clk_ops_gen_mux;
+ clk_ops_debug_mux.get_rate = measure_get_rate;
+
+ gcc_debug_mux_ops = mux_reg_ops;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get CC base.\n");
+ return -EINVAL;
+ }
+ virt_dbgbase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!virt_dbgbase) {
+ dev_err(&pdev->dev, "Failed to map in CC registers.\n");
+ return -ENOMEM;
+ }
+
+ ret = of_msm_clock_register(pdev->dev.of_node,
+ msm_clocks_measure_9650,
+ ARRAY_SIZE(msm_clocks_measure_9650));
+ if (ret)
+ return ret;
+
+ dev_info(&pdev->dev, "Registered debug mux.\n");
+ return ret;
+}
+
+static struct platform_driver msm_clock_debug_driver = {
+ .probe = msm_clock_debug_9650_probe,
+ .driver = {
+ .name = "qcom,cc-debug-9650",
+ .of_match_table = msm_clock_debug_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init msm_clock_debug_9650_init(void)
+{
+ return platform_driver_register(&msm_clock_debug_driver);
+}
+late_initcall(msm_clock_debug_9650_init);
diff --git a/drivers/clk/msm/clock-rpm-8909.c b/drivers/clk/msm/clock-rpm-8909.c
new file mode 100644
index 0000000..6730ad1
--- /dev/null
+++ b/drivers/clk/msm/clock-rpm-8909.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2014, 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/clock-rpm.h>
+#include <soc/qcom/clock-voter.h>
+#include <soc/qcom/rpm-smd.h>
+
+#include <linux/clk/msm-clock-generic.h>
+
+#include <dt-bindings/clock/msm-clocks-8909.h>
+
+#include "clock.h"
+
+#define GCC_DEBUG_CLK_CTL 0x74000
+#define RPM_MISC_CLK_TYPE 0x306b6c63
+#define RPM_BUS_CLK_TYPE 0x316b6c63
+#define RPM_MEM_CLK_TYPE 0x326b6c63
+#define RPM_SMD_KEY_ENABLE 0x62616E45
+#define RPM_QPIC_CLK_TYPE 0x63697071
+
+#define CXO_ID 0x0
+#define QDSS_ID 0x1
+#define BUS_SCALING 0x2
+
+#define PCNOC_ID 0x0
+#define SNOC_ID 0x1
+#define BIMC_ID 0x0
+#define QPIC_ID 0x0
+
+/* XO clock */
+#define BB_CLK1_ID 1
+#define BB_CLK2_ID 2
+#define BB_CLK3_ID 3
+#define RF_CLK2_ID 5
+
+static void __iomem *virt_base;
+
+/* SMD clocks */
+DEFINE_CLK_RPM_SMD(pcnoc_clk, pcnoc_a_clk, RPM_BUS_CLK_TYPE, PCNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
+DEFINE_CLK_RPM_SMD(qpic_clk, qpic_a_clk, RPM_QPIC_CLK_TYPE, QPIC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD_BRANCH(xo_clk_src, xo_a_clk_src,
+ RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
+
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID);
+
+/* SMD_XO_BUFFER */
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk1, bb_clk1_a, BB_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk2, bb_clk2_a, BB_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk3, bb_clk3_a, BB_CLK3_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk2, rf_clk2_a, RF_CLK2_ID);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk1_pin, bb_clk1_a_pin, BB_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk2_pin, bb_clk2_a_pin, BB_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk3_pin, bb_clk3_a_pin, BB_CLK3_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(rf_clk2_pin, rf_clk2_a_pin, RF_CLK2_ID);
+
+/* Voter clocks */
+static DEFINE_CLK_VOTER(pcnoc_msmbus_clk, &pcnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_mm_msmbus_clk, &snoc_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pcnoc_msmbus_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_keepalive_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_mm_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pcnoc_usb_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_usb_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_usb_a_clk, &bimc_a_clk.c, LONG_MAX);
+
+/* Branch Voter clocks */
+static DEFINE_CLK_BRANCH_VOTER(xo_gcc, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_otg_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_lpm_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_pronto_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_mss_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_wlan_clk, &xo_clk_src.c);
+
+static struct mux_clk rpm_debug_mux = {
+ .ops = &mux_reg_ops,
+ .offset = GCC_DEBUG_CLK_CTL,
+ .mask = 0x1FF,
+ .en_offset = GCC_DEBUG_CLK_CTL,
+ .en_mask = BIT(16),
+ .base = &virt_base,
+ MUX_SRC_LIST(
+ {&snoc_clk.c, 0x0000},
+ {&pcnoc_clk.c, 0x0008},
+ /* BIMC_CLK is 2x clock to the BIMC Core as well as DDR, while the
+ * axi clock is for the BIMC AXI interface. The AXI clock is 1/2 of
+ * the BIMC Clock. measure the gcc_bimc_apss_axi_clk.
+ */
+ {&bimc_clk.c, 0x0155},
+ ),
+ .c = {
+ .dbg_name = "rpm_debug_mux",
+ .ops = &clk_ops_gen_mux,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(rpm_debug_mux.c),
+ },
+};
+
+/* Lookup Table */
+static struct clk_lookup msm_clocks_rpm[] = {
+ CLK_LIST(xo_clk_src),
+ CLK_LIST(xo_a_clk_src),
+ CLK_LIST(xo_otg_clk),
+ CLK_LIST(xo_lpm_clk),
+ CLK_LIST(xo_pil_mss_clk),
+ CLK_LIST(xo_pil_pronto_clk),
+ CLK_LIST(xo_wlan_clk),
+
+ CLK_LIST(snoc_msmbus_clk),
+ CLK_LIST(snoc_msmbus_a_clk),
+ CLK_LIST(snoc_mm_msmbus_clk),
+ CLK_LIST(snoc_mm_msmbus_a_clk),
+ CLK_LIST(pcnoc_msmbus_clk),
+ CLK_LIST(pcnoc_msmbus_a_clk),
+ CLK_LIST(bimc_msmbus_clk),
+ CLK_LIST(bimc_msmbus_a_clk),
+ CLK_LIST(pcnoc_keepalive_a_clk),
+
+ CLK_LIST(pcnoc_usb_a_clk),
+ CLK_LIST(snoc_usb_a_clk),
+ CLK_LIST(bimc_usb_a_clk),
+
+ /* CoreSight clocks */
+ CLK_LIST(qdss_clk),
+ CLK_LIST(qdss_a_clk),
+
+ CLK_LIST(snoc_clk),
+ CLK_LIST(pcnoc_clk),
+ CLK_LIST(bimc_clk),
+ CLK_LIST(snoc_a_clk),
+ CLK_LIST(pcnoc_a_clk),
+ CLK_LIST(bimc_a_clk),
+ CLK_LIST(qpic_clk),
+ CLK_LIST(qpic_a_clk),
+
+ CLK_LIST(bb_clk1),
+ CLK_LIST(bb_clk2),
+ CLK_LIST(rf_clk2),
+
+ CLK_LIST(bb_clk1_pin),
+ CLK_LIST(bb_clk2_pin),
+ CLK_LIST(rf_clk2_pin),
+
+ /* RPM debug Mux*/
+ CLK_LIST(rpm_debug_mux),
+};
+
+/* Lookup Table for MSM8909w-PM660 */
+static struct clk_lookup msm_clocks_rpm_8909_pm660[] = {
+ CLK_LIST(xo_clk_src),
+ CLK_LIST(xo_a_clk_src),
+ CLK_LIST(xo_otg_clk),
+ CLK_LIST(xo_lpm_clk),
+ CLK_LIST(xo_pil_mss_clk),
+ CLK_LIST(xo_pil_pronto_clk),
+ CLK_LIST(xo_wlan_clk),
+
+ CLK_LIST(snoc_msmbus_clk),
+ CLK_LIST(snoc_msmbus_a_clk),
+ CLK_LIST(snoc_mm_msmbus_clk),
+ CLK_LIST(snoc_mm_msmbus_a_clk),
+ CLK_LIST(pcnoc_msmbus_clk),
+ CLK_LIST(pcnoc_msmbus_a_clk),
+ CLK_LIST(bimc_msmbus_clk),
+ CLK_LIST(bimc_msmbus_a_clk),
+ CLK_LIST(pcnoc_keepalive_a_clk),
+
+ CLK_LIST(pcnoc_usb_a_clk),
+ CLK_LIST(snoc_usb_a_clk),
+ CLK_LIST(bimc_usb_a_clk),
+
+ /* CoreSight clocks */
+ CLK_LIST(qdss_clk),
+ CLK_LIST(qdss_a_clk),
+
+ CLK_LIST(snoc_clk),
+ CLK_LIST(pcnoc_clk),
+ CLK_LIST(bimc_clk),
+ CLK_LIST(snoc_a_clk),
+ CLK_LIST(pcnoc_a_clk),
+ CLK_LIST(bimc_a_clk),
+ CLK_LIST(qpic_clk),
+ CLK_LIST(qpic_a_clk),
+
+ CLK_LIST(bb_clk1),
+ CLK_LIST(bb_clk2),
+ CLK_LIST(bb_clk3),
+ CLK_LIST(rf_clk2),
+
+ CLK_LIST(bb_clk1_pin),
+ CLK_LIST(bb_clk2_pin),
+ CLK_LIST(bb_clk3_pin),
+ CLK_LIST(rf_clk2_pin),
+
+ /* RPM debug Mux*/
+ CLK_LIST(rpm_debug_mux),
+};
+
+static int msm_rpmcc_8909_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret, is_8909_pm660 = 0;
+
+ ret = enable_rpm_scaling();
+ if (ret)
+ return ret;
+
+ is_8909_pm660 = of_device_is_compatible(pdev->dev.of_node,
+ "qcom,rpmcc-8909-pm660");
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get register base\n");
+ return -ENOMEM;
+ }
+
+ virt_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!virt_base) {
+ dev_err(&pdev->dev, "Failed to map CC registers\n");
+ return -ENOMEM;
+ }
+
+ if (is_8909_pm660)
+ ret = of_msm_clock_register(pdev->dev.of_node,
+ msm_clocks_rpm_8909_pm660,
+ ARRAY_SIZE(msm_clocks_rpm_8909_pm660));
+ else
+ ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_rpm,
+ ARRAY_SIZE(msm_clocks_rpm));
+
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to register RPM clocks\n");
+ return ret;
+ }
+
+ /*
+ * Hold an active set vote for PCNOC AHB source. Sleep set vote is 0.
+ */
+ clk_set_rate(&pcnoc_keepalive_a_clk.c, 19200000);
+ clk_prepare_enable(&pcnoc_keepalive_a_clk.c);
+
+ clk_prepare_enable(&xo_a_clk_src.c);
+
+ dev_info(&pdev->dev, "Registered RPM clocks.\n");
+
+ return 0;
+}
+
+static const struct of_device_id msm_clk_rpm_match_table[] = {
+ { .compatible = "qcom,rpmcc-8909" },
+ { .compatible = "qcom,rpmcc-8909-pm660" },
+ {}
+};
+
+static struct platform_driver msm_clock_rpm_driver = {
+ .probe = msm_rpmcc_8909_probe,
+ .driver = {
+ .name = "qcom,rpmcc-8909",
+ .of_match_table = msm_clk_rpm_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_rpmcc_8909_init(void)
+{
+ return platform_driver_register(&msm_clock_rpm_driver);
+}
+arch_initcall(msm_rpmcc_8909_init);
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c
index c5d12e5..20b8e34 100644
--- a/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c
@@ -485,7 +485,8 @@
struct dsi_pll_input *pin = &pdb->in;
struct dsi_pll_output *pout = &pdb->out;
s64 multiplier = BIT(20);
- s64 dec_start_multiple, dec_start, pll_comp_val;
+ s64 dec_start_multiple, dec_start;
+ u64 pll_comp_val;
s32 duration, div_frac_start;
s64 vco_clk_rate = pll->vco_current_rate;
s64 fref = pll->vco_ref_clk_rate;
@@ -560,8 +561,8 @@
{
struct dsi_pll_input *pin = &pdb->in;
struct dsi_pll_output *pout = &pdb->out;
- s64 data;
- u32 cnt;
+ u64 data;
+ u64 cnt;
data = fref * pin->vco_measure_time;
do_div(data, 1000000);
diff --git a/drivers/clk/msm/vdd-level-9650.h b/drivers/clk/msm/vdd-level-9650.h
new file mode 100644
index 0000000..d8f95b0
--- /dev/null
+++ b/drivers/clk/msm/vdd-level-9650.h
@@ -0,0 +1,96 @@
+/*
+ * 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 __DRIVERS_CLK_QCOM_VDD_LEVEL_9650_H
+#define __DRIVERS_CLK_QCOM_VDD_LEVEL_9650_H
+
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+#include <linux/regulator/consumer.h>
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP4(l1, f1, l2, f2, l3, f3, l4, f4) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ [VDD_DIG_##l4] = (f4), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP2_AO(l1, f1, l2, f2) \
+ .vdd_class = &vdd_dig_ao, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+
+#define VDD_GPU_PLL_FMAX_MAP2(l1, f1, l2, f2) \
+ .vdd_class = &vdd_gpucc_mx, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+
+#define VDD_GPU_PLL_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+ .vdd_class = &vdd_gpucc_mx, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+
+enum vdd_dig_levels {
+ VDD_DIG_NONE,
+ VDD_DIG_MIN, /* MIN SVS */
+ VDD_DIG_LOWER, /* SVS2 */
+ VDD_DIG_LOW, /* SVS */
+ VDD_DIG_NOMINAL, /* NOM */
+ VDD_DIG_HIGH, /* TURBO */
+ VDD_DIG_NUM
+};
+
+static int vdd_corner[] = {
+ RPM_REGULATOR_LEVEL_NONE, /* VDD_DIG_NONE */
+ RPM_REGULATOR_LEVEL_MIN_SVS, /* VDD_DIG_MIN */
+ RPM_REGULATOR_LEVEL_LOW_SVS, /* VDD_DIG_LOWER */
+ RPM_REGULATOR_LEVEL_SVS, /* VDD_DIG_LOW */
+ RPM_REGULATOR_LEVEL_NOM, /* VDD_DIG_NOMINAL */
+ RPM_REGULATOR_LEVEL_TURBO, /* VDD_DIG_HIGH */
+};
+
+#endif
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 87d067a..79739bc 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -252,4 +252,13 @@
Say Y if you want to support CPU clock scaling using
CPUfreq drivers for dyanmic power management.
+config MDM_DEBUGCC_SDXPOORWILLS
+ tristate "SDXPOORWILLS Debug Clock Controller"
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the debug clock controller on sdxpoorwills
+ based devices.
+ Say Y if you want to support the clock measurement
+ functionality.
+
source "drivers/clk/qcom/mdss/Kconfig"
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 8cb46a7..0cd2e94 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -23,6 +23,7 @@
obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o
obj-$(CONFIG_MDM_CLOCK_CPU_SDXPOORWILLS) += clk-cpu-a7.o
+obj-$(CONFIG_MDM_DEBUGCC_SDXPOORWILLS) += debugcc-sdxpoorwills.o
obj-$(CONFIG_MDM_GCC_9615) += gcc-mdm9615.o
obj-$(CONFIG_MDM_GCC_SDXPOORWILLS) += gcc-sdxpoorwills.o
obj-$(CONFIG_MDM_LCC_9615) += lcc-mdm9615.o
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index bf4df55..f53d1ee 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -432,6 +432,7 @@
static DEFINE_CLK_VOTER(l3_cluster0_vote_clk, l3_clk, 0);
static DEFINE_CLK_VOTER(l3_cluster1_vote_clk, l3_clk, 0);
static DEFINE_CLK_VOTER(l3_misc_vote_clk, l3_clk, 0);
+static DEFINE_CLK_VOTER(l3_gpu_vote_clk, l3_clk, 0);
static struct clk_osm pwrcl_clk = {
.cluster_num = 1,
@@ -581,6 +582,7 @@
[L3_CLUSTER0_VOTE_CLK] = &l3_cluster0_vote_clk.hw,
[L3_CLUSTER1_VOTE_CLK] = &l3_cluster1_vote_clk.hw,
[L3_MISC_VOTE_CLK] = &l3_misc_vote_clk.hw,
+ [L3_GPU_VOTE_CLK] = &l3_gpu_vote_clk.hw,
[PWRCL_CLK] = &pwrcl_clk.hw,
[CPU0_PWRCL_CLK] = &cpu0_pwrcl_clk.hw,
[CPU1_PWRCL_CLK] = &cpu1_pwrcl_clk.hw,
@@ -1345,6 +1347,8 @@
"clk: Failed to enable cluster1 clock for L3\n");
WARN(clk_prepare_enable(l3_misc_vote_clk.hw.clk),
"clk: Failed to enable misc clock for L3\n");
+ WARN(clk_prepare_enable(l3_gpu_vote_clk.hw.clk),
+ "clk: Failed to enable iocoherent bwmon clock for L3\n");
/*
* Call clk_prepare_enable for the silver clock explicitly in order to
diff --git a/drivers/clk/qcom/clk-debug.c b/drivers/clk/qcom/clk-debug.c
index d366ad4..d101536 100644
--- a/drivers/clk/qcom/clk-debug.c
+++ b/drivers/clk/qcom/clk-debug.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -275,7 +275,7 @@
if (clk_set_parent(measure->clk, hw->clk))
return 0;
- debugfs_create_file("clk_measure", 0x444, dentry, hw,
+ debugfs_create_file("clk_measure", 0444, dentry, hw,
&clk_measure_fops);
return 0;
}
diff --git a/drivers/clk/qcom/clk-debug.h b/drivers/clk/qcom/clk-debug.h
index aa8d97b..a9f71b4 100644
--- a/drivers/clk/qcom/clk-debug.h
+++ b/drivers/clk/qcom/clk-debug.h
@@ -44,6 +44,7 @@
GPU_CC,
VIDEO_CC,
CPU,
+ MAX_NUM_CC,
};
/**
diff --git a/drivers/clk/qcom/debugcc-sdxpoorwills.c b/drivers/clk/qcom/debugcc-sdxpoorwills.c
new file mode 100644
index 0000000..d66a623
--- /dev/null
+++ b/drivers/clk/qcom/debugcc-sdxpoorwills.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2017-2018, 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.
+ */
+
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "clk-debug.h"
+
+static struct measure_clk_data debug_mux_priv = {
+ .ctl_reg = 0x79004,
+ .status_reg = 0x79008,
+ .xo_div4_cbcr = 0x22008,
+};
+
+static const char *const debug_mux_parent_names[] = {
+ "gcc_blsp1_ahb_clk",
+ "gcc_blsp1_qup1_i2c_apps_clk",
+ "gcc_blsp1_qup1_spi_apps_clk",
+ "gcc_blsp1_qup2_i2c_apps_clk",
+ "gcc_blsp1_qup2_spi_apps_clk",
+ "gcc_blsp1_qup3_i2c_apps_clk",
+ "gcc_blsp1_qup3_spi_apps_clk",
+ "gcc_blsp1_qup4_i2c_apps_clk",
+ "gcc_blsp1_qup4_spi_apps_clk",
+ "gcc_blsp1_sleep_clk",
+ "gcc_blsp1_uart1_apps_clk",
+ "gcc_blsp1_uart2_apps_clk",
+ "gcc_blsp1_uart3_apps_clk",
+ "gcc_blsp1_uart4_apps_clk",
+ "gcc_boot_rom_ahb_clk",
+ "gcc_ce1_ahb_clk",
+ "gcc_ce1_axi_clk",
+ "gcc_ce1_clk",
+ "gcc_cpuss_ahb_clk",
+ "gcc_cpuss_gnoc_clk",
+ "gcc_cpuss_rbcpr_clk",
+ "gcc_eth_axi_clk",
+ "gcc_eth_ptp_clk",
+ "gcc_eth_rgmii_clk",
+ "gcc_eth_slave_ahb_clk",
+ "gcc_gp1_clk",
+ "gcc_gp2_clk",
+ "gcc_gp3_clk",
+ "gcc_pcie_aux_clk",
+ "gcc_pcie_cfg_ahb_clk",
+ "gcc_pcie_mstr_axi_clk",
+ "gcc_pcie_phy_refgen_clk",
+ "gcc_pcie_pipe_clk",
+ "gcc_pcie_sleep_clk",
+ "gcc_pcie_slv_axi_clk",
+ "gcc_pcie_slv_q2a_axi_clk",
+ "gcc_pdm2_clk",
+ "gcc_pdm_ahb_clk",
+ "gcc_pdm_xo4_clk",
+ "gcc_prng_ahb_clk",
+ "gcc_sdcc1_ahb_clk",
+ "gcc_sdcc1_apps_clk",
+ "gcc_spmi_fetcher_ahb_clk",
+ "gcc_spmi_fetcher_clk",
+ "gcc_sys_noc_cpuss_ahb_clk",
+ "gcc_sys_noc_usb3_clk",
+ "gcc_usb30_master_clk",
+ "gcc_usb30_mock_utmi_clk",
+ "gcc_usb30_sleep_clk",
+ "gcc_usb3_phy_aux_clk",
+ "gcc_usb3_phy_pipe_clk",
+ "gcc_usb_phy_cfg_ahb2phy_clk",
+ "gcc_xo_div4_clk",
+ "measure_only_ipa_2x_clk",
+};
+
+static struct clk_debug_mux gcc_debug_mux = {
+ .priv = &debug_mux_priv,
+ .debug_offset = 0x79000,
+ .post_div_offset = 0x29000,
+ .cbcr_offset = 0x29004,
+ .src_sel_mask = 0x3FF,
+ .src_sel_shift = 0,
+ .post_div_mask = 0xF,
+ .post_div_shift = 0,
+ MUX_SRC_LIST(
+ { "gcc_blsp1_ahb_clk", 0x34, 4, GCC,
+ 0x34, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_blsp1_qup1_i2c_apps_clk", 0x37, 4, GCC,
+ 0x37, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_blsp1_qup1_spi_apps_clk", 0x36, 4, GCC,
+ 0x36, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_blsp1_qup2_i2c_apps_clk", 0x3B, 4, GCC,
+ 0x3B, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_blsp1_qup2_spi_apps_clk", 0x3A, 4, GCC,
+ 0x3A, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_blsp1_qup3_i2c_apps_clk", 0x3F, 4, GCC,
+ 0x3F, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_blsp1_qup3_spi_apps_clk", 0x3E, 4, GCC,
+ 0x3E, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_blsp1_qup4_i2c_apps_clk", 0x43, 4, GCC,
+ 0x43, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_blsp1_qup4_spi_apps_clk", 0x42, 4, GCC,
+ 0x42, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_blsp1_sleep_clk", 0x35, 4, GCC,
+ 0x35, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_blsp1_uart1_apps_clk", 0x38, 4, GCC,
+ 0x38, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_blsp1_uart2_apps_clk", 0x3C, 4, GCC,
+ 0x3C, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_blsp1_uart3_apps_clk", 0x40, 4, GCC,
+ 0x40, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_blsp1_uart4_apps_clk", 0x44, 4, GCC,
+ 0x44, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_boot_rom_ahb_clk", 0x4B, 4, GCC,
+ 0x4B, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_ce1_ahb_clk", 0x60, 4, GCC,
+ 0x60, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_ce1_axi_clk", 0x5F, 4, GCC,
+ 0x5F, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_ce1_clk", 0x5E, 4, GCC,
+ 0x5E, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_cpuss_ahb_clk", 0x74, 4, GCC,
+ 0x74, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_cpuss_gnoc_clk", 0x75, 4, GCC,
+ 0x75, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_cpuss_rbcpr_clk", 0x76, 4, GCC,
+ 0x76, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_eth_axi_clk", 0xCB, 4, GCC,
+ 0xCB, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_eth_ptp_clk", 0xFD, 4, GCC,
+ 0xFD, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_eth_rgmii_clk", 0xC9, 4, GCC,
+ 0xC9, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_eth_slave_ahb_clk", 0xCA, 4, GCC,
+ 0xCA, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_gp1_clk", 0x85, 4, GCC,
+ 0x85, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_gp2_clk", 0x86, 4, GCC,
+ 0x86, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_gp3_clk", 0x87, 4, GCC,
+ 0x87, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_pcie_aux_clk", 0x99, 4, GCC,
+ 0x99, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_pcie_cfg_ahb_clk", 0x98, 4, GCC,
+ 0x98, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_pcie_mstr_axi_clk", 0x97, 4, GCC,
+ 0x97, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_pcie_phy_refgen_clk", 0x104, 4, GCC,
+ 0x104, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_pcie_pipe_clk", 0x9A, 4, GCC,
+ 0x9A, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_pcie_sleep_clk", 0x9C, 4, GCC,
+ 0x9C, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_pcie_slv_axi_clk", 0x96, 4, GCC,
+ 0x96, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_pcie_slv_q2a_axi_clk", 0x95, 4, GCC,
+ 0x95, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_pdm2_clk", 0x48, 4, GCC,
+ 0x48, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_pdm_ahb_clk", 0x46, 4, GCC,
+ 0x46, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_pdm_xo4_clk", 0x47, 4, GCC,
+ 0x47, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_prng_ahb_clk", 0x49, 4, GCC,
+ 0x49, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_sdcc1_ahb_clk", 0x33, 4, GCC,
+ 0x33, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_sdcc1_apps_clk", 0x32, 4, GCC,
+ 0x32, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_spmi_fetcher_ahb_clk", 0xB5, 4, GCC,
+ 0xB5, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_spmi_fetcher_clk", 0xB4, 4, GCC,
+ 0xB4, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_sys_noc_cpuss_ahb_clk", 0x10B, 4, GCC,
+ 0x10B, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_sys_noc_usb3_clk", 0xB, 4, GCC,
+ 0xB, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_usb30_master_clk", 0x28, 4, GCC,
+ 0x28, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_usb30_mock_utmi_clk", 0x2A, 4, GCC,
+ 0x2A, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_usb30_sleep_clk", 0x29, 4, GCC,
+ 0x29, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_usb3_phy_aux_clk", 0x2B, 4, GCC,
+ 0x2B, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_usb3_phy_pipe_clk", 0x2D, 4, GCC,
+ 0x2D, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_usb_phy_cfg_ahb2phy_clk", 0x31, 4, GCC,
+ 0x31, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "gcc_xo_div4_clk", 0x63, 4, GCC,
+ 0x63, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ { "measure_only_ipa_2x_clk", 0xAC, 4, GCC,
+ 0xAC, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+ ),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_debug_mux",
+ .ops = &clk_debug_mux_ops,
+ .parent_names = debug_mux_parent_names,
+ .num_parents = ARRAY_SIZE(debug_mux_parent_names),
+ .flags = CLK_IS_MEASURE,
+ },
+};
+
+static const struct of_device_id clk_debug_match_table[] = {
+ { .compatible = "qcom,debugcc-sdxpoorwills" },
+ { }
+};
+
+static int clk_debug_sdxpoorwills_probe(struct platform_device *pdev)
+{
+ struct clk *clk;
+ int ret = 0;
+
+ clk = devm_clk_get(&pdev->dev, "xo_clk_src");
+ if (IS_ERR(clk)) {
+ if (PTR_ERR(clk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get xo clock\n");
+ return PTR_ERR(clk);
+ }
+
+ debug_mux_priv.cxo = clk;
+
+ gcc_debug_mux.regmap = devm_kcalloc(&pdev->dev, MAX_NUM_CC,
+ sizeof(*gcc_debug_mux.regmap), GFP_KERNEL);
+ if (!gcc_debug_mux.regmap)
+ return -ENOMEM;
+
+ if (!of_get_property(pdev->dev.of_node, "qcom,gcc", NULL))
+ return -ENODEV;
+
+ gcc_debug_mux.regmap[GCC] =
+ syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "qcom,gcc");
+ if (IS_ERR(gcc_debug_mux.regmap[GCC])) {
+ pr_err("Failed to map qcom,gcc\n");
+ return PTR_ERR(gcc_debug_mux.regmap[GCC]);
+ }
+
+ clk = devm_clk_register(&pdev->dev, &gcc_debug_mux.hw);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "Unable to register GCC debug mux\n");
+ return PTR_ERR(clk);
+ }
+
+ ret = clk_debug_measure_register(&gcc_debug_mux.hw);
+ if (ret)
+ dev_err(&pdev->dev, "Could not register Measure clock\n");
+
+ return ret;
+}
+
+static struct platform_driver clk_debug_driver = {
+ .probe = clk_debug_sdxpoorwills_probe,
+ .driver = {
+ .name = "debugcc-sdxpoorwills",
+ .of_match_table = clk_debug_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init clk_debug_sdxpoorwills_init(void)
+{
+ return platform_driver_register(&clk_debug_driver);
+}
+fs_initcall(clk_debug_sdxpoorwills_init);
+
+MODULE_DESCRIPTION("QTI DEBUG CC SDXPOORWILLS Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:debugcc-sdxpoorwills");
diff --git a/drivers/clk/qcom/gcc-sdxpoorwills.c b/drivers/clk/qcom/gcc-sdxpoorwills.c
index c6e8faa..4050683 100644
--- a/drivers/clk/qcom/gcc-sdxpoorwills.c
+++ b/drivers/clk/qcom/gcc-sdxpoorwills.c
@@ -1711,6 +1711,19 @@
},
};
+/* Measure-only clock for gcc_ipa_2x_clk. */
+static struct clk_dummy measure_only_ipa_2x_clk = {
+ .rrate = 1000,
+ .hw.init = &(struct clk_init_data){
+ .name = "measure_only_ipa_2x_clk",
+ .ops = &clk_dummy_ops,
+ },
+};
+
+static struct clk_hw *gcc_sdxpoorwills_hws[] = {
+ [MEASURE_ONLY_IPA_2X_CLK] = &measure_only_ipa_2x_clk.hw,
+};
+
static struct clk_regmap *gcc_sdxpoorwills_clocks[] = {
[GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr,
[GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr,
@@ -1826,6 +1839,7 @@
[GCC_USB30_BCR] = { 0xb000 },
[GCC_USB3_PHY_BCR] = { 0xc000 },
[GCC_USB3PHY_PHY_BCR] = { 0xc004 },
+ [GCC_QUSB2PHY_BCR] = { 0xd000 },
[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0xe000 },
};
@@ -1854,7 +1868,8 @@
static int gcc_sdxpoorwills_probe(struct platform_device *pdev)
{
- int ret = 0;
+ int i, ret = 0;
+ struct clk *clk;
struct regmap *regmap;
regmap = qcom_cc_map(pdev, &gcc_sdxpoorwills_desc);
@@ -1869,6 +1884,13 @@
return PTR_ERR(vdd_cx.regulator[0]);
}
+ /* Register the dummy measurement clocks */
+ for (i = 0; i < ARRAY_SIZE(gcc_sdxpoorwills_hws); i++) {
+ clk = devm_clk_register(&pdev->dev, gcc_sdxpoorwills_hws[i]);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ }
+
ret = qcom_cc_really_probe(pdev, &gcc_sdxpoorwills_desc, regmap);
if (ret) {
dev_err(&pdev->dev, "Failed to register GCC clocks\n");
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index 7290205..874c229 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -925,6 +925,11 @@
if (!vco->priv)
pr_err("vco priv is null\n");
+ if (!pll) {
+ pr_err("pll is null\n");
+ return 0;
+ }
+
/*
* Calculate the vco rate from HW registers only for handoff cases.
* For other cases where a vco_10nm_set_rate() has already been
diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
index 254d952..4e8e9bc 100644
--- a/drivers/clk/sunxi-ng/Kconfig
+++ b/drivers/clk/sunxi-ng/Kconfig
@@ -1,6 +1,7 @@
config SUNXI_CCU
bool "Clock support for Allwinner SoCs"
depends on ARCH_SUNXI || COMPILE_TEST
+ select RESET_CONTROLLER
default ARCH_SUNXI
if SUNXI_CCU
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index 1b2574c..b167cc6 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -16,6 +16,7 @@
#include <linux/of_irq.h>
#include <linux/clk.h>
#include <linux/reset.h>
+#include <linux/slab.h>
#define TIM_CR1 0x00
#define TIM_DIER 0x0c
@@ -106,6 +107,10 @@
unsigned long rate, max_delta;
int irq, ret, bits, prescaler = 1;
+ data = kmemdup(&clock_event_ddata, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
@@ -156,8 +161,8 @@
writel_relaxed(prescaler - 1, data->base + TIM_PSC);
writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR);
- writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
writel_relaxed(0, data->base + TIM_SR);
+ writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ);
@@ -184,6 +189,7 @@
err_clk_enable:
clk_put(clk);
err_clk_get:
+ kfree(data);
return ret;
}
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index bb540a5..597aa57 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -102,14 +102,6 @@
governor. If unsure have a look at the help section of the
driver. Fallback governor will be the performance governor.
-config CPU_FREQ_DEFAULT_GOV_SCHED
- bool "sched"
- select CPU_FREQ_GOV_SCHED
- help
- Use the CPUfreq governor 'sched' as default. This scales
- cpu frequency using CPU utilization estimates from the
- scheduler.
-
config CPU_FREQ_DEFAULT_GOV_INTERACTIVE
bool "interactive"
select CPU_FREQ_GOV_INTERACTIVE
@@ -238,19 +230,6 @@
If in doubt, say N.
-config CPU_FREQ_GOV_SCHED
- bool "'sched' cpufreq governor"
- depends on CPU_FREQ
- depends on SMP
- select CPU_FREQ_GOV_COMMON
- help
- 'sched' - this governor scales cpu frequency from the
- scheduler as a function of cpu capacity utilization. It does
- not evaluate utilization on a periodic basis (as ondemand
- does) but instead is event-driven by the scheduler.
-
- If in doubt, say N.
-
config CPU_FREQ_GOV_SCHEDUTIL
bool "'schedutil' cpufreq policy governor"
depends on CPU_FREQ && SMP
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 297e912..1ee3674 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -648,7 +648,7 @@
if (c->x86_vendor == X86_VENDOR_INTEL) {
if ((c->x86 == 15) &&
(c->x86_model == 6) &&
- (c->x86_mask == 8)) {
+ (c->x86_stepping == 8)) {
pr_info("Intel(R) Xeon(R) 7100 Errata AL30, processors may lock up on frequency changes: disabling acpi-cpufreq\n");
return -ENODEV;
}
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index 4d3ec92..e4cbfe5 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -280,6 +280,13 @@
policy->cpuinfo.transition_latency = transition_latency;
+ /*
+ * Android: set default parameters for parity between schedutil and
+ * schedfreq
+ */
+ policy->up_transition_delay_us = transition_latency / NSEC_PER_USEC;
+ policy->down_transition_delay_us = 50000; /* 50ms */
+
return 0;
out_free_cpufreq_table:
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index ff72d8a..8059ef9 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -325,33 +325,24 @@
*********************************************************************/
static DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
+static DEFINE_PER_CPU(unsigned long, max_freq_cpu);
static DEFINE_PER_CPU(unsigned long, max_freq_scale) = SCHED_CAPACITY_SCALE;
+static DEFINE_PER_CPU(unsigned long, min_freq_scale);
static void
-scale_freq_capacity(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs)
+scale_freq_capacity(const cpumask_t *cpus, unsigned long cur_freq,
+ unsigned long max_freq)
{
- unsigned long cur = freqs ? freqs->new : policy->cur;
- unsigned long scale = (cur << SCHED_CAPACITY_SHIFT) / policy->max;
- struct cpufreq_cpuinfo *cpuinfo = &policy->cpuinfo;
+ unsigned long scale = (cur_freq << SCHED_CAPACITY_SHIFT) / max_freq;
int cpu;
- pr_debug("cpus %*pbl cur/cur max freq %lu/%u kHz freq scale %lu\n",
- cpumask_pr_args(policy->cpus), cur, policy->max, scale);
-
- for_each_cpu(cpu, policy->cpus)
+ for_each_cpu(cpu, cpus) {
per_cpu(freq_scale, cpu) = scale;
+ per_cpu(max_freq_cpu, cpu) = max_freq;
+ }
- if (freqs)
- return;
-
- scale = (policy->max << SCHED_CAPACITY_SHIFT) / cpuinfo->max_freq;
-
- pr_debug("cpus %*pbl cur max/max freq %u/%u kHz max freq scale %lu\n",
- cpumask_pr_args(policy->cpus), policy->max, cpuinfo->max_freq,
- scale);
-
- for_each_cpu(cpu, policy->cpus)
- per_cpu(max_freq_scale, cpu) = scale;
+ pr_debug("cpus %*pbl cur freq/max freq %lu/%lu kHz freq scale %lu\n",
+ cpumask_pr_args(cpus), cur_freq, max_freq, scale);
}
unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu)
@@ -359,11 +350,62 @@
return per_cpu(freq_scale, cpu);
}
-unsigned long cpufreq_scale_max_freq_capacity(int cpu)
+static void
+scale_max_freq_capacity(const cpumask_t *cpus, unsigned long policy_max_freq)
+{
+ unsigned long scale, max_freq;
+ int cpu = cpumask_first(cpus);
+
+ if (cpu >= nr_cpu_ids)
+ return;
+
+ max_freq = per_cpu(max_freq_cpu, cpu);
+
+ if (!max_freq)
+ return;
+
+ scale = (policy_max_freq << SCHED_CAPACITY_SHIFT) / max_freq;
+
+ for_each_cpu(cpu, cpus)
+ per_cpu(max_freq_scale, cpu) = scale;
+
+ pr_debug("cpus %*pbl policy max freq/max freq %lu/%lu kHz max freq scale %lu\n",
+ cpumask_pr_args(cpus), policy_max_freq, max_freq, scale);
+}
+
+unsigned long cpufreq_scale_max_freq_capacity(struct sched_domain *sd, int cpu)
{
return per_cpu(max_freq_scale, cpu);
}
+static void
+scale_min_freq_capacity(const cpumask_t *cpus, unsigned long policy_min_freq)
+{
+ unsigned long scale, max_freq;
+ int cpu = cpumask_first(cpus);
+
+ if (cpu >= nr_cpu_ids)
+ return;
+
+ max_freq = per_cpu(max_freq_cpu, cpu);
+
+ if (!max_freq)
+ return;
+
+ scale = (policy_min_freq << SCHED_CAPACITY_SHIFT) / max_freq;
+
+ for_each_cpu(cpu, cpus)
+ per_cpu(min_freq_scale, cpu) = scale;
+
+ pr_debug("cpus %*pbl policy min freq/max freq %lu/%lu kHz min freq scale %lu\n",
+ cpumask_pr_args(cpus), policy_min_freq, max_freq, scale);
+}
+
+unsigned long cpufreq_scale_min_freq_capacity(struct sched_domain *sd, int cpu)
+{
+ return per_cpu(min_freq_scale, cpu);
+}
+
static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, unsigned int state)
{
@@ -471,7 +513,7 @@
spin_unlock(&policy->transition_lock);
- scale_freq_capacity(policy, freqs);
+ scale_freq_capacity(policy->cpus, freqs->new, policy->cpuinfo.max_freq);
#ifdef CONFIG_SMP
for_each_cpu(cpu, policy->cpus)
trace_cpu_capacity(capacity_curr_of(cpu), cpu);
@@ -2275,7 +2317,8 @@
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_NOTIFY, new_policy);
- scale_freq_capacity(new_policy, NULL);
+ scale_max_freq_capacity(policy->cpus, policy->max);
+ scale_min_freq_capacity(policy->cpus, policy->min);
policy->min = new_policy->min;
policy->max = new_policy->max;
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index c46a12d..d5e27bc 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -775,7 +775,7 @@
break;
case 7:
- switch (c->x86_mask) {
+ switch (c->x86_stepping) {
case 0:
longhaul_version = TYPE_LONGHAUL_V1;
cpu_model = CPU_SAMUEL2;
@@ -787,7 +787,7 @@
break;
case 1 ... 15:
longhaul_version = TYPE_LONGHAUL_V2;
- if (c->x86_mask < 8) {
+ if (c->x86_stepping < 8) {
cpu_model = CPU_SAMUEL2;
cpuname = "C3 'Samuel 2' [C5B]";
} else {
@@ -814,7 +814,7 @@
numscales = 32;
memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults));
memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr));
- switch (c->x86_mask) {
+ switch (c->x86_stepping) {
case 0 ... 1:
cpu_model = CPU_NEHEMIAH;
cpuname = "C3 'Nehemiah A' [C5XLOE]";
diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c
index fd77812..a25741b 100644
--- a/drivers/cpufreq/p4-clockmod.c
+++ b/drivers/cpufreq/p4-clockmod.c
@@ -168,7 +168,7 @@
#endif
/* Errata workaround */
- cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask;
+ cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_stepping;
switch (cpuid) {
case 0x0f07:
case 0x0f0a:
diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c
index 9f013ed..ef276f6 100644
--- a/drivers/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -131,7 +131,7 @@
return 0;
}
- if ((c->x86_model == 6) && (c->x86_mask == 0)) {
+ if ((c->x86_model == 6) && (c->x86_stepping == 0)) {
pr_info("K7 660[A0] core detected, enabling errata workarounds\n");
have_a0 = 1;
}
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c
index a84724e..6fb3cd2 100644
--- a/drivers/cpufreq/powernv-cpufreq.c
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -260,9 +260,9 @@
if (id == pstate_max)
powernv_pstate_info.max = i;
- else if (id == pstate_nominal)
+ if (id == pstate_nominal)
powernv_pstate_info.nominal = i;
- else if (id == pstate_min)
+ if (id == pstate_min)
powernv_pstate_info.min = i;
}
diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c
index 41bc539..4fa5adf 100644
--- a/drivers/cpufreq/speedstep-centrino.c
+++ b/drivers/cpufreq/speedstep-centrino.c
@@ -37,7 +37,7 @@
{
__u8 x86; /* CPU family */
__u8 x86_model; /* model */
- __u8 x86_mask; /* stepping */
+ __u8 x86_stepping; /* stepping */
};
enum {
@@ -277,7 +277,7 @@
{
if ((c->x86 == x->x86) &&
(c->x86_model == x->x86_model) &&
- (c->x86_mask == x->x86_mask))
+ (c->x86_stepping == x->x86_stepping))
return 1;
return 0;
}
diff --git a/drivers/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c
index 1b80621..ade98a2 100644
--- a/drivers/cpufreq/speedstep-lib.c
+++ b/drivers/cpufreq/speedstep-lib.c
@@ -272,9 +272,9 @@
ebx = cpuid_ebx(0x00000001);
ebx &= 0x000000FF;
- pr_debug("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask);
+ pr_debug("ebx value is %x, x86_stepping is %x\n", ebx, c->x86_stepping);
- switch (c->x86_mask) {
+ switch (c->x86_stepping) {
case 4:
/*
* B-stepping [M-P4-M]
@@ -361,7 +361,7 @@
msr_lo, msr_hi);
if ((msr_hi & (1<<18)) &&
(relaxed_check ? 1 : (msr_hi & (3<<24)))) {
- if (c->x86_mask == 0x01) {
+ if (c->x86_stepping == 0x01) {
pr_debug("early PIII version\n");
return SPEEDSTEP_CPU_PIII_C_EARLY;
} else
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 4615122..7fca843 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -99,6 +99,8 @@
module_param_named(tmr_add, tmr_add, uint, 0664);
static uint32_t ref_premature_cnt = 1;
+module_param_named(ref_premature_cnt, ref_premature_cnt, uint, 0664);
+
static uint32_t bias_hyst;
module_param_named(bias_hyst, bias_hyst, uint, 0664);
@@ -1371,11 +1373,6 @@
const struct cpumask *cpumask = get_cpu_mask(dev->cpu);
ktime_t start = ktime_get();
uint64_t start_time = ktime_to_ns(start), end_time;
- struct power_params *pwr_params;
-
- pwr_params = &cpu->levels[idx].pwr;
- sched_set_cpu_cstate(dev->cpu, idx + 1,
- pwr_params->energy_overhead, pwr_params->latency_us);
cpu_prepare(cpu, idx, true);
cluster_prepare(cpu->parent, cpumask, idx, true, start_time);
@@ -1394,7 +1391,6 @@
cluster_unprepare(cpu->parent, cpumask, idx, true, end_time);
cpu_unprepare(cpu, idx, true);
- sched_set_cpu_cstate(smp_processor_id(), 0, 0, 0);
dev->last_residency = ktime_us_delta(ktime_get(), start);
update_history(dev, idx);
trace_cpu_idle_exit(idx, success);
@@ -1748,7 +1744,7 @@
int cpu;
for_each_possible_cpu(cpu) {
- rc = arm_cpuidle_init(smp_processor_id());
+ rc = arm_cpuidle_init(cpu);
if (rc) {
pr_err("CPU%d ARM CPUidle init failed (%d)\n", cpu, rc);
return rc;
diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c
index 10db7df..2ee1180 100644
--- a/drivers/crypto/bfin_crc.c
+++ b/drivers/crypto/bfin_crc.c
@@ -494,7 +494,8 @@
.cra_driver_name = DRIVER_NAME,
.cra_priority = 100,
.cra_flags = CRYPTO_ALG_TYPE_AHASH |
- CRYPTO_ALG_ASYNC,
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_OPTIONAL_KEY,
.cra_blocksize = CHKSUM_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct bfin_crypto_crc_ctx),
.cra_alignmask = 3,
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 98468b9..2ca101a 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -228,12 +228,16 @@
* without any error (HW optimizations for later
* CAAM eras), then try again.
*/
- rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
- if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) ||
- !(rdsta_val & (1 << sh_idx)))
- ret = -EAGAIN;
if (ret)
break;
+
+ rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
+ if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) ||
+ !(rdsta_val & (1 << sh_idx))) {
+ ret = -EAGAIN;
+ break;
+ }
+
dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx);
/* Clear the contents before recreating the descriptor */
memset(desc, 0x00, CAAM_CMD_SZ * 7);
diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c
index 182097c..6fa91ae 100644
--- a/drivers/crypto/msm/ice.c
+++ b/drivers/crypto/msm/ice.c
@@ -25,8 +25,26 @@
#include <soc/qcom/scm.h>
#include <soc/qcom/qseecomi.h>
#include "iceregs.h"
-#include <linux/pfk.h>
+#ifdef CONFIG_PFK
+#include <linux/pfk.h>
+#else
+#include <linux/bio.h>
+static inline int pfk_load_key_start(const struct bio *bio,
+ struct ice_crypto_setting *ice_setting, bool *is_pfe, bool async)
+{
+ return 0;
+}
+
+static inline int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
+{
+ return 0;
+}
+
+static inline void pfk_clear_on_reset(void)
+{
+}
+#endif
#define TZ_SYSCALL_CREATE_SMC_ID(o, s, f) \
((uint32_t)((((o & 0x3f) << 24) | (s & 0xff) << 8) | (f & 0xff)))
@@ -126,9 +144,6 @@
return -EPERM;
}
- if (!setting)
- return -EINVAL;
-
if ((short)(crypto_data->key_index) >= 0) {
memcpy(&setting->crypto_data, crypto_data,
@@ -1436,7 +1451,7 @@
int ret = 0;
bool is_pfe = false;
- if (!pdev || !req) {
+ if (!pdev || !req || !setting) {
pr_err("%s: Invalid params passed\n", __func__);
return -EINVAL;
}
@@ -1455,7 +1470,6 @@
/* It is not an error to have a request with no bio */
return 0;
}
- //pr_err("%s bio is %pK\n", __func__, req->bio);
ret = pfk_load_key_start(req->bio, &pfk_crypto_data, &is_pfe, async);
if (is_pfe) {
@@ -1619,7 +1633,7 @@
list_for_each_entry(ice_dev, &ice_devices, list) {
if (!strcmp(ice_dev->ice_instance_type, storage_type)) {
- pr_debug("%s: ice device %pK\n", __func__, ice_dev);
+ pr_info("%s: found ice device %p\n", __func__, ice_dev);
return ice_dev;
}
}
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 4426bc7..8643667 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -5929,8 +5929,7 @@
int len = DUMMY_REQ_DATA_LEN;
memcpy(pce_dev->dummyreq_in_buf, input, len);
- sg_set_buf(&pce_dev->dummyreq.sg, pce_dev->dummyreq_in_buf, len);
- sg_mark_end(&pce_dev->dummyreq.sg);
+ sg_init_one(&pce_dev->dummyreq.sg, pce_dev->dummyreq_in_buf, len);
pce_dev->dummyreq.sreq.alg = QCE_HASH_SHA1;
pce_dev->dummyreq.sreq.qce_cb = qce_dummy_complete;
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index 441e86b..9126627 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -531,7 +531,7 @@
printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n");
- if (c->x86 == 6 && c->x86_model == 15 && c->x86_mask == 2) {
+ if (c->x86 == 6 && c->x86_model == 15 && c->x86_stepping == 2) {
ecb_fetch_blocks = MAX_ECB_FETCH_BLOCKS;
cbc_fetch_blocks = MAX_CBC_FETCH_BLOCKS;
printk(KERN_NOTICE PFX "VIA Nano stepping 2 detected: enabling workaround.\n");
diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c
index a668286..500e409 100644
--- a/drivers/crypto/s5p-sss.c
+++ b/drivers/crypto/s5p-sss.c
@@ -542,15 +542,21 @@
uint32_t aes_control;
unsigned long flags;
int err;
+ u8 *iv;
aes_control = SSS_AES_KEY_CHANGE_MODE;
if (mode & FLAGS_AES_DECRYPT)
aes_control |= SSS_AES_MODE_DECRYPT;
- if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC)
+ if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) {
aes_control |= SSS_AES_CHAIN_MODE_CBC;
- else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR)
+ iv = req->info;
+ } else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) {
aes_control |= SSS_AES_CHAIN_MODE_CTR;
+ iv = req->info;
+ } else {
+ iv = NULL; /* AES_ECB */
+ }
if (dev->ctx->keylen == AES_KEYSIZE_192)
aes_control |= SSS_AES_KEY_SIZE_192;
@@ -581,7 +587,7 @@
goto outdata_error;
SSS_AES_WRITE(dev, AES_CONTROL, aes_control);
- s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen);
+ s5p_set_aes(dev, dev->ctx->aes_key, iv, dev->ctx->keylen);
s5p_set_dma_indata(dev, dev->sg_src);
s5p_set_dma_outdata(dev, dev->sg_dst);
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 1c8d79d..42c060c 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -1124,6 +1124,11 @@
struct talitos_private *priv = dev_get_drvdata(dev);
bool is_sec1 = has_ftr_sec1(priv);
+ if (!src) {
+ *ptr = zero_entry;
+ return 1;
+ }
+
to_talitos_ptr_len(ptr, len, is_sec1);
to_talitos_ptr_ext_set(ptr, 0, is_sec1);
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index b263696..a7df9cb 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -708,7 +708,7 @@
devfreq = devfreq_add_device(dev, profile, governor_name, data);
if (IS_ERR(devfreq)) {
devres_free(ptr);
- return ERR_PTR(-ENOMEM);
+ return devfreq;
}
*ptr = devfreq;
diff --git a/drivers/devfreq/devfreq_spdm_debugfs.c b/drivers/devfreq/devfreq_spdm_debugfs.c
index 4e49d5b..d39ff73 100644
--- a/drivers/devfreq/devfreq_spdm_debugfs.c
+++ b/drivers/devfreq/devfreq_spdm_debugfs.c
@@ -34,7 +34,7 @@
int i;
int next_idx;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, data, size)) {
@@ -42,6 +42,8 @@
size = -EINVAL;
}
+ buf[size] = '\0';
+
if (sscanf(buf, "%u\n", &i) != 1) {
size = -EINVAL;
goto err;
@@ -105,7 +107,7 @@
int ext_status = 0;
int i;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, data, size)) {
@@ -113,6 +115,8 @@
goto out;
}
+ buf[size] = '\0';
+
if (sscanf(buf, "%u %u\n", &spdm_data->config_data.pl_freqs[0],
&spdm_data->config_data.pl_freqs[1]) != 2) {
size = -EINVAL;
@@ -164,7 +168,7 @@
struct spdm_args desc = { { 0 } };
int ext_status = 0;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, data, size)) {
@@ -172,6 +176,8 @@
goto out;
}
+ buf[size] = '\0';
+
if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[0],
&spdm_data->config_data.reject_rate[1]) != 2) {
size = -EINVAL;
@@ -224,13 +230,16 @@
struct spdm_args desc = { { 0 } };
int ext_status = 0;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, data, size)) {
size = -EINVAL;
goto out;
}
+
+ buf[size] = '\0';
+
if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[2],
&spdm_data->config_data.reject_rate[3]) != 2) {
size = -EINVAL;
@@ -282,13 +291,16 @@
struct spdm_args desc = { { 0 } };
int ext_status = 0;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, data, size)) {
size = -EINVAL;
goto out;
}
+
+ buf[size] = '\0';
+
if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[4],
&spdm_data->config_data.reject_rate[5]) != 2) {
size = -EINVAL;
@@ -340,13 +352,16 @@
struct spdm_args desc = { { 0 } };
int ext_status = 0;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, data, size)) {
size = -EINVAL;
goto out;
}
+
+ buf[size] = '\0';
+
if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[0],
&spdm_data->config_data.response_time_us[1]) != 2) {
size = -EINVAL;
@@ -398,13 +413,16 @@
struct spdm_args desc = { { 0 } };
int ext_status = 0;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, data, size)) {
size = -EINVAL;
goto out;
}
+
+ buf[size] = '\0';
+
if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[2],
&spdm_data->config_data.response_time_us[3]) != 2) {
size = -EINVAL;
@@ -456,13 +474,16 @@
struct spdm_args desc = { { 0 } };
int ext_status = 0;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, data, size)) {
size = -EINVAL;
goto out;
}
+
+ buf[size] = '\0';
+
if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[4],
&spdm_data->config_data.response_time_us[5]) != 2) {
size = -EINVAL;
@@ -515,13 +536,16 @@
struct spdm_args desc = { { 0 } };
int ext_status = 0;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, data, size)) {
size = -EINVAL;
goto out;
}
+
+ buf[size] = '\0';
+
if (sscanf(buf, "%u %u\n",
&spdm_data->config_data.cci_response_time_us[0],
&spdm_data->config_data.cci_response_time_us[1]) != 2) {
@@ -575,13 +599,16 @@
struct spdm_args desc = { { 0 } };
int ext_status = 0;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, data, size)) {
size = -EINVAL;
goto out;
}
+
+ buf[size] = '\0';
+
if (sscanf(buf, "%u %u\n",
&spdm_data->config_data.cci_response_time_us[2],
&spdm_data->config_data.cci_response_time_us[3]) != 2) {
@@ -635,13 +662,16 @@
struct spdm_args desc = { { 0 } };
int ext_status = 0;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, data, size)) {
size = -EINVAL;
goto out;
}
+
+ buf[size] = '\0';
+
if (sscanf(buf, "%u %u\n",
&spdm_data->config_data.cci_response_time_us[4],
&spdm_data->config_data.cci_response_time_us[5]) != 2){
@@ -694,13 +724,16 @@
struct spdm_args desc = { { 0 } };
int ext_status = 0;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, data, size)) {
size = -EINVAL;
goto out;
}
+
+ buf[size] = '\0';
+
if (sscanf(buf, "%u\n", &spdm_data->config_data.max_cci_freq) != 1) {
size = -EINVAL;
goto out;
@@ -748,13 +781,16 @@
struct spdm_args desc = { { 0 } };
int ext_status = 0;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, data, size)) {
size = -EINVAL;
goto out;
}
+
+ buf[size] = '\0';
+
if (sscanf(buf, "%u %u %u %u\n", &spdm_data->config_data.upstep,
&spdm_data->config_data.downstep,
&spdm_data->config_data.max_vote,
diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c
index 3026bc2..cb04014 100644
--- a/drivers/devfreq/governor_bw_hwmon.c
+++ b/drivers/devfreq/governor_bw_hwmon.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, 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
@@ -171,7 +171,7 @@
#define MAX_MS 500U
/* Returns MBps of read/writes for the sampling window. */
-static unsigned int bytes_to_mbps(long long bytes, unsigned int us)
+static unsigned long bytes_to_mbps(unsigned long long bytes, unsigned int us)
{
bytes *= USEC_PER_SEC;
do_div(bytes, us);
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index a4c8f80..e2cec5b 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -709,7 +709,7 @@
unsigned long flags)
{
struct at_dma_chan *atchan = to_at_dma_chan(chan);
- struct data_chunk *first = xt->sgl;
+ struct data_chunk *first;
struct at_desc *desc = NULL;
size_t xfer_count;
unsigned int dwidth;
@@ -721,6 +721,8 @@
if (unlikely(!xt || xt->numf != 1 || !xt->frame_size))
return NULL;
+ first = xt->sgl;
+
dev_info(chan2dev(chan),
"%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n",
__func__, &xt->src_start, &xt->dst_start, xt->numf,
diff --git a/drivers/dma/dma-jz4740.c b/drivers/dma/dma-jz4740.c
index d50273f..afd5e10 100644
--- a/drivers/dma/dma-jz4740.c
+++ b/drivers/dma/dma-jz4740.c
@@ -555,7 +555,7 @@
ret = dma_async_device_register(dd);
if (ret)
- return ret;
+ goto err_clk;
irq = platform_get_irq(pdev, 0);
ret = request_irq(irq, jz4740_dma_irq, 0, dev_name(&pdev->dev), dmadev);
@@ -568,6 +568,8 @@
err_unregister:
dma_async_device_unregister(dd);
+err_clk:
+ clk_disable_unprepare(dmadev->clk);
return ret;
}
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index e0bd578..ebe72a4 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -339,7 +339,7 @@
{
struct dmatest_done *done = arg;
struct dmatest_thread *thread =
- container_of(arg, struct dmatest_thread, done_wait);
+ container_of(done, struct dmatest_thread, test_done);
if (!thread->done) {
done->done = true;
wake_up_all(done->wait);
diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
index 0dea6d55..84eb83e 100644
--- a/drivers/dma/ioat/init.c
+++ b/drivers/dma/ioat/init.c
@@ -388,7 +388,7 @@
if (memcmp(src, dest, IOAT_TEST_SIZE)) {
dev_err(dev, "Self-test copy failed compare, disabling\n");
err = -ENODEV;
- goto free_resources;
+ goto unmap_dma;
}
unmap_dma:
diff --git a/drivers/dma/zx296702_dma.c b/drivers/dma/zx296702_dma.c
index 6059d81..8e55403 100644
--- a/drivers/dma/zx296702_dma.c
+++ b/drivers/dma/zx296702_dma.c
@@ -26,7 +26,7 @@
#define DRIVER_NAME "zx-dma"
#define DMA_ALIGN 4
-#define DMA_MAX_SIZE (0x10000 - PAGE_SIZE)
+#define DMA_MAX_SIZE (0x10000 - 512)
#define LLI_BLOCK_SIZE (4 * PAGE_SIZE)
#define REG_ZX_SRC_ADDR 0x00
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 6e197c1..1c5f232 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -2719,7 +2719,7 @@
struct amd64_family_type *fam_type = NULL;
pvt->ext_model = boot_cpu_data.x86_model >> 4;
- pvt->stepping = boot_cpu_data.x86_mask;
+ pvt->stepping = boot_cpu_data.x86_stepping;
pvt->model = boot_cpu_data.x86_model;
pvt->fam = boot_cpu_data.x86;
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index 7db692e..ac0c6c8 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -948,7 +948,7 @@
pr_emerg(HW_ERR "CPU:%d (%x:%x:%x) MC%d_STATUS[%s|%s|%s|%s|%s",
m->extcpu,
- c->x86, c->x86_model, c->x86_mask,
+ c->x86, c->x86_model, c->x86_stepping,
m->bank,
((m->status & MCI_STATUS_OVER) ? "Over" : "-"),
((m->status & MCI_STATUS_UC) ? "UE" :
diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c
index cda6dab..6b65a10 100644
--- a/drivers/edac/octeon_edac-lmc.c
+++ b/drivers/edac/octeon_edac-lmc.c
@@ -79,6 +79,7 @@
if (!pvt->inject)
int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx));
else {
+ int_reg.u64 = 0;
if (pvt->error_type == 1)
int_reg.s.sec_err = 1;
if (pvt->error_type == 2)
diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c
index b8cde09..41245d8 100644
--- a/drivers/extcon/extcon-qcom-spmi-misc.c
+++ b/drivers/extcon/extcon-qcom-spmi-misc.c
@@ -1,6 +1,6 @@
/**
* extcon-qcom-spmi-misc.c - Qualcomm USB extcon driver to support USB ID
- * detection based on extcon-usb-gpio.c.
+ * and VBUS detection based on extcon-usb-gpio.c.
*
* Copyright (C) 2016 Linaro, Ltd.
* Stephen Boyd <stephen.boyd@linaro.org>
@@ -28,30 +28,56 @@
struct qcom_usb_extcon_info {
struct extcon_dev *edev;
- int irq;
+ int id_irq;
+ int vbus_irq;
struct delayed_work wq_detcable;
unsigned long debounce_jiffies;
};
static const unsigned int qcom_usb_extcon_cable[] = {
+ EXTCON_USB,
EXTCON_USB_HOST,
EXTCON_NONE,
};
static void qcom_usb_extcon_detect_cable(struct work_struct *work)
{
- bool id;
+ bool state = 0;
int ret;
+ union extcon_property_value val;
struct qcom_usb_extcon_info *info = container_of(to_delayed_work(work),
struct qcom_usb_extcon_info,
wq_detcable);
- /* check ID and update cable state */
- ret = irq_get_irqchip_state(info->irq, IRQCHIP_STATE_LINE_LEVEL, &id);
- if (ret)
- return;
+ if (info->id_irq > 0) {
+ /* check ID and update cable state */
+ ret = irq_get_irqchip_state(info->id_irq,
+ IRQCHIP_STATE_LINE_LEVEL, &state);
+ if (ret)
+ return;
- extcon_set_state_sync(info->edev, EXTCON_USB_HOST, !id);
+ if (!state) {
+ val.intval = true;
+ extcon_set_property(info->edev, EXTCON_USB_HOST,
+ EXTCON_PROP_USB_SS, val);
+ }
+ extcon_set_state_sync(info->edev, EXTCON_USB_HOST, !state);
+ }
+
+ if (info->vbus_irq > 0) {
+ /* check VBUS and update cable state */
+ ret = irq_get_irqchip_state(info->vbus_irq,
+ IRQCHIP_STATE_LINE_LEVEL, &state);
+ if (ret)
+ return;
+
+ if (state) {
+ val.intval = true;
+ extcon_set_property(info->edev, EXTCON_USB,
+ EXTCON_PROP_USB_SS, val);
+ }
+ extcon_set_cable_state_(info->edev, EXTCON_USB, state);
+ }
}
static irqreturn_t qcom_usb_irq_handler(int irq, void *dev_id)
@@ -86,21 +112,48 @@
return ret;
}
+ ret = extcon_set_property_capability(info->edev,
+ EXTCON_USB, EXTCON_PROP_USB_SS);
+ ret |= extcon_set_property_capability(info->edev,
+ EXTCON_USB_HOST, EXTCON_PROP_USB_SS);
+ if (ret) {
+ dev_err(dev, "failed to register extcon props rc=%d\n",
+ ret);
+ return ret;
+ }
+
info->debounce_jiffies = msecs_to_jiffies(USB_ID_DEBOUNCE_MS);
INIT_DELAYED_WORK(&info->wq_detcable, qcom_usb_extcon_detect_cable);
- info->irq = platform_get_irq_byname(pdev, "usb_id");
- if (info->irq < 0)
- return info->irq;
-
- ret = devm_request_threaded_irq(dev, info->irq, NULL,
+ info->id_irq = platform_get_irq_byname(pdev, "usb_id");
+ if (info->id_irq > 0) {
+ ret = devm_request_threaded_irq(dev, info->id_irq, NULL,
qcom_usb_irq_handler,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
pdev->name, info);
- if (ret < 0) {
- dev_err(dev, "failed to request handler for ID IRQ\n");
- return ret;
+ if (ret < 0) {
+ dev_err(dev, "failed to request handler for ID IRQ\n");
+ return ret;
+ }
+ }
+
+ info->vbus_irq = platform_get_irq_byname(pdev, "usb_vbus");
+ if (info->vbus_irq > 0) {
+ ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL,
+ qcom_usb_irq_handler,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ pdev->name, info);
+ if (ret < 0) {
+ dev_err(dev, "failed to request handler for VBUS IRQ\n");
+ return ret;
+ }
+ }
+
+ if (info->id_irq < 0 && info->vbus_irq < 0) {
+ dev_err(dev, "ID and VBUS IRQ not found\n");
+ return -EINVAL;
}
platform_set_drvdata(pdev, info);
@@ -127,8 +180,12 @@
struct qcom_usb_extcon_info *info = dev_get_drvdata(dev);
int ret = 0;
- if (device_may_wakeup(dev))
- ret = enable_irq_wake(info->irq);
+ if (device_may_wakeup(dev)) {
+ if (info->id_irq > 0)
+ ret = enable_irq_wake(info->id_irq);
+ if (info->vbus_irq > 0)
+ ret = enable_irq_wake(info->vbus_irq);
+ }
return ret;
}
@@ -138,8 +195,12 @@
struct qcom_usb_extcon_info *info = dev_get_drvdata(dev);
int ret = 0;
- if (device_may_wakeup(dev))
- ret = disable_irq_wake(info->irq);
+ if (device_may_wakeup(dev)) {
+ if (info->id_irq > 0)
+ ret = disable_irq_wake(info->id_irq);
+ if (info->vbus_irq > 0)
+ ret = disable_irq_wake(info->vbus_irq);
+ }
return ret;
}
@@ -150,6 +211,7 @@
static const struct of_device_id qcom_usb_extcon_dt_match[] = {
{ .compatible = "qcom,pm8941-misc", },
+ { .compatible = "qcom,pmd-vbus-det", },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_usb_extcon_dt_match);
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index f9a1e98..219556c 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -10,7 +10,7 @@
-fPIC -fno-strict-aliasing -mno-red-zone \
-mno-mmx -mno-sse
-cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS))
+cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS)) -fpie
cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) -g0 \
-fno-builtin -fpic -mno-single-pic-base
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 993aa56..7ec09ea 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -18,8 +18,6 @@
#include "efistub.h"
-bool __nokaslr;
-
static int efi_get_secureboot(efi_system_table_t *sys_table_arg)
{
static efi_char16_t const sb_var_name[] = {
@@ -268,18 +266,6 @@
goto fail;
}
- /* check whether 'nokaslr' was passed on the command line */
- if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
- static const u8 default_cmdline[] = CONFIG_CMDLINE;
- const u8 *str, *cmdline = cmdline_ptr;
-
- if (IS_ENABLED(CONFIG_CMDLINE_FORCE))
- cmdline = default_cmdline;
- str = strstr(cmdline, "nokaslr");
- if (str == cmdline || (str > cmdline && *(str - 1) == ' '))
- __nokaslr = true;
- }
-
si = setup_graphics(sys_table);
status = handle_kernel_image(sys_table, image_addr, &image_size,
@@ -291,9 +277,13 @@
goto fail_free_cmdline;
}
- status = efi_parse_options(cmdline_ptr);
- if (status != EFI_SUCCESS)
- pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n");
+ if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) ||
+ IS_ENABLED(CONFIG_CMDLINE_FORCE) ||
+ cmdline_size == 0)
+ efi_parse_options(CONFIG_CMDLINE);
+
+ if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0)
+ efi_parse_options(cmdline_ptr);
secure_boot = efi_get_secureboot(sys_table);
if (secure_boot > 0)
diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index eae693e..f7a6970 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -9,15 +9,21 @@
* published by the Free Software Foundation.
*
*/
+
+/*
+ * To prevent the compiler from emitting GOT-indirected (and thus absolute)
+ * references to the section markers, override their visibility as 'hidden'
+ */
+#pragma GCC visibility push(hidden)
+#include <asm/sections.h>
+#pragma GCC visibility pop
+
#include <linux/efi.h>
#include <asm/efi.h>
-#include <asm/sections.h>
#include <asm/sysreg.h>
#include "efistub.h"
-extern bool __nokaslr;
-
efi_status_t check_platform_features(efi_system_table_t *sys_table_arg)
{
u64 tg;
@@ -52,7 +58,7 @@
u64 phys_seed = 0;
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
- if (!__nokaslr) {
+ if (!nokaslr()) {
status = efi_get_random_bytes(sys_table_arg,
sizeof(phys_seed),
(u8 *)&phys_seed);
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index aded106..2db141c 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -41,6 +41,13 @@
#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE
#endif
+static int __section(.data) __nokaslr;
+
+int __pure nokaslr(void)
+{
+ return __nokaslr;
+}
+
#define EFI_MMAP_NR_SLACK_SLOTS 8
struct file_info {
@@ -351,10 +358,14 @@
* environments, first in the early boot environment of the EFI boot
* stub, and subsequently during the kernel boot.
*/
-efi_status_t efi_parse_options(char *cmdline)
+efi_status_t efi_parse_options(char const *cmdline)
{
char *str;
+ str = strstr(cmdline, "nokaslr");
+ if (str == cmdline || (str && str > cmdline && *(str - 1) == ' '))
+ __nokaslr = 1;
+
/*
* If no EFI parameters were specified on the cmdline we've got
* nothing to do.
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index fac6799..d0e5aca 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -15,6 +15,8 @@
*/
#undef __init
+extern int __pure nokaslr(void);
+
void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image,
diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c
index 164de64..9d46af0 100644
--- a/drivers/gpio/gpio-intel-mid.c
+++ b/drivers/gpio/gpio-intel-mid.c
@@ -321,7 +321,7 @@
}
}
-static int intel_gpio_runtime_idle(struct device *dev)
+static int __maybe_unused intel_gpio_runtime_idle(struct device *dev)
{
int err = pm_schedule_suspend(dev, 500);
return err ?: -EBUSY;
diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c
index 40a8881..f1c6ec1 100644
--- a/drivers/gpio/gpio-xgene.c
+++ b/drivers/gpio/gpio-xgene.c
@@ -42,9 +42,7 @@
struct gpio_chip chip;
void __iomem *base;
spinlock_t lock;
-#ifdef CONFIG_PM
u32 set_dr_val[XGENE_MAX_GPIO_BANKS];
-#endif
};
static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset)
@@ -138,8 +136,7 @@
return 0;
}
-#ifdef CONFIG_PM
-static int xgene_gpio_suspend(struct device *dev)
+static __maybe_unused int xgene_gpio_suspend(struct device *dev)
{
struct xgene_gpio *gpio = dev_get_drvdata(dev);
unsigned long bank_offset;
@@ -152,7 +149,7 @@
return 0;
}
-static int xgene_gpio_resume(struct device *dev)
+static __maybe_unused int xgene_gpio_resume(struct device *dev)
{
struct xgene_gpio *gpio = dev_get_drvdata(dev);
unsigned long bank_offset;
@@ -166,10 +163,6 @@
}
static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
-#define XGENE_GPIO_PM_OPS (&xgene_gpio_pm)
-#else
-#define XGENE_GPIO_PM_OPS NULL
-#endif
static int xgene_gpio_probe(struct platform_device *pdev)
{
@@ -241,7 +234,7 @@
.name = "xgene-gpio",
.of_match_table = xgene_gpio_of_match,
.acpi_match_table = ACPI_PTR(xgene_gpio_acpi_match),
- .pm = XGENE_GPIO_PM_OPS,
+ .pm = &xgene_gpio_pm,
},
.probe = xgene_gpio_probe,
};
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index a51f8cb..3137adf 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -1178,17 +1178,13 @@
ret = devm_request_irq(dev, irq, armada_drm_irq, 0, "armada_drm_crtc",
dcrtc);
- if (ret < 0) {
- kfree(dcrtc);
- return ret;
- }
+ if (ret < 0)
+ goto err_crtc;
if (dcrtc->variant->init) {
ret = dcrtc->variant->init(dcrtc, dev);
- if (ret) {
- kfree(dcrtc);
- return ret;
- }
+ if (ret)
+ goto err_crtc;
}
/* Ensure AXI pipeline is enabled */
@@ -1199,13 +1195,15 @@
dcrtc->crtc.port = port;
primary = kzalloc(sizeof(*primary), GFP_KERNEL);
- if (!primary)
- return -ENOMEM;
+ if (!primary) {
+ ret = -ENOMEM;
+ goto err_crtc;
+ }
ret = armada_drm_plane_init(primary);
if (ret) {
kfree(primary);
- return ret;
+ goto err_crtc;
}
ret = drm_universal_plane_init(drm, &primary->base, 0,
@@ -1215,7 +1213,7 @@
DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret) {
kfree(primary);
- return ret;
+ goto err_crtc;
}
ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, &primary->base, NULL,
@@ -1234,6 +1232,9 @@
err_crtc_init:
primary->base.funcs->destroy(&primary->base);
+err_crtc:
+ kfree(dcrtc);
+
return ret;
}
diff --git a/drivers/gpu/drm/bridge/lt9611.c b/drivers/gpu/drm/bridge/lt9611.c
index 4327e93..887dd6f 100644
--- a/drivers/gpu/drm/bridge/lt9611.c
+++ b/drivers/gpu/drm/bridge/lt9611.c
@@ -708,15 +708,24 @@
u32 h_act = 0;
struct lt9611_reg_cfg reg_cfg[] = {
{0xff, 0x83, 0},
+ {0x0b, 0x01, 0},
+ {0x0c, 0x10, 0},
+ {0x48, 0x00, 0},
+ {0x49, 0x81, 0},
- {0x2d, 0x38, 0}, /* up_lmt */
- {0x2e, 0x00, 0},
- {0x31, 0x10, 0}, /* low lmt */
- {0x32, 0x00, 0},
+ /* stage 1 */
+ {0x21, 0x4a, 0},
+ {0x24, 0x71, 0},
+ {0x25, 0x30, 0},
+ {0x2a, 0x01, 0},
- {0xff, 0x80, 0},
- {0x11, 0x5a, 0}, /* pcr reset */
- {0x11, 0xfa, 0},
+ /* stage 2 */
+ {0x4a, 0x40, 0},
+ {0x1d, 0x10, 0},
+
+ /* MK limit */
+ {0x2d, 0x38, 0},
+ {0x31, 0x08, 0},
};
if (!pdata || !cfg) {
@@ -724,54 +733,31 @@
return -EINVAL;
}
+ lt9611_write_array(pdata, reg_cfg, sizeof(reg_cfg));
+
h_act = cfg->h_active;
if (h_act == 1920) {
- lt9611_write(pdata, 0xff, 0x83);
- lt9611_write(pdata, 0x48, 0x00);
- lt9611_write(pdata, 0x49, 0x81);
-
- lt9611_write(pdata, 0x4a, 0x10);
- lt9611_write(pdata, 0x1d, 0x10);
- lt9611_write(pdata, 0x21, 0x41);
- lt9611_write(pdata, 0x22, 0x40);
- lt9611_write(pdata, 0x24, 0x11);
- lt9611_write(pdata, 0x25, 0x30);
lt9611_write(pdata, 0x26, 0x37);
- lt9611_write(pdata, 0x2a, 0x02);
} else if (h_act == 3840) {
- lt9611_write(pdata, 0xff, 0x83);
lt9611_write(pdata, 0x0b, 0x03);
lt9611_write(pdata, 0x0c, 0xd0);
lt9611_write(pdata, 0x48, 0x03);
- lt9611_write(pdata, 0x49, 0xd0);
-
- lt9611_write(pdata, 0x4a, 0x01);
- lt9611_write(pdata, 0x1d, 0x10);
- lt9611_write(pdata, 0x21, 0x41);
- lt9611_write(pdata, 0x22, 0x40);
- lt9611_write(pdata, 0x24, 0x70);
- lt9611_write(pdata, 0x25, 0x50);
- lt9611_write(pdata, 0x26, 0x37);
- lt9611_write(pdata, 0x2a, 0x03);
- } else if (h_act == 640) {
- lt9611_write(pdata, 0xff, 0x83);
- lt9611_write(pdata, 0x0b, 0x01);
- lt9611_write(pdata, 0x0c, 0x20);
- lt9611_write(pdata, 0x48, 0x00);
- lt9611_write(pdata, 0x49, 0x81);
-
+ lt9611_write(pdata, 0x49, 0xe0);
+ lt9611_write(pdata, 0x24, 0x72);
+ lt9611_write(pdata, 0x25, 0x00);
+ lt9611_write(pdata, 0x2a, 0x01);
lt9611_write(pdata, 0x4a, 0x10);
lt9611_write(pdata, 0x1d, 0x10);
- lt9611_write(pdata, 0x21, 0x41);
- lt9611_write(pdata, 0x22, 0x40);
- lt9611_write(pdata, 0x24, 0x11);
- lt9611_write(pdata, 0x25, 0x30);
- lt9611_write(pdata, 0x26, 0x13);
- lt9611_write(pdata, 0x2a, 0x03);
+ lt9611_write(pdata, 0x26, 0x37);
+ } else if (h_act == 640) {
+ lt9611_write(pdata, 0x26, 0x14);
}
- lt9611_write_array(pdata, reg_cfg, sizeof(reg_cfg));
+ /* pcr rst */
+ lt9611_write(pdata, 0xff, 0x80);
+ lt9611_write(pdata, 0x11, 0x5a);
+ lt9611_write(pdata, 0x11, 0xfa);
return 0;
}
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c
index 61146f5..0a6bf81 100644
--- a/drivers/gpu/drm/drm_modeset_lock.c
+++ b/drivers/gpu/drm/drm_modeset_lock.c
@@ -81,7 +81,7 @@
struct drm_modeset_acquire_ctx *ctx;
int ret;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL | __GFP_NOFAIL);
if (WARN_ON(!ctx))
return;
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 38eaa63..4198e50 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -1939,8 +1939,7 @@
return 0;
}
-#ifdef CONFIG_PM
-static int exynos_hdmi_suspend(struct device *dev)
+static int __maybe_unused exynos_hdmi_suspend(struct device *dev)
{
struct hdmi_context *hdata = dev_get_drvdata(dev);
@@ -1949,7 +1948,7 @@
return 0;
}
-static int exynos_hdmi_resume(struct device *dev)
+static int __maybe_unused exynos_hdmi_resume(struct device *dev)
{
struct hdmi_context *hdata = dev_get_drvdata(dev);
int ret;
@@ -1960,7 +1959,6 @@
return 0;
}
-#endif
static const struct dev_pm_ops exynos_hdmi_pm_ops = {
SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 7fdc42e..74163a9 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -5063,6 +5063,12 @@
*/
final->t8 = 1;
final->t9 = 1;
+
+ /*
+ * HW has only a 100msec granularity for t11_t12 so round it up
+ * accordingly.
+ */
+ final->t11_t12 = roundup(final->t11_t12, 100 * 10);
}
static void
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index a19ec06..6a9860d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1581,7 +1581,7 @@
int intel_backlight_device_register(struct intel_connector *connector);
void intel_backlight_device_unregister(struct intel_connector *connector);
#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */
-static int intel_backlight_device_register(struct intel_connector *connector)
+static inline int intel_backlight_device_register(struct intel_connector *connector)
{
return 0;
}
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index be4b4d5..1cb1b01 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -544,25 +544,6 @@
return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS);
}
-static u32 intel_panel_get_backlight(struct intel_connector *connector)
-{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- struct intel_panel *panel = &connector->panel;
- u32 val = 0;
-
- mutex_lock(&dev_priv->backlight_lock);
-
- if (panel->backlight.enabled) {
- val = panel->backlight.get(connector);
- val = intel_panel_compute_brightness(connector, val);
- }
-
- mutex_unlock(&dev_priv->backlight_lock);
-
- DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
- return val;
-}
-
static void lpt_set_backlight(struct intel_connector *connector, u32 level)
{
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
@@ -646,30 +627,6 @@
panel->backlight.set(connector, level);
}
-/* set backlight brightness to level in range [0..max], scaling wrt hw min */
-static void intel_panel_set_backlight(struct intel_connector *connector,
- u32 user_level, u32 user_max)
-{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- struct intel_panel *panel = &connector->panel;
- u32 hw_level;
-
- if (!panel->backlight.present)
- return;
-
- mutex_lock(&dev_priv->backlight_lock);
-
- WARN_ON(panel->backlight.max == 0);
-
- hw_level = scale_user_to_hw(connector, user_level, user_max);
- panel->backlight.level = hw_level;
-
- if (panel->backlight.enabled)
- intel_panel_actually_set_backlight(connector, hw_level);
-
- mutex_unlock(&dev_priv->backlight_lock);
-}
-
/* set backlight brightness to level in range [0..max], assuming hw min is
* respected.
*/
@@ -1122,6 +1079,49 @@
}
#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
+static u32 intel_panel_get_backlight(struct intel_connector *connector)
+{
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct intel_panel *panel = &connector->panel;
+ u32 val = 0;
+
+ mutex_lock(&dev_priv->backlight_lock);
+
+ if (panel->backlight.enabled) {
+ val = panel->backlight.get(connector);
+ val = intel_panel_compute_brightness(connector, val);
+ }
+
+ mutex_unlock(&dev_priv->backlight_lock);
+
+ DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
+ return val;
+}
+
+/* set backlight brightness to level in range [0..max], scaling wrt hw min */
+static void intel_panel_set_backlight(struct intel_connector *connector,
+ u32 user_level, u32 user_max)
+{
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct intel_panel *panel = &connector->panel;
+ u32 hw_level;
+
+ if (!panel->backlight.present)
+ return;
+
+ mutex_lock(&dev_priv->backlight_lock);
+
+ WARN_ON(panel->backlight.max == 0);
+
+ hw_level = scale_user_to_hw(connector, user_level, user_max);
+ panel->backlight.level = hw_level;
+
+ if (panel->backlight.enabled)
+ intel_panel_actually_set_backlight(connector, hw_level);
+
+ mutex_unlock(&dev_priv->backlight_lock);
+}
+
static int intel_backlight_device_update_status(struct backlight_device *bd)
{
struct intel_connector *connector = bl_get_data(bd);
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index b1d03d6..bf903b9 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -48,11 +48,6 @@
void *hdcp1;
void *hdcp2;
- int enc_lvl;
-
- bool auth_state;
- bool hdcp1_present;
- bool hdcp2_present;
bool feature_enabled;
};
@@ -65,6 +60,8 @@
bool power_on;
bool audio_supported;
+ atomic_t aborted;
+
struct platform_device *pdev;
struct dentry *root;
struct completion notification_comp;
@@ -93,7 +90,6 @@
struct work_struct attention_work;
struct mutex hdcp_mutex;
struct mutex session_lock;
- int hdcp_status;
unsigned long audio_status;
};
@@ -109,9 +105,8 @@
static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp)
{
- return dp->hdcp.feature_enabled &&
- (dp->hdcp.hdcp1_present || dp->hdcp.hdcp2_present) &&
- dp->hdcp.ops;
+ return dp->hdcp.feature_enabled && dp->link->hdcp_status.hdcp_version
+ && dp->hdcp.ops;
}
static irqreturn_t dp_display_irq(int irq, void *dev_id)
@@ -156,32 +151,25 @@
ops = dp->hdcp.ops;
- switch (dp->hdcp_status) {
- case HDCP_STATE_AUTHENTICATING:
- pr_debug("start authenticaton\n");
+ pr_debug("%s: %s\n",
+ sde_hdcp_version(dp->link->hdcp_status.hdcp_version),
+ sde_hdcp_state_name(dp->link->hdcp_status.hdcp_state));
+ switch (dp->link->hdcp_status.hdcp_state) {
+ case HDCP_STATE_AUTHENTICATING:
if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
rc = dp->hdcp.ops->authenticate(dp->hdcp.data);
-
- break;
- case HDCP_STATE_AUTHENTICATED:
- pr_debug("hdcp authenticated\n");
- dp->hdcp.auth_state = true;
break;
case HDCP_STATE_AUTH_FAIL:
- dp->hdcp.auth_state = false;
-
if (dp->power_on) {
- pr_debug("Reauthenticating\n");
if (ops && ops->reauthenticate) {
rc = ops->reauthenticate(dp->hdcp.data);
if (rc)
- pr_err("reauth failed rc=%d\n", rc);
+ pr_err("failed rc=%d\n", rc);
}
} else {
pr_debug("not reauthenticating, cable disconnected\n");
}
-
break;
default:
break;
@@ -189,7 +177,7 @@
}
static void dp_display_notify_hdcp_status_cb(void *ptr,
- enum sde_hdcp_states status)
+ enum sde_hdcp_state state)
{
struct dp_display_private *dp = ptr;
@@ -198,7 +186,7 @@
return;
}
- dp->hdcp_status = status;
+ dp->link->hdcp_status.hdcp_state = state;
if (dp->dp_display.is_connected)
queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ/4);
@@ -214,12 +202,16 @@
{
void *fd = NULL;
struct sde_hdcp_ops *ops = NULL;
+ bool hdcp2_present = false, hdcp1_present = false;
if (!dp) {
pr_err("invalid input\n");
return;
}
+ dp->link->hdcp_status.hdcp_state = HDCP_STATE_INACTIVE;
+ dp->link->hdcp_status.hdcp_version = HDCP_VERSION_NONE;
+
if (!dp->hdcp.feature_enabled) {
pr_debug("feature not enabled\n");
return;
@@ -230,26 +222,29 @@
ops = sde_dp_hdcp2p2_start(fd);
if (ops && ops->feature_supported)
- dp->hdcp.hdcp2_present = ops->feature_supported(fd);
+ hdcp2_present = ops->feature_supported(fd);
else
- dp->hdcp.hdcp2_present = false;
+ hdcp2_present = false;
pr_debug("hdcp2p2: %s\n",
- dp->hdcp.hdcp2_present ? "supported" : "not supported");
+ hdcp2_present ? "supported" : "not supported");
- if (!dp->hdcp.hdcp2_present) {
- dp->hdcp.hdcp1_present = hdcp1_check_if_supported_load_app();
+ if (!hdcp2_present) {
+ hdcp1_present = hdcp1_check_if_supported_load_app();
- if (dp->hdcp.hdcp1_present) {
+ if (hdcp1_present) {
fd = dp->hdcp.hdcp1;
ops = sde_hdcp_1x_start(fd);
+ dp->link->hdcp_status.hdcp_version = HDCP_VERSION_1X;
}
+ } else {
+ dp->link->hdcp_status.hdcp_version = HDCP_VERSION_2P2;
}
pr_debug("hdcp1x: %s\n",
- dp->hdcp.hdcp1_present ? "supported" : "not supported");
+ hdcp1_present ? "supported" : "not supported");
- if (dp->hdcp.hdcp2_present || dp->hdcp.hdcp1_present) {
+ if (hdcp2_present || hdcp1_present) {
dp->hdcp.data = fd;
dp->hdcp.ops = ops;
} else {
@@ -290,7 +285,6 @@
hdcp_init_data.drm_aux = dp->aux->drm_aux;
hdcp_init_data.cb_data = (void *)dp;
hdcp_init_data.workq = dp->wq;
- hdcp_init_data.mutex = &dp->hdcp_mutex;
hdcp_init_data.sec_access = true;
hdcp_init_data.notify_status = dp_display_notify_hdcp_status_cb;
hdcp_init_data.dp_ahb = &parser->get_io(parser, "dp_ahb")->io;
@@ -302,6 +296,7 @@
hdcp_init_data.hdcp_io = &parser->get_io(parser,
"hdcp_physical")->io;
hdcp_init_data.revision = &dp->panel->link_info.revision;
+ hdcp_init_data.msm_hdcp_dev = dp->parser->msm_hdcp_dev;
dp->hdcp.hdcp1 = sde_hdcp_1x_init(&hdcp_init_data);
if (IS_ERR_OR_NULL(dp->hdcp.hdcp1)) {
@@ -627,7 +622,7 @@
static void dp_display_clean(struct dp_display_private *dp)
{
if (dp_display_is_hdcp_enabled(dp)) {
- dp->hdcp_status = HDCP_STATE_INACTIVE;
+ dp->link->hdcp_status.hdcp_state = HDCP_STATE_INACTIVE;
cancel_delayed_work_sync(&dp->hdcp_cb_work);
if (dp->hdcp.ops->off)
@@ -646,6 +641,11 @@
int rc;
rc = dp_display_process_hpd_low(dp);
+ if (rc) {
+ /* cancel any pending request */
+ dp->ctrl->abort(dp->ctrl);
+ dp->aux->abort(dp->aux);
+ }
mutex_lock(&dp->session_lock);
if (rc && dp->power_on)
@@ -688,6 +688,7 @@
dp->link->psm_config(dp->link, &dp->panel->link_info, true);
/* cancel any pending request */
+ atomic_set(&dp->aborted, 1);
dp->ctrl->abort(dp->ctrl);
dp->aux->abort(dp->aux);
@@ -696,6 +697,7 @@
flush_workqueue(dp->wq);
dp_display_handle_disconnect(dp);
+ atomic_set(&dp->aborted, 0);
end:
return rc;
}
@@ -779,6 +781,12 @@
return -ENODEV;
}
+ /* check if framework is ready */
+ if (!dp_display_framework_ready(dp)) {
+ pr_err("framework not ready\n");
+ return -ENODEV;
+ }
+
if (dp->usbpd->hpd_irq && dp->usbpd->hpd_high &&
dp->power_on) {
dp->link->process_request(dp->link);
@@ -787,6 +795,7 @@
queue_delayed_work(dp->wq, &dp->connect_work, 0);
} else {
/* cancel any pending request */
+ atomic_set(&dp->aborted, 1);
dp->ctrl->abort(dp->ctrl);
dp->aux->abort(dp->aux);
@@ -795,6 +804,7 @@
flush_workqueue(dp->wq);
dp_display_handle_disconnect(dp);
+ atomic_set(&dp->aborted, 0);
}
return 0;
@@ -806,11 +816,16 @@
struct dp_display_private *dp = container_of(dw,
struct dp_display_private, connect_work);
- if (dp->dp_display.is_connected) {
+ if (dp->dp_display.is_connected && dp_display_framework_ready(dp)) {
pr_debug("HPD already on\n");
return;
}
+ if (atomic_read(&dp->aborted)) {
+ pr_err("aborted\n");
+ return;
+ }
+
dp_display_process_hpd_high(dp);
}
@@ -1063,8 +1078,18 @@
goto end;
}
+ if (atomic_read(&dp->aborted)) {
+ pr_err("aborted\n");
+ goto end;
+ }
+
dp->aux->init(dp->aux, dp->parser->aux_cfg);
+ if (dp->debug->psm_enabled) {
+ dp->link->psm_config(dp->link, &dp->panel->link_info, false);
+ dp->debug->psm_enabled = false;
+ }
+
rc = dp->ctrl->on(dp->ctrl);
if (dp->debug->tpg_state)
@@ -1095,6 +1120,11 @@
goto end;
}
+ if (atomic_read(&dp->aborted)) {
+ pr_err("aborted\n");
+ goto end;
+ }
+
dp->panel->spd_config(dp->panel);
if (dp->audio_supported) {
@@ -1108,7 +1138,7 @@
if (dp_display_is_hdcp_enabled(dp)) {
cancel_delayed_work_sync(&dp->hdcp_cb_work);
- dp->hdcp_status = HDCP_STATE_AUTHENTICATING;
+ dp->link->hdcp_status.hdcp_state = HDCP_STATE_AUTHENTICATING;
queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ / 2);
}
@@ -1142,7 +1172,7 @@
}
if (dp_display_is_hdcp_enabled(dp)) {
- dp->hdcp_status = HDCP_STATE_INACTIVE;
+ dp->link->hdcp_status.hdcp_state = HDCP_STATE_INACTIVE;
cancel_delayed_work_sync(&dp->hdcp_cb_work);
if (dp->hdcp.ops->off)
@@ -1202,10 +1232,9 @@
* any notification from driver. Initialize post_open callback to notify
* DP connection once framework restarts.
*/
- if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done) {
+ if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done)
dp_display->post_open = dp_display_post_open;
- dp->dp_display.is_connected = false;
- }
+
dp->power_on = false;
dp->aux->state = DP_STATE_CTRL_POWERED_OFF;
end:
@@ -1370,6 +1399,7 @@
dp->pdev = pdev;
dp->name = "drm_dp";
dp->audio_status = -ENODEV;
+ atomic_set(&dp->aborted, 0);
rc = dp_display_create_workqueue(dp);
if (rc) {
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index b834230..7c817d3 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -184,7 +184,12 @@
bridge = to_dp_bridge(drm_bridge);
dp = bridge->display;
- if (dp && dp->connector)
+ if (!dp) {
+ pr_err("dp is null\n");
+ return;
+ }
+
+ if (dp->connector)
sde_connector_helper_bridge_disable(dp->connector);
rc = dp->pre_disable(dp);
diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c
index 0e1490f..2b7b217 100644
--- a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c
+++ b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -19,6 +19,7 @@
#include <linux/types.h>
#include <linux/kthread.h>
#include <linux/hdcp_qseecom.h>
+#include <linux/msm_hdcp.h>
#include <drm/drm_dp_helper.h>
#include "sde_hdcp.h"
@@ -320,35 +321,16 @@
struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)client_ctx;
struct hdcp_lib_wakeup_data cdata = {
HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE};
- bool enc_notify = true;
- int enc_lvl;
if (!ctrl) {
pr_err("invalid input\n");
return;
}
- switch (min_enc_level) {
- case 0:
- enc_lvl = HDCP_STATE_AUTH_ENC_NONE;
- break;
- case 1:
- enc_lvl = HDCP_STATE_AUTH_ENC_1X;
- break;
- case 2:
- enc_lvl = HDCP_STATE_AUTH_ENC_2P2;
- break;
- default:
- enc_notify = false;
- }
-
pr_debug("enc level changed %d\n", min_enc_level);
cdata.context = ctrl->lib_ctx;
dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
-
- if (enc_notify && ctrl->init_data.notify_status)
- ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl);
}
static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl)
@@ -812,7 +794,6 @@
static struct hdcp_client_ops client_ops = {
.wakeup = dp_hdcp2p2_wakeup,
- .notify_lvl_change = dp_hdcp2p2_min_level_change,
};
static struct dp_hdcp2p2_int_set int_set1[] = {
{BIT(17), "authentication successful", NULL},
@@ -867,6 +848,9 @@
goto error;
}
+ msm_hdcp_register_cb(init_data->msm_hdcp_dev, ctrl,
+ dp_hdcp2p2_min_level_change);
+
kthread_init_worker(&ctrl->worker);
kthread_init_work(&ctrl->auth, dp_hdcp2p2_auth_work);
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index 46d30a7..d14b881 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -72,6 +72,11 @@
u32 test_audio_period_ch_8;
};
+struct dp_link_hdcp_status {
+ int hdcp_state;
+ int hdcp_version;
+};
+
struct dp_link_phy_params {
u32 phy_test_pattern_sel;
u8 v_level;
@@ -110,6 +115,7 @@
struct dp_link_test_audio test_audio;
struct dp_link_phy_params phy_params;
struct dp_link_params link_params;
+ struct dp_link_hdcp_status hdcp_status;
u32 (*get_test_bits_depth)(struct dp_link *dp_link, u32 bpp);
int (*process_request)(struct dp_link *dp_link);
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c
index adcc762..0174ea10 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -15,6 +15,7 @@
#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
#include "dp_parser.h"
@@ -159,6 +160,30 @@
return 0;
}
+static int dp_parser_msm_hdcp_dev(struct dp_parser *parser)
+{
+ struct device_node *node;
+ struct platform_device *pdev;
+
+ node = of_find_compatible_node(NULL, NULL, "qcom,msm-hdcp");
+ if (!node) {
+ // This is a non-fatal error, module initialization can proceed
+ pr_warn("couldn't find msm-hdcp node\n");
+ return 0;
+ }
+
+ pdev = of_find_device_by_node(node);
+ if (!pdev) {
+ // This is a non-fatal error, module initialization can proceed
+ pr_warn("couldn't find msm-hdcp pdev\n");
+ return 0;
+ }
+
+ parser->msm_hdcp_dev = &pdev->dev;
+
+ return 0;
+}
+
static int dp_parser_pinctrl(struct dp_parser *parser)
{
int rc = 0;
@@ -587,6 +612,10 @@
goto err;
rc = dp_parser_pinctrl(parser);
+ if (rc)
+ goto err;
+
+ rc = dp_parser_msm_hdcp_dev(parser);
err:
return rc;
}
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h
index 6e78db2..a768ca3 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -156,6 +156,7 @@
* struct dp_parser - DP parser's data exposed to clients
*
* @pdev: platform data of the client
+ * @msm_hdcp_dev: device pointer for the HDCP driver
* @mp: gpio, regulator and clock related data
* @pinctrl: pin-control related data
* @ctrl_resouce: controller's register address realated data
@@ -167,6 +168,7 @@
*/
struct dp_parser {
struct platform_device *pdev;
+ struct device *msm_hdcp_dev;
struct dss_module_power mp[DP_MAX_PM];
struct dp_pinctrl pinctrl;
struct dp_io io;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index f2c2985..d083e72 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -67,6 +67,8 @@
ctrl->ops.error_intr_ctrl = dsi_ctrl_hw_cmn_error_intr_ctrl;
ctrl->ops.get_error_mask = dsi_ctrl_hw_cmn_get_error_mask;
ctrl->ops.get_hw_version = dsi_ctrl_hw_cmn_get_hw_version;
+ ctrl->ops.wait_for_cmd_mode_mdp_idle =
+ dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle;
switch (version) {
case DSI_CTRL_VERSION_1_4:
@@ -213,6 +215,7 @@
dsi_phy_hw_v3_0_is_lanes_in_ulps;
phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v3_0;
phy->ops.phy_lane_reset = dsi_phy_hw_v3_0_lane_reset;
+ phy->ops.toggle_resync_fifo = dsi_phy_hw_v3_0_toggle_resync_fifo;
}
/**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index f7756dc..0e2db430 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -103,6 +103,7 @@
int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
u32 *timing_val, u32 size);
int dsi_phy_hw_v3_0_lane_reset(struct dsi_phy_hw *phy);
+void dsi_phy_hw_v3_0_toggle_resync_fifo(struct dsi_phy_hw *phy);
/* DSI controller common ops */
u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl);
@@ -186,6 +187,7 @@
void dsi_ctrl_hw_cmn_error_intr_ctrl(struct dsi_ctrl_hw *ctrl, bool en);
u32 dsi_ctrl_hw_cmn_get_error_mask(struct dsi_ctrl_hw *ctrl);
u32 dsi_ctrl_hw_cmn_get_hw_version(struct dsi_ctrl_hw *ctrl);
+int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl);
/* Definitions specific to 1.4 DSI controller hardware */
int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
index fa80317..d89760e 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
@@ -232,6 +232,15 @@
int dsi_deregister_clk_handle(void *client);
/**
+ * dsi_display_link_clk_force_update_ctrl() - force to set link clks
+ * @handle: Handle of desired DSI clock client.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+
+int dsi_display_link_clk_force_update_ctrl(void *handle);
+
+/**
* dsi_display_clk_ctrl() - set frequencies for link clks
* @handle: Handle of desired DSI clock client.
* @clk_type: Clock which is being controlled.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
index bff8627..189a5c3 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
@@ -1071,6 +1071,76 @@
DEFINE_MUTEX(dsi_mngr_clk_mutex);
+static int dsi_display_link_clk_force_update(void *client)
+{
+ int rc = 0;
+ struct dsi_clk_client_info *c = client;
+ struct dsi_clk_mngr *mngr;
+ struct dsi_link_clks *l_clks;
+
+ if (!client) {
+ pr_err("%s: Invalid arg\n", __func__);
+ return -EINVAL;
+ }
+ mngr = c->mngr;
+
+ mutex_lock(&mngr->clk_mutex);
+
+ l_clks = mngr->link_clks;
+
+ /*
+ * When link_clk_state is DSI_CLK_OFF, don't change DSI clock rate
+ * since it is possible to be overwritten, and return -EAGAIN to
+ * dynamic DSI writing interface to defer the reenabling to the next
+ * drm commit.
+ */
+ if (mngr->link_clk_state == DSI_CLK_OFF) {
+ rc = -EAGAIN;
+ goto error;
+ }
+
+ rc = dsi_display_link_clk_disable(l_clks,
+ mngr->dsi_ctrl_count, mngr->master_ndx);
+ if (rc) {
+ pr_err("%s, failed to stop link clk, rc = %d\n",
+ __func__, rc);
+ goto error;
+ }
+
+ rc = dsi_display_link_clk_enable(l_clks,
+ mngr->dsi_ctrl_count, mngr->master_ndx);
+ if (rc) {
+ pr_err("%s, failed to start link clk rc= %d\n",
+ __func__, rc);
+ goto error;
+ }
+
+error:
+ mutex_unlock(&mngr->clk_mutex);
+ return rc;
+
+}
+
+int dsi_display_link_clk_force_update_ctrl(void *handle)
+{
+ int rc = 0;
+
+ if (!handle) {
+ pr_err("%s: Invalid arg\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&dsi_mngr_clk_mutex);
+
+ rc = dsi_display_link_clk_force_update(handle);
+ if (rc && (rc != -EAGAIN))
+ pr_err("%s: failed set clk state, rc = %d\n", __func__, rc);
+
+ mutex_unlock(&dsi_mngr_clk_mutex);
+
+ return rc;
+}
+
int dsi_display_clk_ctrl(void *handle, u32 clk_type, u32 clk_state)
{
int rc = 0;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 0113c83..c9e8a01 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -915,6 +915,27 @@
return rc;
}
+int dsi_ctrl_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl *dsi_ctrl)
+{
+ int rc = 0;
+
+ if (!dsi_ctrl) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ if (dsi_ctrl->host_config.panel_mode != DSI_OP_CMD_MODE)
+ return -EINVAL;
+
+ mutex_lock(&dsi_ctrl->ctrl_lock);
+
+ rc = dsi_ctrl->hw.ops.wait_for_cmd_mode_mdp_idle(&dsi_ctrl->hw);
+
+ mutex_unlock(&dsi_ctrl->ctrl_lock);
+
+ return rc;
+}
+
static void dsi_ctrl_wait_for_video_done(struct dsi_ctrl *dsi_ctrl)
{
u32 v_total = 0, v_blank = 0, sleep_ms = 0, fps = 0, ret;
@@ -1416,8 +1437,7 @@
u32 lanes = 0;
u32 ulps_lanes;
- if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE)
- lanes = dsi_ctrl->host_config.common_config.data_lanes;
+ lanes = dsi_ctrl->host_config.common_config.data_lanes;
rc = dsi_ctrl->hw.ops.wait_for_lane_idle(&dsi_ctrl->hw, lanes);
if (rc) {
@@ -1458,9 +1478,7 @@
return 0;
}
- if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE)
- lanes = dsi_ctrl->host_config.common_config.data_lanes;
-
+ lanes = dsi_ctrl->host_config.common_config.data_lanes;
lanes |= DSI_CLOCK_LANE;
ulps_lanes = dsi_ctrl->hw.ops.ulps_ops.get_lanes_in_ulps(&dsi_ctrl->hw);
@@ -2439,6 +2457,31 @@
}
/**
+ * dsi_ctrl_update_host_init_state() - Update the host initialization state.
+ * @dsi_ctrl: DSI controller handle.
+ * @enable: boolean signifying host state.
+ *
+ * Update the host initialization status only while exiting from ulps during
+ * suspend state.
+ *
+ * Return: error code.
+ */
+int dsi_ctrl_update_host_init_state(struct dsi_ctrl *dsi_ctrl, bool enable)
+{
+ int rc = 0;
+ u32 state = enable ? 0x1 : 0x0;
+
+ rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, state);
+ if (rc) {
+ pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
+ dsi_ctrl->cell_index, rc);
+ return rc;
+ }
+ dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, state);
+ return rc;
+}
+
+/**
* dsi_ctrl_host_init() - Initialize DSI host hardware.
* @dsi_ctrl: DSI controller handle.
* @is_splash_enabled: boolean signifying splash status.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index 9636dbe..4f85cda 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -743,4 +743,16 @@
int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl,
bool *state);
+/**
+ * dsi_ctrl_update_host_init_state() - Set the host initialization state
+ */
+int dsi_ctrl_update_host_init_state(struct dsi_ctrl *dsi_ctrl, bool en);
+
+/**
+ * dsi_ctrl_wait_for_cmd_mode_mdp_idle() - Wait for command mode engine not to
+ * be busy sending data from display engine.
+ * @dsi_ctrl: DSI controller handle.
+ */
+int dsi_ctrl_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl *dsi_ctrl);
+
#endif /* _DSI_CTRL_H_ */
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 567f289..d6fab59 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -798,6 +798,13 @@
* @ctrl: Pointer to the controller host hardware.
*/
u32 (*get_hw_version)(struct dsi_ctrl_hw *ctrl);
+
+ /**
+ * wait_for_cmd_mode_mdp_idle() - wait for command mode engine not to
+ * be busy sending data from display engine
+ * @ctrl: Pointer to the controller host hardware.
+ */
+ int (*wait_for_cmd_mode_mdp_idle)(struct dsi_ctrl_hw *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 594b3f5..f0e7ba6 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
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -1476,3 +1476,18 @@
return reg;
}
+
+int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl)
+{
+ int rc = 0, val = 0;
+ u32 cmd_mode_mdp_busy_mask = BIT(2);
+ u32 const sleep_us = 2 * 1000;
+ u32 const timeout_us = 200 * 1000;
+
+ rc = readl_poll_timeout(ctrl->base + DSI_STATUS, val,
+ !(val & cmd_mode_mdp_busy_mask), sleep_us, timeout_us);
+ if (rc)
+ pr_err("%s: waiting failed, ret=%d\n", __func__, rc);
+
+ return rc;
+}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index fd18905..5b19aee 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -17,6 +17,7 @@
#include <linux/list.h>
#include <linux/of.h>
#include <linux/of_graph.h>
+#include <linux/of_gpio.h>
#include <linux/err.h>
#include "msm_drv.h"
@@ -36,9 +37,12 @@
#define NO_OVERRIDE -1
#define MISR_BUFF_SIZE 256
+#define ESD_MODE_STRING_MAX_LEN 256
#define MAX_NAME_SIZE 64
+#define DSI_CLOCK_BITRATE_RADIX 10
+
static DEFINE_MUTEX(dsi_display_list_lock);
static LIST_HEAD(dsi_display_list);
static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN];
@@ -309,6 +313,89 @@
dsi_panel_release_panel_lock(display->panel);
}
+static irqreturn_t dsi_display_panel_te_irq_handler(int irq, void *data)
+{
+ struct dsi_display *display = (struct dsi_display *)data;
+
+ /*
+ * This irq handler is used for sole purpose of identifying
+ * ESD attacks on panel and we can safely assume IRQ_HANDLED
+ * in case of display not being initalized yet
+ */
+ if (!display)
+ return IRQ_HANDLED;
+
+ complete_all(&display->esd_te_gate);
+ return IRQ_HANDLED;
+}
+
+static void dsi_display_change_te_irq_status(struct dsi_display *display,
+ bool enable)
+{
+ if (!display) {
+ pr_err("Invalid params\n");
+ return;
+ }
+
+ /* Handle unbalanced irq enable/disbale calls */
+ if (enable && !display->is_te_irq_enabled) {
+ enable_irq(gpio_to_irq(display->disp_te_gpio));
+ display->is_te_irq_enabled = true;
+ } else if (!enable && display->is_te_irq_enabled) {
+ disable_irq(gpio_to_irq(display->disp_te_gpio));
+ display->is_te_irq_enabled = false;
+ }
+}
+
+static void dsi_display_register_te_irq(struct dsi_display *display)
+{
+ int rc;
+ struct platform_device *pdev;
+ struct device *dev;
+
+ pdev = display->pdev;
+ if (!pdev) {
+ pr_err("invalid platform device\n");
+ return;
+ }
+
+ dev = &pdev->dev;
+ if (!dev) {
+ pr_err("invalid device\n");
+ return;
+ }
+
+ rc = devm_request_irq(dev, gpio_to_irq(display->disp_te_gpio),
+ dsi_display_panel_te_irq_handler, IRQF_TRIGGER_FALLING,
+ "TE_GPIO", display);
+ if (rc) {
+ pr_err("TE request_irq failed for ESD rc:%d\n", rc);
+ return;
+ }
+
+ init_completion(&display->esd_te_gate);
+
+ disable_irq(gpio_to_irq(display->disp_te_gpio));
+ display->is_te_irq_enabled = false;
+}
+
+static bool dsi_display_is_te_based_esd(struct dsi_display *display)
+{
+ u32 status_mode = 0;
+
+ if (!display->panel) {
+ pr_err("Invalid panel data\n");
+ return false;
+ }
+
+ status_mode = display->panel->esd_config.status_mode;
+
+ if (status_mode == ESD_MODE_PANEL_TE &&
+ gpio_is_valid(display->disp_te_gpio))
+ return true;
+ return false;
+}
+
/* Allocate memory for cmd dma tx buffer */
static int dsi_host_alloc_cmd_tx_buffer(struct dsi_display *display)
{
@@ -421,6 +508,27 @@
return false;
}
+static void dsi_display_parse_te_gpio(struct dsi_display *display)
+{
+ struct platform_device *pdev;
+ struct device *dev;
+
+ pdev = display->pdev;
+ if (!pdev) {
+ pr_err("Inavlid platform device\n");
+ return;
+ }
+
+ dev = &pdev->dev;
+ if (!dev) {
+ pr_err("Inavlid platform device\n");
+ return;
+ }
+
+ display->disp_te_gpio = of_get_named_gpio(dev->of_node,
+ "qcom,platform-te-gpio", 0);
+}
+
static int dsi_display_read_status(struct dsi_display_ctrl *ctrl,
struct dsi_panel *panel)
{
@@ -544,10 +652,9 @@
}
}
exit:
- if (rc <= 0) {
- dsi_display_ctrl_irq_update(display, false);
+ /* mask only error interrupts */
+ if (rc <= 0)
dsi_display_mask_ctrl_error_interrupts(display);
- }
dsi_display_cmd_engine_disable(display);
done:
@@ -566,10 +673,19 @@
static int dsi_display_status_check_te(struct dsi_display *display)
{
- int rc = 0;
+ int rc = 1;
+ int const esd_te_timeout = msecs_to_jiffies(3*20);
- pr_debug(" ++\n");
- /* TODO: wait for TE interrupt from panel */
+ dsi_display_change_te_irq_status(display, true);
+
+ reinit_completion(&display->esd_te_gate);
+ if (!wait_for_completion_timeout(&display->esd_te_gate,
+ esd_te_timeout)) {
+ pr_err("ESD check failed\n");
+ rc = -EINVAL;
+ }
+
+ dsi_display_change_te_irq_status(display, false);
return rc;
}
@@ -917,62 +1033,6 @@
return rc;
}
-static ssize_t debugfs_esd_trigger_check(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;
- u32 esd_trigger;
-
- if (!display)
- return -ENODEV;
-
- if (*ppos)
- return 0;
-
- if (user_len > sizeof(u32))
- return -EINVAL;
-
- buf = kzalloc(user_len, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- if (copy_from_user(buf, user_buf, user_len)) {
- rc = -EINVAL;
- goto error;
- }
-
- buf[user_len] = '\0'; /* terminate the string */
-
- if (kstrtouint(buf, 10, &esd_trigger)) {
- rc = -EINVAL;
- goto error;
- }
-
- if (esd_trigger != 1) {
- rc = -EINVAL;
- goto error;
- }
-
- display->esd_trigger = esd_trigger;
-
- if (display->esd_trigger) {
- rc = dsi_panel_trigger_esd_attack(display->panel);
- if (rc) {
- pr_err("Failed to trigger ESD attack\n");
- return rc;
- }
- }
-
- rc = user_len;
-error:
- kfree(buf);
- return rc;
-}
-
static ssize_t debugfs_misr_read(struct file *file,
char __user *user_buf,
size_t user_len,
@@ -1038,6 +1098,191 @@
return len;
}
+static ssize_t debugfs_esd_trigger_check(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;
+ u32 esd_trigger;
+
+ if (!display)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ if (user_len > sizeof(u32))
+ return -EINVAL;
+
+ buf = kzalloc(user_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, user_buf, user_len)) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ buf[user_len] = '\0'; /* terminate the string */
+
+ if (kstrtouint(buf, 10, &esd_trigger)) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (esd_trigger != 1) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ display->esd_trigger = esd_trigger;
+
+ if (display->esd_trigger) {
+ rc = dsi_panel_trigger_esd_attack(display->panel);
+ if (rc) {
+ pr_err("Failed to trigger ESD attack\n");
+ return rc;
+ }
+ }
+
+ rc = user_len;
+error:
+ kfree(buf);
+ return rc;
+}
+
+static ssize_t debugfs_alter_esd_check_mode(struct file *file,
+ const char __user *user_buf,
+ size_t user_len,
+ loff_t *ppos)
+{
+ struct dsi_display *display = file->private_data;
+ struct drm_panel_esd_config *esd_config;
+ char *buf;
+ int rc = 0;
+ size_t len = min_t(size_t, user_len, ESD_MODE_STRING_MAX_LEN);
+
+ if (!display)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, user_buf, user_len)) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ buf[len] = '\0'; /* terminate the string */
+ if (!display->panel) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ esd_config = &display->panel->esd_config;
+ if (!esd_config) {
+ pr_err("Invalid panel esd config\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (!esd_config->esd_enabled)
+ goto error;
+
+ if (!strcmp(buf, "te_signal_check\n")) {
+ esd_config->status_mode = ESD_MODE_PANEL_TE;
+ dsi_display_change_te_irq_status(display, true);
+ }
+
+ if (!strcmp(buf, "reg_read\n")) {
+ rc = dsi_panel_parse_esd_reg_read_configs(display->panel,
+ display->panel_of);
+ if (rc) {
+ pr_err("failed to alter esd check mode,rc=%d\n",
+ rc);
+ rc = user_len;
+ goto error;
+ }
+ esd_config->status_mode = ESD_MODE_REG_READ;
+ if (dsi_display_is_te_based_esd(display))
+ dsi_display_change_te_irq_status(display, false);
+ }
+
+ rc = len;
+error:
+ kfree(buf);
+ return rc;
+}
+
+static ssize_t debugfs_read_esd_check_mode(struct file *file,
+ char __user *user_buf,
+ size_t user_len,
+ loff_t *ppos)
+{
+ struct dsi_display *display = file->private_data;
+ struct drm_panel_esd_config *esd_config;
+ char *buf;
+ int rc = 0;
+ size_t len = min_t(size_t, user_len, ESD_MODE_STRING_MAX_LEN);
+
+ if (!display)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ if (!display->panel) {
+ pr_err("invalid panel data\n");
+ return -EINVAL;
+ }
+
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ esd_config = &display->panel->esd_config;
+ if (!esd_config) {
+ pr_err("Invalid panel esd config\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (!esd_config->esd_enabled) {
+ rc = snprintf(buf, len, "ESD feature not enabled");
+ goto output_mode;
+ }
+
+ if (esd_config->status_mode == ESD_MODE_REG_READ)
+ rc = snprintf(buf, len, "reg_read");
+
+ if (esd_config->status_mode == ESD_MODE_PANEL_TE)
+ rc = snprintf(buf, len, "te_signal_check");
+
+output_mode:
+ if (!rc) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (copy_to_user(user_buf, buf, len)) {
+ rc = -EFAULT;
+ goto error;
+ }
+
+ *ppos += len;
+
+error:
+ kfree(buf);
+ return len;
+}
+
static const struct file_operations dump_info_fops = {
.open = simple_open,
.read = debugfs_dump_info_read,
@@ -1054,6 +1299,12 @@
.write = debugfs_esd_trigger_check,
};
+static const struct file_operations esd_check_mode_fops = {
+ .open = simple_open,
+ .write = debugfs_alter_esd_check_mode,
+ .read = debugfs_read_esd_check_mode,
+};
+
static int dsi_display_debugfs_init(struct dsi_display *display)
{
int rc = 0;
@@ -1093,6 +1344,18 @@
goto error_remove_dir;
}
+ dump_file = debugfs_create_file("esd_check_mode",
+ 0644,
+ dir,
+ display,
+ &esd_check_mode_fops);
+ if (IS_ERR_OR_NULL(dump_file)) {
+ rc = PTR_ERR(dump_file);
+ pr_err("[%s] debugfs for esd check mode failed, rc=%d\n",
+ display->name, rc);
+ goto error_remove_dir;
+ }
+
misr_data = debugfs_create_file("misr_data",
0600,
dir,
@@ -1901,6 +2164,20 @@
return 0;
}
+static void dsi_display_toggle_resync_fifo(struct dsi_display *display)
+{
+ struct dsi_display_ctrl *ctrl;
+ int i;
+
+ if (!display)
+ return;
+
+ for (i = 0; i < display->ctrl_count; i++) {
+ ctrl = &display->ctrl[i];
+ dsi_phy_toggle_resync_fifo(ctrl->phy);
+ }
+}
+
static int dsi_display_ctrl_update(struct dsi_display *display)
{
int rc = 0;
@@ -1933,18 +2210,34 @@
int i;
struct dsi_display_ctrl *ctrl;
- for (i = 0 ; i < display->ctrl_count; i++) {
- ctrl = &display->ctrl[i];
- rc = dsi_ctrl_host_init(ctrl->ctrl,
- display->is_cont_splash_enabled);
- if (rc) {
- pr_err("[%s] failed to init host_%d, rc=%d\n",
- display->name, i, rc);
- goto error_host_deinit;
+ /* when ULPS suspend feature is enabled, we will keep the lanes in
+ * ULPS during suspend state and clamp DSI phy. Hence while resuming
+ * we will programe DSI controller as part of core clock enable.
+ * After that we should not re-configure DSI controller again here for
+ * usecases where we are resuming from ulps suspend as it might put
+ * the HW in bad state.
+ */
+ if (!display->panel->ulps_suspend_enabled || !display->ulps_enabled) {
+ for (i = 0 ; i < display->ctrl_count; i++) {
+ ctrl = &display->ctrl[i];
+ rc = dsi_ctrl_host_init(ctrl->ctrl,
+ display->is_cont_splash_enabled);
+ if (rc) {
+ pr_err("[%s] failed to init host_%d, rc=%d\n",
+ display->name, i, rc);
+ goto error_host_deinit;
+ }
+ }
+ } else {
+ for (i = 0 ; i < display->ctrl_count; i++) {
+ ctrl = &display->ctrl[i];
+ rc = dsi_ctrl_update_host_init_state(ctrl->ctrl, true);
+ if (rc)
+ pr_debug("host init update failed rc=%d\n", rc);
}
}
- return 0;
+ return rc;
error_host_deinit:
for (i = i - 1; i >= 0; i--) {
ctrl = &display->ctrl[i];
@@ -2810,6 +3103,15 @@
dsi_display_ctrl_irq_update(display, true);
}
if (clk & DSI_LINK_CLK) {
+ /*
+ * Toggle the resync FIFO everytime clock changes, except
+ * when cont-splash screen transition is going on.
+ * Toggling resync FIFO during cont splash transition
+ * can lead to blinks on the display.
+ */
+ if (!display->is_cont_splash_enabled)
+ dsi_display_toggle_resync_fifo(display);
+
if (display->ulps_enabled) {
rc = dsi_display_set_ulps(display, false);
if (rc) {
@@ -3078,6 +3380,9 @@
display->type = DSI_DISPLAY_SINGLE;
}
+ /* Parse TE gpio */
+ dsi_display_parse_te_gpio(display);
+
error:
return rc;
}
@@ -3644,22 +3949,24 @@
}
/**
- * dsi_display_splash_res_init() - Initialize resources for continuous splash
- * @display: Pointer to dsi display
+ * dsi_display_cont_splash_config() - Initialize resources for continuous splash
+ * @dsi_display: Pointer to dsi display
* Returns: Zero on success
*/
-static int dsi_display_splash_res_init(struct dsi_display *display)
+int dsi_display_cont_splash_config(void *dsi_display)
{
+ struct dsi_display *display = dsi_display;
int rc = 0;
/* Continuous splash not supported by external bridge */
- if (dsi_display_has_ext_bridge(display)) {
+ if (!display || dsi_display_has_ext_bridge(display)) {
display->is_cont_splash_enabled = false;
return 0;
}
- /* Vote for gdsc required to read register address space */
+ mutex_lock(&display->display_lock);
+ /* Vote for gdsc required to read register address space */
display->cont_splash_client = sde_power_client_create(display->phandle,
"cont_splash_client");
rc = sde_power_resource_enable(display->phandle,
@@ -3667,6 +3974,7 @@
if (rc) {
pr_err("failed to vote gdsc for continuous splash, rc=%d\n",
rc);
+ mutex_unlock(&display->display_lock);
return -EINVAL;
}
@@ -3684,6 +3992,9 @@
dsi_display_clk_mngr_update_splash_status(display->clk_mngr,
display->is_cont_splash_enabled);
+ /* Set up ctrl isr before enabling core clk */
+ dsi_display_ctrl_isr_configure(display, true);
+
/* Vote for Core clk and link clk. Votes on ctrl and phy
* regulator are inplicit from pre clk on callback
*/
@@ -3704,6 +4015,7 @@
}
dsi_config_host_engine_state_for_cont_splash(display);
+ mutex_unlock(&display->display_lock);
return rc;
@@ -3712,6 +4024,7 @@
DSI_ALL_CLKS, DSI_CLK_OFF);
clk_manager_update:
+ dsi_display_ctrl_isr_configure(display, false);
/* Update splash status for clock manager */
dsi_display_clk_mngr_update_splash_status(display->clk_mngr,
false);
@@ -3720,6 +4033,7 @@
(void)sde_power_resource_enable(display->phandle,
display->cont_splash_client, false);
display->is_cont_splash_enabled = false;
+ mutex_unlock(&display->display_lock);
return rc;
}
@@ -3755,6 +4069,246 @@
return rc;
}
+static int dsi_display_force_update_dsi_clk(struct dsi_display *display)
+{
+ int rc = 0;
+
+ if (!display || !display->panel) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ rc = dsi_display_link_clk_force_update_ctrl(display->dsi_clk_handle);
+
+ if (!rc) {
+ pr_info("dsi bit clk has been configured to %d\n",
+ display->cached_clk_rate);
+
+ atomic_set(&display->clkrate_change_pending, 0);
+ } else if (rc == -EAGAIN) {
+ pr_info("Clock is disabled, update it next time\n");
+ } else {
+ pr_err("Failed to configure dsi bit clock '%d'. rc = %d\n",
+ display->cached_clk_rate, rc);
+ }
+
+ return rc;
+}
+
+static int dsi_display_request_update_dsi_bitrate(struct dsi_display *display,
+ u32 bit_clk_rate)
+{
+ int rc = 0;
+ int i;
+
+ pr_debug("%s:bit rate:%d\n", __func__, bit_clk_rate);
+ if (!display || !display->panel) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ if (bit_clk_rate == 0) {
+ pr_err("Invalid bit clock rate\n");
+ return -EINVAL;
+ }
+
+ display->config.bit_clk_rate_hz = bit_clk_rate;
+
+ for (i = 0; i < display->ctrl_count; i++) {
+ struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i];
+ struct dsi_ctrl *ctrl = dsi_disp_ctrl->ctrl;
+ u32 num_of_lanes = 0;
+ u32 bpp = 3;
+ u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate;
+ struct dsi_host_common_cfg *host_cfg;
+
+ mutex_lock(&ctrl->ctrl_lock);
+
+ host_cfg = &display->panel->host_config;
+ if (host_cfg->data_lanes & DSI_DATA_LANE_0)
+ num_of_lanes++;
+ if (host_cfg->data_lanes & DSI_DATA_LANE_1)
+ num_of_lanes++;
+ if (host_cfg->data_lanes & DSI_DATA_LANE_2)
+ num_of_lanes++;
+ if (host_cfg->data_lanes & DSI_DATA_LANE_3)
+ num_of_lanes++;
+
+ if (num_of_lanes == 0) {
+ pr_err("Invalid lane count\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ bit_rate = display->config.bit_clk_rate_hz * num_of_lanes;
+ bit_rate_per_lane = bit_rate;
+ do_div(bit_rate_per_lane, num_of_lanes);
+ pclk_rate = bit_rate;
+ do_div(pclk_rate, (8 * bpp));
+ byte_clk_rate = bit_rate_per_lane;
+ do_div(byte_clk_rate, 8);
+ pr_debug("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n",
+ bit_rate, bit_rate_per_lane);
+ pr_debug("byte_clk_rate = %llu, pclk_rate = %llu\n",
+ byte_clk_rate, pclk_rate);
+
+ ctrl->clk_freq.byte_clk_rate = byte_clk_rate;
+ ctrl->clk_freq.pix_clk_rate = pclk_rate;
+ rc = dsi_clk_set_link_frequencies(display->dsi_clk_handle,
+ ctrl->clk_freq, ctrl->cell_index);
+ if (rc) {
+ pr_err("Failed to update link frequencies\n");
+ goto error;
+ }
+
+ ctrl->host_config.bit_clk_rate_hz = bit_clk_rate;
+error:
+ mutex_unlock(&ctrl->ctrl_lock);
+
+ /* TODO: recover ctrl->clk_freq in case of failure */
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static ssize_t sysfs_dynamic_dsi_clk_read(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int rc = 0;
+ struct dsi_display *display;
+ struct dsi_display_ctrl *m_ctrl;
+ struct dsi_ctrl *ctrl;
+
+ if (!dev) {
+ pr_err("Invalid device\n");
+ return -EINVAL;
+ }
+
+ display = dev_get_drvdata(dev);
+ if (!display) {
+ pr_err("Invalid display\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&display->display_lock);
+
+ m_ctrl = &display->ctrl[display->cmd_master_idx];
+ ctrl = m_ctrl->ctrl;
+ if (ctrl)
+ display->cached_clk_rate = ctrl->clk_freq.
+ byte_clk_rate * 8;
+
+ rc = snprintf(buf, PAGE_SIZE, "%d\n", display->cached_clk_rate);
+ pr_info("%s: read dsi clk rate %d\n", __func__,
+ display->cached_clk_rate);
+
+ mutex_unlock(&display->display_lock);
+
+ return rc;
+}
+
+static ssize_t sysfs_dynamic_dsi_clk_write(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int rc = 0;
+ int clk_rate;
+ struct dsi_display *display;
+
+ if (!dev) {
+ pr_err("Invalid device\n");
+ return -EINVAL;
+ }
+
+ display = dev_get_drvdata(dev);
+ if (!display) {
+ pr_err("Invalid display\n");
+ return -EINVAL;
+ }
+
+ rc = kstrtoint(buf, DSI_CLOCK_BITRATE_RADIX, &clk_rate);
+ if (rc) {
+ pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+ return rc;
+ }
+
+ if (clk_rate <= 0) {
+ pr_err("%s: bitrate should be greater than 0\n", __func__);
+ return -EINVAL;
+ }
+
+ if (clk_rate == display->cached_clk_rate) {
+ pr_info("%s: ignore duplicated DSI clk setting\n", __func__);
+ return count;
+ }
+
+ pr_info("%s: bitrate param value: '%d'\n", __func__, clk_rate);
+
+ mutex_lock(&display->display_lock);
+
+ display->cached_clk_rate = clk_rate;
+ rc = dsi_display_request_update_dsi_bitrate(display, clk_rate);
+ if (!rc) {
+ pr_info("%s: bit clk is ready to be configured to '%d'\n",
+ __func__, clk_rate);
+ } else {
+ pr_err("%s: Failed to prepare to configure '%d'. rc = %d\n",
+ __func__, clk_rate, rc);
+ /*Caching clock failed, so don't go on doing so.*/
+ atomic_set(&display->clkrate_change_pending, 0);
+ display->cached_clk_rate = 0;
+
+ mutex_unlock(&display->display_lock);
+
+ return rc;
+ }
+ atomic_set(&display->clkrate_change_pending, 1);
+
+ mutex_unlock(&display->display_lock);
+
+ return count;
+
+}
+
+static DEVICE_ATTR(dynamic_dsi_clock, 0644,
+ sysfs_dynamic_dsi_clk_read,
+ sysfs_dynamic_dsi_clk_write);
+
+static struct attribute *dynamic_dsi_clock_fs_attrs[] = {
+ &dev_attr_dynamic_dsi_clock.attr,
+ NULL,
+};
+static struct attribute_group dynamic_dsi_clock_fs_attrs_group = {
+ .attrs = dynamic_dsi_clock_fs_attrs,
+};
+
+static int dsi_display_sysfs_init(struct dsi_display *display)
+{
+ int rc = 0;
+ struct device *dev = &display->pdev->dev;
+
+ if (display->panel->panel_mode == DSI_OP_CMD_MODE)
+ rc = sysfs_create_group(&dev->kobj,
+ &dynamic_dsi_clock_fs_attrs_group);
+ pr_debug("[%s] dsi_display_sysfs_init:%d,panel mode:%d\n",
+ display->name, rc, display->panel->panel_mode);
+ return rc;
+
+}
+
+static int dsi_display_sysfs_deinit(struct dsi_display *display)
+{
+ struct device *dev = &display->pdev->dev;
+
+ if (display->panel->panel_mode == DSI_OP_CMD_MODE)
+ sysfs_remove_group(&dev->kobj,
+ &dynamic_dsi_clock_fs_attrs_group);
+
+ return 0;
+
+}
+
/**
* dsi_display_bind - bind dsi device with controlling device
* @dev: Pointer to base of platform device
@@ -3802,6 +4356,15 @@
goto error;
}
+ atomic_set(&display->clkrate_change_pending, 0);
+ display->cached_clk_rate = 0;
+
+ rc = dsi_display_sysfs_init(display);
+ if (rc) {
+ pr_err("[%s] sysfs init failed, rc=%d\n", display->name, rc);
+ goto error;
+ }
+
memset(&info, 0x0, sizeof(info));
for (i = 0; i < display->ctrl_count; i++) {
@@ -3934,10 +4497,8 @@
}
}
- /* Initialize resources for continuous splash */
- rc = dsi_display_splash_res_init(display);
- if (rc)
- pr_err("Continuous splash resource init failed, rc=%d\n", rc);
+ /* register te irq handler */
+ dsi_display_register_te_irq(display);
goto error;
@@ -3953,6 +4514,7 @@
(void)dsi_phy_drv_deinit(display_ctrl->phy);
(void)dsi_ctrl_drv_deinit(display_ctrl->ctrl);
}
+ (void)dsi_display_sysfs_deinit(display);
(void)dsi_display_debugfs_deinit(display);
error:
mutex_unlock(&display->display_lock);
@@ -4010,6 +4572,9 @@
pr_err("[%s] failed to deinit ctrl%d driver, rc=%d\n",
display->name, i, rc);
}
+
+ atomic_set(&display->clkrate_change_pending, 0);
+ (void)dsi_display_sysfs_deinit(display);
(void)dsi_display_debugfs_deinit(display);
mutex_unlock(&display->display_lock);
@@ -4830,6 +5395,10 @@
adj_mode = *mode;
adjust_timing_by_ctrl_count(display, &adj_mode);
+ /*For dynamic DSI setting, use specified clock rate */
+ if (display->cached_clk_rate > 0)
+ adj_mode.priv_info->clk_rate_hz = display->cached_clk_rate;
+
rc = dsi_display_validate_mode_set(display, &adj_mode, flags);
if (rc) {
pr_err("[%s] mode cannot be set\n", display->name);
@@ -5426,6 +5995,7 @@
struct msm_display_kickoff_params *params)
{
int rc = 0;
+ int i;
/* check and setup MISR */
if (display->misr_enable)
@@ -5433,6 +6003,44 @@
rc = dsi_display_set_roi(display, params->rois);
+ /* dynamic DSI clock setting */
+ if (atomic_read(&display->clkrate_change_pending)) {
+ mutex_lock(&display->display_lock);
+ /*
+ * acquire panel_lock to make sure no commands are in progress
+ */
+ dsi_panel_acquire_panel_lock(display->panel);
+
+ /*
+ * Wait for DSI command engine not to be busy sending data
+ * from display engine.
+ * If waiting fails, return "rc" instead of below "ret" so as
+ * not to impact DRM commit. The clock updating would be
+ * deferred to the next DRM commit.
+ */
+ for (i = 0; i < display->ctrl_count; i++) {
+ struct dsi_ctrl *ctrl = display->ctrl[i].ctrl;
+ int ret = 0;
+
+ ret = dsi_ctrl_wait_for_cmd_mode_mdp_idle(ctrl);
+ if (ret) {
+ pr_info("Failed to wait for cmd engine not to be busy sending data from MDP, rc: %d\n",
+ ret);
+ goto wait_failure;
+ }
+ }
+
+ /*
+ * Don't check the return value so as not to impact DRM commit
+ * when error occurs.
+ */
+ (void)dsi_display_force_update_dsi_clk(display);
+wait_failure:
+ /* release panel_lock */
+ dsi_panel_release_panel_lock(display->panel);
+ mutex_unlock(&display->display_lock);
+ }
+
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 53004e4..0a84c6f 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -132,6 +132,9 @@
* @is_active: Is display active.
* @is_cont_splash_enabled: Is continuous splash enabled
* @display_lock: Mutex for dsi_display interface.
+ * @disp_te_gpio: GPIO for panel TE interrupt.
+ * @is_te_irq_enabled:bool to specify whether TE interrupt is enabled.
+ * @esd_te_gate: completion gate to signal TE interrupt.
* @ctrl_count: Number of DSI interfaces required by panel.
* @ctrl: Controller information for DSI display.
* @panel: Handle to DSI panel.
@@ -142,6 +145,8 @@
* index into the ctrl[MAX_DSI_CTRLS_PER_DISPLAY] array.
* @cmd_master_idx: The master controller for sending DSI commands to panel.
* @video_master_idx: The master controller for enabling video engine.
+ * @cached_clk_rate: The cached DSI clock rate set dynamically by sysfs.
+ * @clkrate_change_pending: Flag indicating the pending DSI clock re-enabling.
* @clock_info: Clock sourcing for DSI display.
* @config: DSI host configuration information.
* @lane_map: Lane mapping between DSI host and Panel.
@@ -173,6 +178,9 @@
bool is_active;
bool is_cont_splash_enabled;
struct mutex display_lock;
+ int disp_te_gpio;
+ bool is_te_irq_enabled;
+ struct completion esd_te_gate;
u32 ctrl_count;
struct dsi_display_ctrl ctrl[MAX_DSI_CTRLS_PER_DISPLAY];
@@ -188,6 +196,10 @@
u32 cmd_master_idx;
u32 video_master_idx;
+ /* dynamic DSI clock info*/
+ u32 cached_clk_rate;
+ atomic_t clkrate_change_pending;
+
struct dsi_display_clk_info clock_info;
struct dsi_host_config config;
struct dsi_lane_map lane_map;
@@ -628,4 +640,11 @@
*/
enum dsi_pixel_format dsi_display_get_dst_format(void *display);
+/**
+ * dsi_display_cont_splash_config() - initialize splash resources
+ * @display: Handle to display
+ *
+ * Return: Zero on Success
+ */
+int dsi_display_cont_splash_config(void *display);
#endif /* _DSI_DISPLAY_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index d8b90e3..31d6fd1 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -18,6 +18,7 @@
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <video/mipi_display.h>
+#include <linux/firmware.h>
#include "dsi_panel.h"
#include "dsi_ctrl_hw.h"
@@ -710,12 +711,58 @@
error:
return rc;
}
-static int dsi_panel_parse_timing(struct dsi_mode_info *mode,
- struct device_node *of_node)
+
+static int dsi_panel_fw_parse(const struct firmware *fw_entry,
+ char *id_match, u32 *param_value)
{
- int rc = 0;
+ int value, numlen = 1, index = 0;
+ char id[SZ_256];
+
+ while (sscanf(fw_entry->data + index,
+ "%255s %d", id, &value) > 0) {
+ if (!strcmp(id, id_match)) {
+ *param_value = value;
+ return 0;
+ }
+
+ while ((value / 10) > 0) {
+ value /= 10;
+ numlen++;
+ }
+
+ index += (strlen(id) + numlen + 1);
+ numlen = 1;
+ }
+
+ return -EINVAL;
+}
+
+static int dsi_panel_parse(struct device_node *of_node,
+ const struct firmware *fw_entry, char *id_match, u32 *val)
+{
+ if (fw_entry && fw_entry->data)
+ return dsi_panel_fw_parse(fw_entry, id_match, val);
+ else
+ return of_property_read_u32(of_node, id_match, val);
+
+ return 0;
+}
+
+static int dsi_panel_parse_timing(struct device *parent,
+ struct dsi_mode_info *mode, const char *name,
+ struct device_node *of_node)
+{
+ int fw = 0, rc = 0;
u64 tmp64;
struct dsi_display_mode *display_mode;
+ const struct firmware *fw_entry = NULL;
+ char *fw_name = "dsi_prop";
+
+ if (strcmp(name, "Simulator video mode dsi panel") == 0)
+ fw = request_firmware(&fw_entry, fw_name, parent);
+
+ if (fw)
+ fw_entry = NULL;
display_mode = container_of(mode, struct dsi_display_mode, timing);
@@ -730,47 +777,47 @@
mode->clk_rate_hz = !rc ? tmp64 : 0;
display_mode->priv_info->clk_rate_hz = mode->clk_rate_hz;
- rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-framerate",
- &mode->refresh_rate);
+ rc = dsi_panel_parse(of_node, fw_entry,
+ "qcom,mdss-dsi-panel-framerate", &mode->refresh_rate);
if (rc) {
pr_err("failed to read qcom,mdss-dsi-panel-framerate, rc=%d\n",
rc);
goto error;
}
- rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-width",
- &mode->h_active);
+ rc = dsi_panel_parse(of_node, fw_entry,
+ "qcom,mdss-dsi-panel-width", &mode->h_active);
if (rc) {
pr_err("failed to read qcom,mdss-dsi-panel-width, rc=%d\n", rc);
goto error;
}
- rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-front-porch",
- &mode->h_front_porch);
+ rc = dsi_panel_parse(of_node, fw_entry,
+ "qcom,mdss-dsi-h-front-porch", &mode->h_front_porch);
if (rc) {
pr_err("failed to read qcom,mdss-dsi-h-front-porch, rc=%d\n",
rc);
goto error;
}
- rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-back-porch",
- &mode->h_back_porch);
+ rc = dsi_panel_parse(of_node, fw_entry,
+ "qcom,mdss-dsi-h-back-porch", &mode->h_back_porch);
if (rc) {
pr_err("failed to read qcom,mdss-dsi-h-back-porch, rc=%d\n",
rc);
goto error;
}
- rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-pulse-width",
- &mode->h_sync_width);
+ rc = dsi_panel_parse(of_node, fw_entry,
+ "qcom,mdss-dsi-h-pulse-width", &mode->h_sync_width);
if (rc) {
pr_err("failed to read qcom,mdss-dsi-h-pulse-width, rc=%d\n",
rc);
goto error;
}
- rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-sync-skew",
- &mode->h_skew);
+ rc = dsi_panel_parse(of_node, fw_entry,
+ "qcom,mdss-dsi-h-sync-skew", &mode->h_skew);
if (rc)
pr_err("qcom,mdss-dsi-h-sync-skew is not defined, rc=%d\n", rc);
@@ -778,32 +825,32 @@
mode->h_active, mode->h_front_porch, mode->h_back_porch,
mode->h_sync_width);
- rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-height",
- &mode->v_active);
+ rc = dsi_panel_parse(of_node, fw_entry,
+ "qcom,mdss-dsi-panel-height", &mode->v_active);
if (rc) {
pr_err("failed to read qcom,mdss-dsi-panel-height, rc=%d\n",
rc);
goto error;
}
- rc = of_property_read_u32(of_node, "qcom,mdss-dsi-v-back-porch",
- &mode->v_back_porch);
+ rc = dsi_panel_parse(of_node, fw_entry,
+ "qcom,mdss-dsi-v-back-porch", &mode->v_back_porch);
if (rc) {
pr_err("failed to read qcom,mdss-dsi-v-back-porch, rc=%d\n",
rc);
goto error;
}
- rc = of_property_read_u32(of_node, "qcom,mdss-dsi-v-front-porch",
- &mode->v_front_porch);
+ rc = dsi_panel_parse(of_node, fw_entry,
+ "qcom,mdss-dsi-v-front-porch", &mode->v_front_porch);
if (rc) {
pr_err("failed to read qcom,mdss-dsi-v-back-porch, rc=%d\n",
rc);
goto error;
}
- rc = of_property_read_u32(of_node, "qcom,mdss-dsi-v-pulse-width",
- &mode->v_sync_width);
+ rc = dsi_panel_parse(of_node, fw_entry,
+ "qcom,mdss-dsi-v-pulse-width", &mode->v_sync_width);
if (rc) {
pr_err("failed to read qcom,mdss-dsi-v-pulse-width, rc=%d\n",
rc);
@@ -2580,54 +2627,23 @@
kfree(esd_config->status_cmd.cmds);
}
-static int dsi_panel_parse_esd_config(struct dsi_panel *panel,
- struct device_node *of_node)
+int dsi_panel_parse_esd_reg_read_configs(struct dsi_panel *panel,
+ struct device_node *of_node)
{
+ struct drm_panel_esd_config *esd_config;
int rc = 0;
u32 tmp;
u32 i, status_len, *lenp;
struct property *data;
- const char *string;
- struct drm_panel_esd_config *esd_config;
- u8 *esd_mode = NULL;
- esd_config = &panel->esd_config;
- esd_config->status_mode = ESD_MODE_MAX;
- esd_config->esd_enabled = of_property_read_bool(of_node,
- "qcom,esd-check-enabled");
-
- if (!esd_config->esd_enabled)
- return 0;
-
- rc = of_property_read_string(of_node,
- "qcom,mdss-dsi-panel-status-check-mode", &string);
- if (!rc) {
- if (!strcmp(string, "bta_check")) {
- esd_config->status_mode = ESD_MODE_SW_BTA;
- } else if (!strcmp(string, "reg_read")) {
- esd_config->status_mode = ESD_MODE_REG_READ;
- } else if (!strcmp(string, "te_signal_check")) {
- if (panel->panel_mode == DSI_OP_CMD_MODE) {
- esd_config->status_mode = ESD_MODE_PANEL_TE;
- } else {
- pr_err("TE-ESD not valid for video mode\n");
- rc = -EINVAL;
- goto error;
- }
- } else {
- pr_err("No valid panel-status-check-mode string\n");
- rc = -EINVAL;
- goto error;
- }
- } else {
- pr_debug("status check method not defined!\n");
- rc = -EINVAL;
- goto error;
+ if (!panel || !of_node) {
+ pr_err("Invalid Params\n");
+ return -EINVAL;
}
- if ((esd_config->status_mode == ESD_MODE_SW_BTA) ||
- (esd_config->status_mode == ESD_MODE_PANEL_TE))
- return 0;
+ esd_config = &panel->esd_config;
+ if (!esd_config)
+ return -EINVAL;
dsi_panel_parse_cmd_sets_sub(&esd_config->status_cmd,
DSI_CMD_SET_PANEL_STATUS, of_node);
@@ -2702,8 +2718,10 @@
}
esd_config->status_buf = kzalloc(SZ_4K, GFP_KERNEL);
- if (!esd_config->status_buf)
+ if (!esd_config->status_buf) {
+ rc = -ENOMEM;
goto error4;
+ }
rc = of_property_read_u32_array(of_node,
"qcom,mdss-dsi-panel-status-value",
@@ -2714,15 +2732,6 @@
esd_config->groups * status_len);
}
- if (panel->esd_config.status_mode == ESD_MODE_REG_READ)
- esd_mode = "register_read";
- else if (panel->esd_config.status_mode == ESD_MODE_SW_BTA)
- esd_mode = "bta_trigger";
- else if (panel->esd_config.status_mode == ESD_MODE_PANEL_TE)
- esd_mode = "te_check";
-
- pr_info("ESD enabled with mode: %s\n", esd_mode);
-
return 0;
error4:
@@ -2735,6 +2744,70 @@
error1:
kfree(esd_config->status_cmd.cmds);
error:
+ return rc;
+}
+
+static int dsi_panel_parse_esd_config(struct dsi_panel *panel,
+ struct device_node *of_node)
+{
+ int rc = 0;
+ const char *string;
+ struct drm_panel_esd_config *esd_config;
+ u8 *esd_mode = NULL;
+
+ esd_config = &panel->esd_config;
+ esd_config->status_mode = ESD_MODE_MAX;
+ esd_config->esd_enabled = of_property_read_bool(of_node,
+ "qcom,esd-check-enabled");
+
+ if (!esd_config->esd_enabled)
+ return 0;
+
+ rc = of_property_read_string(of_node,
+ "qcom,mdss-dsi-panel-status-check-mode", &string);
+ if (!rc) {
+ if (!strcmp(string, "bta_check")) {
+ esd_config->status_mode = ESD_MODE_SW_BTA;
+ } else if (!strcmp(string, "reg_read")) {
+ esd_config->status_mode = ESD_MODE_REG_READ;
+ } else if (!strcmp(string, "te_signal_check")) {
+ if (panel->panel_mode == DSI_OP_CMD_MODE) {
+ esd_config->status_mode = ESD_MODE_PANEL_TE;
+ } else {
+ pr_err("TE-ESD not valid for video mode\n");
+ rc = -EINVAL;
+ goto error;
+ }
+ } else {
+ pr_err("No valid panel-status-check-mode string\n");
+ rc = -EINVAL;
+ goto error;
+ }
+ } else {
+ pr_debug("status check method not defined!\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (panel->esd_config.status_mode == ESD_MODE_REG_READ) {
+ rc = dsi_panel_parse_esd_reg_read_configs(panel, of_node);
+ if (rc) {
+ pr_err("failed to parse esd reg read mode params, rc=%d\n",
+ rc);
+ goto error;
+ }
+ esd_mode = "register_read";
+ } else if (panel->esd_config.status_mode == ESD_MODE_SW_BTA) {
+ esd_mode = "bta_trigger";
+ } else if (panel->esd_config.status_mode == ESD_MODE_PANEL_TE) {
+ esd_mode = "te_check";
+ }
+
+ pr_info("ESD enabled with mode: %s\n", esd_mode);
+
+ return 0;
+
+error:
panel->esd_config.esd_enabled = false;
return rc;
}
@@ -3090,7 +3163,8 @@
if (index != child_idx++)
continue;
- rc = dsi_panel_parse_timing(&mode->timing, child_np);
+ rc = dsi_panel_parse_timing(panel->parent, &mode->timing,
+ panel->name, child_np);
if (rc) {
pr_err("failed to parse panel timing, rc=%d\n", rc);
goto parse_fail;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 3b226b0..f8b65ab 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -283,6 +283,9 @@
struct device_node *of_node,
int topology_override);
+int dsi_panel_parse_esd_reg_read_configs(struct dsi_panel *panel,
+ struct device_node *of_node);
+
void dsi_panel_ext_bridge_put(struct dsi_panel *panel);
#endif /* _DSI_PANEL_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
index 07b2305..6a7a84c 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -694,8 +694,7 @@
u32 lanes = 0;
u32 ulps_lanes;
- if (config->panel_mode == DSI_OP_CMD_MODE)
- lanes = config->common_config.data_lanes;
+ lanes = config->common_config.data_lanes;
lanes |= DSI_CLOCK_LANE;
/*
@@ -730,8 +729,7 @@
{
u32 ulps_lanes, lanes = 0;
- if (config->panel_mode == DSI_OP_CMD_MODE)
- lanes = config->common_config.data_lanes;
+ lanes = config->common_config.data_lanes;
lanes |= DSI_CLOCK_LANE;
ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
@@ -754,6 +752,16 @@
return 0;
}
+void dsi_phy_toggle_resync_fifo(struct msm_dsi_phy *phy)
+{
+ if (!phy)
+ return;
+
+ if (!phy->hw.ops.toggle_resync_fifo)
+ return;
+
+ phy->hw.ops.toggle_resync_fifo(&phy->hw);
+}
int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config,
bool enable, bool clamp_enabled)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
index a158812..56d5ee3 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -250,6 +250,16 @@
int dsi_phy_lane_reset(struct msm_dsi_phy *phy);
/**
+ * dsi_phy_toggle_resync_fifo() - toggle resync retime FIFO
+ * @phy: DSI PHY handle
+ *
+ * Toggle the resync retime FIFO to synchronize the data paths.
+ * This should be done everytime there is a change in the link clock
+ * rate
+ */
+void dsi_phy_toggle_resync_fifo(struct msm_dsi_phy *phy);
+
+/**
* dsi_phy_drv_register() - register platform driver for dsi phy
*/
void dsi_phy_drv_register(void);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
index efebd99..e31899d4 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -240,6 +240,13 @@
*/
int (*phy_lane_reset)(struct dsi_phy_hw *phy);
+ /**
+ * toggle_resync_fifo() - toggle resync retime FIFO to sync data paths
+ * @phy: Pointer to DSI PHY hardware object.
+ * Return: error code.
+ */
+ void (*toggle_resync_fifo)(struct dsi_phy_hw *phy);
+
void *timing_ops;
struct phy_ulps_config_ops ulps_ops;
};
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
index 8d91141..b078231 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -118,6 +118,15 @@
/* Nothing to be done for DSI PHY regulator disable */
}
+void dsi_phy_hw_v3_0_toggle_resync_fifo(struct dsi_phy_hw *phy)
+{
+ DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x00);
+ /* ensure that the FIFO is off */
+ wmb();
+ DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x1);
+ /* ensure that the FIFO is toggled back on */
+ wmb();
+}
static int dsi_phy_hw_v3_0_is_pll_on(struct dsi_phy_hw *phy)
{
diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c
index 211acce..85867b2 100644
--- a/drivers/gpu/drm/msm/msm_smmu.c
+++ b/drivers/gpu/drm/msm/msm_smmu.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
@@ -321,7 +321,7 @@
DRM_DEBUG("%pad/0x%x/0x%x/0x%lx\n", &sgt->sgl->dma_address,
sgt->sgl->dma_length, dir, attrs);
SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length,
- dir, attrs);
+ dir, attrs, client->secure);
}
return 0;
@@ -342,7 +342,8 @@
if (sgt && sgt->sgl) {
DRM_DEBUG("%pad/0x%x/0x%x\n", &sgt->sgl->dma_address,
sgt->sgl->dma_length, dir);
- SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length, dir);
+ SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length, dir,
+ client->secure);
}
msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir, dma_buf);
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c
index 3e3533e..919ed97 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.c
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c
@@ -25,6 +25,7 @@
#include "sde_hw_interrupts.h"
#include "sde_core_irq.h"
#include "dsi_panel.h"
+#include "sde_hw_color_processing.h"
struct sde_cp_node {
u32 property_id;
@@ -148,6 +149,24 @@
SDE_CP_CRTC_MAX_FEATURES,
};
+#define HIGH_BUS_VOTE_NEEDED(feature) ((feature == SDE_CP_CRTC_DSPP_IGC) |\
+ (feature == SDE_CP_CRTC_DSPP_GC) |\
+ (feature == SDE_CP_CRTC_DSPP_SIXZONE) |\
+ (feature == SDE_CP_CRTC_DSPP_GAMUT))
+
+static u32 crtc_feature_map[SDE_CP_CRTC_MAX_FEATURES] = {
+ [SDE_CP_CRTC_DSPP_IGC] = SDE_DSPP_IGC,
+ [SDE_CP_CRTC_DSPP_PCC] = SDE_DSPP_PCC,
+ [SDE_CP_CRTC_DSPP_GC] = SDE_DSPP_GC,
+ [SDE_CP_CRTC_DSPP_MEMCOL_SKIN] = SDE_DSPP_MEMCOLOR,
+ [SDE_CP_CRTC_DSPP_MEMCOL_SKY] = SDE_DSPP_MEMCOLOR,
+ [SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE] = SDE_DSPP_MEMCOLOR,
+ [SDE_CP_CRTC_DSPP_SIXZONE] = SDE_DSPP_SIXZONE,
+ [SDE_CP_CRTC_DSPP_GAMUT] = SDE_DSPP_GAMUT,
+ [SDE_CP_CRTC_DSPP_DITHER] = SDE_DSPP_DITHER,
+ [SDE_CP_CRTC_DSPP_VLUT] = SDE_DSPP_VLUT,
+};
+
#define INIT_PROP_ATTACH(p, crtc, prop, node, feature, val) \
do { \
(p)->crtc = crtc; \
@@ -859,6 +878,10 @@
struct sde_hw_ctl *ctl;
uint32_t flush_mask = 0;
u32 num_mixers = 0, i = 0;
+ u32 sde_dspp_feature = SDE_DSPP_MAX;
+ struct msm_drm_private *priv = NULL;
+ struct sde_kms *sde_kms = NULL;
+ bool mdss_bus_vote = false;
if (!crtc || !crtc->dev) {
DRM_ERROR("invalid crtc %pK dev %pK\n", crtc,
@@ -878,6 +901,17 @@
return;
}
+ priv = crtc->dev->dev_private;
+ if (!priv || !priv->kms) {
+ SDE_ERROR("invalid kms\n");
+ return;
+ }
+ sde_kms = to_sde_kms(priv->kms);
+ if (!sde_kms) {
+ SDE_ERROR("invalid sde kms\n");
+ return;
+ }
+
mutex_lock(&sde_crtc->crtc_cp_lock);
/* Check if dirty lists are empty and ad features are disabled for
@@ -896,6 +930,16 @@
list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list,
dirty_list) {
+ sde_dspp_feature = crtc_feature_map[prop_node->feature];
+ if (!mdss_bus_vote && HIGH_BUS_VOTE_NEEDED(prop_node->feature)
+ && !reg_dmav1_dspp_feature_support(sde_dspp_feature)) {
+ sde_power_scale_reg_bus(&priv->phandle,
+ sde_kms->core_client,
+ VOTE_INDEX_HIGH, false);
+ pr_debug("Vote HIGH for data bus: feature %d\n",
+ prop_node->feature);
+ mdss_bus_vote = true;
+ }
sde_cp_crtc_setfeature(prop_node, sde_crtc);
/* Set the flush flag to true */
if (prop_node->is_dspp_feature)
@@ -903,6 +947,12 @@
else
set_lm_flush = true;
}
+ if (mdss_bus_vote) {
+ sde_power_scale_reg_bus(&priv->phandle, sde_kms->core_client,
+ VOTE_INDEX_LOW, false);
+ pr_debug("Vote LOW for data bus\n");
+ mdss_bus_vote = false;
+ }
list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_dirty,
dirty_list) {
@@ -1180,6 +1230,7 @@
{
struct sde_crtc *sde_crtc = NULL;
struct sde_cp_node *prop_node = NULL, *n = NULL;
+ bool ad_suspend = false;
if (!crtc) {
DRM_ERROR("crtc %pK\n", crtc);
@@ -1202,8 +1253,12 @@
active_list) {
sde_cp_update_list(prop_node, sde_crtc, true);
list_del_init(&prop_node->active_list);
+ ad_suspend = true;
}
mutex_unlock(&sde_crtc->crtc_cp_lock);
+
+ if (ad_suspend)
+ sde_cp_ad_set_prop(sde_crtc, AD_SUSPEND);
}
void sde_cp_crtc_resume(struct drm_crtc *crtc)
@@ -1639,6 +1694,9 @@
struct sde_crtc *crtc;
struct drm_event event;
int i;
+ struct msm_drm_private *priv;
+ struct sde_kms *kms;
+ int ret;
crtc = to_sde_crtc(crtc_drm);
num_mixers = crtc->num_mixers;
@@ -1655,9 +1713,25 @@
if (!hw_dspp)
return;
+ kms = get_kms(crtc_drm);
+ if (!kms || !kms->dev) {
+ SDE_ERROR("invalid arg(s)\n");
+ return;
+ }
+
+ priv = kms->dev->dev_private;
+ ret = sde_power_resource_enable(&priv->phandle, kms->core_client, true);
+ if (ret) {
+ SDE_ERROR("failed to enable power resource %d\n", ret);
+ SDE_EVT32(ret, SDE_EVTLOG_ERROR);
+ return;
+ }
+
hw_dspp->ops.ad_read_intr_resp(hw_dspp, AD4_IN_OUT_BACKLIGHT,
&input_bl, &output_bl);
+ sde_power_resource_enable(&priv->phandle, kms->core_client,
+ false);
if (!input_bl || input_bl < output_bl)
return;
@@ -1898,6 +1972,9 @@
struct drm_event event;
struct drm_msm_hist *hist_data;
struct drm_msm_hist tmp_hist_data;
+ struct msm_drm_private *priv;
+ struct sde_kms *kms;
+ int ret;
u32 i, j;
if (!crtc_drm) {
@@ -1914,6 +1991,20 @@
if (!crtc->hist_blob)
return;
+ kms = get_kms(crtc_drm);
+ if (!kms || !kms->dev) {
+ SDE_ERROR("invalid arg(s)\n");
+ return;
+ }
+
+ priv = kms->dev->dev_private;
+ ret = sde_power_resource_enable(&priv->phandle, kms->core_client, true);
+ if (ret) {
+ SDE_ERROR("failed to enable power resource %d\n", ret);
+ SDE_EVT32(ret, SDE_EVTLOG_ERROR);
+ return;
+ }
+
/* read histogram data into blob */
hist_data = (struct drm_msm_hist *)crtc->hist_blob->data;
for (i = 0; i < crtc->num_mixers; i++) {
@@ -1921,6 +2012,8 @@
if (!hw_dspp || !hw_dspp->ops.read_histogram) {
DRM_ERROR("invalid dspp %pK or read_histogram func\n",
hw_dspp);
+ sde_power_resource_enable(&priv->phandle,
+ kms->core_client, false);
return;
}
if (!i) {
@@ -1933,6 +2026,8 @@
}
}
+ sde_power_resource_enable(&priv->phandle, kms->core_client,
+ false);
/* send histogram event with blob id */
event.length = sizeof(u32);
event.type = DRM_EVENT_HISTOGRAM;
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 21b67d9..f908e7f 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -417,13 +417,23 @@
sde_connector_get_info(connector, &info);
if (c_conn->ops.check_status &&
(info.capabilities & MSM_DISPLAY_ESD_ENABLED)) {
- if (en)
+ if (en) {
+ u32 interval;
+
+ /*
+ * If debugfs property is not set then take
+ * default value
+ */
+ interval = c_conn->esd_status_interval ?
+ c_conn->esd_status_interval :
+ STATUS_CHECK_INTERVAL_MS;
/* Schedule ESD status check */
schedule_delayed_work(&c_conn->status_work,
- msecs_to_jiffies(STATUS_CHECK_INTERVAL_MS));
- else
+ msecs_to_jiffies(interval));
+ } else {
/* Cancel any pending ESD status check */
cancel_delayed_work_sync(&c_conn->status_work);
+ }
}
}
@@ -1542,10 +1552,14 @@
sde_connector_get_info(connector, &info);
if (sde_connector->ops.check_status &&
- (info.capabilities & MSM_DISPLAY_ESD_ENABLED))
+ (info.capabilities & MSM_DISPLAY_ESD_ENABLED)) {
debugfs_create_u32("force_panel_dead", 0600,
connector->debugfs_entry,
&sde_connector->force_panel_dead);
+ debugfs_create_u32("esd_status_interval", 0600,
+ connector->debugfs_entry,
+ &sde_connector->esd_status_interval);
+ }
if (!debugfs_create_bool("fb_kmap", 0600, connector->debugfs_entry,
&sde_connector->fb_kmap)) {
@@ -1720,10 +1734,16 @@
}
if (rc > 0) {
+ u32 interval;
+
SDE_DEBUG("esd check status success conn_id: %d enc_id: %d\n",
conn->base.base.id, conn->encoder->base.id);
+
+ /* If debugfs property is not set then take default value */
+ interval = conn->esd_status_interval ?
+ conn->esd_status_interval : STATUS_CHECK_INTERVAL_MS;
schedule_delayed_work(&conn->status_work,
- msecs_to_jiffies(STATUS_CHECK_INTERVAL_MS));
+ msecs_to_jiffies(interval));
return;
}
@@ -1736,6 +1756,7 @@
event.length = sizeof(bool);
msm_mode_object_event_notify(&conn->base.base,
conn->base.dev, &event, (u8 *)&panel_dead);
+ sde_encoder_display_failure_notification(conn->encoder);
}
static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 9c37869..1495622 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -251,6 +251,12 @@
int (*config_hdr)(void *display,
struct sde_connector_state *c_state);
+ /**
+ * cont_splash_config - initialize splash resources
+ * @display: Pointer to private display handle
+ * Returns: zero for success, negetive for failure
+ */
+ int (*cont_splash_config)(void *display);
};
/**
@@ -307,6 +313,7 @@
* @bl_device: backlight device node
* @status_work: work object to perform status checks
* @force_panel_dead: variable to trigger forced ESD recovery
+ * @esd_status_interval: variable to change ESD check interval in millisec
* @bl_scale_dirty: Flag to indicate PP BL scale value(s) is changed
* @bl_scale: BL scale value for ABA feature
* @bl_scale_ad: BL scale value for AD feature
@@ -347,6 +354,7 @@
struct backlight_device *bl_device;
struct delayed_work status_work;
u32 force_panel_dead;
+ u32 esd_status_interval;
bool bl_scale_dirty;
u32 bl_scale;
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 8c1599e..7649012 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -38,15 +38,6 @@
#include "sde_power_handle.h"
#include "sde_core_perf.h"
#include "sde_trace.h"
-#include <soc/qcom/scm.h>
-#include "soc/qcom/secure_buffer.h"
-
-/* defines for secure channel call */
-#define SEC_SID_CNT 2
-#define SEC_SID_MASK_0 0x80881
-#define SEC_SID_MASK_1 0x80C81
-#define MEM_PROTECT_SD_CTRL_SWITCH 0x18
-#define MDP_DEVICE_ID 0x1A
#define SDE_PSTATES_MAX (SDE_STAGE_MAX * 4)
#define SDE_MULTIRECT_PLANE_MAX (SDE_STAGE_MAX * 2)
@@ -1330,15 +1321,6 @@
return -E2BIG;
}
- /**
- * TODO: Need to check against ROI alignment restrictions if partial
- * update support is added for destination scalar configurations
- */
- if (sde_crtc_state->num_ds_enabled) {
- SDE_ERROR("DS and PU concurrency is not supported\n");
- return -EINVAL;
- }
-
rc = _sde_crtc_set_crtc_roi(crtc, state);
if (rc)
return rc;
@@ -1795,8 +1777,9 @@
struct drm_plane *plane;
struct drm_encoder *encoder;
struct sde_crtc *sde_crtc;
- struct sde_crtc_state *cstate;
- struct sde_crtc_smmu_state_data *smmu_state;
+ struct sde_kms *sde_kms;
+ struct sde_mdss_cfg *catalog;
+ struct sde_kms_smmu_state_data *smmu_state;
uint32_t translation_mode = 0, secure_level;
int ops = 0;
bool post_commit = false;
@@ -1806,10 +1789,14 @@
return -EINVAL;
}
+ sde_kms = _sde_crtc_get_kms(crtc);
+ if (!sde_kms)
+ return -EINVAL;
+
+ smmu_state = &sde_kms->smmu_state;
sde_crtc = to_sde_crtc(crtc);
- cstate = to_sde_crtc_state(crtc->state);
- smmu_state = &sde_crtc->smmu_state;
secure_level = sde_crtc_get_secure_level(crtc, crtc->state);
+ catalog = sde_kms->catalog;
SDE_DEBUG("crtc%d, secure_level%d old_valid_fb%d\n",
crtc->base.id, secure_level, old_valid_fb);
@@ -1850,6 +1837,8 @@
break;
}
+ mutex_lock(&sde_kms->secure_transition_lock);
+
switch (translation_mode) {
case SDE_DRM_FB_SEC_DIR_TRANS:
/* secure display usecase */
@@ -1857,18 +1846,22 @@
(secure_level == SDE_DRM_SEC_ONLY)) {
smmu_state->state = DETACH_ALL_REQ;
smmu_state->transition_type = PRE_COMMIT;
- ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
+ ops |= SDE_KMS_OPS_SECURE_STATE_CHANGE;
if (old_valid_fb) {
ops |= (SDE_KMS_OPS_WAIT_FOR_TX_DONE |
SDE_KMS_OPS_CLEANUP_PLANE_FB);
}
+ if (catalog->sui_misr_supported)
+ smmu_state->sui_misr_state =
+ SUI_MISR_ENABLE_REQ;
/* secure camera usecase */
} else if (smmu_state->state == ATTACHED) {
smmu_state->state = DETACH_SEC_REQ;
smmu_state->transition_type = PRE_COMMIT;
- ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
+ ops |= SDE_KMS_OPS_SECURE_STATE_CHANGE;
}
break;
+
case SDE_DRM_FB_SEC:
case SDE_DRM_FB_NON_SEC:
if ((smmu_state->state == DETACHED_SEC) ||
@@ -1876,7 +1869,7 @@
smmu_state->state = ATTACH_SEC_REQ;
smmu_state->transition_type = post_commit ?
POST_COMMIT : PRE_COMMIT;
- ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
+ ops |= SDE_KMS_OPS_SECURE_STATE_CHANGE;
if (old_valid_fb)
ops |= SDE_KMS_OPS_WAIT_FOR_TX_DONE;
} else if ((smmu_state->state == DETACHED) ||
@@ -1884,16 +1877,19 @@
smmu_state->state = ATTACH_ALL_REQ;
smmu_state->transition_type = post_commit ?
POST_COMMIT : PRE_COMMIT;
- ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
+ ops |= SDE_KMS_OPS_SECURE_STATE_CHANGE;
if (old_valid_fb)
ops |= (SDE_KMS_OPS_WAIT_FOR_TX_DONE |
SDE_KMS_OPS_CLEANUP_PLANE_FB);
+ if (catalog->sui_misr_supported)
+ smmu_state->sui_misr_state =
+ SUI_MISR_DISABLE_REQ;
}
break;
+
default:
SDE_ERROR("invalid plane fb_mode:%d\n", translation_mode);
- ops = 0;
- return -EINVAL;
+ ops = -EINVAL;
}
SDE_DEBUG("SMMU State:%d, type:%d ops:%x\n", smmu_state->state,
@@ -1903,58 +1899,13 @@
SDE_EVT32(DRMID(crtc), secure_level, translation_mode,
smmu_state->state, smmu_state->transition_type,
ops, old_valid_fb, SDE_EVTLOG_FUNC_EXIT);
+
+ mutex_unlock(&sde_kms->secure_transition_lock);
+
return ops;
}
/**
- * _sde_crtc_scm_call - makes secure channel call to switch the VMIDs
- * @vimd: switch the stage 2 translation to this VMID.
- */
-static int _sde_crtc_scm_call(int vmid)
-{
- struct scm_desc desc = {0};
- uint32_t num_sids;
- uint32_t *sec_sid;
- uint32_t mem_protect_sd_ctrl_id = MEM_PROTECT_SD_CTRL_SWITCH;
- int ret = 0;
-
- /* This info should be queried from catalog */
- num_sids = SEC_SID_CNT;
- sec_sid = kcalloc(num_sids, sizeof(uint32_t), GFP_KERNEL);
- if (!sec_sid)
- return -ENOMEM;
-
- /**
- * derive this info from device tree/catalog, this is combination of
- * smr mask and SID for secure
- */
- sec_sid[0] = SEC_SID_MASK_0;
- sec_sid[1] = SEC_SID_MASK_1;
- dmac_flush_range(sec_sid, sec_sid + num_sids);
-
- SDE_DEBUG("calling scm_call for vmid %d", vmid);
-
- desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
- desc.args[0] = MDP_DEVICE_ID;
- desc.args[1] = SCM_BUFFER_PHYS(sec_sid);
- desc.args[2] = sizeof(uint32_t) * num_sids;
- desc.args[3] = vmid;
-
- ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
- mem_protect_sd_ctrl_id), &desc);
- if (ret) {
- SDE_ERROR("Error:scm_call2, vmid (%lld): ret%d\n",
- desc.args[3], ret);
- }
- SDE_EVT32(mem_protect_sd_ctrl_id,
- desc.args[0], desc.args[3], num_sids,
- sec_sid[0], sec_sid[1], ret);
-
- kfree(sec_sid);
- return ret;
-}
-
-/**
* _sde_crtc_setup_scaler3_lut - Set up scaler lut
* LUTs are configured only once during boot
* @sde_crtc: Pointer to sde crtc
@@ -2024,130 +1975,6 @@
sde_fence_timeline_status(&sde_crtc->output_fence, &crtc->base);
}
-/**
- * sde_crtc_secure_ctrl - Initiates the operations to swtich between secure
- * and non-secure mode
- * @crtc: Pointer to crtc
- * @post_commit: if this operation is triggered after commit
- */
-int sde_crtc_secure_ctrl(struct drm_crtc *crtc, bool post_commit)
-{
- struct sde_crtc *sde_crtc;
- struct sde_crtc_state *cstate;
- struct sde_kms *sde_kms;
- struct sde_crtc_smmu_state_data *smmu_state;
- int ret = 0;
- int old_smmu_state;
-
- if (!crtc || !crtc->state) {
- SDE_ERROR("invalid crtc\n");
- return -EINVAL;
- }
-
- sde_kms = _sde_crtc_get_kms(crtc);
- if (!sde_kms) {
- SDE_ERROR("invalid kms\n");
- return -EINVAL;
- }
-
- sde_crtc = to_sde_crtc(crtc);
- cstate = to_sde_crtc_state(crtc->state);
- smmu_state = &sde_crtc->smmu_state;
- old_smmu_state = smmu_state->state;
-
- SDE_EVT32(DRMID(crtc), smmu_state->state, smmu_state->transition_type,
- post_commit, SDE_EVTLOG_FUNC_ENTRY);
-
- if ((!smmu_state->transition_type) ||
- ((smmu_state->transition_type == POST_COMMIT) && !post_commit))
- /* Bail out */
- return 0;
-
- /* Secure UI use case enable */
- switch (smmu_state->state) {
- case DETACH_ALL_REQ:
- /* detach_all_contexts */
- ret = sde_kms_mmu_detach(sde_kms, false);
- if (ret) {
- SDE_ERROR("crtc: %d, failed to detach %d\n",
- crtc->base.id, ret);
- goto error;
- }
-
- ret = _sde_crtc_scm_call(VMID_CP_SEC_DISPLAY);
- if (ret)
- goto error;
-
- smmu_state->state = DETACHED;
- break;
- /* Secure UI use case disable */
- case ATTACH_ALL_REQ:
- ret = _sde_crtc_scm_call(VMID_CP_PIXEL);
- if (ret)
- goto error;
-
- /* attach_all_contexts */
- ret = sde_kms_mmu_attach(sde_kms, false);
- if (ret) {
- SDE_ERROR("crtc: %d, failed to attach %d\n",
- crtc->base.id,
- ret);
- goto error;
- }
-
- smmu_state->state = ATTACHED;
-
- break;
- /* Secure preview enable */
- case DETACH_SEC_REQ:
- /* detach secure_context */
- ret = sde_kms_mmu_detach(sde_kms, true);
- if (ret) {
- SDE_ERROR("crtc: %d, failed to detach %d\n",
- crtc->base.id,
- ret);
- goto error;
- }
-
- smmu_state->state = DETACHED_SEC;
- ret = _sde_crtc_scm_call(VMID_CP_CAMERA_PREVIEW);
- if (ret)
- goto error;
-
- break;
-
- /* Secure preview disable */
- case ATTACH_SEC_REQ:
- ret = _sde_crtc_scm_call(VMID_CP_PIXEL);
- if (ret)
- goto error;
-
- ret = sde_kms_mmu_attach(sde_kms, true);
- if (ret) {
- SDE_ERROR("crtc: %d, failed to attach %d\n",
- crtc->base.id,
- ret);
- goto error;
- }
- smmu_state->state = ATTACHED;
- break;
- default:
- break;
- }
-
- SDE_DEBUG("crtc: %d, old_state %d new_state %d\n", crtc->base.id,
- old_smmu_state,
- smmu_state->state);
- smmu_state->transition_type = NONE;
-
-error:
- smmu_state->transition_error = ret ? true : false;
- SDE_EVT32(DRMID(crtc), smmu_state->state, smmu_state->transition_type,
- smmu_state->transition_error, ret,
- SDE_EVTLOG_FUNC_EXIT);
- return ret;
-}
-
static int _sde_validate_hw_resources(struct sde_crtc *sde_crtc)
{
int i;
@@ -2583,7 +2410,6 @@
struct drm_crtc_state *old_state)
{
struct sde_crtc *sde_crtc;
- struct sde_crtc_smmu_state_data *smmu_state;
if (!crtc || !crtc->state) {
SDE_ERROR("invalid crtc\n");
@@ -2592,13 +2418,8 @@
sde_crtc = to_sde_crtc(crtc);
SDE_EVT32_VERBOSE(DRMID(crtc));
- smmu_state = &sde_crtc->smmu_state;
sde_core_perf_crtc_update(crtc, 0, false);
-
- /* complete secure transitions if any */
- if (smmu_state->transition_type == POST_COMMIT)
- sde_crtc_secure_ctrl(crtc, true);
}
/**
@@ -3204,7 +3025,7 @@
struct drm_encoder *encoder;
struct drm_device *dev;
unsigned long flags;
- struct sde_crtc_smmu_state_data *smmu_state;
+ struct sde_kms *sde_kms;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
@@ -3222,11 +3043,14 @@
return;
}
+ sde_kms = _sde_crtc_get_kms(crtc);
+ if (!sde_kms)
+ return;
+
SDE_DEBUG("crtc%d\n", crtc->base.id);
sde_crtc = to_sde_crtc(crtc);
dev = crtc->dev;
- smmu_state = &sde_crtc->smmu_state;
if (!sde_crtc->num_mixers) {
_sde_crtc_setup_mixers(crtc);
@@ -3269,14 +3093,11 @@
/*
* Since CP properties use AXI buffer to program the
- * HW, check if context bank is in attached
- * state,
+ * HW, check if context bank is in attached state,
* apply color processing properties only if
* smmu state is attached,
*/
- if ((smmu_state->state != DETACHED) &&
- (smmu_state->state != DETACH_ALL_REQ) &&
- sde_crtc->enabled)
+ if (!sde_kms_is_secure_session_inprogress(sde_kms))
sde_cp_crtc_apply_properties(crtc);
/*
@@ -3299,6 +3120,7 @@
struct msm_drm_thread *event_thread;
unsigned long flags;
struct sde_crtc_state *cstate;
+ struct sde_kms *sde_kms;
int idle_time = 0;
if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
@@ -3317,6 +3139,12 @@
return;
}
+ sde_kms = _sde_crtc_get_kms(crtc);
+ if (!sde_kms) {
+ SDE_ERROR("invalid kms\n");
+ return;
+ }
+
SDE_DEBUG("crtc%d\n", crtc->base.id);
sde_crtc = to_sde_crtc(crtc);
@@ -3390,7 +3218,7 @@
* everything" call below.
*/
drm_atomic_crtc_for_each_plane(plane, crtc) {
- if (sde_crtc->smmu_state.transition_error)
+ if (sde_kms->smmu_state.transition_error)
sde_plane_set_error(plane, true);
sde_plane_flush(plane);
}
@@ -4486,46 +4314,6 @@
return rc;
}
-static int _sde_crtc_excl_rect_overlap_check(struct plane_state pstates[],
- int cnt, int curr_cnt, struct sde_rect *excl_rect)
-{
- struct sde_rect dst_rect, intersect;
- int i, rc = -EINVAL;
- const struct drm_plane_state *pstate;
-
- for (i = 0; i < cnt; i++) {
- if (i == curr_cnt)
- continue;
-
- pstate = pstates[i].drm_pstate;
- POPULATE_RECT(&dst_rect, pstate->crtc_x, pstate->crtc_y,
- pstate->crtc_w, pstate->crtc_h, false);
- sde_kms_rect_intersect(&dst_rect, excl_rect, &intersect);
-
- /* complete intersection of excl_rect is required */
- if (intersect.w == excl_rect->w && intersect.h == excl_rect->h
- /* intersecting rect should be in another z_order */
- && pstates[curr_cnt].stage != pstates[i].stage) {
- rc = 0;
- goto end;
- }
- }
-
- SDE_ERROR(
- "no overlapping rect for [%d] z_pos:%d, excl_rect:{%d,%d,%d,%d}\n",
- i, pstates[curr_cnt].stage,
- excl_rect->x, excl_rect->y, excl_rect->w, excl_rect->h);
- for (i = 0; i < cnt; i++) {
- pstate = pstates[i].drm_pstate;
- SDE_ERROR("[%d] p:%d, z_pos:%d, src:{%d,%d,%d,%d}\n",
- i, pstate->plane->base.id, pstates[i].stage,
- pstate->crtc_x, pstate->crtc_y,
- pstate->crtc_w, pstate->crtc_h);
- }
-end:
- return rc;
-}
-
/* no input validation - caller API has all the checks */
static int _sde_crtc_excl_dim_layer_check(struct drm_crtc_state *state,
struct plane_state pstates[], int cnt)
@@ -4558,17 +4346,16 @@
}
}
- /* this is traversing on sorted z-order pstates */
+ /* log all src and excl_rect, useful for debugging */
for (i = 0; i < cnt; i++) {
pstate = pstates[i].drm_pstate;
sde_pstate = to_sde_plane_state(pstate);
- if (sde_pstate->excl_rect.w && sde_pstate->excl_rect.h) {
- /* check overlap on any other z-order */
- rc = _sde_crtc_excl_rect_overlap_check(pstates, cnt,
- i, &sde_pstate->excl_rect);
- if (rc)
- goto end;
- }
+ SDE_DEBUG("p %d z %d src{%d,%d,%d,%d} excl_rect{%d,%d,%d,%d}\n",
+ pstate->plane->base.id, pstates[i].stage,
+ pstate->crtc_x, pstate->crtc_y,
+ pstate->crtc_w, pstate->crtc_h,
+ sde_pstate->excl_rect.x, sde_pstate->excl_rect.y,
+ sde_pstate->excl_rect.w, sde_pstate->excl_rect.h);
}
end:
@@ -4579,10 +4366,12 @@
struct drm_crtc_state *state, struct plane_state pstates[],
int cnt)
{
+ struct drm_plane *plane;
struct drm_encoder *encoder;
struct sde_crtc_state *cstate;
struct sde_crtc *sde_crtc;
- struct sde_crtc_smmu_state_data *smmu_state;
+ struct sde_kms *sde_kms;
+ struct sde_kms_smmu_state_data *smmu_state;
uint32_t secure;
uint32_t fb_ns = 0, fb_sec = 0, fb_sec_dir = 0;
int encoder_cnt = 0, i;
@@ -4594,6 +4383,12 @@
return -EINVAL;
}
+ sde_kms = _sde_crtc_get_kms(crtc);
+ if (!sde_kms) {
+ SDE_ERROR("invalid kms\n");
+ return -EINVAL;
+ }
+
cstate = to_sde_crtc_state(state);
secure = sde_crtc_get_property(cstate, CRTC_PROP_SECURITY_LEVEL);
@@ -4617,8 +4412,25 @@
return -EINVAL;
}
- /* only one blending stage is allowed in sec_crtc */
+ /*
+ * - only one blending stage is allowed in sec_crtc
+ * - validate if pipe is allowed for sec-ui updates
+ */
for (i = 1; i < cnt; i++) {
+ if (!pstates[i].drm_pstate
+ || !pstates[i].drm_pstate->plane) {
+ SDE_ERROR("crtc%d: invalid pstate at i:%d\n",
+ crtc->base.id, i);
+ return -EINVAL;
+ }
+ plane = pstates[i].drm_pstate->plane;
+
+ if (!sde_plane_is_sec_ui_allowed(plane)) {
+ SDE_ERROR("crtc%d: sec-ui not allowed in p%d\n",
+ crtc->base.id, plane->base.id);
+ return -EINVAL;
+ }
+
if (pstates[i].stage != pstates[i-1].stage) {
SDE_ERROR(
"crtc%d: invalid blend stages %d:%d, %d:%d\n",
@@ -4655,7 +4467,7 @@
}
sde_crtc = to_sde_crtc(crtc);
- smmu_state = &sde_crtc->smmu_state;
+ smmu_state = &sde_kms->smmu_state;
/*
* In video mode check for null commit before transition
* from secure to non secure and vice versa
@@ -5500,6 +5312,46 @@
return ret;
}
+void sde_crtc_misr_setup(struct drm_crtc *crtc, bool enable, u32 frame_count)
+{
+ struct sde_kms *sde_kms;
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_mixer *m;
+ int i;
+
+ if (!crtc) {
+ SDE_ERROR("invalid argument\n");
+ return;
+ }
+ sde_crtc = to_sde_crtc(crtc);
+
+ sde_kms = _sde_crtc_get_kms(crtc);
+ if (!sde_kms) {
+ SDE_ERROR("invalid sde_kms\n");
+ return;
+ }
+
+ mutex_lock(&sde_crtc->crtc_lock);
+ if (sde_kms_is_secure_session_inprogress(sde_kms)) {
+ SDE_DEBUG("crtc:%d misr enable/disable not allowed\n",
+ DRMID(crtc));
+ mutex_unlock(&sde_crtc->crtc_lock);
+ return;
+ }
+
+ sde_crtc->misr_enable = enable;
+ sde_crtc->misr_frame_count = frame_count;
+ for (i = 0; i < sde_crtc->num_mixers; ++i) {
+ sde_crtc->misr_data[i] = 0;
+ m = &sde_crtc->mixers[i];
+ if (!m->hw_lm || !m->hw_lm->ops.setup_misr)
+ continue;
+
+ m->hw_lm->ops.setup_misr(m->hw_lm, enable, frame_count);
+ }
+ mutex_unlock(&sde_crtc->crtc_lock);
+}
+
#ifdef CONFIG_DEBUG_FS
static int _sde_debugfs_status_show(struct seq_file *s, void *data)
{
@@ -5647,9 +5499,9 @@
static ssize_t _sde_crtc_misr_setup(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos)
{
+ struct drm_crtc *crtc;
struct sde_crtc *sde_crtc;
- struct sde_crtc_mixer *m;
- int i = 0, rc;
+ int rc;
char buf[MISR_BUFF_SIZE + 1];
u32 frame_count, enable;
size_t buff_copy;
@@ -5658,6 +5510,8 @@
return -EINVAL;
sde_crtc = file->private_data;
+ crtc = &sde_crtc->base;
+
buff_copy = min_t(size_t, count, MISR_BUFF_SIZE);
if (copy_from_user(buf, user_buf, buff_copy)) {
SDE_ERROR("buffer copy failed\n");
@@ -5673,18 +5527,7 @@
if (rc)
return rc;
- mutex_lock(&sde_crtc->crtc_lock);
- sde_crtc->misr_enable = enable;
- sde_crtc->misr_frame_count = frame_count;
- for (i = 0; i < sde_crtc->num_mixers; ++i) {
- sde_crtc->misr_data[i] = 0;
- m = &sde_crtc->mixers[i];
- if (!m->hw_lm || !m->hw_lm->ops.setup_misr)
- continue;
-
- m->hw_lm->ops.setup_misr(m->hw_lm, enable, frame_count);
- }
- mutex_unlock(&sde_crtc->crtc_lock);
+ sde_crtc_misr_setup(crtc, enable, frame_count);
_sde_crtc_power_enable(sde_crtc, false);
return count;
@@ -5693,7 +5536,9 @@
static ssize_t _sde_crtc_misr_read(struct file *file,
char __user *user_buff, size_t count, loff_t *ppos)
{
+ struct drm_crtc *crtc;
struct sde_crtc *sde_crtc;
+ struct sde_kms *sde_kms;
struct sde_crtc_mixer *m;
int i = 0, rc;
u32 misr_status;
@@ -5707,11 +5552,21 @@
return -EINVAL;
sde_crtc = file->private_data;
+ crtc = &sde_crtc->base;
+ sde_kms = _sde_crtc_get_kms(crtc);
+ if (!sde_kms)
+ return -EINVAL;
+
rc = _sde_crtc_power_enable(sde_crtc, true);
if (rc)
return rc;
mutex_lock(&sde_crtc->crtc_lock);
+ if (sde_kms_is_secure_session_inprogress(sde_kms)) {
+ SDE_DEBUG("crtc:%d misr read not allowed\n", DRMID(crtc));
+ goto end;
+ }
+
if (!sde_crtc->misr_enable) {
len += snprintf(buf + len, MISR_BUFF_SIZE - len,
"disabled\n");
@@ -6227,6 +6082,7 @@
spin_lock_irqsave(&crtc->spin_lock, flags);
list_for_each_entry(node, &crtc->user_event_list, list) {
if (node->event == event) {
+ list_del(&node->list);
found = true;
break;
}
@@ -6242,7 +6098,6 @@
* no need to disable/de-register.
*/
if (!crtc_drm->enabled) {
- list_del(&node->list);
kfree(node);
return 0;
}
@@ -6251,13 +6106,11 @@
if (ret) {
SDE_ERROR("failed to enable power resource %d\n", ret);
SDE_EVT32(ret, SDE_EVTLOG_ERROR);
- list_del(&node->list);
kfree(node);
return ret;
}
ret = node->func(crtc_drm, false, &node->irq);
- list_del(&node->list);
kfree(node);
sde_power_resource_enable(&priv->phandle, kms->core_client, false);
return ret;
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 21ce3db..bc1614c 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -48,50 +48,6 @@
};
/**
- * enum sde_crtc_smmu_state: smmu state
- * @ATTACHED: all the context banks are attached.
- * @DETACHED: all the context banks are detached.
- * @DETACHED_SEC: secure context bank is detached.
- * @ATTACH_ALL_REQ: transient state of attaching context banks.
- * @DETACH_ALL_REQ: transient state of detaching context banks.
- * @DETACH_SEC_REQ: tranisent state of secure context bank is detached
- * @ATTACH_SEC_REQ: transient state of attaching secure context bank.
- */
-enum sde_crtc_smmu_state {
- ATTACHED = 0,
- DETACHED,
- DETACHED_SEC,
- ATTACH_ALL_REQ,
- DETACH_ALL_REQ,
- DETACH_SEC_REQ,
- ATTACH_SEC_REQ,
-};
-
-/**
- * enum sde_crtc_smmu_state_transition_type: state transition type
- * @NONE: no pending state transitions
- * @PRE_COMMIT: state transitions should be done before processing the commit
- * @POST_COMMIT: state transitions to be done after processing the commit.
- */
-enum sde_crtc_smmu_state_transition_type {
- NONE,
- PRE_COMMIT,
- POST_COMMIT
-};
-
-/**
- * struct sde_crtc_smmu_state_data: stores the smmu state and transition type
- * @state: current state of smmu context banks
- * @transition_type: transition request type
- * @transition_error: whether there is error while transitioning the state
- */
-struct sde_crtc_smmu_state_data {
- uint32_t state;
- uint32_t transition_type;
- uint32_t transition_error;
-};
-
-/**
* @connectors : Currently associated drm connectors for retire event
* @num_connectors: Number of associated drm connectors for retire event
* @list: event list
@@ -300,8 +256,6 @@
struct mutex rp_lock;
struct list_head rp_head;
- struct sde_crtc_smmu_state_data smmu_state;
-
/* blob for histogram data */
struct drm_property_blob *hist_blob;
};
@@ -787,4 +741,12 @@
*/
uint64_t sde_crtc_get_sbuf_clk(struct drm_crtc_state *state);
+/**
+ * sde_crtc_misr_setup - to configure and enable/disable MISR
+ * @crtc: Pointer to drm crtc structure
+ * @enable: boolean to indicate enable/disable misr
+ * @frame_count: frame_count to be configured
+ */
+void sde_crtc_misr_setup(struct drm_crtc *crtc, bool enable, u32 frame_count);
+
#endif /* _SDE_CRTC_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index e0023d0..1614c83 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -203,6 +203,7 @@
* clks and resources after IDLE_TIMEOUT time.
* @vsync_event_work: worker to handle vsync event for autorefresh
* @input_event_work: worker to handle input device touch events
+ * @esd_trigger_work: worker to handle esd trigger events
* @input_handler: handler for input device events
* @topology: topology of the display
* @vblank_enabled: boolean to track userspace vblank vote
@@ -249,6 +250,7 @@
struct kthread_delayed_work delayed_off_work;
struct kthread_work vsync_event_work;
struct kthread_work input_event_work;
+ struct kthread_work esd_trigger_work;
struct input_handler *input_handler;
struct msm_display_topology topology;
bool vblank_enabled;
@@ -1513,6 +1515,29 @@
return ret;
}
+static int _sde_encoder_switch_to_watchdog_vsync(struct drm_encoder *drm_enc)
+{
+ struct sde_encoder_virt *sde_enc;
+ struct msm_display_info disp_info;
+
+ if (!drm_enc) {
+ pr_err("invalid drm encoder\n");
+ return -EINVAL;
+ }
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+
+ sde_encoder_control_te(drm_enc, false);
+
+ memcpy(&disp_info, &sde_enc->disp_info, sizeof(disp_info));
+ disp_info.is_te_using_watchdog_timer = true;
+ _sde_encoder_update_vsync_source(sde_enc, &disp_info, false);
+
+ sde_encoder_control_te(drm_enc, true);
+
+ return 0;
+}
+
static int _sde_encoder_update_rsc_client(
struct drm_encoder *drm_enc,
struct sde_encoder_rsc_config *config, bool enable)
@@ -1652,7 +1677,12 @@
if (ret) {
SDE_ERROR_ENC(sde_enc,
"wait for vblank failed ret:%d\n", ret);
- break;
+ /**
+ * rsc hardware may hang without vsync. avoid rsc hang
+ * by generating the vsync from watchdog timer.
+ */
+ if (crtc->base.id == wait_vblank_crtc_id)
+ _sde_encoder_switch_to_watchdog_vsync(drm_enc);
}
}
@@ -2546,6 +2576,9 @@
return;
}
+ if (drm_enc->crtc && !sde_enc->crtc)
+ sde_enc->crtc = drm_enc->crtc;
+
comp_info = &mode_info.comp_info;
cur_mode = &sde_enc->base.crtc->state->adjusted_mode;
@@ -3508,6 +3541,20 @@
&sde_enc->vsync_event_work);
}
+static void sde_encoder_esd_trigger_work_handler(struct kthread_work *work)
+{
+ struct sde_encoder_virt *sde_enc = container_of(work,
+ struct sde_encoder_virt, esd_trigger_work);
+
+ if (!sde_enc) {
+ SDE_ERROR("invalid sde encoder\n");
+ return;
+ }
+
+ sde_encoder_resource_control(&sde_enc->base,
+ SDE_ENC_RC_EVENT_KICKOFF);
+}
+
static void sde_encoder_input_event_work_handler(struct kthread_work *work)
{
struct sde_encoder_virt *sde_enc = container_of(work,
@@ -4497,6 +4544,9 @@
kthread_init_work(&sde_enc->input_event_work,
sde_encoder_input_event_work_handler);
+ kthread_init_work(&sde_enc->esd_trigger_work,
+ sde_encoder_esd_trigger_work_handler);
+
memcpy(&sde_enc->disp_info, disp_info, sizeof(*disp_info));
SDE_DEBUG_ENC(sde_enc, "created\n");
@@ -4755,3 +4805,44 @@
return ret;
}
+
+int sde_encoder_display_failure_notification(struct drm_encoder *enc)
+{
+ struct msm_drm_thread *disp_thread = NULL;
+ struct msm_drm_private *priv = NULL;
+ struct sde_encoder_virt *sde_enc = NULL;
+
+ if (!enc || !enc->dev || !enc->dev->dev_private) {
+ SDE_ERROR("invalid parameters\n");
+ return -EINVAL;
+ }
+
+ priv = enc->dev->dev_private;
+ sde_enc = to_sde_encoder_virt(enc);
+ if (!sde_enc->crtc || (sde_enc->crtc->index
+ >= ARRAY_SIZE(priv->disp_thread))) {
+ SDE_DEBUG_ENC(sde_enc,
+ "invalid cached CRTC: %d or crtc index: %d\n",
+ sde_enc->crtc == NULL,
+ sde_enc->crtc ? sde_enc->crtc->index : -EINVAL);
+ return -EINVAL;
+ }
+
+ SDE_EVT32_VERBOSE(DRMID(enc));
+
+ disp_thread = &priv->disp_thread[sde_enc->crtc->index];
+
+ kthread_queue_work(&disp_thread->worker,
+ &sde_enc->esd_trigger_work);
+ kthread_flush_work(&sde_enc->esd_trigger_work);
+ /**
+ * panel may stop generating te signal (vsync) during esd failure. rsc
+ * hardware may hang without vsync. Avoid rsc hang by generating the
+ * vsync from watchdog timer instead of panel.
+ */
+ _sde_encoder_switch_to_watchdog_vsync(enc);
+
+ sde_encoder_wait_for_event(enc, MSM_ENC_TX_COMPLETE);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index 2c84e20..0e8e9dd 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -237,4 +237,19 @@
*/
int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder);
+/**
+ * sde_encoder_display_failure_notification - update sde encoder state for
+ * esd timeout or other display failure notification. This event flows from
+ * dsi, sde_connector to sde_encoder.
+ *
+ * This api must not be called from crtc_commit (display) thread because it
+ * requests the flush work on same thread. It is called from esd check thread
+ * based on current design.
+ *
+ * TODO: manage the event at sde_kms level for forward processing.
+ * @drm_enc: Pointer to drm encoder structure
+ * @Return: true if successful in updating the encoder structure
+ */
+int sde_encoder_display_failure_notification(struct drm_encoder *enc);
+
#endif /* __SDE_ENCODER_H__ */
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 53c8dfb..792654d 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018 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
@@ -450,6 +450,17 @@
cmd_enc->pp_timeout_report_cnt++;
+ if (sde_encoder_phys_cmd_is_master(phys_enc)) {
+ /* trigger the retire fence if it was missed */
+ if (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);
+ atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0);
+ }
+
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),
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index cdc6a9c..92c74d8 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -80,6 +80,17 @@
#define LINE_LM_OFFSET 5
#define LINE_MODE_WB_OFFSET 2
+/**
+ * these configurations are decided based on max mdp clock. It accounts
+ * for max and min display resolution based on virtual hardware resource
+ * support.
+ */
+#define MAX_DISPLAY_HEIGHT_WITH_DECIMATION 2160
+#define MAX_DISPLAY_HEIGHT 5120
+#define MIN_DISPLAY_HEIGHT 0
+#define MIN_DISPLAY_WIDTH 0
+#define MAX_LM_PER_DISPLAY 2
+
/* maximum XIN halt timeout in usec */
#define VBIF_XIN_HALT_TIMEOUT 0x4000
@@ -3216,7 +3227,7 @@
return rc;
}
-static int _sde_hardware_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
+static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
{
int rc = 0;
@@ -3249,6 +3260,56 @@
return rc;
}
+static int _sde_hardware_post_caps(struct sde_mdss_cfg *sde_cfg,
+ uint32_t hw_rev)
+{
+ int rc = 0, i;
+ u32 max_horz_deci = 0, max_vert_deci = 0;
+
+ if (!sde_cfg)
+ return -EINVAL;
+
+ for (i = 0; i < sde_cfg->sspp_count; i++) {
+ if (sde_cfg->sspp[i].sblk) {
+ max_horz_deci = max(max_horz_deci,
+ sde_cfg->sspp[i].sblk->maxhdeciexp);
+ max_vert_deci = max(max_vert_deci,
+ sde_cfg->sspp[i].sblk->maxvdeciexp);
+ }
+
+ /*
+ * set sec-ui blocked SSPP feature flag based on blocked
+ * xin-mask if sec-ui-misr feature is enabled;
+ */
+ if (sde_cfg->sui_misr_supported
+ && (sde_cfg->sui_block_xin_mask
+ & BIT(sde_cfg->sspp[i].xin_id)))
+ set_bit(SDE_SSPP_BLOCK_SEC_UI,
+ &sde_cfg->sspp[i].features);
+ }
+
+ /* this should be updated based on HW rev in future */
+ sde_cfg->max_lm_per_display = MAX_LM_PER_DISPLAY;
+
+ if (max_horz_deci)
+ sde_cfg->max_display_width = sde_cfg->max_sspp_linewidth *
+ max_horz_deci;
+ else
+ sde_cfg->max_display_width = sde_cfg->max_mixer_width *
+ sde_cfg->max_lm_per_display;
+
+ if (max_vert_deci)
+ sde_cfg->max_display_height =
+ MAX_DISPLAY_HEIGHT_WITH_DECIMATION * max_vert_deci;
+ else
+ sde_cfg->max_display_height = MAX_DISPLAY_HEIGHT;
+
+ sde_cfg->min_display_height = MIN_DISPLAY_HEIGHT;
+ sde_cfg->min_display_width = MIN_DISPLAY_WIDTH;
+
+ return rc;
+}
+
void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg)
{
int i;
@@ -3307,7 +3368,7 @@
sde_cfg->hwversion = hw_rev;
- rc = _sde_hardware_caps(sde_cfg, hw_rev);
+ rc = _sde_hardware_pre_caps(sde_cfg, hw_rev);
if (rc)
goto end;
@@ -3379,6 +3440,10 @@
if (rc)
goto end;
+ rc = _sde_hardware_post_caps(sde_cfg, hw_rev);
+ if (rc)
+ goto end;
+
return sde_cfg;
end:
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index aa6c482..963b48f 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -120,6 +120,7 @@
* @SDE_SSPP_TS_PREFILL Supports prefill with traffic shaper
* @SDE_SSPP_TS_PREFILL_REC1 Supports prefill with traffic shaper multirec
* @SDE_SSPP_CDP Supports client driven prefetch
+ * @SDE_SSPP_BLOCK_SEC_UI Blocks secure-ui layers
* @SDE_SSPP_MAX maximum value
*/
enum {
@@ -143,6 +144,7 @@
SDE_SSPP_TS_PREFILL,
SDE_SSPP_TS_PREFILL_REC1,
SDE_SSPP_CDP,
+ SDE_SSPP_BLOCK_SEC_UI,
SDE_SSPP_MAX
};
@@ -909,6 +911,11 @@
* @max_mixer_blendstages max layer mixer blend stages or
* supported z order
* @max_wb_linewidth max writeback line width support.
+ * @max_display_width maximum display width support.
+ * @max_display_height maximum display height support.
+ * @max_lm_per_display maximum layer mixer per display
+ * @min_display_width minimum display width support.
+ * @min_display_height minimum display height support.
* @qseed_type qseed2 or qseed3 support.
* @csc_type csc or csc_10bit support.
* @smart_dma_rev Supported version of SmartDMA feature.
@@ -927,6 +934,9 @@
* @wb_formats Supported formats for wb
* @vbif_qos_nlvl number of vbif QoS priority level
* @ts_prefill_rev prefill traffic shaper feature revision
+ * @sui_misr_supported indicate if secure-ui-misr is supported
+ * @sui_block_xin_mask mask of all the xin-clients to be blocked during
+ * secure-ui when secure-ui-misr feature is supported
*/
struct sde_mdss_cfg {
u32 hwversion;
@@ -935,6 +945,13 @@
u32 max_mixer_width;
u32 max_mixer_blendstages;
u32 max_wb_linewidth;
+
+ u32 max_display_width;
+ u32 max_display_height;
+ u32 min_display_width;
+ u32 min_display_height;
+ u32 max_lm_per_display;
+
u32 qseed_type;
u32 csc_type;
u32 smart_dma_rev;
@@ -950,6 +967,9 @@
u32 vbif_qos_nlvl;
u32 ts_prefill_rev;
+ bool sui_misr_supported;
+ u32 sui_block_xin_mask;
+
bool has_hdr;
u32 mdss_count;
struct sde_mdss_base_cfg mdss[MAX_BLOCKS];
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 0dc3fed..01d2f52 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -24,8 +24,7 @@
#define GAMUT_LUT_MEM_SIZE ((sizeof(struct drm_msm_3d_gamut)) + \
REG_DMA_HEADERS_BUFFER_SZ)
-#define GAMUT_SCALE_OFF_LEN (GAMUT_3D_SCALE_OFF_SZ * \
- GAMUT_3D_SCALE_OFF_TBL_NUM * sizeof(u32))
+#define GAMUT_SCALE_OFF_LEN (GAMUT_3D_SCALE_OFF_SZ * sizeof(u32))
#define GAMUT_SCALE_OFF_LEN_12 (GAMUT_3D_SCALEB_OFF_SZ * sizeof(u32))
#define GC_LUT_MEM_SIZE ((sizeof(struct drm_msm_pgc_lut)) + \
@@ -248,6 +247,32 @@
return rc;
}
+bool reg_dmav1_dspp_feature_support(int feature)
+{
+ struct sde_hw_reg_dma_ops *dma_ops;
+ bool is_supported = false;
+
+ if (feature >= SDE_DSPP_MAX) {
+ DRM_ERROR("invalid feature %x max %x\n",
+ feature, SDE_DSPP_MAX);
+ return is_supported;
+ }
+
+ if (feature_map[feature] >= REG_DMA_FEATURES_MAX) {
+ DRM_ERROR("invalid feature map %d for feature %d\n",
+ feature_map[feature], feature);
+ return is_supported;
+ }
+
+ dma_ops = sde_reg_dma_get_ops();
+ if (IS_ERR_OR_NULL(dma_ops))
+ return is_supported;
+
+ dma_ops->check_support(feature_map[feature], DSPP0, &is_supported);
+
+ return is_supported;
+}
+
int reg_dmav1_init_dspp_op_v4(int feature, enum sde_dspp idx)
{
int rc = -ENOTSUPP;
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 a8115d6..5cd212a 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -25,6 +25,13 @@
int reg_dmav1_init_dspp_op_v4(int feature, enum sde_dspp idx);
/**
+ * reg_dmav1_dspp_feature_support() - check if dspp feature using REG_DMA
+ * or not.
+ * @feature: dspp feature
+ */
+bool reg_dmav1_dspp_feature_support(int feature);
+
+/**
* reg_dma_init_sspp_op_v4() - initialize the sspp feature op for sde v4
* @feature: sspp feature
* @idx: sspp idx
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index 9355080..356f9ef 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -375,19 +375,24 @@
c = &ctx->hw;
- if (enable) {
- if ((rect_mode == SDE_SSPP_RECT_SOLO)
- || (rect_mode == SDE_SSPP_RECT_0))
- secure_bit_mask =
- (rect_mode == SDE_SSPP_RECT_SOLO) ? 0xF : 0x5;
- else
- secure_bit_mask = 0xA;
+ if ((rect_mode == SDE_SSPP_RECT_SOLO)
+ || (rect_mode == SDE_SSPP_RECT_0))
+ secure_bit_mask =
+ (rect_mode == SDE_SSPP_RECT_SOLO) ? 0xF : 0x5;
+ else
+ secure_bit_mask = 0xA;
- secure = SDE_REG_READ(c, SSPP_SRC_ADDR_SW_STATUS + idx);
+ secure = SDE_REG_READ(c, SSPP_SRC_ADDR_SW_STATUS + idx);
+
+ if (enable)
secure |= secure_bit_mask;
- }
+ else
+ secure &= ~secure_bit_mask;
SDE_REG_WRITE(c, SSPP_SRC_ADDR_SW_STATUS + idx, secure);
+
+ /* multiple planes share same sw_status register */
+ wmb();
}
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 5895a4d..ca205c8 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -46,9 +46,19 @@
#include "sde_crtc.h"
#include "sde_reg_dma.h"
+#include <soc/qcom/scm.h>
+#include "soc/qcom/secure_buffer.h"
+
#define CREATE_TRACE_POINTS
#include "sde_trace.h"
+/* defines for secure channel call */
+#define SEC_SID_CNT 2
+#define SEC_SID_MASK_0 0x80881
+#define SEC_SID_MASK_1 0x80C81
+#define MEM_PROTECT_SD_CTRL_SWITCH 0x18
+#define MDP_DEVICE_ID 0x1A
+
static const char * const iommu_ports[] = {
"mdp_0",
};
@@ -402,6 +412,292 @@
}
}
+static int _sde_kms_secure_ctrl_xin_clients(struct sde_kms *sde_kms,
+ struct drm_crtc *crtc, bool enable)
+{
+ struct drm_device *dev;
+ struct msm_drm_private *priv;
+ struct sde_mdss_cfg *sde_cfg;
+ struct drm_plane *plane;
+ int i, ret;
+
+ dev = sde_kms->dev;
+ priv = dev->dev_private;
+ sde_cfg = sde_kms->catalog;
+
+ ret = sde_vbif_halt_xin_mask(sde_kms,
+ sde_cfg->sui_block_xin_mask, enable);
+ if (ret) {
+ SDE_ERROR("failed to halt some xin-clients, ret:%d\n", ret);
+ return ret;
+ }
+
+ if (enable) {
+ for (i = 0; i < priv->num_planes; i++) {
+ plane = priv->planes[i];
+ sde_plane_secure_ctrl_xin_client(plane, crtc);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * _sde_kms_scm_call - makes secure channel call to switch the VMIDs
+ * @vimd: switch the stage 2 translation to this VMID.
+ */
+static int _sde_kms_scm_call(int vmid)
+{
+ struct scm_desc desc = {0};
+ uint32_t num_sids;
+ uint32_t *sec_sid;
+ uint32_t mem_protect_sd_ctrl_id = MEM_PROTECT_SD_CTRL_SWITCH;
+ int ret = 0;
+
+ /* This info should be queried from catalog */
+ num_sids = SEC_SID_CNT;
+ sec_sid = kcalloc(num_sids, sizeof(uint32_t), GFP_KERNEL);
+ if (!sec_sid)
+ return -ENOMEM;
+
+ /*
+ * derive this info from device tree/catalog, this is combination of
+ * smr mask and SID for secure
+ */
+ sec_sid[0] = SEC_SID_MASK_0;
+ sec_sid[1] = SEC_SID_MASK_1;
+ dmac_flush_range(sec_sid, sec_sid + num_sids);
+
+ SDE_DEBUG("calling scm_call for vmid %d", vmid);
+
+ desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
+ desc.args[0] = MDP_DEVICE_ID;
+ desc.args[1] = SCM_BUFFER_PHYS(sec_sid);
+ desc.args[2] = sizeof(uint32_t) * num_sids;
+ desc.args[3] = vmid;
+
+ ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
+ mem_protect_sd_ctrl_id), &desc);
+ if (ret)
+ SDE_ERROR("Error:scm_call2, vmid (%lld): ret%d\n",
+ desc.args[3], ret);
+ SDE_EVT32(mem_protect_sd_ctrl_id,
+ desc.args[0], desc.args[3], num_sids,
+ sec_sid[0], sec_sid[1], ret);
+
+ kfree(sec_sid);
+ return ret;
+}
+
+static int _sde_kms_detach_all_cb(struct sde_kms *sde_kms)
+{
+ u32 ret = 0;
+
+ if (atomic_inc_return(&sde_kms->detach_all_cb) > 1)
+ goto end;
+
+ /* detach_all_contexts */
+ ret = sde_kms_mmu_detach(sde_kms, false);
+ if (ret) {
+ SDE_ERROR("failed to detach all cb ret:%d\n", ret);
+ goto end;
+ }
+
+ ret = _sde_kms_scm_call(VMID_CP_SEC_DISPLAY);
+ if (ret)
+ goto end;
+
+end:
+ return ret;
+}
+
+static int _sde_kms_attach_all_cb(struct sde_kms *sde_kms)
+{
+ u32 ret = 0;
+
+ if (atomic_dec_return(&sde_kms->detach_all_cb) != 0)
+ goto end;
+
+ ret = _sde_kms_scm_call(VMID_CP_PIXEL);
+ if (ret)
+ goto end;
+
+ /* attach_all_contexts */
+ ret = sde_kms_mmu_attach(sde_kms, false);
+ if (ret) {
+ SDE_ERROR("failed to attach all cb ret:%d\n", ret);
+ goto end;
+ }
+
+end:
+ return ret;
+}
+
+static int _sde_kms_detach_sec_cb(struct sde_kms *sde_kms)
+{
+ u32 ret = 0;
+
+ if (atomic_inc_return(&sde_kms->detach_sec_cb) > 1)
+ goto end;
+
+ /* detach secure_context */
+ ret = sde_kms_mmu_detach(sde_kms, true);
+ if (ret) {
+ SDE_ERROR("failed to detach sec cb ret:%d\n", ret);
+ goto end;
+ }
+
+ ret = _sde_kms_scm_call(VMID_CP_CAMERA_PREVIEW);
+ if (ret)
+ goto end;
+
+end:
+ return ret;
+}
+
+static int _sde_kms_attach_sec_cb(struct sde_kms *sde_kms)
+{
+ u32 ret = 0;
+
+ if (atomic_dec_return(&sde_kms->detach_sec_cb) != 0)
+ goto end;
+
+ ret = _sde_kms_scm_call(VMID_CP_PIXEL);
+ if (ret)
+ goto end;
+
+ ret = sde_kms_mmu_attach(sde_kms, true);
+ if (ret) {
+ SDE_ERROR("failed to attach sec cb ret:%d\n", ret);
+ goto end;
+ }
+
+end:
+ return ret;
+}
+
+static int _sde_kms_sui_misr_ctrl(struct sde_kms *sde_kms,
+ struct drm_crtc *crtc, bool enable)
+{
+ struct drm_device *dev = sde_kms->dev;
+ struct msm_drm_private *priv = dev->dev_private;
+ int ret;
+
+ if (enable) {
+ ret = sde_power_resource_enable(&priv->phandle,
+ sde_kms->core_client, true);
+ if (ret) {
+ SDE_ERROR("failed to enable resource, ret:%d\n", ret);
+ return ret;
+ }
+
+ sde_crtc_misr_setup(crtc, true, 1);
+
+ ret = _sde_kms_secure_ctrl_xin_clients(sde_kms, crtc, true);
+ if (ret) {
+ sde_power_resource_enable(&priv->phandle,
+ sde_kms->core_client, false);
+ return ret;
+ }
+
+ } else {
+ _sde_kms_secure_ctrl_xin_clients(sde_kms, crtc, false);
+ sde_crtc_misr_setup(crtc, false, 0);
+ sde_power_resource_enable(&priv->phandle,
+ sde_kms->core_client, false);
+ }
+
+ return 0;
+}
+
+static int _sde_kms_secure_ctrl(struct sde_kms *sde_kms, struct drm_crtc *crtc,
+ bool post_commit)
+{
+ struct sde_kms_smmu_state_data *smmu_state = &sde_kms->smmu_state;
+ int old_smmu_state = smmu_state->state;
+ int ret = 0;
+
+ if (!sde_kms || !crtc) {
+ SDE_ERROR("invalid argument(s)\n");
+ return -EINVAL;
+ }
+
+ SDE_EVT32(DRMID(crtc), smmu_state->state, smmu_state->transition_type,
+ post_commit, smmu_state->sui_misr_state,
+ SDE_EVTLOG_FUNC_ENTRY);
+
+ if ((!smmu_state->transition_type) ||
+ ((smmu_state->transition_type == POST_COMMIT) && !post_commit))
+ /* Bail out */
+ return 0;
+
+ /* enable sui misr if requested, before the transition */
+ if (smmu_state->sui_misr_state == SUI_MISR_ENABLE_REQ) {
+ ret = _sde_kms_sui_misr_ctrl(sde_kms, crtc, true);
+ if (ret)
+ goto end;
+ }
+
+ mutex_lock(&sde_kms->secure_transition_lock);
+ switch (smmu_state->state) {
+ /* Secure UI use case enable */
+ case DETACH_ALL_REQ:
+ ret = _sde_kms_detach_all_cb(sde_kms);
+ if (!ret)
+ smmu_state->state = DETACHED;
+ break;
+
+ /* Secure UI use case disable */
+ case ATTACH_ALL_REQ:
+ ret = _sde_kms_attach_all_cb(sde_kms);
+ if (!ret)
+ smmu_state->state = ATTACHED;
+ break;
+
+ /* Secure preview enable */
+ case DETACH_SEC_REQ:
+ ret = _sde_kms_detach_sec_cb(sde_kms);
+ if (!ret)
+ smmu_state->state = DETACHED_SEC;
+ break;
+
+ /* Secure preview disable */
+ case ATTACH_SEC_REQ:
+ ret = _sde_kms_attach_sec_cb(sde_kms);
+ if (!ret)
+ smmu_state->state = ATTACHED;
+ break;
+
+ default:
+ SDE_ERROR("crtc:%d invalid smmu state:%d transition type:%d\n",
+ DRMID(crtc), smmu_state->state,
+ smmu_state->transition_type);
+ ret = -EINVAL;
+ break;
+ }
+ mutex_unlock(&sde_kms->secure_transition_lock);
+
+ /* disable sui misr if requested, after the transition */
+ if (!ret && (smmu_state->sui_misr_state == SUI_MISR_DISABLE_REQ)) {
+ ret = _sde_kms_sui_misr_ctrl(sde_kms, crtc, false);
+ if (ret)
+ goto end;
+ }
+
+end:
+ smmu_state->sui_misr_state = NONE;
+ smmu_state->transition_type = NONE;
+ smmu_state->transition_error = ret ? true : false;
+
+ SDE_DEBUG("crtc:%d, old_state %d new_state %d, ret %d\n",
+ DRMID(crtc), old_smmu_state, smmu_state->state, ret);
+ SDE_EVT32(DRMID(crtc), smmu_state->state, smmu_state->transition_type,
+ smmu_state->transition_error, ret,
+ SDE_EVTLOG_FUNC_EXIT);
+
+ return ret;
+}
+
static int sde_kms_prepare_secure_transition(struct msm_kms *kms,
struct drm_atomic_state *state)
{
@@ -466,9 +762,9 @@
SDE_DEBUG("cleanup planes\n");
drm_atomic_helper_cleanup_planes(dev, state);
}
- if (ops & SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE) {
+ if (ops & SDE_KMS_OPS_SECURE_STATE_CHANGE) {
SDE_DEBUG("secure ctrl\n");
- sde_crtc_secure_ctrl(crtc, false);
+ _sde_kms_secure_ctrl(sde_kms, crtc, false);
}
if (ops & SDE_KMS_OPS_PREPARE_PLANE_FB) {
SDE_DEBUG("prepare planes %d",
@@ -674,9 +970,14 @@
return;
}
- for_each_crtc_in_state(old_state, crtc, old_crtc_state, i)
+ for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
sde_crtc_complete_commit(crtc, old_crtc_state);
+ /* complete secure transitions if any */
+ if (sde_kms->smmu_state.transition_type == POST_COMMIT)
+ _sde_kms_secure_ctrl(sde_kms, crtc, true);
+ }
+
for_each_connector_in_state(old_state, connector, old_conn_state, i) {
struct sde_connector *c_conn;
@@ -926,6 +1227,7 @@
.check_status = dsi_display_check_status,
.enable_event = dsi_conn_enable_event,
.cmd_transfer = dsi_display_cmd_transfer,
+ .cont_splash_config = dsi_display_cont_splash_config,
};
static const struct sde_connector_ops wb_ops = {
.post_init = sde_wb_connector_post_init,
@@ -939,6 +1241,7 @@
.get_dst_format = NULL,
.check_status = NULL,
.cmd_transfer = NULL,
+ .cont_splash_config = NULL,
};
static const struct sde_connector_ops dp_ops = {
.post_init = dp_connector_post_init,
@@ -951,6 +1254,7 @@
.check_status = NULL,
.config_hdr = dp_connector_config_hdr,
.cmd_transfer = NULL,
+ .cont_splash_config = NULL,
};
static const struct sde_connector_ops ext_bridge_ops = {
.set_info_blob = dsi_conn_set_info_blob,
@@ -962,6 +1266,7 @@
.get_dst_format = dsi_display_get_dst_format,
.enable_event = dsi_conn_enable_event,
.cmd_transfer = NULL,
+ .cont_splash_config = NULL,
};
struct msm_display_info info;
struct drm_encoder *encoder;
@@ -2251,6 +2556,7 @@
struct list_head *connector_list = NULL;
struct drm_connector *conn_iter = NULL;
struct drm_connector *connector = NULL;
+ struct sde_connector *sde_conn = NULL;
if (!kms) {
SDE_ERROR("invalid kms\n");
@@ -2315,7 +2621,7 @@
* configuration.
*/
if (conn_iter &&
- conn_iter->encoder_ids[0] == encoder->base.id) {
+ (conn_iter->encoder_ids[0] == encoder->base.id)) {
connector = conn_iter;
break;
}
@@ -2362,6 +2668,10 @@
sde_crtc_update_cont_splash_mixer_settings(crtc);
+ sde_conn = to_sde_connector(connector);
+ if (sde_conn && sde_conn->ops.cont_splash_config)
+ sde_conn->ops.cont_splash_config(sde_conn->display);
+
return rc;
}
@@ -3016,15 +3326,14 @@
goto drm_obj_init_err;
}
- dev->mode_config.min_width = 0;
- dev->mode_config.min_height = 0;
+ dev->mode_config.min_width = sde_kms->catalog->min_display_width;
+ dev->mode_config.min_height = sde_kms->catalog->min_display_height;
+ dev->mode_config.max_width = sde_kms->catalog->max_display_width;
+ dev->mode_config.max_height = sde_kms->catalog->max_display_height;
- /*
- * max crtc width is equal to the max mixer width * 2 and max height is
- * is 4K
- */
- dev->mode_config.max_width = sde_kms->catalog->max_mixer_width * 2;
- dev->mode_config.max_height = 4096;
+ mutex_init(&sde_kms->secure_transition_lock);
+ atomic_set(&sde_kms->detach_sec_cb, 0);
+ atomic_set(&sde_kms->detach_all_cb, 0);
/*
* Support format modifiers for compression etc.
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index 48f85bf..ad6d279 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
@@ -105,14 +105,71 @@
#define MAX_ALLOWED_ENCODER_CNT_PER_SECURE_CRTC 1
/* defines the operations required for secure state transition */
-#define SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE BIT(0)
-#define SDE_KMS_OPS_WAIT_FOR_TX_DONE BIT(1)
-#define SDE_KMS_OPS_CLEANUP_PLANE_FB BIT(2)
-#define SDE_KMS_OPS_PREPARE_PLANE_FB BIT(3)
+#define SDE_KMS_OPS_SECURE_STATE_CHANGE BIT(0)
+#define SDE_KMS_OPS_WAIT_FOR_TX_DONE BIT(1)
+#define SDE_KMS_OPS_CLEANUP_PLANE_FB BIT(2)
+#define SDE_KMS_OPS_PREPARE_PLANE_FB BIT(3)
/* ESD status check interval in miliseconds */
#define STATUS_CHECK_INTERVAL_MS 5000
+/**
+ * enum sde_kms_smmu_state: smmu state
+ * @ATTACHED: all the context banks are attached.
+ * @DETACHED: all the context banks are detached.
+ * @DETACHED_SEC: secure context bank is detached.
+ * @ATTACH_ALL_REQ: transient state of attaching context banks.
+ * @DETACH_ALL_REQ: transient state of detaching context banks.
+ * @DETACH_SEC_REQ: tranisent state of secure context bank is detached
+ * @ATTACH_SEC_REQ: transient state of attaching secure context bank.
+ */
+enum sde_kms_smmu_state {
+ ATTACHED = 0,
+ DETACHED,
+ DETACHED_SEC,
+ ATTACH_ALL_REQ,
+ DETACH_ALL_REQ,
+ DETACH_SEC_REQ,
+ ATTACH_SEC_REQ,
+};
+
+/**
+ * enum sde_kms_smmu_state_transition_type: state transition type
+ * @NONE: no pending state transitions
+ * @PRE_COMMIT: state transitions should be done before processing the commit
+ * @POST_COMMIT: state transitions to be done after processing the commit.
+ */
+enum sde_kms_smmu_state_transition_type {
+ NONE,
+ PRE_COMMIT,
+ POST_COMMIT
+};
+
+/**
+ * enum sde_kms_sui_misr_state: state request for enabling/disabling MISR
+ * @NONE: no request
+ * @ENABLE_SUI_MISR_REQ: request to enable sui MISR
+ * @DISABLE_SUI_MISR_REQ: request to disable sui MISR
+ */
+enum sde_kms_sui_misr_state {
+ SUI_MISR_NONE,
+ SUI_MISR_ENABLE_REQ,
+ SUI_MISR_DISABLE_REQ
+};
+
+/**
+ * struct sde_kms_smmu_state_data: stores the smmu state and transition type
+ * @state: current state of smmu context banks
+ * @transition_type: transition request type
+ * @transition_error: whether there is error while transitioning the state
+ */
+struct sde_kms_smmu_state_data {
+ uint32_t state;
+ uint32_t transition_type;
+ uint32_t transition_error;
+ uint32_t sui_misr_state;
+};
+
/*
* struct sde_irq_callback - IRQ callback handlers
* @list: list to callback
@@ -226,6 +283,11 @@
void **dp_displays;
bool has_danger_ctrl;
+
+ struct sde_kms_smmu_state_data smmu_state;
+ atomic_t detach_sec_cb;
+ atomic_t detach_all_cb;
+ struct mutex secure_transition_lock;
};
struct vsync_info {
@@ -287,6 +349,48 @@
}
/**
+ * sde_kms_is_secure_session_inprogress - to indicate if secure-session is in
+ * currently in-progress based on the current smmu_state
+ *
+ * @sde_kms: Pointer to sde_kms
+ *
+ * return: true if secure-session is in progress; false otherwise
+ */
+static inline bool sde_kms_is_secure_session_inprogress(struct sde_kms *sde_kms)
+{
+ bool ret = false;
+
+ if (!sde_kms)
+ return false;
+
+ mutex_lock(&sde_kms->secure_transition_lock);
+ if (sde_kms->smmu_state.state == DETACHED)
+ ret = true;
+ mutex_unlock(&sde_kms->secure_transition_lock);
+
+ return ret;
+}
+
+/**
+ * sde_kms_is_vbif_operation_allowed - resticts the VBIF programming
+ * during secure-ui, if the sec_ui_misr feature is enabled
+ *
+ * @sde_kms: Pointer to sde_kms
+ *
+ * return: false if secure-session is in progress; true otherwise
+ */
+static inline bool sde_kms_is_vbif_operation_allowed(struct sde_kms *sde_kms)
+{
+ if (!sde_kms)
+ return false;
+
+ if (!sde_kms->catalog->sui_misr_supported)
+ return true;
+
+ return !sde_kms_is_secure_session_inprogress(sde_kms);
+}
+
+/**
* Debugfs functions - extra helper functions for debugfs support
*
* Main debugfs documentation is located at,
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 4c281666..2e46599 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -204,6 +204,18 @@
state->crtc->state->enable;
}
+bool sde_plane_is_sec_ui_allowed(struct drm_plane *plane)
+{
+ struct sde_plane *psde;
+
+ if (!plane)
+ return false;
+
+ psde = to_sde_plane(plane);
+
+ return !(psde->features & BIT(SDE_SSPP_BLOCK_SEC_UI));
+}
+
/**
* _sde_plane_calc_fill_level - calculate fill level of the given source format
* @plane: Pointer to drm plane
@@ -2565,6 +2577,25 @@
psde->xin_halt_forced_clk, enable);
}
+void sde_plane_secure_ctrl_xin_client(struct drm_plane *plane,
+ struct drm_crtc *crtc)
+{
+ struct sde_plane *psde;
+
+ if (!plane || !crtc) {
+ SDE_ERROR("invalid plane/crtc\n");
+ return;
+ }
+ psde = to_sde_plane(plane);
+
+ if (psde->features & BIT(SDE_SSPP_BLOCK_SEC_UI))
+ return;
+
+ /* do all VBIF programming for the sec-ui allowed SSPP */
+ _sde_plane_set_qos_remap(plane);
+ _sde_plane_set_ot_limit(plane, crtc);
+}
+
int sde_plane_reset_rot(struct drm_plane *plane, struct drm_plane_state *state)
{
struct sde_plane *psde;
@@ -4370,6 +4401,8 @@
psde->pipe_sblk->maxvdeciexp);
sde_kms_info_add_keyint(info, "max_per_pipe_bw",
psde->pipe_sblk->max_per_pipe_bw * 1000LL);
+ if (psde->features & BIT(SDE_SSPP_BLOCK_SEC_UI))
+ sde_kms_info_add_keyint(info, "block_sec_ui", 1);
msm_property_set_blob(&psde->property_info, &psde->blob_info,
info->data, SDE_KMS_INFO_DATALEN(info),
PLANE_PROP_INFO);
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h
index ad58097..f924aa6 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.h
+++ b/drivers/gpu/drm/msm/sde/sde_plane.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
@@ -334,4 +334,20 @@
int sde_plane_helper_reset_custom_properties(struct drm_plane *plane,
struct drm_plane_state *plane_state);
+/**
+ * sde_plane_is_sec_ui_allowed - indicates if the sspp allows secure-ui layers
+ * @plane: Pointer to DRM plane object
+ * Returns: true if allowed; false otherwise
+ */
+bool sde_plane_is_sec_ui_allowed(struct drm_plane *plane);
+
+/* sde_plane_secure_ctrl_xin_client - controls the VBIF programming of
+ * the xin-client before the secure-ui session. Programs the QOS
+ * and OT limits in VBIF for the sec-ui allowed xins
+ * @plane: Pointer to DRM plane object
+ * @crtc: Pointer to DRM CRTC state object
+ */
+void sde_plane_secure_ctrl_xin_client(struct drm_plane *plane,
+ struct drm_crtc *crtc);
+
#endif /* _SDE_PLANE_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index 93304e16..52a5bc9 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -398,7 +398,7 @@
void __iomem *mmio,
struct drm_device *dev)
{
- int rc, i;
+ int rc = 0, i;
enum sde_hw_blk_type type;
if (!rm || !cat || !mmio || !dev) {
@@ -1182,7 +1182,7 @@
}
SDE_EVT32(status, irq_idx_pp_done, SDE_EVTLOG_ERROR);
- SDE_ERROR("polling timed out. status = 0x%x\n", status);
+ SDE_DEBUG("polling timed out. status = 0x%x\n", status);
return -ETIMEDOUT;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_vbif.c b/drivers/gpu/drm/msm/sde/sde_vbif.c
index c19ee82..33a60f9 100644
--- a/drivers/gpu/drm/msm/sde/sde_vbif.c
+++ b/drivers/gpu/drm/msm/sde/sde_vbif.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -18,6 +18,8 @@
#include "sde_hw_vbif.h"
#include "sde_trace.h"
+#define MAX_XIN_CLIENT 16
+
/**
* _sde_vbif_wait_for_xin_halt - wait for the xin to halt
* @vbif: Pointer to hardware vbif driver
@@ -73,6 +75,11 @@
return -EINVAL;
}
+ if (!sde_kms_is_vbif_operation_allowed(sde_kms)) {
+ SDE_DEBUG("vbif operations not permitted\n");
+ return 0;
+ }
+
vbif = sde_kms->hw_vbif[VBIF_RT];
mdp = sde_kms->hw_mdp;
if (!vbif || !mdp || !vbif->ops.get_halt_ctrl ||
@@ -225,6 +232,12 @@
SDE_ERROR("invalid arguments\n");
return;
}
+
+ if (!sde_kms_is_vbif_operation_allowed(sde_kms)) {
+ SDE_DEBUG("vbif operations not permitted\n");
+ return;
+ }
+
mdp = sde_kms->hw_mdp;
for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) {
@@ -293,6 +306,12 @@
SDE_ERROR("invalid arguments\n");
return false;
}
+
+ if (!sde_kms_is_vbif_operation_allowed(sde_kms)) {
+ SDE_DEBUG("vbif operations not permitted\n");
+ return true;
+ }
+
mdp = sde_kms->hw_mdp;
for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) {
@@ -352,6 +371,12 @@
SDE_ERROR("invalid arguments\n");
return;
}
+
+ if (!sde_kms_is_vbif_operation_allowed(sde_kms)) {
+ SDE_DEBUG("vbif operations not permitted\n");
+ return;
+ }
+
mdp = sde_kms->hw_mdp;
for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) {
@@ -408,6 +433,11 @@
return;
}
+ if (!sde_kms_is_vbif_operation_allowed(sde_kms)) {
+ SDE_DEBUG("vbif operations not permitted\n");
+ return;
+ }
+
for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) {
vbif = sde_kms->hw_vbif[i];
if (vbif && vbif->ops.clear_errors) {
@@ -433,6 +463,11 @@
return;
}
+ if (!sde_kms_is_vbif_operation_allowed(sde_kms)) {
+ SDE_DEBUG("vbif operations not permitted\n");
+ return;
+ }
+
for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) {
vbif = sde_kms->hw_vbif[i];
if (vbif && vbif->cap && vbif->ops.set_mem_type) {
@@ -445,6 +480,52 @@
}
}
+int sde_vbif_halt_xin_mask(struct sde_kms *sde_kms, u32 xin_id_mask,
+ bool halt)
+{
+ struct sde_hw_vbif *vbif;
+ int i = 0, status, rc;
+
+ if (!sde_kms) {
+ SDE_ERROR("invalid argument\n");
+ return -EINVAL;
+ }
+
+ vbif = sde_kms->hw_vbif[VBIF_RT];
+
+ if (!vbif->ops.get_halt_ctrl || !vbif->ops.set_halt_ctrl)
+ return 0;
+
+ SDE_EVT32(xin_id_mask, halt);
+
+ for (i = 0; i < MAX_XIN_CLIENT; i++) {
+ if (xin_id_mask & BIT(i)) {
+ /* unhalt the xin-clients */
+ if (!halt) {
+ vbif->ops.set_halt_ctrl(vbif, i, false);
+ continue;
+ }
+
+ status = vbif->ops.get_halt_ctrl(vbif, i);
+ if (status)
+ continue;
+
+ /* halt xin-clients and wait for ack */
+ vbif->ops.set_halt_ctrl(vbif, i, true);
+
+ rc = _sde_vbif_wait_for_xin_halt(vbif, i);
+ if (rc) {
+ SDE_ERROR("xin_halt failed for xin:%d, rc:%d\n",
+ i, rc);
+ SDE_EVT32(xin_id_mask, i, rc, SDE_EVTLOG_ERROR);
+ return rc;
+ }
+ }
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_DEBUG_FS
void sde_debugfs_vbif_destroy(struct sde_kms *sde_kms)
{
diff --git a/drivers/gpu/drm/msm/sde/sde_vbif.h b/drivers/gpu/drm/msm/sde/sde_vbif.h
index 0edc1a6..1d12fd7 100644
--- a/drivers/gpu/drm/msm/sde/sde_vbif.h
+++ b/drivers/gpu/drm/msm/sde/sde_vbif.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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,15 @@
int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id,
u32 clk_ctrl);
+/**
+ * sde_vbif_halt_xin_mask - halts/unhalts all the xin clients present in
+ * the mask.
+ * @sde_kms: SDE handler
+ * @xin_id_mask: Mask of all the xin-ids to be halted/unhalted
+ * halt: boolen to indicate halt/unhalt
+ */
+int sde_vbif_halt_xin_mask(struct sde_kms *sde_kms, u32 xin_id_mask, bool halt);
+
#ifdef CONFIG_DEBUG_FS
int sde_debugfs_vbif_init(struct sde_kms *sde_kms, struct dentry *debugfs_root);
void sde_debugfs_vbif_destroy(struct sde_kms *sde_kms);
diff --git a/drivers/gpu/drm/msm/sde_hdcp.h b/drivers/gpu/drm/msm/sde_hdcp.h
index 6c44260..c8e84d3cc 100644
--- a/drivers/gpu/drm/msm/sde_hdcp.h
+++ b/drivers/gpu/drm/msm/sde_hdcp.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2014-2018, 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
@@ -30,17 +30,21 @@
HDCP_CLIENT_DP,
};
-enum sde_hdcp_states {
+enum sde_hdcp_state {
HDCP_STATE_INACTIVE,
HDCP_STATE_AUTHENTICATING,
HDCP_STATE_AUTHENTICATED,
HDCP_STATE_AUTH_FAIL,
- HDCP_STATE_AUTH_ENC_NONE,
- HDCP_STATE_AUTH_ENC_1X,
- HDCP_STATE_AUTH_ENC_2P2
+};
+
+enum sde_hdcp_version {
+ HDCP_VERSION_NONE,
+ HDCP_VERSION_1X,
+ HDCP_VERSION_2P2
};
struct sde_hdcp_init_data {
+ struct device *msm_hdcp_dev;
struct dss_io_data *core_io;
struct dss_io_data *dp_ahb;
struct dss_io_data *dp_aux;
@@ -52,7 +56,7 @@
struct mutex *mutex;
struct workqueue_struct *workq;
void *cb_data;
- void (*notify_status)(void *cb_data, enum sde_hdcp_states status);
+ void (*notify_status)(void *cb_data, enum sde_hdcp_state state);
u8 sink_rx_status;
unsigned char *revision;
u32 phy_addr;
@@ -69,11 +73,32 @@
void (*off)(void *hdcp_ctrl);
};
+static inline const char *sde_hdcp_state_name(enum sde_hdcp_state hdcp_state)
+{
+ switch (hdcp_state) {
+ case HDCP_STATE_INACTIVE: return "HDCP_STATE_INACTIVE";
+ case HDCP_STATE_AUTHENTICATING: return "HDCP_STATE_AUTHENTICATING";
+ case HDCP_STATE_AUTHENTICATED: return "HDCP_STATE_AUTHENTICATED";
+ case HDCP_STATE_AUTH_FAIL: return "HDCP_STATE_AUTH_FAIL";
+ default: return "???";
+ }
+}
+
+static inline const char *sde_hdcp_version(enum sde_hdcp_version hdcp_version)
+{
+ switch (hdcp_version) {
+ case HDCP_VERSION_NONE: return "HDCP_VERSION_NONE";
+ case HDCP_VERSION_1X: return "HDCP_VERSION_1X";
+ case HDCP_VERSION_2P2: return "HDCP_VERSION_2P2";
+ default: return "???";
+ }
+}
+
void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data);
void sde_hdcp_1x_deinit(void *input);
struct sde_hdcp_ops *sde_hdcp_1x_start(void *input);
void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data);
void sde_dp_hdcp2p2_deinit(void *input);
-const char *sde_hdcp_state_name(enum sde_hdcp_states hdcp_state);
+const char *sde_hdcp_state_name(enum sde_hdcp_state hdcp_state);
struct sde_hdcp_ops *sde_dp_hdcp2p2_start(void *input);
#endif /* __SDE_HDCP_H__ */
diff --git a/drivers/gpu/drm/msm/sde_hdcp_1x.c b/drivers/gpu/drm/msm/sde_hdcp_1x.c
index 2f900ece..2c7f52c 100644
--- a/drivers/gpu/drm/msm/sde_hdcp_1x.c
+++ b/drivers/gpu/drm/msm/sde_hdcp_1x.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/iopoll.h>
+#include <linux/msm_hdcp.h>
#include <linux/hdcp_qseecom.h>
#include <drm/drm_dp_helper.h>
#include "sde_hdcp.h"
@@ -213,8 +214,7 @@
bool sink_r0_ready;
bool reauth;
bool ksv_ready;
- enum sde_hdcp_states hdcp_state;
- struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
+ enum sde_hdcp_state hdcp_state;
struct HDCP_V2V1_MSG_TOPOLOGY current_tp;
struct delayed_work hdcp_auth_work;
struct completion r0_checked;
@@ -227,17 +227,6 @@
struct workqueue_struct *workq;
};
-const char *sde_hdcp_state_name(enum sde_hdcp_states hdcp_state)
-{
- switch (hdcp_state) {
- case HDCP_STATE_INACTIVE: return "HDCP_STATE_INACTIVE";
- case HDCP_STATE_AUTHENTICATING: return "HDCP_STATE_AUTHENTICATING";
- case HDCP_STATE_AUTHENTICATED: return "HDCP_STATE_AUTHENTICATED";
- case HDCP_STATE_AUTH_FAIL: return "HDCP_STATE_AUTH_FAIL";
- default: return "???";
- }
-}
-
static int sde_hdcp_1x_count_one(u8 *array, u8 len)
{
int i, j, count = 0;
@@ -1062,30 +1051,12 @@
return rc;
}
-static void sde_hdcp_1x_cache_topology(struct sde_hdcp_1x *hdcp)
-{
- if (!hdcp || !hdcp->init_data.dp_ahb || !hdcp->init_data.dp_aux ||
- !hdcp->init_data.dp_link || !hdcp->init_data.dp_p0) {
- pr_err("invalid input\n");
- return;
- }
-
- memcpy((void *)&hdcp->cached_tp,
- (void *) &hdcp->current_tp,
- sizeof(hdcp->cached_tp));
- hdcp1_cache_repeater_topology((void *)&hdcp->cached_tp);
-}
-
-static void sde_hdcp_1x_notify_topology(void)
-{
- hdcp1_notify_topology();
-}
-
static void sde_hdcp_1x_update_auth_status(struct sde_hdcp_1x *hdcp)
{
if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) {
- sde_hdcp_1x_cache_topology(hdcp);
- sde_hdcp_1x_notify_topology();
+ msm_hdcp_cache_repeater_topology(hdcp->init_data.msm_hdcp_dev,
+ &hdcp->current_tp);
+ msm_hdcp_notify_topology(hdcp->init_data.msm_hdcp_dev);
}
if (hdcp->init_data.notify_status &&
@@ -1262,11 +1233,9 @@
* Also, need to set the state to inactive here so that any ongoing
* reauth works will know that the HDCP session has been turned off.
*/
- mutex_lock(hdcp->init_data.mutex);
DSS_REG_W(io, isr->int_reg,
DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN);
hdcp->hdcp_state = HDCP_STATE_INACTIVE;
- mutex_unlock(hdcp->init_data.mutex);
/* complete any wait pending */
complete_all(&hdcp->sink_r0_available);
@@ -1510,7 +1479,7 @@
.off = sde_hdcp_1x_off
};
- if (!init_data || !init_data->mutex || !init_data->notify_status ||
+ if (!init_data || !init_data->notify_status ||
!init_data->workq || !init_data->cb_data) {
pr_err("invalid input\n");
goto error;
diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c
index 40542ab..037c036 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.c
+++ b/drivers/gpu/drm/msm/sde_power_handle.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -844,6 +844,68 @@
sde_rsc_client_destroy(phandle->rsc_client);
}
+
+int sde_power_scale_reg_bus(struct sde_power_handle *phandle,
+ struct sde_power_client *pclient, u32 usecase_ndx, bool skip_lock)
+{
+ struct sde_power_client *client;
+ int rc = 0;
+ u32 max_usecase_ndx = VOTE_INDEX_DISABLE;
+
+ if (!skip_lock) {
+ mutex_lock(&phandle->phandle_lock);
+
+ if (WARN_ON(pclient->refcount == 0)) {
+ /*
+ * This is not expected, clients calling without skip
+ * lock are outside the power resource enable, which
+ * means that they should have enabled the power
+ * resource before trying to scale.
+ */
+ rc = -EINVAL;
+ goto exit;
+ }
+ }
+
+ pr_debug("%pS: current idx:%d requested:%d client:%d\n",
+ __builtin_return_address(0), pclient->usecase_ndx,
+ usecase_ndx, pclient->id);
+
+ pclient->usecase_ndx = usecase_ndx;
+
+ list_for_each_entry(client, &phandle->power_client_clist, list) {
+ if (client->usecase_ndx < VOTE_INDEX_MAX &&
+ client->usecase_ndx > max_usecase_ndx)
+ max_usecase_ndx = client->usecase_ndx;
+ }
+
+ rc = sde_power_reg_bus_update(phandle->reg_bus_hdl,
+ max_usecase_ndx);
+ if (rc)
+ pr_err("failed to set reg bus vote rc=%d\n", rc);
+
+exit:
+ if (!skip_lock)
+ mutex_unlock(&phandle->phandle_lock);
+
+ return rc;
+}
+
+static inline bool _resource_changed(u32 current_usecase_ndx,
+ u32 max_usecase_ndx)
+{
+ WARN_ON((current_usecase_ndx >= VOTE_INDEX_MAX)
+ || (max_usecase_ndx >= VOTE_INDEX_MAX));
+
+ if (((current_usecase_ndx >= VOTE_INDEX_LOW) && /*current enabled */
+ (max_usecase_ndx == VOTE_INDEX_DISABLE)) || /* max disabled */
+ ((current_usecase_ndx == VOTE_INDEX_DISABLE) && /* disabled */
+ (max_usecase_ndx >= VOTE_INDEX_LOW))) /* max enabled */
+ return true;
+
+ return false;
+}
+
int sde_power_resource_enable(struct sde_power_handle *phandle,
struct sde_power_client *pclient, bool enable)
{
@@ -877,7 +939,15 @@
max_usecase_ndx = client->usecase_ndx;
}
- if (phandle->current_usecase_ndx != max_usecase_ndx) {
+ /*
+ * Check if we need to enable/disable the power resource, we won't
+ * only-scale up/down the AHB vote in this API; if a client wants to
+ * bump up the AHB clock above the LOW (default) level, it needs to
+ * call 'sde_power_scale_reg_bus' with the desired vote after the power
+ * resource was enabled.
+ */
+ if (_resource_changed(phandle->current_usecase_ndx,
+ max_usecase_ndx)) {
changed = true;
prev_usecase_ndx = phandle->current_usecase_ndx;
phandle->current_usecase_ndx = max_usecase_ndx;
@@ -920,8 +990,8 @@
}
}
- rc = sde_power_reg_bus_update(phandle->reg_bus_hdl,
- max_usecase_ndx);
+ rc = sde_power_scale_reg_bus(phandle, pclient,
+ max_usecase_ndx, true);
if (rc) {
pr_err("failed to set reg bus vote rc=%d\n", rc);
goto reg_bus_hdl_err;
@@ -952,8 +1022,8 @@
sde_power_rsc_update(phandle, false);
- sde_power_reg_bus_update(phandle->reg_bus_hdl,
- max_usecase_ndx);
+ sde_power_scale_reg_bus(phandle, pclient,
+ max_usecase_ndx, true);
if (!phandle->rsc_client)
msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
@@ -975,7 +1045,7 @@
clk_err:
sde_power_rsc_update(phandle, false);
rsc_err:
- sde_power_reg_bus_update(phandle->reg_bus_hdl, prev_usecase_ndx);
+ sde_power_scale_reg_bus(phandle, pclient, max_usecase_ndx, true);
reg_bus_hdl_err:
if (!phandle->rsc_client)
msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
diff --git a/drivers/gpu/drm/msm/sde_power_handle.h b/drivers/gpu/drm/msm/sde_power_handle.h
index fb7322e..f02ca0a 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.h
+++ b/drivers/gpu/drm/msm/sde_power_handle.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -43,11 +43,15 @@
* mdss_bus_vote_type: register bus vote type
* VOTE_INDEX_DISABLE: removes the client vote
* VOTE_INDEX_LOW: keeps the lowest vote for register bus
+ * VOTE_INDEX_MEDIUM: keeps medium vote for register bus
+ * VOTE_INDEX_HIGH: keeps the highest vote for register bus
* VOTE_INDEX_MAX: invalid
*/
enum mdss_bus_vote_type {
VOTE_INDEX_DISABLE,
VOTE_INDEX_LOW,
+ VOTE_INDEX_MEDIUM,
+ VOTE_INDEX_HIGH,
VOTE_INDEX_MAX,
};
@@ -228,6 +232,19 @@
struct sde_power_client *pclient, bool enable);
/**
+ * sde_power_scale_reg_bus() - Scale the registers bus for the specified client
+ * @pdata: power handle containing the resources
+ * @client: client information to scale its vote
+ * @usecase_ndx: new use case to scale the reg bus
+ * @skip_lock: will skip holding the power rsrc mutex during the call, this is
+ * for internal callers that already hold this required lock.
+ *
+ * Return: error code.
+ */
+int sde_power_scale_reg_bus(struct sde_power_handle *phandle,
+ struct sde_power_client *pclient, u32 usecase_ndx, bool skip_lock);
+
+/**
* sde_power_resource_is_enabled() - return true if power resource is enabled
* @pdata: power handle containing the resources
*
diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c
index a0d1245..d40b0ad 100644
--- a/drivers/gpu/drm/msm/sde_rsc_hw.c
+++ b/drivers/gpu/drm/msm/sde_rsc_hw.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -99,6 +99,10 @@
#define MAX_CHECK_LOOPS 500
#define POWER_CTRL_BIT_12 12
+#define SDE_RSC_MODE_0_VAL 0
+#define SDE_RSC_MODE_1_VAL 1
+#define MAX_MODE2_ENTRY_TRY 3
+
static void rsc_event_trigger(struct sde_rsc_priv *rsc, uint32_t event_type)
{
struct sde_rsc_event *event;
@@ -406,23 +410,12 @@
return rc;
}
-static int sde_rsc_mode2_entry(struct sde_rsc_priv *rsc)
+static int sde_rsc_mode2_entry_trigger(struct sde_rsc_priv *rsc)
{
int rc;
int count, wrapper_status;
unsigned long reg;
- if (rsc->power_collapse_block)
- return -EINVAL;
-
- rc = regulator_set_mode(rsc->fs, REGULATOR_MODE_FAST);
- if (rc) {
- pr_err("vdd reg fast mode set failed rc:%d\n", rc);
- return rc;
- }
-
- rsc_event_trigger(rsc, SDE_RSC_EVENT_PRE_CORE_PC);
-
/* update qtimers to high during clk & video mode state */
if ((rsc->current_state == SDE_RSC_VID_STATE) ||
(rsc->current_state == SDE_RSC_CLK_STATE)) {
@@ -467,11 +460,69 @@
usleep_range(10, 100);
}
- if (rc) {
- pr_err("mdss gdsc power down failed rc:%d\n", rc);
- SDE_EVT32(rc, SDE_EVTLOG_ERROR);
- goto end;
+ return rc;
+}
+
+static void sde_rsc_reset_mode_0_1(struct sde_rsc_priv *rsc)
+{
+ u32 seq_busy, current_mode, curr_inst_addr;
+
+ seq_busy = dss_reg_r(&rsc->drv_io, SDE_RSCC_SEQ_BUSY_DRV0,
+ rsc->debug_mode);
+ current_mode = dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_STATUS2_DRV0,
+ rsc->debug_mode);
+ curr_inst_addr = dss_reg_r(&rsc->drv_io, SDE_RSCC_SEQ_PROGRAM_COUNTER,
+ rsc->debug_mode);
+ SDE_EVT32(seq_busy, current_mode, curr_inst_addr);
+
+ if (seq_busy && (current_mode == SDE_RSC_MODE_0_VAL ||
+ current_mode == SDE_RSC_MODE_1_VAL)) {
+ dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO,
+ 0xffffffff, rsc->debug_mode);
+ dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI,
+ 0xffffffff, rsc->debug_mode);
+ /* unstick f1 qtimer */
+ wmb();
+
+ dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO,
+ 0x0, rsc->debug_mode);
+ dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI,
+ 0x0, rsc->debug_mode);
+ /* manually trigger f1 qtimer interrupt */
+ wmb();
}
+}
+
+static int sde_rsc_mode2_entry(struct sde_rsc_priv *rsc)
+{
+ int rc = 0, i;
+
+ if (rsc->power_collapse_block)
+ return -EINVAL;
+
+ rc = regulator_set_mode(rsc->fs, REGULATOR_MODE_FAST);
+ if (rc) {
+ pr_err("vdd reg fast mode set failed rc:%d\n", rc);
+ return rc;
+ }
+
+ rsc_event_trigger(rsc, SDE_RSC_EVENT_PRE_CORE_PC);
+
+ for (i = 0; i <= MAX_MODE2_ENTRY_TRY; i++) {
+ rc = sde_rsc_mode2_entry_trigger(rsc);
+ if (!rc)
+ break;
+
+ pr_err("try:%d mdss gdsc power down failed rc:%d\n", i, rc);
+ SDE_EVT32(rc, i, SDE_EVTLOG_ERROR);
+
+ /* avoid touching f1 qtimer for last try */
+ if (i != MAX_MODE2_ENTRY_TRY)
+ sde_rsc_reset_mode_0_1(rsc);
+ }
+
+ if (rc)
+ goto end;
if ((rsc->current_state == SDE_RSC_VID_STATE) ||
(rsc->current_state == SDE_RSC_CLK_STATE)) {
@@ -546,7 +597,7 @@
reg = dss_reg_r(&rsc->wrapper_io,
SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
- reg &= ~(BIT(8) | BIT(0));
+ reg &= ~BIT(0);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
reg, rsc->debug_mode);
/* make sure that solver mode is disabled */
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 72e2399..909f69a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -369,7 +369,7 @@
{
struct nouveau_cli *cli = nouveau_cli(file_priv);
int trycnt = 0;
- int ret, i;
+ int ret = -EINVAL, i;
struct nouveau_bo *res_bo = NULL;
LIST_HEAD(gart_list);
LIST_HEAD(vram_list);
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c
index 0cd0e7b..16239b0 100644
--- a/drivers/gpu/drm/radeon/radeon_uvd.c
+++ b/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -995,7 +995,7 @@
/* calc dclk divider with current vco freq */
dclk_div = radeon_uvd_calc_upll_post_div(vco_freq, dclk,
pd_min, pd_even);
- if (vclk_div > pd_max)
+ if (dclk_div > pd_max)
break; /* vco is too big, it has to stop */
/* calc score with current vco freq */
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index 8bd9e6c..574ab00 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -3029,6 +3029,11 @@
max_sclk = 75000;
max_mclk = 80000;
}
+ if ((rdev->pdev->revision == 0xC3) ||
+ (rdev->pdev->device == 0x6665)) {
+ max_sclk = 60000;
+ max_mclk = 80000;
+ }
} else if (rdev->family == CHIP_OLAND) {
if ((rdev->pdev->revision == 0xC7) ||
(rdev->pdev->revision == 0x80) ||
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index a2ec6d8..3322b15 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -392,6 +392,31 @@
rcrtc->started = true;
}
+static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc)
+{
+ struct rcar_du_device *rcdu = rcrtc->group->dev;
+ struct drm_crtc *crtc = &rcrtc->crtc;
+ u32 status;
+ /* Make sure vblank interrupts are enabled. */
+ drm_crtc_vblank_get(crtc);
+ /*
+ * Disable planes and calculate how many vertical blanking interrupts we
+ * have to wait for. If a vertical blanking interrupt has been triggered
+ * but not processed yet, we don't know whether it occurred before or
+ * after the planes got disabled. We thus have to wait for two vblank
+ * interrupts in that case.
+ */
+ spin_lock_irq(&rcrtc->vblank_lock);
+ rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
+ status = rcar_du_crtc_read(rcrtc, DSSR);
+ rcrtc->vblank_count = status & DSSR_VBK ? 2 : 1;
+ spin_unlock_irq(&rcrtc->vblank_lock);
+ if (!wait_event_timeout(rcrtc->vblank_wait, rcrtc->vblank_count == 0,
+ msecs_to_jiffies(100)))
+ dev_warn(rcdu->dev, "vertical blanking timeout\n");
+ drm_crtc_vblank_put(crtc);
+}
+
static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
{
struct drm_crtc *crtc = &rcrtc->crtc;
@@ -400,17 +425,16 @@
return;
/* Disable all planes and wait for the change to take effect. This is
- * required as the DSnPR registers are updated on vblank, and no vblank
- * will occur once the CRTC is stopped. Disabling planes when starting
- * the CRTC thus wouldn't be enough as it would start scanning out
- * immediately from old frame buffers until the next vblank.
+ * required as the plane enable registers are updated on vblank, and no
+ * vblank will occur once the CRTC is stopped. Disabling planes when
+ * starting the CRTC thus wouldn't be enough as it would start scanning
+ * out immediately from old frame buffers until the next vblank.
*
* This increases the CRTC stop delay, especially when multiple CRTCs
* are stopped in one operation as we now wait for one vblank per CRTC.
* Whether this can be improved needs to be researched.
*/
- rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
- drm_crtc_wait_one_vblank(crtc);
+ rcar_du_crtc_disable_planes(rcrtc);
/* Disable vertical blanking interrupt reporting. We first need to wait
* for page flip completion before stopping the CRTC as userspace
@@ -548,10 +572,25 @@
irqreturn_t ret = IRQ_NONE;
u32 status;
+ spin_lock(&rcrtc->vblank_lock);
+
status = rcar_du_crtc_read(rcrtc, DSSR);
rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
- if (status & DSSR_FRM) {
+ if (status & DSSR_VBK) {
+ /*
+ * Wake up the vblank wait if the counter reaches 0. This must
+ * be protected by the vblank_lock to avoid races in
+ * rcar_du_crtc_disable_planes().
+ */
+ if (rcrtc->vblank_count) {
+ if (--rcrtc->vblank_count == 0)
+ wake_up(&rcrtc->vblank_wait);
+ }
+ }
+ spin_unlock(&rcrtc->vblank_lock);
+
+ if (status & DSSR_VBK) {
drm_crtc_handle_vblank(&rcrtc->crtc);
rcar_du_crtc_finish_page_flip(rcrtc);
ret = IRQ_HANDLED;
@@ -606,6 +645,8 @@
}
init_waitqueue_head(&rcrtc->flip_wait);
+ init_waitqueue_head(&rcrtc->vblank_wait);
+ spin_lock_init(&rcrtc->vblank_lock);
rcrtc->group = rgrp;
rcrtc->mmio_offset = mmio_offsets[index];
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 6f08b7e..48bef05 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -15,6 +15,7 @@
#define __RCAR_DU_CRTC_H__
#include <linux/mutex.h>
+#include <linux/spinlock.h>
#include <linux/wait.h>
#include <drm/drmP.h>
@@ -33,6 +34,9 @@
* @started: whether the CRTC has been started and is running
* @event: event to post when the pending page flip completes
* @flip_wait: wait queue used to signal page flip completion
+ * @vblank_lock: protects vblank_wait and vblank_count
+ * @vblank_wait: wait queue used to signal vertical blanking
+ * @vblank_count: number of vertical blanking interrupts to wait for
* @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC
* @group: CRTC group this CRTC belongs to
*/
@@ -48,6 +52,10 @@
struct drm_pending_vblank_event *event;
wait_queue_head_t flip_wait;
+ spinlock_t vblank_lock;
+ wait_queue_head_t vblank_wait;
+ unsigned int vblank_count;
+
unsigned int outputs;
struct rcar_du_group *group;
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index fef45ec..ef0d7f1 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -923,6 +923,7 @@
#define A6XX_GMU_SYS_BUS_CONFIG 0x1F40F
#define A6XX_GMU_CM3_SYSRESET 0x1F800
#define A6XX_GMU_CM3_BOOT_CONFIG 0x1F801
+#define A6XX_GMU_CX_GMU_WFI_CONFIG 0x1F802
#define A6XX_GMU_CM3_FW_BUSY 0x1F81A
#define A6XX_GMU_CM3_FW_INIT_RESULT 0x1F81C
#define A6XX_GMU_CM3_CFG 0x1F82D
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index ab9f203..763dc18 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -848,6 +848,58 @@
{}
};
+static void adreno_of_get_ca_target_pwrlevel(struct adreno_device *adreno_dev,
+ struct device_node *node)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ unsigned int ca_target_pwrlevel = 1;
+
+ of_property_read_u32(node, "qcom,ca-target-pwrlevel",
+ &ca_target_pwrlevel);
+
+ if (ca_target_pwrlevel > device->pwrctrl.num_pwrlevels - 2)
+ ca_target_pwrlevel = 1;
+
+ device->pwrscale.ctxt_aware_target_pwrlevel = ca_target_pwrlevel;
+}
+
+static void adreno_of_get_ca_aware_properties(struct adreno_device *adreno_dev,
+ struct device_node *parent)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ struct kgsl_pwrscale *pwrscale = &device->pwrscale;
+ struct device_node *node, *child;
+ unsigned int bin = 0;
+
+ pwrscale->ctxt_aware_enable =
+ of_property_read_bool(parent, "qcom,enable-ca-jump");
+
+ if (pwrscale->ctxt_aware_enable) {
+ if (of_property_read_u32(parent, "qcom,ca-busy-penalty",
+ &pwrscale->ctxt_aware_busy_penalty))
+ pwrscale->ctxt_aware_busy_penalty = 12000;
+
+ node = of_find_node_by_name(parent, "qcom,gpu-pwrlevel-bins");
+ if (node == NULL) {
+ adreno_of_get_ca_target_pwrlevel(adreno_dev, parent);
+ return;
+ }
+
+ for_each_child_of_node(node, child) {
+ if (of_property_read_u32(child, "qcom,speed-bin", &bin))
+ continue;
+
+ if (bin == adreno_dev->speed_bin) {
+ adreno_of_get_ca_target_pwrlevel(adreno_dev,
+ child);
+ return;
+ }
+ }
+
+ pwrscale->ctxt_aware_target_pwrlevel = 1;
+ }
+}
+
static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
struct device_node *node)
{
@@ -1005,6 +1057,9 @@
if (adreno_of_get_pwrlevels(adreno_dev, node))
return -EINVAL;
+ /* Get context aware DCVS properties */
+ adreno_of_get_ca_aware_properties(adreno_dev, node);
+
/* get pm-qos-active-latency, set it to default if not found */
if (of_property_read_u32(node, "qcom,pm-qos-active-latency",
&device->pwrctrl.pm_qos_active_latency))
@@ -2470,7 +2525,39 @@
context->pwr_constraint.sub_type);
context->pwr_constraint.type = KGSL_CONSTRAINT_NONE;
break;
+ case KGSL_CONSTRAINT_L3_PWRLEVEL: {
+ struct kgsl_device_constraint_pwrlevel pwr;
+ if (constraint->size != sizeof(pwr)) {
+ status = -EINVAL;
+ break;
+ }
+
+ if (copy_from_user(&pwr, (void __user *)constraint->data,
+ sizeof(pwr))) {
+ status = -EFAULT;
+ break;
+ }
+ if (pwr.level >= KGSL_CONSTRAINT_PWR_MAXLEVELS)
+ pwr.level = KGSL_CONSTRAINT_PWR_MAXLEVELS-1;
+
+ context->l3_pwr_constraint.type = KGSL_CONSTRAINT_L3_PWRLEVEL;
+ context->l3_pwr_constraint.sub_type = pwr.level;
+ trace_kgsl_user_pwrlevel_constraint(device, context->id,
+ context->l3_pwr_constraint.type,
+ context->l3_pwr_constraint.sub_type);
+ }
+ break;
+ case KGSL_CONSTRAINT_L3_NONE: {
+ unsigned int type = context->l3_pwr_constraint.type;
+
+ if (type == KGSL_CONSTRAINT_L3_PWRLEVEL)
+ trace_kgsl_user_pwrlevel_constraint(device, context->id,
+ KGSL_CONSTRAINT_L3_NONE,
+ context->l3_pwr_constraint.sub_type);
+ context->l3_pwr_constraint.type = KGSL_CONSTRAINT_L3_NONE;
+ }
+ break;
default:
status = -EINVAL;
break;
@@ -2552,7 +2639,27 @@
status = adreno_set_constraint(device, context,
&constraint);
+ kgsl_context_put(context);
+ }
+ break;
+ case KGSL_PROP_L3_PWR_CONSTRAINT: {
+ struct kgsl_device_constraint constraint;
+ struct kgsl_context *context;
+ if (sizebytes != sizeof(constraint))
+ break;
+ if (copy_from_user(&constraint, value,
+ sizeof(constraint))) {
+ status = -EFAULT;
+ break;
+ }
+ context = kgsl_context_get_owner(dev_priv,
+ constraint.context_id);
+
+ if (context == NULL)
+ break;
+ status = adreno_set_constraint(device, context,
+ &constraint);
kgsl_context_put(context);
}
break;
@@ -3508,6 +3615,8 @@
.clk_set_options = adreno_clk_set_options,
.gpu_model = adreno_gpu_model,
.stop_fault_timer = adreno_dispatcher_stop_fault_timer,
+ .dispatcher_halt = adreno_dispatcher_halt,
+ .dispatcher_unhalt = adreno_dispatcher_unhalt,
};
static struct platform_driver adreno_platform_driver = {
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index a615dca..4775c3e 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -1353,31 +1353,27 @@
/* todo double check the reg writes */
while ((cur - opcode) < length) {
- switch (cur[0]) {
- /* Write a 32 bit value to a 64 bit reg */
- case 1:
+ if (cur[0] == 1 && ((cur + 4) - opcode) <= length) {
+ /* Write a 32 bit value to a 64 bit reg */
reg = cur[2];
reg = (reg << 32) | cur[1];
kgsl_regwrite(KGSL_DEVICE(adreno_dev), reg, cur[3]);
cur += 4;
- break;
- /* Write a 64 bit value to a 64 bit reg */
- case 2:
+ } else if (cur[0] == 2 && ((cur + 5) - opcode) <= length) {
+ /* Write a 64 bit value to a 64 bit reg */
reg = cur[2];
reg = (reg << 32) | cur[1];
val = cur[4];
val = (val << 32) | cur[3];
kgsl_regwrite(KGSL_DEVICE(adreno_dev), reg, val);
cur += 5;
- break;
- /* Delay for X usec */
- case 3:
+ } else if (cur[0] == 3 && ((cur + 2) - opcode) <= length) {
+ /* Delay for X usec */
udelay(cur[1]);
cur += 2;
- break;
- default:
+ } else
return -EINVAL;
- } }
+ }
return 0;
}
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 7b783a9..daf314d 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -511,7 +511,7 @@
if (adreno_is_a615(adreno_dev))
return 0x00000222;
else
- return 0x00020222;
+ return 0x00020202;
}
static inline unsigned int
@@ -791,13 +791,14 @@
kgsl_regwrite(device, A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE,
0x1);
+ a6xx_protect_init(adreno_dev);
+
if (!patch_reglist && (adreno_dev->pwrup_reglist.gpuaddr != 0)) {
a6xx_patch_pwrup_reglist(adreno_dev);
patch_reglist = true;
}
a6xx_preemption_start(adreno_dev);
- a6xx_protect_init(adreno_dev);
/*
* We start LM here because we want all the following to be up
@@ -1389,6 +1390,7 @@
{
struct gmu_device *gmu = &device->gmu;
+ kgsl_regwrite(device, A6XX_GMU_CX_GMU_WFI_CONFIG, 0x0);
/* Write 1 first to make sure the GMU is reset */
kgsl_gmu_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1);
diff --git a/drivers/gpu/msm/adreno_compat.c b/drivers/gpu/msm/adreno_compat.c
index 5a8d587..1f806da 100644
--- a/drivers/gpu/msm/adreno_compat.c
+++ b/drivers/gpu/msm/adreno_compat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -187,6 +187,37 @@
kgsl_context_put(context);
}
break;
+ case KGSL_PROP_L3_PWR_CONSTRAINT: {
+ struct kgsl_device_constraint_compat constraint32;
+ struct kgsl_device_constraint constraint;
+ struct kgsl_context *context;
+
+ if (sizebytes != sizeof(constraint32))
+ break;
+
+ if (copy_from_user(&constraint32, value,
+ sizeof(constraint32))) {
+ status = -EFAULT;
+ break;
+ }
+
+ constraint.type = constraint32.type;
+ constraint.context_id = constraint32.context_id;
+ constraint.data = compat_ptr(constraint32.data);
+ constraint.size = (size_t)constraint32.size;
+
+ context = kgsl_context_get_owner(dev_priv,
+ constraint.context_id);
+
+ if (context == NULL)
+ break;
+
+ status = adreno_set_constraint(device, context,
+ &constraint);
+ kgsl_context_put(context);
+
+ }
+ break;
default:
/*
* Call adreno_setproperty in case the property type was
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 86b3986..b8c282d 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -2857,6 +2857,16 @@
return ret;
}
+void adreno_dispatcher_halt(struct kgsl_device *device)
+{
+ adreno_get_gpu_halt(ADRENO_DEVICE(device));
+}
+
+void adreno_dispatcher_unhalt(struct kgsl_device *device)
+{
+ adreno_put_gpu_halt(ADRENO_DEVICE(device));
+}
+
/*
* adreno_dispatcher_idle() - Wait for dispatcher to idle
* @adreno_dev: Adreno device whose dispatcher needs to idle
@@ -2887,6 +2897,13 @@
mutex_unlock(&device->mutex);
+ /*
+ * Flush the worker to make sure all executing
+ * or pending dispatcher works on worker are
+ * finished
+ */
+ kthread_flush_worker(&kgsl_driver.worker);
+
ret = wait_for_completion_timeout(&dispatcher->idle_gate,
msecs_to_jiffies(ADRENO_IDLE_TIMEOUT));
if (ret == 0) {
diff --git a/drivers/gpu/msm/adreno_dispatch.h b/drivers/gpu/msm/adreno_dispatch.h
index 48f0cdc..61bd06f 100644
--- a/drivers/gpu/msm/adreno_dispatch.h
+++ b/drivers/gpu/msm/adreno_dispatch.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, 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
@@ -103,6 +103,8 @@
};
void adreno_dispatcher_start(struct kgsl_device *device);
+void adreno_dispatcher_halt(struct kgsl_device *device);
+void adreno_dispatcher_unhalt(struct kgsl_device *device);
int adreno_dispatcher_init(struct adreno_device *adreno_dev);
void adreno_dispatcher_close(struct adreno_device *adreno_dev);
int adreno_dispatcher_idle(struct adreno_device *adreno_dev);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 1faad93..df93606 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -762,10 +762,55 @@
sizedwords, 0, NULL);
}
+static int
+l3_pwrlevel_probe(struct kgsl_device *device, struct device_node *node)
+{
+
+ struct device_node *pwrlevel_node, *child;
+
+ pwrlevel_node = of_find_node_by_name(node, "qcom,l3-pwrlevels");
+
+ if (pwrlevel_node == NULL) {
+ dev_err_once(&device->pdev->dev, "Unable to find 'qcom,l3-pwrlevels'\n");
+ return -EINVAL;
+ }
+
+ device->num_l3_pwrlevels = 0;
+
+ for_each_child_of_node(pwrlevel_node, child) {
+ unsigned int index;
+
+ if (of_property_read_u32(child, "reg", &index))
+ return -EINVAL;
+ if (index >= MAX_L3_LEVELS) {
+ dev_err(&device->pdev->dev, "L3 pwrlevel %d is out of range\n",
+ index);
+ continue;
+ }
+
+ if (index >= device->num_l3_pwrlevels)
+ device->num_l3_pwrlevels = index + 1;
+
+ if (of_property_read_u32(child, "qcom,l3-freq",
+ &device->l3_freq[index]))
+ return -EINVAL;
+
+ }
+
+ return 0;
+
+}
+
static void adreno_ringbuffer_set_constraint(struct kgsl_device *device,
struct kgsl_drawobj *drawobj)
{
struct kgsl_context *context = drawobj->context;
+ struct device *dev = &device->pdev->dev;
+ unsigned long flags = drawobj->flags;
+ struct device_node *node;
+
+ node = device->pdev->dev.of_node;
+
/*
* Check if the context has a constraint and constraint flags are
* set.
@@ -775,6 +820,45 @@
(drawobj->flags & KGSL_CONTEXT_PWR_CONSTRAINT)))
kgsl_pwrctrl_set_constraint(device, &context->pwr_constraint,
context->id);
+
+ if (IS_ERR_OR_NULL(device->l3_clk))
+ device->l3_clk = devm_clk_get(dev, "l3_vote");
+
+ if (IS_ERR_OR_NULL(device->l3_clk)) {
+ KGSL_DEV_ERR_ONCE(device, "Unable to get the l3_vote clock. Cannot set the L3 constraint\n");
+ return;
+ }
+
+ if (context->l3_pwr_constraint.type &&
+ ((context->flags & KGSL_CONTEXT_PWR_CONSTRAINT) ||
+ (flags & KGSL_CONTEXT_PWR_CONSTRAINT))) {
+
+ int ret = l3_pwrlevel_probe(device, node);
+
+ if (ret)
+ return;
+
+ switch (context->l3_pwr_constraint.type) {
+
+ case KGSL_CONSTRAINT_L3_PWRLEVEL: {
+ unsigned int sub_type;
+
+ sub_type = context->l3_pwr_constraint.sub_type;
+
+ if (sub_type == KGSL_CONSTRAINT_L3_PWR_MED)
+ clk_set_rate(device->l3_clk,
+ device->l3_freq[1]);
+
+ if (sub_type == KGSL_CONSTRAINT_L3_PWR_MAX)
+ clk_set_rate(device->l3_clk,
+ device->l3_freq[2]);
+ }
+ break;
+ case KGSL_CONSTRAINT_L3_NONE:
+ clk_set_rate(device->l3_clk, device->l3_freq[0]);
+ break;
+ }
+ }
}
static inline int _get_alwayson_counter(struct adreno_device *adreno_dev,
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 49514e3..913f9bf 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -531,14 +531,21 @@
int ret = 0, id;
struct kgsl_process_private *proc_priv = dev_priv->process_priv;
+ /*
+ * Read and increment the context count under lock to make sure
+ * no process goes beyond the specified context limit.
+ */
+ spin_lock(&proc_priv->ctxt_count_lock);
if (atomic_read(&proc_priv->ctxt_count) > KGSL_MAX_CONTEXTS_PER_PROC) {
KGSL_DRV_ERR(device,
"Per process context limit reached for pid %u",
dev_priv->process_priv->pid);
+ spin_unlock(&proc_priv->ctxt_count_lock);
return -ENOSPC;
}
atomic_inc(&proc_priv->ctxt_count);
+ spin_unlock(&proc_priv->ctxt_count_lock);
id = _kgsl_get_context_id(device);
if (id == -ENOSPC) {
@@ -753,6 +760,8 @@
mutex_lock(&device->mutex);
status = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND);
+ if (status == 0)
+ device->ftbl->dispatcher_halt(device);
mutex_unlock(&device->mutex);
KGSL_PWR_WARN(device, "suspend end\n");
@@ -767,6 +776,7 @@
KGSL_PWR_WARN(device, "resume start\n");
mutex_lock(&device->mutex);
if (device->state == KGSL_STATE_SUSPEND) {
+ device->ftbl->dispatcher_unhalt(device);
kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
} else if (device->state != KGSL_STATE_INIT) {
/*
@@ -918,6 +928,7 @@
spin_lock_init(&private->mem_lock);
spin_lock_init(&private->syncsource_lock);
+ spin_lock_init(&private->ctxt_count_lock);
idr_init(&private->mem_idr);
idr_init(&private->syncsource_idr);
@@ -4039,6 +4050,7 @@
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_gpuobj_set_info *param = data;
struct kgsl_mem_entry *entry;
+ int ret = 0;
if (param->id == 0)
return -EINVAL;
@@ -4051,13 +4063,16 @@
copy_metadata(entry, param->metadata, param->metadata_len);
if (param->flags & KGSL_GPUOBJ_SET_INFO_TYPE) {
- entry->memdesc.flags &= ~((uint64_t) KGSL_MEMTYPE_MASK);
- entry->memdesc.flags |= (uint64_t)(param->type <<
- KGSL_MEMTYPE_SHIFT);
+ if (param->type <= (KGSL_MEMTYPE_MASK >> KGSL_MEMTYPE_SHIFT)) {
+ entry->memdesc.flags &= ~((uint64_t) KGSL_MEMTYPE_MASK);
+ entry->memdesc.flags |= (uint64_t)((param->type <<
+ KGSL_MEMTYPE_SHIFT) & KGSL_MEMTYPE_MASK);
+ } else
+ ret = -EINVAL;
}
kgsl_mem_entry_put(entry);
- return 0;
+ return ret;
}
/**
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index b6a2edb..c737801 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -104,6 +104,7 @@
/* Allocate 600K for the snapshot static region*/
#define KGSL_SNAPSHOT_MEMSIZE (600 * 1024)
+#define MAX_L3_LEVELS 3
struct kgsl_device;
struct platform_device;
@@ -190,6 +191,8 @@
void (*gpu_model)(struct kgsl_device *device, char *str,
size_t bufsz);
void (*stop_fault_timer)(struct kgsl_device *device);
+ void (*dispatcher_halt)(struct kgsl_device *device);
+ void (*dispatcher_unhalt)(struct kgsl_device *device);
};
struct kgsl_ioctl {
@@ -330,6 +333,9 @@
/* Number of active contexts seen globally for this device */
int active_context_count;
struct kobject *gpu_sysfs_kobj;
+ struct clk *l3_clk;
+ unsigned int l3_freq[MAX_L3_LEVELS];
+ unsigned int num_l3_pwrlevels;
};
#define KGSL_MMU_DEVICE(_mmu) \
@@ -408,6 +414,7 @@
struct kgsl_event_group events;
unsigned int flags;
struct kgsl_pwr_constraint pwr_constraint;
+ struct kgsl_pwr_constraint l3_pwr_constraint;
unsigned int fault_count;
unsigned long fault_time;
struct kgsl_mem_entry *user_ctxt_record;
@@ -443,6 +450,7 @@
* @syncsource_lock: Spinlock to protect the syncsource idr
* @fd_count: Counter for the number of FDs for this process
* @ctxt_count: Count for the number of contexts for this process
+ * @ctxt_count_lock: Spinlock to protect ctxt_count
*/
struct kgsl_process_private {
unsigned long priv;
@@ -463,6 +471,7 @@
spinlock_t syncsource_lock;
int fd_count;
atomic_t ctxt_count;
+ spinlock_t ctxt_count_lock;
};
/**
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 10446f7..dbf517a 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -309,7 +309,7 @@
* @gmu: Pointer to GMU device
* @node: Pointer to GMU device node
*/
-int gmu_iommu_init(struct gmu_device *gmu, struct device_node *node)
+static int gmu_iommu_init(struct gmu_device *gmu, struct device_node *node)
{
struct device_node *child;
struct gmu_iommu_context *ctx = NULL;
@@ -346,7 +346,7 @@
* from IOMMU context banks.
* @gmu: Pointer to GMU device
*/
-void gmu_kmem_close(struct gmu_device *gmu)
+static void gmu_kmem_close(struct gmu_device *gmu)
{
int i;
struct gmu_memdesc *md = &gmu->fw_image;
@@ -386,7 +386,7 @@
iommu_domain_free(ctx->domain);
}
-void gmu_memory_close(struct gmu_device *gmu)
+static void gmu_memory_close(struct gmu_device *gmu)
{
gmu_kmem_close(gmu);
/* Free user memory context */
@@ -400,7 +400,7 @@
* @gmu: Pointer to GMU device
* @node: Pointer to GMU device node
*/
-int gmu_memory_probe(struct gmu_device *gmu, struct device_node *node)
+static int gmu_memory_probe(struct gmu_device *gmu, struct device_node *node)
{
int ret;
@@ -753,7 +753,7 @@
return 0;
}
-int gmu_rpmh_init(struct gmu_device *gmu, struct kgsl_pwrctrl *pwr)
+static int gmu_rpmh_init(struct gmu_device *gmu, struct kgsl_pwrctrl *pwr)
{
struct rpmh_arc_vals gfx_arc, cx_arc, mx_arc;
int ret;
diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c
index daac9f1..b1e6c83 100644
--- a/drivers/gpu/msm/kgsl_hfi.c
+++ b/drivers/gpu/msm/kgsl_hfi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -259,7 +259,7 @@
return rc;
}
-int hfi_send_gmu_init(struct gmu_device *gmu, uint32_t boot_state)
+static int hfi_send_gmu_init(struct gmu_device *gmu, uint32_t boot_state)
{
struct hfi_gmu_init_cmd init_msg = {
.hdr = {
@@ -292,7 +292,7 @@
return rc;
}
-int hfi_get_fw_version(struct gmu_device *gmu,
+static int hfi_get_fw_version(struct gmu_device *gmu,
uint32_t expected_ver, uint32_t *ver)
{
struct hfi_fw_version_cmd fw_ver = {
@@ -356,7 +356,7 @@
return rc;
}
-int hfi_send_perftbl(struct gmu_device *gmu)
+static int hfi_send_perftbl(struct gmu_device *gmu)
{
struct hfi_dcvstable_cmd dcvstbl = {
.hdr = {
@@ -397,7 +397,7 @@
return rc;
}
-int hfi_send_bwtbl(struct gmu_device *gmu)
+static int hfi_send_bwtbl(struct gmu_device *gmu)
{
struct hfi_bwtable_cmd bwtbl = {
.hdr = {
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 1baf20e..ee9e5df 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2602,6 +2602,9 @@
static void kgsl_pwrctrl_disable(struct kgsl_device *device)
{
+ if (!IS_ERR_OR_NULL(device->l3_clk))
+ clk_set_rate(device->l3_clk, 0);
+
if (kgsl_gmu_isenabled(device)) {
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
return gmu_stop(device);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 3f7ea18..2b8b6df 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -892,12 +892,6 @@
return PTR_ERR(opp);
}
- max_freq = dev_pm_opp_get_freq(opp);
- if (!max_freq) {
- rcu_read_unlock();
- return result;
- }
-
opp = dev_pm_opp_find_freq_ceil(dev, &min_freq);
if (IS_ERR(opp))
min_freq = pwr->pwrlevels[pwr->min_pwrlevel].gpu_freq;
@@ -1039,24 +1033,12 @@
data->disable_busy_time_burst = of_property_read_bool(
device->pdev->dev.of_node, "qcom,disable-busy-time-burst");
- data->ctxt_aware_enable =
- of_property_read_bool(device->pdev->dev.of_node,
- "qcom,enable-ca-jump");
-
- if (data->ctxt_aware_enable) {
- if (of_property_read_u32(device->pdev->dev.of_node,
- "qcom,ca-target-pwrlevel",
- &data->bin.ctxt_aware_target_pwrlevel))
- data->bin.ctxt_aware_target_pwrlevel = 1;
-
- if ((data->bin.ctxt_aware_target_pwrlevel >
- pwr->num_pwrlevels))
- data->bin.ctxt_aware_target_pwrlevel = 1;
-
- if (of_property_read_u32(device->pdev->dev.of_node,
- "qcom,ca-busy-penalty",
- &data->bin.ctxt_aware_busy_penalty))
- data->bin.ctxt_aware_busy_penalty = 12000;
+ if (pwrscale->ctxt_aware_enable) {
+ data->ctxt_aware_enable = pwrscale->ctxt_aware_enable;
+ data->bin.ctxt_aware_target_pwrlevel =
+ pwrscale->ctxt_aware_target_pwrlevel;
+ data->bin.ctxt_aware_busy_penalty =
+ pwrscale->ctxt_aware_busy_penalty;
}
if (of_property_read_bool(device->pdev->dev.of_node,
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index 7e906a0..9e28b65 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2018, 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
@@ -91,6 +91,11 @@
* @popp_level - Current level of POPP mitigation
* @popp_state - Control state for POPP, on/off, recently pushed, etc
* @cooling_dev - Thermal cooling device handle
+ * @ctxt_aware_enable - Whether or not ctxt aware DCVS feature is enabled
+ * @ctxt_aware_busy_penalty - The time in microseconds required to trigger
+ * ctxt aware power level jump
+ * @ctxt_aware_target_pwrlevel - pwrlevel to jump on in case of ctxt aware
+ * power level jump
*/
struct kgsl_pwrscale {
struct devfreq *devfreqptr;
@@ -113,6 +118,9 @@
int popp_level;
unsigned long popp_state;
struct thermal_cooling_device *cooling_dev;
+ bool ctxt_aware_enable;
+ unsigned int ctxt_aware_target_pwrlevel;
+ unsigned int ctxt_aware_busy_penalty;
};
int kgsl_pwrscale_init(struct device *dev, const char *governor);
diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h
index 7c9f334e..955401d 100644
--- a/drivers/gpu/msm/kgsl_sync.h
+++ b/drivers/gpu/msm/kgsl_sync.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014,2017-2018 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
@@ -137,8 +137,8 @@
}
-struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
- void (*func)(void *priv), void *priv,
+static inline struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
+ bool (*func)(void *priv), void *priv,
char *fence_name, int name_len)
{
return NULL;
@@ -188,7 +188,7 @@
}
-void kgsl_dump_fence(struct kgsl_drawobj_sync_event *event,
+static inline void kgsl_dump_fence(struct kgsl_drawobj_sync_event *event,
char *fence_str, int len)
{
}
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index f2a7483..b5888db 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2366,7 +2366,6 @@
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) },
- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
@@ -2636,6 +2635,17 @@
strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0)
return true;
break;
+ case USB_VENDOR_ID_ELAN:
+ /*
+ * Many Elan devices have a product id of 0x0401 and are handled
+ * by the elan_i2c input driver. But the ACPI HID ELAN0800 dev
+ * is not (and cannot be) handled by that driver ->
+ * Ignore all 0x0401 devs except for the ELAN0800 dev.
+ */
+ if (hdev->product == 0x0401 &&
+ strncmp(hdev->name, "ELAN0800", 8) != 0)
+ return true;
+ break;
}
if (hdev->type == HID_TYPE_USBMOUSE &&
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 6a27eb2..be1e380 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -269,13 +269,13 @@
for (i = 0; i < ARRAY_SIZE(tjmax_model_table); i++) {
const struct tjmax_model *tm = &tjmax_model_table[i];
if (c->x86_model == tm->model &&
- (tm->mask == ANY || c->x86_mask == tm->mask))
+ (tm->mask == ANY || c->x86_stepping == tm->mask))
return tm->tjmax;
}
/* Early chips have no MSR for TjMax */
- if (c->x86_model == 0xf && c->x86_mask < 4)
+ if (c->x86_model == 0xf && c->x86_stepping < 4)
usemsr_ee = 0;
if (c->x86_model > 0xe && usemsr_ee) {
@@ -426,7 +426,7 @@
* Readings might stop update when processor visited too deep sleep,
* fixed for stepping D0 (6EC).
*/
- if (c->x86_model == 0xe && c->x86_mask < 0xc && c->microcode < 0x39) {
+ if (c->x86_model == 0xe && c->x86_stepping < 0xc && c->microcode < 0x39) {
pr_err("Errata AE18 not fixed, update BIOS or microcode of the CPU!\n");
return -ENODEV;
}
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
index ef91b8a..84e9128 100644
--- a/drivers/hwmon/hwmon-vid.c
+++ b/drivers/hwmon/hwmon-vid.c
@@ -293,7 +293,7 @@
if (c->x86 < 6) /* Any CPU with family lower than 6 */
return 0; /* doesn't have VID */
- vrm_ret = find_vrm(c->x86, c->x86_model, c->x86_mask, c->x86_vendor);
+ vrm_ret = find_vrm(c->x86, c->x86_model, c->x86_stepping, c->x86_vendor);
if (vrm_ret == 134)
vrm_ret = get_via_model_d_vrm();
if (vrm_ret == 0)
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index 9cdfde6..0124584 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -179,7 +179,7 @@
* and AM3 formats, but that's the best we can do.
*/
return boot_cpu_data.x86_model < 4 ||
- (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_mask <= 2);
+ (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_stepping <= 2);
}
static int k10temp_probe(struct pci_dev *pdev,
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
index 734d55d..4865027 100644
--- a/drivers/hwmon/k8temp.c
+++ b/drivers/hwmon/k8temp.c
@@ -187,7 +187,7 @@
return -ENOMEM;
model = boot_cpu_data.x86_model;
- stepping = boot_cpu_data.x86_mask;
+ stepping = boot_cpu_data.x86_stepping;
/* feature available since SH-C0, exclude older revisions */
if ((model == 4 && stepping == 0) ||
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index f3e16b3..62ad4f4 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -677,6 +677,80 @@
{124, 980}
};
+/* Voltage to temperature */
+static const struct qpnp_vadc_map_pt adcmap_batt_therm_qrd[] = {
+ {1840, -400},
+ {1835, -380},
+ {1828, -360},
+ {1821, -340},
+ {1813, -320},
+ {1803, -300},
+ {1793, -280},
+ {1781, -260},
+ {1768, -240},
+ {1753, -220},
+ {1737, -200},
+ {1719, -180},
+ {1700, -160},
+ {1679, -140},
+ {1655, -120},
+ {1630, -100},
+ {1603, -80},
+ {1574, -60},
+ {1543, -40},
+ {1510, -20},
+ {1475, 00},
+ {1438, 20},
+ {1400, 40},
+ {1360, 60},
+ {1318, 80},
+ {1276, 100},
+ {1232, 120},
+ {1187, 140},
+ {1142, 160},
+ {1097, 180},
+ {1051, 200},
+ {1005, 220},
+ {960, 240},
+ {915, 260},
+ {871, 280},
+ {828, 300},
+ {786, 320},
+ {745, 340},
+ {705, 360},
+ {666, 380},
+ {629, 400},
+ {594, 420},
+ {560, 440},
+ {527, 460},
+ {497, 480},
+ {467, 500},
+ {439, 520},
+ {413, 540},
+ {388, 560},
+ {365, 580},
+ {343, 600},
+ {322, 620},
+ {302, 640},
+ {284, 660},
+ {267, 680},
+ {251, 700},
+ {235, 720},
+ {221, 740},
+ {208, 760},
+ {195, 780},
+ {184, 800},
+ {173, 820},
+ {163, 840},
+ {153, 860},
+ {144, 880},
+ {136, 900},
+ {128, 920},
+ {120, 940},
+ {114, 960},
+ {107, 980}
+};
+
/*
* Voltage to temperature table for 100k pull up for NTCG104EF104 with
* 1.875V reference.
@@ -1016,6 +1090,36 @@
}
EXPORT_SYMBOL(qpnp_adc_batt_therm);
+int32_t qpnp_adc_batt_therm_qrd(struct qpnp_vadc_chip *chip,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int64_t batt_thm_voltage = 0;
+
+ if (!chan_properties || !chan_properties->offset_gain_numerator ||
+ !chan_properties->offset_gain_denominator || !adc_properties
+ || !adc_chan_result)
+ return -EINVAL;
+
+ if (adc_properties->adc_hc) {
+ /* (code * vref_vadc (1.875V) * 1000) / (scale_code * 1000) */
+ if (adc_code > QPNP_VADC_HC_MAX_CODE)
+ adc_code = 0;
+ batt_thm_voltage = (int64_t) adc_code;
+ batt_thm_voltage *= (adc_properties->adc_vdd_reference
+ * 1000);
+ batt_thm_voltage = div64_s64(batt_thm_voltage,
+ adc_properties->full_scale_code * 1000);
+ qpnp_adc_map_voltage_temp(adcmap_batt_therm_qrd,
+ ARRAY_SIZE(adcmap_batt_therm_qrd),
+ batt_thm_voltage, &adc_chan_result->physical);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_batt_therm_qrd);
+
int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *chip,
int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
@@ -1929,6 +2033,34 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_pmi_chg_temp);
+int32_t qpnp_adc_scale_die_temp_1390(struct qpnp_vadc_chip *chip,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int rc = 0;
+
+ if (!chan_properties || !chan_properties->offset_gain_numerator ||
+ !chan_properties->offset_gain_denominator || !adc_properties
+ || !adc_chan_result)
+ return -EINVAL;
+
+ rc = qpnp_adc_scale_default(chip, adc_code, adc_properties,
+ chan_properties, adc_chan_result);
+ if (rc < 0)
+ return rc;
+
+ pr_debug("raw_code:%x, v_adc:%lld\n", adc_code,
+ adc_chan_result->physical);
+ /* T = (1.49322 – V) / 0.00356 */
+ adc_chan_result->physical = 1493220 - adc_chan_result->physical;
+ adc_chan_result->physical = div64_s64(adc_chan_result->physical, 356);
+
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_scale_die_temp_1390);
+
int32_t qpnp_adc_enable_voltage(struct qpnp_adc_drv *adc)
{
int rc = 0;
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 8b44c0f..59ca208 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -35,6 +35,8 @@
#include <linux/power_supply.h>
#include <linux/thermal.h>
+#define QPNP_VADC_HC_VREF_CODE 0x4000
+
/* QPNP VADC register definition */
#define QPNP_VADC_REVISION1 0x0
#define QPNP_VADC_REVISION2 0x1
@@ -107,7 +109,7 @@
#define QPNP_VADC_CONV_TIME_MIN 1000
#define QPNP_VADC_CONV_TIME_MAX 1100
#define QPNP_ADC_COMPLETION_TIMEOUT HZ
-#define QPNP_VADC_ERR_COUNT 20
+#define QPNP_VADC_ERR_COUNT 50
#define QPNP_OP_MODE_SHIFT 3
#define QPNP_VADC_THR_LSB_MASK(val) (val & 0xff)
@@ -224,6 +226,8 @@
[SCALE_DIE_TEMP] = {qpnp_adc_scale_die_temp},
[SCALE_I_DEFAULT] = {qpnp_iadc_scale_default},
[SCALE_USBIN_I] = {qpnp_adc_scale_usbin_curr},
+ [SCALE_BATT_THERM_TEMP_QRD] = {qpnp_adc_batt_therm_qrd},
+ [SCALE_SMB1390_DIE_TEMP] = {qpnp_adc_scale_die_temp_1390},
};
static struct qpnp_vadc_rscale_fn adc_vadc_rscale_fn[] = {
@@ -556,13 +560,15 @@
goto fail_unlock;
}
- if (!vadc->vadc_init_calib) {
- rc = qpnp_vadc_calib_device(vadc);
- if (rc) {
- pr_err("Calibration failed\n");
- goto fail_unlock;
- } else {
- vadc->vadc_init_calib = true;
+ if (vadc->adc->adc_prop->full_scale_code == QPNP_VADC_HC_VREF_CODE) {
+ if (!vadc->vadc_init_calib) {
+ rc = qpnp_vadc_calib_device(vadc);
+ if (rc) {
+ pr_err("Calibration failed\n");
+ goto fail_unlock;
+ } else {
+ vadc->vadc_init_calib = true;
+ }
}
}
diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.c b/drivers/hwtracing/coresight/coresight-byte-cntr.c
index 81889b6..5173770 100644
--- a/drivers/hwtracing/coresight/coresight-byte-cntr.c
+++ b/drivers/hwtracing/coresight/coresight-byte-cntr.c
@@ -149,6 +149,8 @@
if (!byte_cntr_data->read_active)
goto err0;
+ bufp = (char *)(tmcdrvdata->buf + *ppos);
+
if (byte_cntr_data->enable) {
if (!atomic_read(&byte_cntr_data->irq_cnt)) {
mutex_unlock(&byte_cntr_data->byte_cntr_lock);
@@ -159,7 +161,6 @@
if (!byte_cntr_data->read_active)
goto err0;
}
- bufp = (char *)(tmcdrvdata->buf + *ppos);
if (tmcdrvdata->mem_type == TMC_ETR_MEM_TYPE_CONTIG)
tmc_etr_read_bytes(byte_cntr_data, ppos,
@@ -268,8 +269,12 @@
return -EINVAL;
}
+ /* IRQ is a '8- byte' counter and to observe interrupt at
+ * 'block_size' bytes of data
+ */
coresight_csr_set_byte_cntr(byte_cntr_data->csr,
- byte_cntr_data->block_size);
+ (byte_cntr_data->block_size) / 8);
+
fp->private_data = byte_cntr_data;
nonseekable_open(in, fp);
byte_cntr_data->enable = true;
diff --git a/drivers/hwtracing/coresight/coresight-dbgui.c b/drivers/hwtracing/coresight/coresight-dbgui.c
index e4feea2..eb01fca 100644
--- a/drivers/hwtracing/coresight/coresight-dbgui.c
+++ b/drivers/hwtracing/coresight/coresight-dbgui.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -375,10 +375,10 @@
const char *buf,
size_t size)
{
- uint32_t val;
+ unsigned long val;
struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 16, (unsigned long *)&val))
+ if (kstrtoul(buf, 16, &val))
return -EINVAL;
mutex_lock(&drvdata->mutex);
@@ -403,10 +403,10 @@
const char *buf,
size_t size)
{
- uint32_t val;
+ unsigned long val;
struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 16, (unsigned long *)&val))
+ if (kstrtoul(buf, 16, &val))
return -EINVAL;
mutex_lock(&drvdata->mutex);
@@ -434,10 +434,10 @@
const char *buf,
size_t size)
{
- uint32_t val;
+ unsigned long val;
struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 16, (unsigned long *)&val))
+ if (kstrtoul(buf, 16, &val))
return -EINVAL;
mutex_lock(&drvdata->mutex);
@@ -463,10 +463,10 @@
const char *buf,
size_t size)
{
- uint32_t val;
+ unsigned long val;
struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 16, (unsigned long *)&val))
+ if (kstrtoul(buf, 16, &val))
return -EINVAL;
mutex_lock(&drvdata->mutex);
@@ -492,10 +492,10 @@
const char *buf,
size_t size)
{
- uint32_t val;
+ unsigned long val;
struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 16, (unsigned long *)&val))
+ if (kstrtoul(buf, 16, &val))
return -EINVAL;
if (!val)
@@ -528,10 +528,10 @@
const char *buf,
size_t size)
{
- uint32_t val;
+ unsigned long val;
struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 16, (unsigned long *)&val))
+ if (kstrtoul(buf, 16, &val))
return -EINVAL;
if (val > drvdata->size)
@@ -569,10 +569,10 @@
const char *buf,
size_t size)
{
- uint32_t val;
+ unsigned long val;
struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 16, (unsigned long *)&val))
+ if (kstrtoul(buf, 16, &val))
return -EINVAL;
if (val > drvdata->size)
@@ -615,10 +615,10 @@
const char *buf,
size_t size)
{
- uint32_t val;
+ unsigned long val;
struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 16, (unsigned long *)&val))
+ if (kstrtoul(buf, 16, &val))
return -EINVAL;
mutex_lock(&drvdata->mutex);
@@ -643,10 +643,10 @@
const char *buf,
size_t size)
{
- uint32_t val;
+ unsigned long val;
struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 16, (unsigned long *)&val))
+ if (kstrtoul(buf, 16, &val))
return -EINVAL;
if (val >= drvdata->size)
@@ -674,10 +674,10 @@
const char *buf,
size_t size)
{
- uint32_t val;
+ unsigned long val;
struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 16, (unsigned long *)&val))
+ if (kstrtoul(buf, 16, &val))
return -EINVAL;
mutex_lock(&drvdata->mutex);
@@ -755,9 +755,10 @@
size_t size)
{
struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
- uint32_t val, ret;
+ uint32_t ret;
+ unsigned long val;
- if (kstrtoul(buf, 16, (unsigned long *)&val))
+ if (kstrtoul(buf, 16, &val))
return -EINVAL;
if (val)
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
index a9cedba..13a9ad1 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -203,9 +203,23 @@
event_data = alloc_event_data(event_cpu);
if (!event_data)
return NULL;
-
INIT_WORK(&event_data->work, free_event_data);
+ /*
+ * In theory nothing prevent tracers in a trace session from being
+ * associated with different sinks, nor having a sink per tracer. But
+ * until we have HW with this kind of topology we need to assume tracers
+ * in a trace session are using the same sink. Therefore go through
+ * the coresight bus and pick the first enabled sink.
+ *
+ * When operated from sysFS users are responsible to enable the sink
+ * while from perf, the perf tools will do it based on the choice made
+ * on the cmd line. As such the "enable_sink" flag in sysFS is reset.
+ */
+ sink = coresight_get_enabled_sink(true);
+ if (!sink)
+ goto err;
+
mask = &event_data->mask;
/* Setup the path for each CPU in a trace session */
@@ -221,28 +235,15 @@
* list of devices from source to sink that can be
* referenced later when the path is actually needed.
*/
- event_data->path[cpu] = coresight_build_path(csdev);
+ event_data->path[cpu] = coresight_build_path(csdev, sink);
if (IS_ERR(event_data->path[cpu]))
goto err;
}
- /*
- * In theory nothing prevent tracers in a trace session from being
- * associated with different sinks, nor having a sink per tracer. But
- * until we have HW with this kind of topology and a way to convey
- * sink assignement from the perf cmd line we need to assume tracers
- * in a trace session are using the same sink. Therefore pick the sink
- * found at the end of the first available path.
- */
- cpu = cpumask_first(mask);
- /* Grab the sink at the end of the path */
- sink = coresight_get_sink(event_data->path[cpu]);
- if (!sink)
- goto err;
-
if (!sink_ops(sink)->alloc_buffer)
goto err;
+ cpu = cpumask_first(mask);
/* Get the AUX specific data from the sink buffer */
event_data->snk_config =
sink_ops(sink)->alloc_buffer(sink, cpu, pages,
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index ee4b8b4..a4bf109 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -1035,7 +1035,8 @@
etmdrvdata[drvdata->cpu] = drvdata;
- dev_info(dev, "%s initialized\n", (char *)id->data);
+ dev_info(dev, "CPU%d: %s initialized\n",
+ drvdata->cpu, (char *)id->data);
if (boot_enable) {
coresight_enable(drvdata->csdev);
@@ -1054,20 +1055,25 @@
}
static struct amba_id etm4_ids[] = {
- { /* ETM 4.0 - Cortex-A53 */
+ {
.id = 0x000bb95d,
.mask = 0x000fffff,
- .data = "ETM 4.0",
+ .data = "Cortex-A53 ETM v4.0",
},
- { /* ETM 4.0 - Cortex-A57 */
+ {
.id = 0x000bb95e,
.mask = 0x000fffff,
- .data = "ETM 4.0",
+ .data = "Cortex-A57 ETM v4.0",
},
- { /* ETM 4.0 - A72, Maia, HiSilicon */
+ {
.id = 0x000bb95a,
.mask = 0x000fffff,
- .data = "ETM 4.0",
+ .data = "Cortex-A72 ETM v4.0",
+ },
+ {
+ .id = 0x000bb959,
+ .mask = 0x000fffff,
+ .data = "Cortex-A73 ETM v4.0",
},
{ 0, 0},
};
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index ba721fd..8578023 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -140,7 +140,9 @@
int coresight_enable_path(struct list_head *path, u32 mode);
struct coresight_device *coresight_get_sink(struct list_head *path);
struct coresight_device *coresight_get_source(struct list_head *path);
-struct list_head *coresight_build_path(struct coresight_device *csdev);
+struct coresight_device *coresight_get_enabled_sink(bool reset);
+struct list_head *coresight_build_path(struct coresight_device *csdev,
+ struct coresight_device *sink);
void coresight_release_path(struct coresight_device *csdev,
struct list_head *path);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 4ade209..0f648e0 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -70,7 +70,7 @@
* When operating in sysFS mode the content of the buffer needs to be
* read before the TMC is disabled.
*/
- if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
+ if (drvdata->mode == CS_MODE_SYSFS)
tmc_etb_dump_hw(drvdata);
tmc_disable_hw(drvdata);
@@ -103,19 +103,14 @@
CS_LOCK(drvdata->base);
}
-static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32 mode)
+static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
{
int ret = 0;
bool used = false;
char *buf = NULL;
- long val;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- /* This shouldn't be happening */
- if (WARN_ON(mode != CS_MODE_SYSFS))
- return -EINVAL;
-
/*
* If we don't have a buffer release the lock and allocate memory.
* Otherwise keep the lock and move along.
@@ -138,13 +133,12 @@
goto out;
}
- val = local_xchg(&drvdata->mode, mode);
/*
* In sysFS mode we can have multiple writers per sink. Since this
* sink is already enabled no memory is needed and the HW need not be
* touched.
*/
- if (val == CS_MODE_SYSFS)
+ if (drvdata->mode == CS_MODE_SYSFS)
goto out;
/*
@@ -163,6 +157,7 @@
drvdata->buf = buf;
}
+ drvdata->mode = CS_MODE_SYSFS;
tmc_etb_enable_hw(drvdata);
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -180,34 +175,29 @@
return ret;
}
-static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, u32 mode)
+static int tmc_enable_etf_sink_perf(struct coresight_device *csdev)
{
int ret = 0;
- long val;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- /* This shouldn't be happening */
- if (WARN_ON(mode != CS_MODE_PERF))
- return -EINVAL;
-
spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
ret = -EINVAL;
goto out;
}
- val = local_xchg(&drvdata->mode, mode);
/*
* In Perf mode there can be only one writer per sink. There
* is also no need to continue if the ETB/ETR is already operated
* from sysFS.
*/
- if (val != CS_MODE_DISABLED) {
+ if (drvdata->mode != CS_MODE_DISABLED) {
ret = -EINVAL;
goto out;
}
+ drvdata->mode = CS_MODE_PERF;
tmc_etb_enable_hw(drvdata);
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -219,9 +209,9 @@
{
switch (mode) {
case CS_MODE_SYSFS:
- return tmc_enable_etf_sink_sysfs(csdev, mode);
+ return tmc_enable_etf_sink_sysfs(csdev);
case CS_MODE_PERF:
- return tmc_enable_etf_sink_perf(csdev, mode);
+ return tmc_enable_etf_sink_perf(csdev);
}
/* We shouldn't be here */
@@ -230,7 +220,6 @@
static void tmc_disable_etf_sink(struct coresight_device *csdev)
{
- long val;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -240,10 +229,11 @@
return;
}
- val = local_xchg(&drvdata->mode, CS_MODE_DISABLED);
/* Disable the TMC only if it needs to */
- if (val != CS_MODE_DISABLED)
+ if (drvdata->mode != CS_MODE_DISABLED) {
tmc_etb_disable_hw(drvdata);
+ drvdata->mode = CS_MODE_DISABLED;
+ }
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -266,7 +256,7 @@
}
tmc_etf_enable_hw(drvdata);
- local_set(&drvdata->mode, CS_MODE_SYSFS);
+ drvdata->mode = CS_MODE_SYSFS;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_info(drvdata->dev, "TMC-ETF enabled\n");
@@ -286,7 +276,7 @@
}
tmc_etf_disable_hw(drvdata);
- local_set(&drvdata->mode, CS_MODE_DISABLED);
+ drvdata->mode = CS_MODE_DISABLED;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_info(drvdata->dev, "TMC disabled\n");
@@ -389,7 +379,7 @@
return;
/* This shouldn't happen */
- if (WARN_ON_ONCE(local_read(&drvdata->mode) != CS_MODE_PERF))
+ if (WARN_ON_ONCE(drvdata->mode != CS_MODE_PERF))
return;
CS_UNLOCK(drvdata->base);
@@ -541,7 +531,6 @@
int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
{
- long val;
enum tmc_mode mode;
int ret = 0;
unsigned long flags;
@@ -567,9 +556,8 @@
}
}
- val = local_read(&drvdata->mode);
/* Don't interfere if operated from Perf */
- if (val == CS_MODE_PERF) {
+ if (drvdata->mode == CS_MODE_PERF) {
ret = -EINVAL;
goto out;
}
@@ -581,7 +569,7 @@
}
/* Disable the TMC if need be */
- if (val == CS_MODE_SYSFS)
+ if (drvdata->mode == CS_MODE_SYSFS)
tmc_etb_disable_hw(drvdata);
drvdata->reading = true;
@@ -614,7 +602,7 @@
}
/* Re-enable the TMC if need be */
- if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
+ if (drvdata->mode == CS_MODE_SYSFS) {
/*
* The trace run will continue with the same allocated trace
* buffer. As such zero-out the buffer so that we don't end
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index dcdc3f2..bedb812 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -15,8 +15,11 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/circ_buf.h>
#include <linux/coresight.h>
#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
#include "coresight-priv.h"
#include "coresight-tmc.h"
@@ -416,6 +419,22 @@
}
}
+/**
+ * struct cs_etr_buffer - keep track of a recording session' specifics
+ * @tmc: generic portion of the TMC buffers
+ * @paddr: the physical address of a DMA'able contiguous memory area
+ * @vaddr: the virtual address associated to @paddr
+ * @size: how much memory we have, starting at @paddr
+ * @dev: the device @vaddr has been tied to
+ */
+struct cs_etr_buffers {
+ struct cs_buffers tmc;
+ dma_addr_t paddr;
+ void __iomem *vaddr;
+ u32 size;
+ struct device *dev;
+};
+
void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
{
u32 axictl;
@@ -505,7 +524,7 @@
* When operating in sysFS mode the content of the buffer needs to be
* read before the TMC is disabled.
*/
- if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
+ if (drvdata->mode == CS_MODE_SYSFS)
tmc_etr_dump_hw(drvdata);
tmc_disable_hw(drvdata);
@@ -759,16 +778,12 @@
return sps_register_bam_device(&bamdata->props, &bamdata->handle);
}
-static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32 mode)
+static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
{
int ret = 0;
- long val;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- /* This shouldn't be happening */
- if (WARN_ON(mode != CS_MODE_SYSFS))
- return -EINVAL;
mutex_lock(&drvdata->mem_lock);
@@ -816,16 +831,16 @@
spin_lock_irqsave(&drvdata->spinlock, flags);
- val = local_xchg(&drvdata->mode, mode);
/*
* In sysFS mode we can have multiple writers per sink. Since this
* sink is already enabled no memory is needed and the HW need not be
* touched.
*/
- if (val == CS_MODE_SYSFS)
+ if (drvdata->mode == CS_MODE_SYSFS)
goto out;
if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+ drvdata->mode = CS_MODE_SYSFS;
tmc_etr_enable_hw(drvdata);
drvdata->enable = true;
@@ -842,34 +857,29 @@
return ret;
}
-static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, u32 mode)
+static int tmc_enable_etr_sink_perf(struct coresight_device *csdev)
{
int ret = 0;
- long val;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- /* This shouldn't be happening */
- if (WARN_ON(mode != CS_MODE_PERF))
- return -EINVAL;
-
spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
ret = -EINVAL;
goto out;
}
- val = local_xchg(&drvdata->mode, mode);
/*
* In Perf mode there can be only one writer per sink. There
* is also no need to continue if the ETR is already operated
* from sysFS.
*/
- if (val != CS_MODE_DISABLED) {
+ if (drvdata->mode != CS_MODE_DISABLED) {
ret = -EINVAL;
goto out;
}
+ drvdata->mode = CS_MODE_PERF;
tmc_etr_enable_hw(drvdata);
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -881,9 +891,9 @@
{
switch (mode) {
case CS_MODE_SYSFS:
- return tmc_enable_etr_sink_sysfs(csdev, mode);
+ return tmc_enable_etr_sink_sysfs(csdev);
case CS_MODE_PERF:
- return tmc_enable_etr_sink_perf(csdev, mode);
+ return tmc_enable_etr_sink_perf(csdev);
}
/* We shouldn't be here */
@@ -892,7 +902,6 @@
static void tmc_disable_etr_sink(struct coresight_device *csdev)
{
- long val;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -903,9 +912,8 @@
return;
}
- val = local_xchg(&drvdata->mode, CS_MODE_DISABLED);
/* Disable the TMC only if it needs to */
- if (val != CS_MODE_DISABLED) {
+ if (drvdata->mode != CS_MODE_DISABLED) {
if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
__tmc_etr_disable_to_bam(drvdata);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -914,6 +922,7 @@
goto out;
} else {
tmc_etr_disable_hw(drvdata);
+ drvdata->mode = CS_MODE_DISABLED;
}
}
@@ -949,10 +958,234 @@
dev_info(drvdata->dev, "TMC aborted\n");
}
+static void *tmc_alloc_etr_buffer(struct coresight_device *csdev, int cpu,
+ void **pages, int nr_pages, bool overwrite)
+{
+ int node;
+ struct cs_etr_buffers *buf;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ if (cpu == -1)
+ cpu = smp_processor_id();
+ node = cpu_to_node(cpu);
+
+ /* Allocate memory structure for interaction with Perf */
+ buf = kzalloc_node(sizeof(struct cs_etr_buffers), GFP_KERNEL, node);
+ if (!buf)
+ return NULL;
+
+ buf->dev = drvdata->dev;
+ buf->size = drvdata->size;
+ buf->vaddr = dma_alloc_coherent(buf->dev, buf->size,
+ &buf->paddr, GFP_KERNEL);
+ if (!buf->vaddr) {
+ kfree(buf);
+ return NULL;
+ }
+
+ buf->tmc.snapshot = overwrite;
+ buf->tmc.nr_pages = nr_pages;
+ buf->tmc.data_pages = pages;
+
+ return buf;
+}
+
+static void tmc_free_etr_buffer(void *config)
+{
+ struct cs_etr_buffers *buf = config;
+
+ dma_free_coherent(buf->dev, buf->size, buf->vaddr, buf->paddr);
+ kfree(buf);
+}
+
+static int tmc_set_etr_buffer(struct coresight_device *csdev,
+ struct perf_output_handle *handle,
+ void *sink_config)
+{
+ int ret = 0;
+ unsigned long head;
+ struct cs_etr_buffers *buf = sink_config;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ /* wrap head around to the amount of space we have */
+ head = handle->head & ((buf->tmc.nr_pages << PAGE_SHIFT) - 1);
+
+ /* find the page to write to */
+ buf->tmc.cur = head / PAGE_SIZE;
+
+ /* and offset within that page */
+ buf->tmc.offset = head % PAGE_SIZE;
+
+ local_set(&buf->tmc.data_size, 0);
+
+ /* Tell the HW where to put the trace data */
+ drvdata->vaddr = buf->vaddr;
+ drvdata->paddr = buf->paddr;
+ memset(drvdata->vaddr, 0, drvdata->size);
+
+ return ret;
+}
+
+static unsigned long tmc_reset_etr_buffer(struct coresight_device *csdev,
+ struct perf_output_handle *handle,
+ void *sink_config, bool *lost)
+{
+ long size = 0;
+ struct cs_etr_buffers *buf = sink_config;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ if (buf) {
+ /*
+ * In snapshot mode ->data_size holds the new address of the
+ * ring buffer's head. The size itself is the whole address
+ * range since we want the latest information.
+ */
+ if (buf->tmc.snapshot) {
+ size = buf->tmc.nr_pages << PAGE_SHIFT;
+ handle->head = local_xchg(&buf->tmc.data_size, size);
+ }
+
+ /*
+ * Tell the tracer PMU how much we got in this run and if
+ * something went wrong along the way. Nobody else can use
+ * this cs_etr_buffers instance until we are done. As such
+ * resetting parameters here and squaring off with the ring
+ * buffer API in the tracer PMU is fine.
+ */
+ *lost = !!local_xchg(&buf->tmc.lost, 0);
+ size = local_xchg(&buf->tmc.data_size, 0);
+ }
+
+ /* Get ready for another run */
+ drvdata->vaddr = NULL;
+ drvdata->paddr = 0;
+
+ return size;
+}
+
+static void tmc_update_etr_buffer(struct coresight_device *csdev,
+ struct perf_output_handle *handle,
+ void *sink_config)
+{
+ int i, cur;
+ u32 *buf_ptr;
+ u32 read_ptr, write_ptr;
+ u32 status, to_read;
+ unsigned long offset;
+ struct cs_buffers *buf = sink_config;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ if (!buf)
+ return;
+
+ /* This shouldn't happen */
+ if (WARN_ON_ONCE(drvdata->mode != CS_MODE_PERF))
+ return;
+
+ CS_UNLOCK(drvdata->base);
+
+ tmc_flush_and_stop(drvdata);
+
+ read_ptr = readl_relaxed(drvdata->base + TMC_RRP);
+ write_ptr = readl_relaxed(drvdata->base + TMC_RWP);
+
+ /*
+ * Get a hold of the status register and see if a wrap around
+ * has occurred. If so adjust things accordingly.
+ */
+ status = readl_relaxed(drvdata->base + TMC_STS);
+ if (status & TMC_STS_FULL) {
+ local_inc(&buf->lost);
+ to_read = drvdata->size;
+ } else {
+ to_read = CIRC_CNT(write_ptr, read_ptr, drvdata->size);
+ }
+
+ /*
+ * The TMC RAM buffer may be bigger than the space available in the
+ * perf ring buffer (handle->size). If so advance the RRP so that we
+ * get the latest trace data.
+ */
+ if (to_read > handle->size) {
+ u32 buffer_start, mask = 0;
+
+ /* Read buffer start address in system memory */
+ buffer_start = readl_relaxed(drvdata->base + TMC_DBALO);
+
+ /*
+ * The value written to RRP must be byte-address aligned to
+ * the width of the trace memory databus _and_ to a frame
+ * boundary (16 byte), whichever is the biggest. For example,
+ * for 32-bit, 64-bit and 128-bit wide trace memory, the four
+ * LSBs must be 0s. For 256-bit wide trace memory, the five
+ * LSBs must be 0s.
+ */
+ switch (drvdata->memwidth) {
+ case TMC_MEM_INTF_WIDTH_32BITS:
+ case TMC_MEM_INTF_WIDTH_64BITS:
+ case TMC_MEM_INTF_WIDTH_128BITS:
+ mask = GENMASK(31, 5);
+ break;
+ case TMC_MEM_INTF_WIDTH_256BITS:
+ mask = GENMASK(31, 6);
+ break;
+ }
+
+ /*
+ * Make sure the new size is aligned in accordance with the
+ * requirement explained above.
+ */
+ to_read = handle->size & mask;
+ /* Move the RAM read pointer up */
+ read_ptr = (write_ptr + drvdata->size) - to_read;
+ /* Make sure we are still within our limits */
+ if (read_ptr > (buffer_start + (drvdata->size - 1)))
+ read_ptr -= drvdata->size;
+ /* Tell the HW */
+ writel_relaxed(read_ptr, drvdata->base + TMC_RRP);
+ local_inc(&buf->lost);
+ }
+
+ cur = buf->cur;
+ offset = buf->offset;
+
+ /* for every byte to read */
+ for (i = 0; i < to_read; i += 4) {
+ buf_ptr = buf->data_pages[cur] + offset;
+ *buf_ptr = readl_relaxed(drvdata->base + TMC_RRD);
+
+ offset += 4;
+ if (offset >= PAGE_SIZE) {
+ offset = 0;
+ cur++;
+ /* wrap around at the end of the buffer */
+ cur &= buf->nr_pages - 1;
+ }
+ }
+
+ /*
+ * In snapshot mode all we have to do is communicate to
+ * perf_aux_output_end() the address of the current head. In full
+ * trace mode the same function expects a size to move rb->aux_head
+ * forward.
+ */
+ if (buf->snapshot)
+ local_set(&buf->data_size, (cur * PAGE_SIZE) + offset);
+ else
+ local_add(to_read, &buf->data_size);
+
+ CS_LOCK(drvdata->base);
+}
+
static const struct coresight_ops_sink tmc_etr_sink_ops = {
.enable = tmc_enable_etr_sink,
.disable = tmc_disable_etr_sink,
.abort = tmc_abort_etr_sink,
+ .alloc_buffer = tmc_alloc_etr_buffer,
+ .free_buffer = tmc_free_etr_buffer,
+ .set_buffer = tmc_set_etr_buffer,
+ .reset_buffer = tmc_reset_etr_buffer,
+ .update_buffer = tmc_update_etr_buffer,
};
const struct coresight_ops tmc_etr_cs_ops = {
@@ -962,7 +1195,6 @@
int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
{
int ret = 0;
- long val;
unsigned long flags;
/* config types are set a boot time and never change */
@@ -981,9 +1213,8 @@
goto out;
}
- val = local_read(&drvdata->mode);
/* Don't interfere if operated from Perf */
- if (val == CS_MODE_PERF) {
+ if (drvdata->mode == CS_MODE_PERF) {
ret = -EINVAL;
goto out;
}
@@ -1000,7 +1231,7 @@
}
/* Disable the TMC if need be */
- if (val == CS_MODE_SYSFS)
+ if (drvdata->mode == CS_MODE_SYSFS)
tmc_etr_disable_hw(drvdata);
drvdata->reading = true;
@@ -1023,7 +1254,7 @@
spin_lock_irqsave(&drvdata->spinlock, flags);
/* RE-enable the TMC if need be */
- if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
+ if (drvdata->mode == CS_MODE_SYSFS) {
/*
* The trace run will continue with the same allocated trace
* buffer. The trace buffer is cleared in tmc_etr_enable_hw(),
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 802d4f1..6597fd6 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -487,8 +487,13 @@
if (!drvdata->byte_cntr)
return -EINVAL;
+ if (val && val < 16) {
+ pr_err("Assign minimum block size of 16 bytes\n");
+ return -EINVAL;
+ }
+
mutex_lock(&drvdata->byte_cntr->byte_cntr_lock);
- drvdata->byte_cntr->block_size = val * 8;
+ drvdata->byte_cntr->block_size = val;
mutex_unlock(&drvdata->byte_cntr->byte_cntr_lock);
return size;
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 36117ec..0a271e5 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -172,7 +172,7 @@
void *vaddr;
u32 size;
u32 len;
- local_t mode;
+ u32 mode;
enum tmc_config_type config_type;
enum tmc_mem_intf_width memwidth;
struct mutex mem_lock;
diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c
index 0673baf..ff579a7 100644
--- a/drivers/hwtracing/coresight/coresight-tpiu.c
+++ b/drivers/hwtracing/coresight/coresight-tpiu.c
@@ -46,8 +46,11 @@
#define TPIU_ITATBCTR0 0xef8
/** register definition **/
+/* FFSR - 0x300 */
+#define FFSR_FT_STOPPED BIT(1)
/* FFCR - 0x304 */
#define FFCR_FON_MAN BIT(6)
+#define FFCR_STOP_FI BIT(12)
/**
* @base: memory mapped base address for this component.
@@ -85,10 +88,14 @@
{
CS_UNLOCK(drvdata->base);
- /* Clear formatter controle reg. */
- writel_relaxed(0x0, drvdata->base + TPIU_FFCR);
+ /* Clear formatter and stop on flush */
+ writel_relaxed(FFCR_STOP_FI, drvdata->base + TPIU_FFCR);
/* Generate manual flush */
- writel_relaxed(FFCR_FON_MAN, drvdata->base + TPIU_FFCR);
+ writel_relaxed(FFCR_STOP_FI | FFCR_FON_MAN, drvdata->base + TPIU_FFCR);
+ /* Wait for flush to complete */
+ coresight_timeout(drvdata->base, TPIU_FFCR, FFCR_FON_MAN, 0);
+ /* Wait for formatter to stop */
+ coresight_timeout(drvdata->base, TPIU_FFSR, FFSR_FT_STOPPED, 1);
CS_LOCK(drvdata->base);
}
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
index 7598ab8..1cf60f3 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -382,6 +382,52 @@
return csdev;
}
+static int coresight_enabled_sink(struct device *dev, void *data)
+{
+ bool *reset = data;
+ struct coresight_device *csdev = to_coresight_device(dev);
+
+ if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
+ csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
+ csdev->activated) {
+ /*
+ * Now that we have a handle on the sink for this session,
+ * disable the sysFS "enable_sink" flag so that possible
+ * concurrent perf session that wish to use another sink don't
+ * trip on it. Doing so has no ramification for the current
+ * session.
+ */
+ if (*reset)
+ csdev->activated = false;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * coresight_get_enabled_sink - returns the first enabled sink found on the bus
+ * @deactivate: Whether the 'enable_sink' flag should be reset
+ *
+ * When operated from perf the deactivate parameter should be set to 'true'.
+ * That way the "enabled_sink" flag of the sink that was selected can be reset,
+ * allowing for other concurrent perf sessions to choose a different sink.
+ *
+ * When operated from sysFS users have full control and as such the deactivate
+ * parameter should be set to 'false', hence mandating users to explicitly
+ * clear the flag.
+ */
+struct coresight_device *coresight_get_enabled_sink(bool deactivate)
+{
+ struct device *dev = NULL;
+
+ dev = bus_find_device(&coresight_bustype, NULL, &deactivate,
+ coresight_enabled_sink);
+
+ return dev ? to_coresight_device(dev) : NULL;
+}
+
/**
* _coresight_build_path - recursively build a path from a @csdev to a sink.
* @csdev: The device to start from.
@@ -394,6 +440,7 @@
* last one.
*/
static int _coresight_build_path(struct coresight_device *csdev,
+ struct coresight_device *sink,
struct list_head *path)
{
int i;
@@ -401,15 +448,15 @@
struct coresight_node *node;
/* An activated sink has been found. Enqueue the element */
- if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
- csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && csdev->activated)
+ if (csdev == sink)
goto out;
/* Not a sink - recursively explore each port found on this element */
for (i = 0; i < csdev->nr_outport; i++) {
struct coresight_device *child_dev = csdev->conns[i].child_dev;
- if (child_dev && _coresight_build_path(child_dev, path) == 0) {
+ if (child_dev &&
+ _coresight_build_path(child_dev, sink, path) == 0) {
found = true;
break;
}
@@ -436,18 +483,22 @@
return 0;
}
-struct list_head *coresight_build_path(struct coresight_device *csdev)
+struct list_head *coresight_build_path(struct coresight_device *source,
+ struct coresight_device *sink)
{
struct list_head *path;
int rc;
+ if (!sink)
+ return ERR_PTR(-EINVAL);
+
path = kzalloc(sizeof(struct list_head), GFP_KERNEL);
if (!path)
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(path);
- rc = _coresight_build_path(csdev, path);
+ rc = _coresight_build_path(source, sink, path);
if (rc) {
kfree(path);
return ERR_PTR(rc);
@@ -536,6 +587,7 @@
int coresight_enable(struct coresight_device *csdev)
{
int ret = 0;
+ struct coresight_device *sink;
struct list_head *path;
mutex_lock(&coresight_mutex);
@@ -547,7 +599,17 @@
if (csdev->enable)
goto out;
- path = coresight_build_path(csdev);
+ /*
+ * Search for a valid sink for this session but don't reset the
+ * "enable_sink" flag in sysFS. Users get to do that explicitly.
+ */
+ sink = coresight_get_enabled_sink(false);
+ if (!sink) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ path = coresight_build_path(csdev, sink);
if (IS_ERR(path)) {
pr_err("building path(s) failed\n");
ret = PTR_ERR(path);
diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c
index 4daed7f..ad77697 100644
--- a/drivers/i2c/busses/i2c-msm-v2.c
+++ b/drivers/i2c/busses/i2c-msm-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -1274,10 +1274,10 @@
tx->dir,
(SPS_IOVEC_FLAG_EOT |
SPS_IOVEC_FLAG_NWD));
- if (dma_desc_tx < 0) {
+ if (IS_ERR_OR_NULL(dma_desc_tx)) {
dev_err(ctrl->dev, "error dmaengine_prep_slave_sg tx:%ld\n",
PTR_ERR(dma_desc_tx));
- ret = PTR_ERR(dma_desc_tx);
+ ret = dma_desc_tx ? PTR_ERR(dma_desc_tx) : -ENOMEM;
goto dma_xfer_end;
}
@@ -1292,11 +1292,11 @@
sg_rx_itr - sg_rx, rx->dir,
(SPS_IOVEC_FLAG_EOT |
SPS_IOVEC_FLAG_NWD));
- if (dma_desc_rx < 0) {
+ if (IS_ERR_OR_NULL(dma_desc_rx)) {
dev_err(ctrl->dev,
"error dmaengine_prep_slave_sg rx:%ld\n",
PTR_ERR(dma_desc_rx));
- ret = PTR_ERR(dma_desc_rx);
+ ret = dma_desc_rx ? PTR_ERR(dma_desc_rx) : -ENOMEM;
goto dma_xfer_end;
}
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index c7f6c6b..bc4af98 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -77,6 +77,10 @@
#define I2C_AUTO_SUSPEND_DELAY 250
+#define I2C_TIMEOUT_SAFETY_COEFFICIENT 10
+
+#define I2C_TIMEOUT_MIN_USEC 500000
+
enum i2c_se_mode {
UNINITIALIZED,
FIFO_SE_DMA,
@@ -89,6 +93,7 @@
unsigned int tx_wm;
int irq;
int err;
+ u32 xfer_timeout;
struct i2c_adapter adap;
struct completion xfer;
struct i2c_msg *cur;
@@ -192,12 +197,26 @@
mb();
}
+static inline void qcom_geni_i2c_calc_timeout(struct geni_i2c_dev *gi2c)
+{
+
+ struct geni_i2c_clk_fld *clk_itr = geni_i2c_clk_map + gi2c->clk_fld_idx;
+ size_t bit_cnt = gi2c->cur->len*9;
+ size_t bit_usec = (bit_cnt*USEC_PER_SEC)/clk_itr->clk_freq_out;
+ size_t xfer_max_usec = (bit_usec*I2C_TIMEOUT_SAFETY_COEFFICIENT) +
+ I2C_TIMEOUT_MIN_USEC;
+
+ gi2c->xfer_timeout = usecs_to_jiffies(xfer_max_usec);
+
+}
+
static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
{
if (gi2c->cur)
GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
- "len:%d, slv-addr:0x%x, RD/WR:%d\n", gi2c->cur->len,
- gi2c->cur->addr, gi2c->cur->flags);
+ "len:%d, slv-addr:0x%x, RD/WR:%d timeout:%u\n",
+ gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags,
+ gi2c->xfer_timeout);
if (err == I2C_NACK || err == GENI_ABORT_DONE) {
GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n",
@@ -476,6 +495,7 @@
struct device *tx_dev = gi2c->wrapper_dev;
gi2c->cur = &msgs[i];
+ qcom_geni_i2c_calc_timeout(gi2c);
if (!gi2c->cfg_sent) {
segs++;
sg_init_table(gi2c->tx_sg, segs);
@@ -567,7 +587,8 @@
tx_cookie = dmaengine_submit(gi2c->tx_desc);
dma_async_issue_pending(gi2c->tx_c);
- timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
+ timeout = wait_for_completion_timeout(&gi2c->xfer,
+ gi2c->xfer_timeout);
if (msgs[i].flags & I2C_M_RD)
geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph,
msgs[i].len, DMA_FROM_DEVICE);
@@ -577,7 +598,8 @@
if (!timeout) {
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
- "GSI Txn timed out\n");
+ "GSI Txn timed out: %u len: %d\n",
+ gi2c->xfer_timeout, gi2c->cur->len);
gi2c->err = -ETIMEDOUT;
}
if (gi2c->err) {
@@ -633,6 +655,7 @@
m_param |= ((msgs[i].addr & 0x7F) << SLV_ADDR_SHFT);
gi2c->cur = &msgs[i];
+ qcom_geni_i2c_calc_timeout(gi2c);
mode = msgs[i].len > 32 ? SE_DMA : FIFO_MODE;
ret = geni_se_select_mode(gi2c->base, mode);
if (ret) {
@@ -682,7 +705,8 @@
}
/* Ensure FIFO write go through before waiting for Done evet */
mb();
- timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
+ timeout = wait_for_completion_timeout(&gi2c->xfer,
+ gi2c->xfer_timeout);
if (!timeout) {
geni_i2c_err(gi2c, GENI_TIMEOUT);
gi2c->cur = NULL;
diff --git a/drivers/idle/Kconfig b/drivers/idle/Kconfig
index 4732dfc..331adc5 100644
--- a/drivers/idle/Kconfig
+++ b/drivers/idle/Kconfig
@@ -17,6 +17,7 @@
config I7300_IDLE
tristate "Intel chipset idle memory power saving driver"
+ depends on PCI
select I7300_IDLE_IOAT_CHANNEL
help
Enable memory power savings when idle with certain Intel server
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index a09d6ee..30f0161 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -744,6 +744,7 @@
INIT_LIST_HEAD(&id_priv->mc_list);
get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num);
id_priv->id.route.addr.dev_addr.net = get_net(net);
+ id_priv->seq_num &= 0x00ffffff;
return &id_priv->id;
}
diff --git a/drivers/infiniband/hw/i40iw/i40iw_d.h b/drivers/infiniband/hw/i40iw/i40iw_d.h
index 2fac1db..d1328a6 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_d.h
+++ b/drivers/infiniband/hw/i40iw/i40iw_d.h
@@ -1102,7 +1102,7 @@
#define I40IWQPC_VLANTAG_MASK (0xffffULL << I40IWQPC_VLANTAG_SHIFT)
#define I40IWQPC_ARPIDX_SHIFT 48
-#define I40IWQPC_ARPIDX_MASK (0xfffULL << I40IWQPC_ARPIDX_SHIFT)
+#define I40IWQPC_ARPIDX_MASK (0xffffULL << I40IWQPC_ARPIDX_SHIFT)
#define I40IWQPC_FLOWLABEL_SHIFT 0
#define I40IWQPC_FLOWLABEL_MASK (0xfffffUL << I40IWQPC_FLOWLABEL_SHIFT)
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 8059b7e..c41c8d0 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -2928,9 +2928,8 @@
kfree(ibdev->ib_uc_qpns_bitmap);
err_steer_qp_release:
- if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED)
- mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
- ibdev->steer_qpn_count);
+ mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
+ ibdev->steer_qpn_count);
err_counter:
for (i = 0; i < ibdev->num_ports; ++i)
mlx4_ib_delete_counters_table(ibdev, &ibdev->counters_table[i]);
@@ -3035,11 +3034,9 @@
ibdev->iboe.nb.notifier_call = NULL;
}
- if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED) {
- mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
- ibdev->steer_qpn_count);
- kfree(ibdev->ib_uc_qpns_bitmap);
- }
+ mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
+ ibdev->steer_qpn_count);
+ kfree(ibdev->ib_uc_qpns_bitmap);
iounmap(ibdev->uar_map);
for (p = 0; p < ibdev->num_ports; ++p)
diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c
index c1523f9..e4d4f5c 100644
--- a/drivers/infiniband/hw/qib/qib_rc.c
+++ b/drivers/infiniband/hw/qib/qib_rc.c
@@ -443,13 +443,13 @@
qp->s_state = OP(COMPARE_SWAP);
put_ib_ateth_swap(wqe->atomic_wr.swap,
&ohdr->u.atomic_eth);
- put_ib_ateth_swap(wqe->atomic_wr.compare_add,
- &ohdr->u.atomic_eth);
+ put_ib_ateth_compare(wqe->atomic_wr.compare_add,
+ &ohdr->u.atomic_eth);
} else {
qp->s_state = OP(FETCH_ADD);
put_ib_ateth_swap(wqe->atomic_wr.compare_add,
&ohdr->u.atomic_eth);
- put_ib_ateth_swap(0, &ohdr->u.atomic_eth);
+ put_ib_ateth_compare(0, &ohdr->u.atomic_eth);
}
put_ib_ateth_vaddr(wqe->atomic_wr.remote_addr,
&ohdr->u.atomic_eth);
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
index 19841c8..59f37f4 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -848,6 +848,8 @@
(queue_count(qp->sq.queue) > 1);
rxe_run_task(&qp->req.task, must_sched);
+ if (unlikely(qp->req.state == QP_STATE_ERROR))
+ rxe_run_task(&qp->comp.task, 1);
return err;
}
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c
index 9002298..3048ef3 100644
--- a/drivers/input/keyboard/tca8418_keypad.c
+++ b/drivers/input/keyboard/tca8418_keypad.c
@@ -164,11 +164,18 @@
int error, col, row;
u8 reg, state, code;
- /* Initial read of the key event FIFO */
- error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®);
+ do {
+ error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®);
+ if (error < 0) {
+ dev_err(&keypad_data->client->dev,
+ "unable to read REG_KEY_EVENT_A\n");
+ break;
+ }
- /* Assume that key code 0 signifies empty FIFO */
- while (error >= 0 && reg > 0) {
+ /* Assume that key code 0 signifies empty FIFO */
+ if (reg <= 0)
+ break;
+
state = reg & KEY_EVENT_VALUE;
code = reg & KEY_EVENT_CODE;
@@ -184,11 +191,7 @@
/* Read for next loop */
error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®);
- }
-
- if (error < 0)
- dev_err(&keypad_data->client->dev,
- "unable to read REG_KEY_EVENT_A\n");
+ } while (1);
input_sync(input);
}
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
index 90493b1..e11dc07 100644
--- a/drivers/input/misc/hbtp_input.c
+++ b/drivers/input/misc/hbtp_input.c
@@ -1,5 +1,5 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -30,7 +30,9 @@
#include <linux/delay.h>
#include <linux/completion.h>
+#ifdef CONFIG_DRM
#include <linux/msm_drm_notify.h>
+#endif
#define HBTP_INPUT_NAME "hbtp_input"
#define DISP_COORDS_SIZE 2
@@ -39,6 +41,7 @@
#define HBTP_HOLD_DURATION_US (10)
#define HBTP_PINCTRL_DDIC_SEQ_NUM (4)
#define HBTP_WAIT_TIMEOUT_MS 2000
+#define MSC_HBTP_ACTIVE_BLOB 0x05
struct hbtp_data {
struct platform_device *pdev;
@@ -86,16 +89,19 @@
u32 power_on_delay;
u32 power_off_delay;
bool manage_pin_ctrl;
+ bool init_completion_done_once;
struct kobject *sysfs_kobject;
s16 ROI[MAX_ROI_SIZE];
s16 accelBuffer[MAX_ACCEL_SIZE];
u32 display_status;
+ u32 touch_flag;
};
static struct hbtp_data *hbtp;
static struct kobject *sensor_kobject;
+#ifdef CONFIG_DRM
static int hbtp_dsi_panel_suspend(struct hbtp_data *ts);
static int hbtp_dsi_panel_early_resume(struct hbtp_data *ts);
@@ -141,6 +147,7 @@
}
return 0;
}
+#endif
static ssize_t hbtp_sensor_roi_show(struct file *dev, struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t pos,
@@ -233,6 +240,9 @@
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+ /* for Blob touch interference feature */
+ input_set_capability(input_dev, EV_MSC, MSC_HBTP_ACTIVE_BLOB);
+
for (i = KEY_HOME; i <= KEY_MICMUTE; i++)
__set_bit(i, input_dev->keybit);
@@ -272,10 +282,12 @@
}
static int hbtp_input_report_events(struct hbtp_data *hbtp_data,
- struct hbtp_input_mt *mt_data)
+ struct hbtp_input_mt *mt_data, u32 flag)
{
int i;
struct hbtp_input_touch *tch;
+ u32 flag_change;
+ bool active_blob;
for (i = 0; i < HBTP_MAX_FINGER; i++) {
tch = &(mt_data->touches[i]);
@@ -330,10 +342,19 @@
hbtp_data->touch_status[i] = tch->active;
}
}
+ flag_change = hbtp_data->touch_flag ^ flag;
+ if (flag_change) {
+ if (flag_change & HBTP_FLAG_ACTIVE_BLOB) {
+ active_blob = (flag & HBTP_FLAG_ACTIVE_BLOB) ?
+ true : false;
+ input_event(hbtp_data->input_dev, EV_MSC,
+ MSC_HBTP_ACTIVE_BLOB, active_blob);
+ }
+ }
input_report_key(hbtp->input_dev, BTN_TOUCH, mt_data->num_touches > 0);
input_sync(hbtp->input_dev);
-
+ hbtp_data->touch_flag = flag;
return 0;
}
@@ -594,6 +615,7 @@
{
int error = 0;
struct hbtp_input_mt mt_data;
+ struct hbtp_input_mt_ext mt_data_ext;
struct hbtp_input_absinfo absinfo[ABS_MT_LAST - ABS_MT_FIRST + 1];
struct hbtp_input_key key_data;
enum hbtp_afe_power_cmd power_cmd;
@@ -635,7 +657,26 @@
return -EFAULT;
}
- hbtp_input_report_events(hbtp, &mt_data);
+ hbtp_input_report_events(hbtp, &mt_data, 0);
+ error = 0;
+ break;
+
+ case HBTP_SET_TOUCHDATA_EXT:
+ if (!hbtp || !hbtp->input_dev) {
+ pr_err("%s: The input device hasn't been created\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(&mt_data_ext, (void __user *)arg,
+ sizeof(struct hbtp_input_mt_ext))) {
+ pr_err("%s: Error copying data\n", __func__);
+ return -EFAULT;
+ }
+
+ hbtp_input_report_events(hbtp,
+ (struct hbtp_input_mt *)&mt_data_ext,
+ mt_data_ext.flag);
error = 0;
break;
@@ -783,8 +824,14 @@
return -EFAULT;
}
mutex_lock(&hbtp->mutex);
- init_completion(&hbtp->power_resume_sig);
- init_completion(&hbtp->power_suspend_sig);
+ if (hbtp->init_completion_done_once) {
+ reinit_completion(&hbtp->power_resume_sig);
+ reinit_completion(&hbtp->power_suspend_sig);
+ } else {
+ init_completion(&hbtp->power_resume_sig);
+ init_completion(&hbtp->power_suspend_sig);
+ hbtp->init_completion_done_once = true;
+ }
hbtp->power_sig_enabled = true;
mutex_unlock(&hbtp->mutex);
pr_err("%s: sync_signal option is enabled\n", __func__);
@@ -1163,6 +1210,7 @@
return rc;
}
+#ifdef CONFIG_DRM
static int hbtp_dsi_panel_suspend(struct hbtp_data *ts)
{
int rc;
@@ -1276,6 +1324,7 @@
hbtp_pdev_power_on(ts, false);
return rc;
}
+#endif
static int hbtp_pdev_probe(struct platform_device *pdev)
{
@@ -1438,6 +1487,25 @@
__ATTR(display_pwr, 0660, hbtp_display_pwr_show,
hbtp_display_pwr_store);
+#ifdef CONFIG_DRM
+static int hbtp_drm_register(struct hbtp_data *ts)
+{
+ int ret = 0;
+
+ ts->dsi_panel_notif.notifier_call = dsi_panel_notifier_callback;
+ ret = msm_drm_register_client(&ts->dsi_panel_notif);
+ if (ret)
+ pr_err("%s: Unable to register dsi_panel_notifier: %d\n",
+ HBTP_INPUT_NAME, ret);
+
+ return ret;
+}
+#else
+static int hbtp_drm_register(struct hbtp_data *ts)
+{
+ return 0;
+}
+#endif
static int __init hbtp_init(void)
{
@@ -1455,6 +1523,7 @@
mutex_init(&hbtp->mutex);
mutex_init(&hbtp->sensormutex);
hbtp->display_status = 1;
+ hbtp->init_completion_done_once = false;
error = misc_register(&hbtp_input_misc);
if (error) {
@@ -1462,13 +1531,9 @@
goto err_misc_reg;
}
- hbtp->dsi_panel_notif.notifier_call = dsi_panel_notifier_callback;
- error = msm_drm_register_client(&hbtp->dsi_panel_notif);
- if (error) {
- pr_err("%s: Unable to register dsi_panel_notifier: %d\n",
- HBTP_INPUT_NAME, error);
- goto err_dsi_panel_reg;
- }
+ error = hbtp_drm_register(hbtp);
+ if (error)
+ goto err_drm_reg;
sensor_kobject = kobject_create_and_add("hbtpsensor", kernel_kobj);
if (!sensor_kobject) {
@@ -1517,8 +1582,10 @@
err_sysfs_create_capdata:
kobject_put(sensor_kobject);
err_kobject_create:
+#ifdef CONFIG_DRM
msm_drm_unregister_client(&hbtp->dsi_panel_notif);
-err_dsi_panel_reg:
+#endif
+err_drm_reg:
misc_deregister(&hbtp_input_misc);
err_misc_reg:
kfree(hbtp->sensor_data);
@@ -1539,8 +1606,9 @@
if (hbtp->input_dev)
input_unregister_device(hbtp->input_dev);
+#ifdef CONFIG_DRM
msm_drm_unregister_client(&hbtp->dsi_panel_notif);
-
+#endif
platform_driver_unregister(&hbtp_pdev_driver);
kfree(hbtp->sensor_data);
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 868be8b..40d4a2c 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -535,6 +535,8 @@
struct list_head unassign_list;
struct mutex assign_lock;
struct list_head secure_pool_list;
+ /* nonsecure pool protected by pgtbl_lock */
+ struct list_head nonsecure_pool;
struct iommu_domain domain;
bool qsmmuv500_errata1_init;
@@ -593,6 +595,16 @@
static bool arm_smmu_is_master_side_secure(struct arm_smmu_domain *smmu_domain);
static bool arm_smmu_is_slave_side_secure(struct arm_smmu_domain *smmu_domain);
+static int msm_secure_smmu_map(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, size_t size, int prot);
+static size_t msm_secure_smmu_unmap(struct iommu_domain *domain,
+ unsigned long iova,
+ size_t size);
+static size_t msm_secure_smmu_map_sg(struct iommu_domain *domain,
+ unsigned long iova,
+ struct scatterlist *sg,
+ unsigned int nents, int prot);
+
static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
{
return container_of(dom, struct arm_smmu_domain, domain);
@@ -1313,8 +1325,19 @@
void *page;
struct arm_smmu_domain *smmu_domain = cookie;
- if (!arm_smmu_is_master_side_secure(smmu_domain))
+ if (!arm_smmu_is_master_side_secure(smmu_domain)) {
+ struct page *pg;
+ /* size is expected to be 4K with current configuration */
+ if (size == PAGE_SIZE) {
+ pg = list_first_entry_or_null(
+ &smmu_domain->nonsecure_pool, struct page, lru);
+ if (pg) {
+ list_del_init(&pg->lru);
+ return page_address(pg);
+ }
+ }
return alloc_pages_exact(size, gfp_mask);
+ }
page = arm_smmu_secure_pool_remove(smmu_domain, size);
if (page)
@@ -1353,6 +1376,28 @@
.free_pages_exact = arm_smmu_free_pages_exact,
};
+static void msm_smmu_tlb_inv_context(void *cookie)
+{
+}
+
+static void msm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
+ size_t granule, bool leaf,
+ void *cookie)
+{
+}
+
+static void msm_smmu_tlb_sync(void *cookie)
+{
+}
+
+static struct iommu_gather_ops msm_smmu_gather_ops = {
+ .tlb_flush_all = msm_smmu_tlb_inv_context,
+ .tlb_add_flush = msm_smmu_tlb_inv_range_nosync,
+ .tlb_sync = msm_smmu_tlb_sync,
+ .alloc_pages_exact = arm_smmu_alloc_pages_exact,
+ .free_pages_exact = arm_smmu_free_pages_exact,
+};
+
static phys_addr_t arm_smmu_verify_fault(struct iommu_domain *domain,
dma_addr_t iova, u32 fsr)
{
@@ -1874,6 +1919,9 @@
if (smmu->options & ARM_SMMU_OPT_MMU500_ERRATA1)
tlb = &qsmmuv500_errata1_smmu_gather_ops;
+ if (arm_smmu_is_slave_side_secure(smmu_domain))
+ tlb = &msm_smmu_gather_ops;
+
ret = arm_smmu_alloc_cb(domain, smmu, dev);
if (ret < 0)
goto out_unlock;
@@ -1894,6 +1942,7 @@
.sec_id = smmu->sec_id,
.cbndx = cfg->cbndx,
},
+ .tlb = tlb,
.iommu_dev = smmu->dev,
};
fmt = ARM_MSM_SECURE;
@@ -2080,6 +2129,7 @@
INIT_LIST_HEAD(&smmu_domain->unassign_list);
mutex_init(&smmu_domain->assign_lock);
INIT_LIST_HEAD(&smmu_domain->secure_pool_list);
+ INIT_LIST_HEAD(&smmu_domain->nonsecure_pool);
arm_smmu_domain_reinit(smmu_domain);
return &smmu_domain->domain;
@@ -2263,8 +2313,6 @@
const struct iommu_gather_ops *tlb;
tlb = smmu_domain->pgtbl_cfg.tlb;
- if (!tlb)
- return;
mutex_lock(&smmu->stream_map_mutex);
for_each_cfg_sme(fwspec, i, idx) {
@@ -2432,6 +2480,60 @@
return 0;
}
+static void arm_smmu_prealloc_memory(struct arm_smmu_domain *smmu_domain,
+ size_t size, struct list_head *pool)
+{
+ int i;
+ u32 nr = 0;
+ struct page *page;
+
+ if ((smmu_domain->attributes & (1 << DOMAIN_ATTR_ATOMIC)) ||
+ arm_smmu_has_secure_vmid(smmu_domain))
+ return;
+
+ /* number of 2nd level pagetable entries */
+ nr += round_up(size, SZ_1G) >> 30;
+ /* number of 3rd level pagetabel entries */
+ nr += round_up(size, SZ_2M) >> 21;
+
+ /* Retry later with atomic allocation on error */
+ for (i = 0; i < nr; i++) {
+ page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0);
+ if (!page)
+ break;
+ list_add(&page->lru, pool);
+ }
+}
+
+static void arm_smmu_prealloc_memory_sg(struct arm_smmu_domain *smmu_domain,
+ struct scatterlist *sgl, int nents,
+ struct list_head *pool)
+{
+ int i;
+ size_t size = 0;
+ struct scatterlist *sg;
+
+ if ((smmu_domain->attributes & (1 << DOMAIN_ATTR_ATOMIC)) ||
+ arm_smmu_has_secure_vmid(smmu_domain))
+ return;
+
+ for_each_sg(sgl, sg, nents, i)
+ size += sg->length;
+
+ arm_smmu_prealloc_memory(smmu_domain, size, pool);
+}
+
+static void arm_smmu_release_prealloc_memory(
+ struct arm_smmu_domain *smmu_domain, struct list_head *list)
+{
+ struct page *page, *tmp;
+
+ list_for_each_entry_safe(page, tmp, list, lru) {
+ list_del(&page->lru);
+ __free_pages(page, 0);
+ }
+}
+
static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
{
int ret;
@@ -2510,19 +2612,27 @@
unsigned long flags;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops;
+ LIST_HEAD(nonsecure_pool);
if (!ops)
return -ENODEV;
+ if (arm_smmu_is_slave_side_secure(smmu_domain))
+ return msm_secure_smmu_map(domain, iova, paddr, size, prot);
+
+ arm_smmu_prealloc_memory(smmu_domain, size, &nonsecure_pool);
arm_smmu_secure_domain_lock(smmu_domain);
spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
+ list_splice_init(&nonsecure_pool, &smmu_domain->nonsecure_pool);
ret = ops->map(ops, iova, paddr, size, prot);
+ list_splice_init(&smmu_domain->nonsecure_pool, &nonsecure_pool);
spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
arm_smmu_assign_table(smmu_domain);
arm_smmu_secure_domain_unlock(smmu_domain);
+ arm_smmu_release_prealloc_memory(smmu_domain, &nonsecure_pool);
return ret;
}
@@ -2554,6 +2664,9 @@
if (!ops)
return 0;
+ if (arm_smmu_is_slave_side_secure(smmu_domain))
+ return msm_secure_smmu_unmap(domain, iova, size);
+
ret = arm_smmu_domain_power_on(domain, smmu_domain->smmu);
if (ret)
return ret;
@@ -2589,10 +2702,15 @@
unsigned int idx_start, idx_end;
struct scatterlist *sg_start, *sg_end;
unsigned long __saved_iova_start;
+ LIST_HEAD(nonsecure_pool);
if (!ops)
return -ENODEV;
+ if (arm_smmu_is_slave_side_secure(smmu_domain))
+ return msm_secure_smmu_map_sg(domain, iova, sg, nents, prot);
+
+ arm_smmu_prealloc_memory_sg(smmu_domain, sg, nents, &nonsecure_pool);
arm_smmu_secure_domain_lock(smmu_domain);
__saved_iova_start = iova;
@@ -2611,8 +2729,10 @@
}
spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
+ list_splice_init(&nonsecure_pool, &smmu_domain->nonsecure_pool);
ret = ops->map_sg(ops, iova, sg_start, idx_end - idx_start,
prot, &size);
+ list_splice_init(&smmu_domain->nonsecure_pool, &nonsecure_pool);
spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
/* Returns 0 on error */
if (!ret) {
@@ -2633,6 +2753,7 @@
iova = __saved_iova_start;
}
arm_smmu_secure_domain_unlock(smmu_domain);
+ arm_smmu_release_prealloc_memory(smmu_domain, &nonsecure_pool);
return iova - __saved_iova_start;
}
@@ -2780,6 +2901,9 @@
if (!smmu)
return true;
+ if (!arm_smmu_is_static_cb(smmu))
+ return false;
+
/* Do not write to global space */
if (((unsigned long)addr & (smmu->size - 1)) < (smmu->size >> 1))
return true;
@@ -2791,6 +2915,56 @@
return false;
}
+
+static int msm_secure_smmu_map(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, size_t size, int prot)
+{
+ size_t ret;
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+ struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
+
+ ret = ops->map(ops, iova, paddr, size, prot);
+
+ return ret;
+}
+
+static size_t msm_secure_smmu_unmap(struct iommu_domain *domain,
+ unsigned long iova,
+ size_t size)
+{
+ size_t ret;
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+ struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
+
+ ret = arm_smmu_domain_power_on(domain, smmu_domain->smmu);
+ if (ret)
+ return ret;
+
+ ret = ops->unmap(ops, iova, size);
+
+ arm_smmu_domain_power_off(domain, smmu_domain->smmu);
+
+ return ret;
+}
+
+static size_t msm_secure_smmu_map_sg(struct iommu_domain *domain,
+ unsigned long iova,
+ struct scatterlist *sg,
+ unsigned int nents, int prot)
+{
+ int ret;
+ size_t size;
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+ struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
+
+ ret = ops->map_sg(ops, iova, sg, nents, prot, &size);
+
+ if (!ret)
+ msm_secure_smmu_unmap(domain, iova, size);
+
+ return ret;
+}
+
#endif
static struct arm_smmu_device *arm_smmu_get_by_list(struct device_node *np)
@@ -4454,6 +4628,11 @@
goto out_exit_power_resources;
smmu->sec_id = msm_dev_to_device_id(dev);
+ INIT_LIST_HEAD(&smmu->list);
+ spin_lock(&arm_smmu_devices_lock);
+ list_add(&smmu->list, &arm_smmu_devices);
+ spin_unlock(&arm_smmu_devices_lock);
+
err = arm_smmu_device_cfg_probe(smmu);
if (err)
goto out_power_off;
@@ -4496,11 +4675,6 @@
arm_smmu_device_reset(smmu);
arm_smmu_power_off(smmu->pwr);
- INIT_LIST_HEAD(&smmu->list);
- spin_lock(&arm_smmu_devices_lock);
- list_add(&smmu->list, &arm_smmu_devices);
- spin_unlock(&arm_smmu_devices_lock);
-
/* bus_set_iommu depends on this. */
bus_for_each_dev(&platform_bus_type, NULL, NULL,
arm_smmu_of_iommu_configure_fixup);
@@ -4530,6 +4704,9 @@
out_power_off:
arm_smmu_power_off(smmu->pwr);
+ spin_lock(&arm_smmu_devices_lock);
+ list_del(&smmu->list);
+ spin_unlock(&arm_smmu_devices_lock);
out_exit_power_resources:
arm_smmu_exit_power_resources(smmu->pwr);
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 981172d..6fbade9 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -207,6 +207,7 @@
unsigned long bits_per_level;
void *pgd;
+ void *pgd_ttbr1;
};
typedef u64 arm_lpae_iopte;
@@ -665,6 +666,8 @@
struct arm_lpae_io_pgtable *data = io_pgtable_to_data(iop);
__arm_lpae_free_pgtable(data, ARM_LPAE_START_LVL(data), data->pgd);
+ __arm_lpae_free_pgtable(data, ARM_LPAE_START_LVL(data),
+ data->pgd_ttbr1);
kfree(data);
}
@@ -1089,14 +1092,22 @@
if (!data->pgd)
goto out_free_data;
+ data->pgd_ttbr1 = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL,
+ cfg, cookie);
+ if (!data->pgd_ttbr1)
+ goto out_free_pgd;
+
/* Ensure the empty pgd is visible before any actual TTBR write */
wmb();
/* TTBRs */
cfg->arm_lpae_s1_cfg.ttbr[0] = virt_to_phys(data->pgd);
- cfg->arm_lpae_s1_cfg.ttbr[1] = 0;
+ cfg->arm_lpae_s1_cfg.ttbr[1] = virt_to_phys(data->pgd_ttbr1);
return &data->iop;
+out_free_pgd:
+ __arm_lpae_free_pages(data->pgd, data->pgd_size, cfg, cookie);
+
out_free_data:
kfree(data);
return NULL;
diff --git a/drivers/iommu/io-pgtable-msm-secure.c b/drivers/iommu/io-pgtable-msm-secure.c
index 983b28b..d0a8a79 100644
--- a/drivers/iommu/io-pgtable-msm-secure.c
+++ b/drivers/iommu/io-pgtable-msm-secure.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -41,6 +41,8 @@
struct msm_secure_io_pgtable {
struct io_pgtable iop;
+ /* lock required while operating on page tables */
+ struct mutex pgtbl_lock;
};
int msm_iommu_sec_pgtbl_init(void)
@@ -71,7 +73,7 @@
/* Now allocate memory for the secure page tables */
attrs = DMA_ATTR_NO_KERNEL_MAPPING;
dev.coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
- arch_setup_dma_ops(&dev, 0, 0, NULL, 1);
+ arch_setup_dma_ops(&dev, 0, 0, NULL, 0);
cpu_addr = dma_alloc_attrs(&dev, psize[0], &paddr, GFP_KERNEL, attrs);
if (!cpu_addr) {
pr_err("%s: Failed to allocate %d bytes for PTBL\n",
@@ -133,6 +135,7 @@
flush_va_end = (void *)
(((unsigned long) flush_va) + sizeof(phys_addr_t));
+ mutex_lock(&data->pgtbl_lock);
/*
* Ensure that the buffer is in RAM by the time it gets to TZ
*/
@@ -142,10 +145,11 @@
SCM_VAL, SCM_VAL, SCM_VAL);
if (is_scm_armv8()) {
- ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_MP,
+ ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
IOMMU_SECURE_MAP2_FLAT), &desc);
resp = desc.ret[0];
}
+ mutex_unlock(&data->pgtbl_lock);
if (ret || resp)
return -EINVAL;
@@ -258,11 +262,13 @@
flush_va_end = (void *) (((unsigned long) flush_va) +
(cnt * sizeof(*pa_list)));
+
+ mutex_lock(&data->pgtbl_lock);
dmac_clean_range(flush_va, flush_va_end);
if (is_scm_armv8()) {
- ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_MP,
- IOMMU_SECURE_MAP2_FLAT), &desc);
+ ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
+ IOMMU_SECURE_MAP2_FLAT), &desc);
resp = desc.ret[0];
if (ret || resp)
@@ -270,6 +276,7 @@
else
ret = len;
}
+ mutex_unlock(&data->pgtbl_lock);
kfree(pa_list);
return ret;
@@ -293,13 +300,15 @@
desc.args[4] = IOMMU_TLBINVAL_FLAG;
desc.arginfo = SCM_ARGS(5);
+ mutex_lock(&data->pgtbl_lock);
if (is_scm_armv8()) {
- ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_MP,
- IOMMU_SECURE_UNMAP2_FLAT), &desc);
+ ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
+ IOMMU_SECURE_UNMAP2_FLAT), &desc);
if (!ret)
ret = len;
}
+ mutex_unlock(&data->pgtbl_lock);
return ret;
}
@@ -324,6 +333,7 @@
.unmap = msm_secure_unmap,
.iova_to_phys = msm_secure_iova_to_phys,
};
+ mutex_init(&data->pgtbl_lock);
return data;
}
diff --git a/drivers/iommu/msm_dma_iommu_mapping.c b/drivers/iommu/msm_dma_iommu_mapping.c
index 3f739a2..180edf3 100644
--- a/drivers/iommu/msm_dma_iommu_mapping.c
+++ b/drivers/iommu/msm_dma_iommu_mapping.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -183,7 +183,7 @@
mutex_lock(&iommu_meta->lock);
iommu_map = msm_iommu_lookup(iommu_meta, dev);
if (!iommu_map) {
- iommu_map = kmalloc(sizeof(*iommu_map), GFP_ATOMIC);
+ iommu_map = kmalloc(sizeof(*iommu_map), GFP_KERNEL);
if (!iommu_map) {
ret = -ENOMEM;
diff --git a/drivers/irqchip/qcom/Makefile b/drivers/irqchip/qcom/Makefile
index 1a8ee65..8871f9a 100644
--- a/drivers/irqchip/qcom/Makefile
+++ b/drivers/irqchip/qcom/Makefile
@@ -2,4 +2,4 @@
obj-$(CONFIG_QTI_PDC_SDM845) += pdc-sdm845.o
obj-$(CONFIG_QTI_PDC_SDM670) += pdc-sdm670.o
obj-$(CONFIG_QTI_PDC_SDXPOORWILLS) += pdc-sdxpoorwills.o
-obj-$(CONFIG_QTI_MPM) += mpm.o mpm-8953.o
+obj-$(CONFIG_QTI_MPM) += mpm.o mpm-8953.o mpm-8937.o
diff --git a/drivers/irqchip/qcom/mpm-8937.c b/drivers/irqchip/qcom/mpm-8937.c
new file mode 100644
index 0000000..d6875eb
--- /dev/null
+++ b/drivers/irqchip/qcom/mpm-8937.c
@@ -0,0 +1,74 @@
+/* Copyright (c) 2018, 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 "mpm.h"
+
+const struct mpm_pin mpm_msm8937_gic_chip_data[] = {
+ {2, 216},
+ {49, 172},
+ {53, 104},
+ {58, 166},
+ {62, 222},
+ {-1},
+};
+
+const struct mpm_pin mpm_msm8937_gpio_chip_data[] = {
+ {3, 38},
+ {4, 1},
+ {5, 5},
+ {6, 9},
+ {8, 37},
+ {9, 36},
+ {10, 13},
+ {11, 35},
+ {12, 17},
+ {13, 21},
+ {14, 54},
+ {15, 34},
+ {16, 31},
+ {17, 58},
+ {18, 28},
+ {19, 42},
+ {20, 25},
+ {21, 12},
+ {22, 43},
+ {23, 44},
+ {24, 45},
+ {25, 46},
+ {26, 48},
+ {27, 65},
+ {28, 93},
+ {29, 97},
+ {30, 63},
+ {31, 70},
+ {32, 71},
+ {33, 72},
+ {34, 81},
+ {35, 126},
+ {36, 90},
+ {37, 128},
+ {38, 91},
+ {39, 41},
+ {40, 127},
+ {41, 86},
+ {50, 67},
+ {51, 73},
+ {52, 74},
+ {53, 62},
+ {54, 124},
+ {55, 61},
+ {56, 130},
+ {57, 59},
+ {59, 50},
+ {-1},
+};
diff --git a/drivers/irqchip/qcom/mpm-8953.c b/drivers/irqchip/qcom/mpm-8953.c
index c9b15af..358f40b 100644
--- a/drivers/irqchip/qcom/mpm-8953.c
+++ b/drivers/irqchip/qcom/mpm-8953.c
@@ -22,3 +22,60 @@
{88, 222}, /* ee0_krait_hlos_spmi_periph_irq */
{-1},
};
+
+const struct mpm_pin mpm_msm8953_gpio_chip_data[] = {
+ {3, 38},
+ {4, 1},
+ {5, 5},
+ {6, 9},
+ {8, 37},
+ {9, 36},
+ {10, 13},
+ {11, 35},
+ {12, 17},
+ {13, 21},
+ {14, 54},
+ {15, 34},
+ {16, 31},
+ {17, 58},
+ {18, 28},
+ {19, 42},
+ {20, 25},
+ {21, 12},
+ {22, 43},
+ {23, 44},
+ {24, 45},
+ {25, 46},
+ {26, 48},
+ {27, 65},
+ {28, 93},
+ {29, 97},
+ {30, 63},
+ {31, 70},
+ {32, 71},
+ {33, 72},
+ {34, 81},
+ {35, 85},
+ {36, 90},
+ {50, 67},
+ {51, 73},
+ {52, 74},
+ {53, 62},
+ {59, 59},
+ {60, 60},
+ {61, 61},
+ {62, 86},
+ {63, 87},
+ {64, 91},
+ {65, 129},
+ {66, 130},
+ {67, 131},
+ {68, 132},
+ {69, 133},
+ {70, 137},
+ {71, 138},
+ {72, 139},
+ {73, 140},
+ {74, 141},
+ {-1},
+};
diff --git a/drivers/irqchip/qcom/mpm.c b/drivers/irqchip/qcom/mpm.c
index ba4cfa5..72bd7fd 100644
--- a/drivers/irqchip/qcom/mpm.c
+++ b/drivers/irqchip/qcom/mpm.c
@@ -20,6 +20,7 @@
#include <linux/irq.h>
#include <linux/tick.h>
#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic-v3.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include<linux/ktime.h>
@@ -59,6 +60,7 @@
void __iomem *mpm_ipc_reg;
irq_hw_number_t ipc_irq;
struct irq_domain *gic_chip_domain;
+ struct irq_domain *gpio_chip_domain;
};
static int msm_pm_sleep_time_override;
@@ -200,6 +202,22 @@
}
}
+static void msm_mpm_gpio_chip_mask(struct irq_data *d)
+{
+ msm_mpm_enable_irq(d, false);
+}
+
+static void msm_mpm_gpio_chip_unmask(struct irq_data *d)
+{
+ msm_mpm_enable_irq(d, true);
+}
+
+static int msm_mpm_gpio_chip_set_type(struct irq_data *d, unsigned int type)
+{
+ msm_mpm_set_type(d, type);
+ return 0;
+}
+
static void msm_mpm_gic_chip_mask(struct irq_data *d)
{
msm_mpm_enable_irq(d, false);
@@ -227,9 +245,58 @@
.irq_retrigger = irq_chip_retrigger_hierarchy,
.irq_set_type = msm_mpm_gic_chip_set_type,
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
-#ifdef CONFIG_SMP
.irq_set_affinity = irq_chip_set_affinity_parent,
-#endif
+};
+
+static struct irq_chip msm_mpm_gpio_chip = {
+ .name = "mpm-gpio",
+ .irq_mask = msm_mpm_gpio_chip_mask,
+ .irq_disable = msm_mpm_gpio_chip_mask,
+ .irq_unmask = msm_mpm_gpio_chip_unmask,
+ .irq_set_type = msm_mpm_gpio_chip_set_type,
+ .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+};
+
+static int msm_mpm_gpio_chip_translate(struct irq_domain *d,
+ struct irq_fwspec *fwspec,
+ unsigned long *hwirq,
+ unsigned int *type)
+{
+ if (is_of_node(fwspec->fwnode)) {
+ if (fwspec->param_count != 2)
+ return -EINVAL;
+ *hwirq = fwspec->param[0];
+ *type = fwspec->param[1];
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int msm_mpm_gpio_chip_alloc(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs,
+ void *data)
+{
+ int ret = 0;
+ struct irq_fwspec *fwspec = data;
+ irq_hw_number_t hwirq;
+ unsigned int type = IRQ_TYPE_NONE;
+
+ ret = msm_mpm_gpio_chip_translate(domain, fwspec, &hwirq, &type);
+ if (ret)
+ return ret;
+
+ irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+ &msm_mpm_gpio_chip, NULL);
+
+ return 0;
+}
+
+static const struct irq_domain_ops msm_mpm_gpio_chip_domain_ops = {
+ .translate = msm_mpm_gpio_chip_translate,
+ .alloc = msm_mpm_gpio_chip_alloc,
+ .free = irq_domain_free_irqs_common,
};
static int msm_mpm_gic_chip_translate(struct irq_domain *d,
@@ -240,10 +307,34 @@
if (is_of_node(fwspec->fwnode)) {
if (fwspec->param_count < 3)
return -EINVAL;
- *hwirq = fwspec->param[1];
+
+ switch (fwspec->param[0]) {
+ case 0: /* SPI */
+ *hwirq = fwspec->param[1] + 32;
+ break;
+ case 1: /* PPI */
+ *hwirq = fwspec->param[1] + 16;
+ break;
+ case GIC_IRQ_TYPE_LPI: /* LPI */
+ *hwirq = fwspec->param[1];
+ break;
+ default:
+ return -EINVAL;
+ }
+
*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
return 0;
}
+
+ if (is_fwnode_irqchip(fwspec->fwnode)) {
+ if (fwspec->param_count != 2)
+ return -EINVAL;
+
+ *hwirq = fwspec->param[0];
+ *type = fwspec->param[1];
+ return 0;
+ }
+
return -EINVAL;
}
@@ -296,15 +387,20 @@
irq_set_affinity(msm_mpm_dev_data.ipc_irq, cpumask);
}
-static int msm_get_mpm_pin_map(unsigned int mpm_irq)
+static int msm_get_apps_irq(unsigned int mpm_irq)
{
- struct mpm_pin *mpm_gic_pin_map = NULL;
+ struct mpm_pin *mpm_pin = NULL;
int apps_irq;
- mpm_gic_pin_map = (struct mpm_pin *)
+ mpm_pin = (struct mpm_pin *)
msm_mpm_dev_data.gic_chip_domain->host_data;
- apps_irq = msm_get_irq_pin(mpm_irq, mpm_gic_pin_map);
- return apps_irq;
+ apps_irq = msm_get_irq_pin(mpm_irq, mpm_pin);
+ if (apps_irq >= 0)
+ return apps_irq;
+
+ mpm_pin = (struct mpm_pin *)
+ msm_mpm_dev_data.gpio_chip_domain->host_data;
+ return msm_get_irq_pin(mpm_irq, mpm_pin);
}
@@ -407,7 +503,7 @@
trace_mpm_wakeup_pending_irqs(i, pending);
for_each_set_bit(k, &pending, 32) {
mpm_irq = 32 * i + k;
- apps_irq = msm_get_mpm_pin_map(mpm_irq);
+ apps_irq = msm_get_apps_irq(mpm_irq);
desc = apps_irq ?
irq_to_desc(apps_irq) : NULL;
@@ -420,7 +516,7 @@
return IRQ_HANDLED;
}
-static int msm_mpm_probe(struct device_node *node)
+static int msm_mpm_init(struct device_node *node)
{
struct msm_mpm_device_data *dev = &msm_mpm_dev_data;
int ret = 0;
@@ -480,17 +576,35 @@
.compatible = "qcom,mpm-gic-msm8953",
.data = mpm_msm8953_gic_chip_data,
},
+ {
+ .compatible = "qcom,mpm-gic-msm8937",
+ .data = mpm_msm8937_gic_chip_data,
+ },
{}
};
MODULE_DEVICE_TABLE(of, mpm_gic_chip_data_table);
+static const struct of_device_id mpm_gpio_chip_data_table[] = {
+ {
+ .compatible = "qcom,mpm-gpio-msm8953",
+ .data = mpm_msm8953_gpio_chip_data,
+ },
+ {
+ .compatible = "qcom,mpm-gpio-msm8937",
+ .data = mpm_msm8937_gpio_chip_data,
+ },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, mpm_gpio_chip_data_table);
+
static int __init mpm_gic_chip_init(struct device_node *node,
struct device_node *parent)
{
struct irq_domain *parent_domain;
const struct of_device_id *id;
- struct device_node *parent_node;
+ int ret;
if (!parent) {
pr_err("%s(): no parent for mpm-gic\n", node->full_name);
@@ -507,12 +621,13 @@
mpm_to_irq = kcalloc(num_mpm_irqs, sizeof(*mpm_to_irq), GFP_KERNEL);
if (!mpm_to_irq)
- return -ENOMEM;
+ return -ENOMEM;
id = of_match_node(mpm_gic_chip_data_table, node);
if (!id) {
pr_err("can not find mpm_gic_data_table of_node\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto mpm_map_err;
}
msm_mpm_dev_data.gic_chip_domain = irq_domain_add_hierarchy(
@@ -520,13 +635,45 @@
&msm_mpm_gic_chip_domain_ops, (void *)id->data);
if (!msm_mpm_dev_data.gic_chip_domain) {
pr_err("gic domain add failed\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto mpm_map_err;
}
msm_mpm_dev_data.gic_chip_domain->name = "qcom,mpm-gic";
- parent_node = of_get_parent(node);
- return msm_mpm_probe(parent_node);
+ ret = msm_mpm_init(node);
+ if (!ret)
+ return ret;
+ irq_domain_remove(msm_mpm_dev_data.gic_chip_domain);
+
+mpm_map_err:
+ kfree(mpm_to_irq);
+ return ret;
}
IRQCHIP_DECLARE(mpm_gic_chip, "qcom,mpm-gic", mpm_gic_chip_init);
+
+static int __init mpm_gpio_chip_init(struct device_node *node,
+ struct device_node *parent)
+{
+ const struct of_device_id *id;
+
+ id = of_match_node(mpm_gpio_chip_data_table, node);
+ if (!id) {
+ pr_err("match_table not found for mpm-gpio\n");
+ return -ENODEV;
+ }
+
+ msm_mpm_dev_data.gpio_chip_domain = irq_domain_create_linear(
+ of_node_to_fwnode(node), num_mpm_irqs,
+ &msm_mpm_gpio_chip_domain_ops, (void *)id->data);
+
+ if (!msm_mpm_dev_data.gpio_chip_domain)
+ return -ENOMEM;
+
+ msm_mpm_dev_data.gpio_chip_domain->name = "qcom,mpm-gpio";
+
+ return 0;
+}
+
+IRQCHIP_DECLARE(mpm_gpio_chip, "qcom,mpm-gpio", mpm_gpio_chip_init);
diff --git a/drivers/irqchip/qcom/mpm.h b/drivers/irqchip/qcom/mpm.h
index 72185fc..50a127f 100644
--- a/drivers/irqchip/qcom/mpm.h
+++ b/drivers/irqchip/qcom/mpm.h
@@ -22,5 +22,9 @@
};
extern const struct mpm_pin mpm_msm8953_gic_chip_data[];
+extern const struct mpm_pin mpm_msm8953_gpio_chip_data[];
+
+extern const struct mpm_pin mpm_msm8937_gic_chip_data[];
+extern const struct mpm_pin mpm_msm8937_gpio_chip_data[];
#endif /* __QCOM_MPM_H__ */
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
index 296f141..3b11422 100644
--- a/drivers/isdn/hardware/eicon/message.c
+++ b/drivers/isdn/hardware/eicon/message.c
@@ -147,7 +147,7 @@
static void listen_check(DIVA_CAPI_ADAPTER *);
static byte AddInfo(byte **, byte **, byte *, byte *);
static byte getChannel(API_PARSE *);
-static void IndParse(PLCI *, word *, byte **, byte);
+static void IndParse(PLCI *, const word *, byte **, byte);
static byte ie_compare(byte *, byte *);
static word find_cip(DIVA_CAPI_ADAPTER *, byte *, byte *);
static word CPN_filter_ok(byte *cpn, DIVA_CAPI_ADAPTER *, word);
@@ -4858,7 +4858,7 @@
/* included before the ESC_MSGTYPE and MAXPARMSIDS has to be incremented */
/* SMSG is situated at the end because its 0 (for compatibility reasons */
/* (see Info_Mask Bit 4, first IE. then the message type) */
- word parms_id[] =
+ static const word parms_id[] =
{MAXPARMSIDS, CPN, 0xff, DSA, OSA, BC, LLC, HLC, ESC_CAUSE, DSP, DT, CHA,
UUI, CONG_RR, CONG_RNR, ESC_CHI, KEY, CHI, CAU, ESC_LAW,
RDN, RDX, CONN_NR, RIN, NI, CAI, ESC_CR,
@@ -4866,12 +4866,12 @@
/* 14 FTY repl by ESC_CHI */
/* 18 PI repl by ESC_LAW */
/* removed OAD changed to 0xff for future use, OAD is multiIE now */
- word multi_fac_id[] = {1, FTY};
- word multi_pi_id[] = {1, PI};
- word multi_CiPN_id[] = {1, OAD};
- word multi_ssext_id[] = {1, ESC_SSEXT};
+ static const word multi_fac_id[] = {1, FTY};
+ static const word multi_pi_id[] = {1, PI};
+ static const word multi_CiPN_id[] = {1, OAD};
+ static const word multi_ssext_id[] = {1, ESC_SSEXT};
- word multi_vswitch_id[] = {1, ESC_VSWITCH};
+ static const word multi_vswitch_id[] = {1, ESC_VSWITCH};
byte *cau;
word ncci;
@@ -8924,7 +8924,7 @@
/* functions for all parameters sent in INDs */
/*------------------------------------------------------------------*/
-static void IndParse(PLCI *plci, word *parms_id, byte **parms, byte multiIEsize)
+static void IndParse(PLCI *plci, const word *parms_id, byte **parms, byte multiIEsize)
{
word ploc; /* points to current location within packet */
byte w;
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 431123b..dac7a71 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -44,7 +44,8 @@
goto unlock;
}
- if (sysfs_streq(buf, "none")) {
+ if (sysfs_streq(buf, "none") &&
+ !(led_cdev->flags & LED_KEEP_TRIGGER)) {
led_trigger_remove(led_cdev);
goto unlock;
}
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index d06ee3b..d4b64ba 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -1222,7 +1222,8 @@
fnode->cdev.brightness = prgm_current_ma;
fnode->current_reg_val = get_current_reg_code(prgm_current_ma,
fnode->ires_ua);
- fnode->led_on = prgm_current_ma != 0;
+ if (prgm_current_ma)
+ fnode->led_on = true;
if (pmic_subtype != PMI632_SUBTYPE &&
led->pdata->chgr_mitigation_sel == FLASH_SW_CHARGER_MITIGATION) {
diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c
index ce2b055..cbb51c2 100644
--- a/drivers/leds/leds-qpnp-flash.c
+++ b/drivers/leds/leds-qpnp-flash.c
@@ -2226,7 +2226,6 @@
"Invalid thermal derate rate\n");
return -EINVAL;
}
-
led->pdata->thermal_derate_rate = (u8)temp_val;
} else {
dev_err(&led->pdev->dev,
@@ -2474,11 +2473,12 @@
if (!led->pdata)
return -ENOMEM;
- led->peripheral_type = (u8)qpnp_flash_led_get_peripheral_type(led);
- if (led->peripheral_type < 0) {
+ rc = qpnp_flash_led_get_peripheral_type(led);
+ if (rc < 0) {
dev_err(&pdev->dev, "Failed to get peripheral type\n");
return rc;
}
+ led->peripheral_type = (u8) rc;
rc = qpnp_flash_led_parse_common_dt(led, node);
if (rc) {
@@ -2521,6 +2521,7 @@
}
for_each_child_of_node(node, temp) {
+ j = -1;
led->flash_node[i].cdev.brightness_set =
qpnp_flash_led_brightness_set;
led->flash_node[i].cdev.brightness_get =
@@ -2595,7 +2596,6 @@
if (rc)
goto error_led_register;
}
-
i++;
}
@@ -2607,7 +2607,7 @@
(long)root);
if (PTR_ERR(root) == -ENODEV)
pr_err("debugfs is not enabled in kernel");
- goto error_led_debugfs;
+ goto error_free_led_sysfs;
}
led->dbgfs_root = root;
@@ -2637,6 +2637,8 @@
return 0;
error_led_debugfs:
+ debugfs_remove_recursive(root);
+error_free_led_sysfs:
i = led->num_leds - 1;
j = ARRAY_SIZE(qpnp_flash_led_attrs) - 1;
error_led_register:
@@ -2647,7 +2649,6 @@
j = ARRAY_SIZE(qpnp_flash_led_attrs) - 1;
led_classdev_unregister(&led->flash_node[i].cdev);
}
- debugfs_remove_recursive(root);
mutex_destroy(&led->flash_led_lock);
destroy_workqueue(led->ordered_workq);
diff --git a/drivers/leds/leds-qti-tri-led.c b/drivers/leds/leds-qti-tri-led.c
index ab5e876..f638bc9 100644
--- a/drivers/leds/leds-qti-tri-led.c
+++ b/drivers/leds/leds-qti-tri-led.c
@@ -41,8 +41,6 @@
#define TRILED_NUM_MAX 3
#define PWM_PERIOD_DEFAULT_NS 1000000
-#define LED_BLINK_ON_MS 125
-#define LED_BLINK_OFF_MS 875
struct pwm_setting {
u32 pre_period_ns;
@@ -309,8 +307,7 @@
led->cdev.blink_set = qpnp_tri_led_set_blink;
led->cdev.default_trigger = led->default_trigger;
led->cdev.brightness = LED_OFF;
- led->cdev.blink_delay_on = LED_BLINK_ON_MS;
- led->cdev.blink_delay_off = LED_BLINK_OFF_MS;
+ led->cdev.flags |= LED_KEEP_TRIGGER;
rc = devm_led_classdev_register(chip->dev, &led->cdev);
if (rc < 0) {
@@ -361,7 +358,7 @@
struct qpnp_led_dev *led;
struct pwm_args pargs;
const __be32 *addr;
- int rc, id, i = 0;
+ int rc = 0, id, i = 0;
addr = of_get_address(chip->dev->of_node, 0, NULL, NULL);
if (!addr) {
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index edb8d1a..723302c 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -1020,7 +1020,7 @@
struct request_queue *q = bdev_get_queue(dc->bdev);
int ret = 0;
- if (bdi_congested(&q->backing_dev_info, bits))
+ if (bdi_congested(q->backing_dev_info, bits))
return 1;
if (cached_dev_get(dc)) {
@@ -1029,7 +1029,7 @@
for_each_cache(ca, d->c, i) {
q = bdev_get_queue(ca->bdev);
- ret |= bdi_congested(&q->backing_dev_info, bits);
+ ret |= bdi_congested(q->backing_dev_info, bits);
}
cached_dev_put(dc);
@@ -1043,7 +1043,7 @@
struct gendisk *g = dc->disk.disk;
g->queue->make_request_fn = cached_dev_make_request;
- g->queue->backing_dev_info.congested_fn = cached_dev_congested;
+ g->queue->backing_dev_info->congested_fn = cached_dev_congested;
dc->disk.cache_miss = cached_dev_cache_miss;
dc->disk.ioctl = cached_dev_ioctl;
}
@@ -1136,7 +1136,7 @@
for_each_cache(ca, d->c, i) {
q = bdev_get_queue(ca->bdev);
- ret |= bdi_congested(&q->backing_dev_info, bits);
+ ret |= bdi_congested(q->backing_dev_info, bits);
}
return ret;
@@ -1147,7 +1147,7 @@
struct gendisk *g = d->disk;
g->queue->make_request_fn = flash_dev_make_request;
- g->queue->backing_dev_info.congested_fn = flash_dev_congested;
+ g->queue->backing_dev_info->congested_fn = flash_dev_congested;
d->cache_miss = flash_dev_cache_miss;
d->ioctl = flash_dev_ioctl;
}
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 28ce342..e44816f 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -804,7 +804,7 @@
blk_queue_make_request(q, NULL);
d->disk->queue = q;
q->queuedata = d;
- q->backing_dev_info.congested_data = d;
+ q->backing_dev_info->congested_data = d;
q->limits.max_hw_sectors = UINT_MAX;
q->limits.max_sectors = UINT_MAX;
q->limits.max_segment_size = UINT_MAX;
@@ -1131,9 +1131,9 @@
set_capacity(dc->disk.disk,
dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
- dc->disk.disk->queue->backing_dev_info.ra_pages =
- max(dc->disk.disk->queue->backing_dev_info.ra_pages,
- q->backing_dev_info.ra_pages);
+ dc->disk.disk->queue->backing_dev_info->ra_pages =
+ max(dc->disk.disk->queue->backing_dev_info->ra_pages,
+ q->backing_dev_info->ra_pages);
bch_cached_dev_request_init(dc);
bch_cached_dev_writeback_init(dc);
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index c817627..bed056c 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -2290,7 +2290,7 @@
static int is_congested(struct dm_dev *dev, int bdi_bits)
{
struct request_queue *q = bdev_get_queue(dev->bdev);
- return bdi_congested(&q->backing_dev_info, bdi_bits);
+ return bdi_congested(q->backing_dev_info, bdi_bits);
}
static int cache_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
diff --git a/drivers/md/dm-era-target.c b/drivers/md/dm-era-target.c
index 80e3df1..68d4084 100644
--- a/drivers/md/dm-era-target.c
+++ b/drivers/md/dm-era-target.c
@@ -1379,7 +1379,7 @@
static int dev_is_congested(struct dm_dev *dev, int bdi_bits)
{
struct request_queue *q = bdev_get_queue(dev->bdev);
- return bdi_congested(&q->backing_dev_info, bdi_bits);
+ return bdi_congested(q->backing_dev_info, bdi_bits);
}
static int era_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index d837a28..b75ccef 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -1756,7 +1756,7 @@
char b[BDEVNAME_SIZE];
if (likely(q))
- r |= bdi_congested(&q->backing_dev_info, bdi_bits);
+ r |= bdi_congested(q->backing_dev_info, bdi_bits);
else
DMWARN_LIMIT("%s: any_congested: nonexistent device %s",
dm_device_name(t->md),
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 0b678b5..eb419a5 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -2715,7 +2715,7 @@
return 1;
q = bdev_get_queue(pt->data_dev->bdev);
- return bdi_congested(&q->backing_dev_info, bdi_bits);
+ return bdi_congested(q->backing_dev_info, bdi_bits);
}
static void requeue_bios(struct pool *pool)
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 73e7262..b6c9f69 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -816,7 +816,8 @@
} else {
/* done with normal IO or empty flush */
trace_block_bio_complete(md->queue, bio, io_error);
- bio->bi_error = io_error;
+ if (io_error)
+ bio->bi_error = io_error;
bio_endio(bio);
}
}
@@ -1380,7 +1381,7 @@
* With request-based DM we only need to check the
* top-level queue for congestion.
*/
- r = md->queue->backing_dev_info.wb.state & bdi_bits;
+ r = md->queue->backing_dev_info->wb.state & bdi_bits;
} else {
map = dm_get_live_table_fast(md);
if (map)
@@ -1463,7 +1464,7 @@
* - must do so here (in alloc_dev callchain) before queue is used
*/
md->queue->queuedata = md;
- md->queue->backing_dev_info.congested_data = md;
+ md->queue->backing_dev_info->congested_data = md;
}
void dm_init_normal_md_queue(struct mapped_device *md)
@@ -1474,7 +1475,7 @@
/*
* Initialize aspects of queue that aren't relevant for blk-mq
*/
- md->queue->backing_dev_info.congested_fn = dm_any_congested;
+ md->queue->backing_dev_info->congested_fn = dm_any_congested;
blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY);
}
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 12abf69..be51805 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -68,7 +68,7 @@
for (i = 0; i < conf->raid_disks && !ret ; i++) {
struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev);
- ret |= bdi_congested(&q->backing_dev_info, bits);
+ ret |= bdi_congested(q->backing_dev_info, bits);
}
rcu_read_unlock();
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 8ebf1b9..df7d606 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -5312,8 +5312,8 @@
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mddev->queue);
else
queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, mddev->queue);
- mddev->queue->backing_dev_info.congested_data = mddev;
- mddev->queue->backing_dev_info.congested_fn = md_congested;
+ mddev->queue->backing_dev_info->congested_data = mddev;
+ mddev->queue->backing_dev_info->congested_fn = md_congested;
}
if (pers->sync_request) {
if (mddev->kobj.sd &&
@@ -5668,7 +5668,7 @@
__md_stop_writes(mddev);
__md_stop(mddev);
- mddev->queue->backing_dev_info.congested_fn = NULL;
+ mddev->queue->backing_dev_info->congested_fn = NULL;
/* tell userspace to handle 'inactive' */
sysfs_notify_dirent_safe(mddev->sysfs_state);
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 673efbd..6a7855a 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -169,7 +169,7 @@
if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct request_queue *q = bdev_get_queue(rdev->bdev);
- ret |= bdi_congested(&q->backing_dev_info, bits);
+ ret |= bdi_congested(q->backing_dev_info, bits);
/* Just like multipath_map, we just check the
* first available device
*/
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 258986a..3716dae 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -35,7 +35,7 @@
for (i = 0; i < raid_disks && !ret ; i++) {
struct request_queue *q = bdev_get_queue(devlist[i]->bdev);
- ret |= bdi_congested(&q->backing_dev_info, bits);
+ ret |= bdi_congested(q->backing_dev_info, bits);
}
return ret;
}
@@ -415,8 +415,8 @@
*/
int stripe = mddev->raid_disks *
(mddev->chunk_sectors << 9) / PAGE_SIZE;
- if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
- mddev->queue->backing_dev_info.ra_pages = 2* stripe;
+ if (mddev->queue->backing_dev_info->ra_pages < 2* stripe)
+ mddev->queue->backing_dev_info->ra_pages = 2* stripe;
}
dump_zones(mddev);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 81a7875..208fbf7 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -717,9 +717,9 @@
* non-congested targets, it can be removed
*/
if ((bits & (1 << WB_async_congested)) || 1)
- ret |= bdi_congested(&q->backing_dev_info, bits);
+ ret |= bdi_congested(q->backing_dev_info, bits);
else
- ret &= bdi_congested(&q->backing_dev_info, bits);
+ ret &= bdi_congested(q->backing_dev_info, bits);
}
}
rcu_read_unlock();
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index b19b551..8d40238 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -833,7 +833,7 @@
if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct request_queue *q = bdev_get_queue(rdev->bdev);
- ret |= bdi_congested(&q->backing_dev_info, bits);
+ ret |= bdi_congested(q->backing_dev_info, bits);
}
}
rcu_read_unlock();
@@ -3754,8 +3754,8 @@
* maybe...
*/
stripe /= conf->geo.near_copies;
- if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
- mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+ if (mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+ mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
}
if (md_integrity_register(mddev))
@@ -4557,8 +4557,8 @@
int stripe = conf->geo.raid_disks *
((conf->mddev->chunk_sectors << 9) / PAGE_SIZE);
stripe /= conf->geo.near_copies;
- if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
- conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+ if (conf->mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+ conf->mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
}
conf->fullsync = 0;
}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 475a7a1..90d863e 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -6155,10 +6155,10 @@
mddev_suspend(mddev);
conf->skip_copy = new;
if (new)
- mddev->queue->backing_dev_info.capabilities |=
+ mddev->queue->backing_dev_info->capabilities |=
BDI_CAP_STABLE_WRITES;
else
- mddev->queue->backing_dev_info.capabilities &=
+ mddev->queue->backing_dev_info->capabilities &=
~BDI_CAP_STABLE_WRITES;
mddev_resume(mddev);
}
@@ -6984,8 +6984,8 @@
int data_disks = conf->previous_raid_disks - conf->max_degraded;
int stripe = data_disks *
((mddev->chunk_sectors << 9) / PAGE_SIZE);
- if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
- mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+ if (mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+ mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
chunk_size = mddev->chunk_sectors << 9;
blk_queue_io_min(mddev->queue, chunk_size);
@@ -7591,8 +7591,8 @@
int data_disks = conf->raid_disks - conf->max_degraded;
int stripe = data_disks * ((conf->chunk_sectors << 9)
/ PAGE_SIZE);
- if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
- conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+ if (conf->mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+ conf->mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
}
}
}
diff --git a/drivers/media/dvb-frontends/ascot2e.c b/drivers/media/dvb-frontends/ascot2e.c
index ad304ee..c61227c 100644
--- a/drivers/media/dvb-frontends/ascot2e.c
+++ b/drivers/media/dvb-frontends/ascot2e.c
@@ -155,7 +155,9 @@
static int ascot2e_write_reg(struct ascot2e_priv *priv, u8 reg, u8 val)
{
- return ascot2e_write_regs(priv, reg, &val, 1);
+ u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+ return ascot2e_write_regs(priv, reg, &tmp, 1);
}
static int ascot2e_read_regs(struct ascot2e_priv *priv,
diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c
index fd0f25e..b97647c 100644
--- a/drivers/media/dvb-frontends/cxd2841er.c
+++ b/drivers/media/dvb-frontends/cxd2841er.c
@@ -261,7 +261,9 @@
static int cxd2841er_write_reg(struct cxd2841er_priv *priv,
u8 addr, u8 reg, u8 val)
{
- return cxd2841er_write_regs(priv, addr, reg, &val, 1);
+ u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+ return cxd2841er_write_regs(priv, addr, reg, &tmp, 1);
}
static int cxd2841er_read_regs(struct cxd2841er_priv *priv,
diff --git a/drivers/media/dvb-frontends/helene.c b/drivers/media/dvb-frontends/helene.c
index dc43c5f..e06bcd4 100644
--- a/drivers/media/dvb-frontends/helene.c
+++ b/drivers/media/dvb-frontends/helene.c
@@ -331,7 +331,9 @@
static int helene_write_reg(struct helene_priv *priv, u8 reg, u8 val)
{
- return helene_write_regs(priv, reg, &val, 1);
+ u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+ return helene_write_regs(priv, reg, &tmp, 1);
}
static int helene_read_regs(struct helene_priv *priv,
diff --git a/drivers/media/dvb-frontends/horus3a.c b/drivers/media/dvb-frontends/horus3a.c
index 0c089b5..4ebddc8 100644
--- a/drivers/media/dvb-frontends/horus3a.c
+++ b/drivers/media/dvb-frontends/horus3a.c
@@ -89,7 +89,9 @@
static int horus3a_write_reg(struct horus3a_priv *priv, u8 reg, u8 val)
{
- return horus3a_write_regs(priv, reg, &val, 1);
+ u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+ return horus3a_write_regs(priv, reg, &tmp, 1);
}
static int horus3a_enter_power_save(struct horus3a_priv *priv)
diff --git a/drivers/media/dvb-frontends/itd1000.c b/drivers/media/dvb-frontends/itd1000.c
index cadcae4..ac9d259 100644
--- a/drivers/media/dvb-frontends/itd1000.c
+++ b/drivers/media/dvb-frontends/itd1000.c
@@ -99,8 +99,9 @@
static inline int itd1000_write_reg(struct itd1000_state *state, u8 r, u8 v)
{
- int ret = itd1000_write_regs(state, r, &v, 1);
- state->shadow[r] = v;
+ u8 tmp = v; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+ int ret = itd1000_write_regs(state, r, &tmp, 1);
+ state->shadow[r] = tmp;
return ret;
}
diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c
index fc08429..7824926 100644
--- a/drivers/media/dvb-frontends/mt312.c
+++ b/drivers/media/dvb-frontends/mt312.c
@@ -142,7 +142,10 @@
static inline int mt312_writereg(struct mt312_state *state,
const enum mt312_reg_addr reg, const u8 val)
{
- return mt312_write(state, reg, &val, 1);
+ u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+
+ return mt312_write(state, reg, &tmp, 1);
}
static inline u32 mt312_div(u32 a, u32 b)
diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c
index 3d171b0..3deddbc 100644
--- a/drivers/media/dvb-frontends/stb0899_drv.c
+++ b/drivers/media/dvb-frontends/stb0899_drv.c
@@ -552,7 +552,8 @@
int stb0899_write_reg(struct stb0899_state *state, unsigned int reg, u8 data)
{
- return stb0899_write_regs(state, reg, &data, 1);
+ u8 tmp = data;
+ return stb0899_write_regs(state, reg, &tmp, 1);
}
/*
diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c
index 5add118..4746b1e 100644
--- a/drivers/media/dvb-frontends/stb6100.c
+++ b/drivers/media/dvb-frontends/stb6100.c
@@ -226,12 +226,14 @@
static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data)
{
+ u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
if (unlikely(reg >= STB6100_NUMREGS)) {
dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
return -EREMOTEIO;
}
- data = (data & stb6100_template[reg].mask) | stb6100_template[reg].set;
- return stb6100_write_reg_range(state, &data, reg, 1);
+ tmp = (tmp & stb6100_template[reg].mask) | stb6100_template[reg].set;
+ return stb6100_write_reg_range(state, &tmp, reg, 1);
}
diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c
index abc379a..94cec81 100644
--- a/drivers/media/dvb-frontends/stv0367.c
+++ b/drivers/media/dvb-frontends/stv0367.c
@@ -804,7 +804,9 @@
static int stv0367_writereg(struct stv0367_state *state, u16 reg, u8 data)
{
- return stv0367_writeregs(state, reg, &data, 1);
+ u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+ return stv0367_writeregs(state, reg, &tmp, 1);
}
static u8 stv0367_readreg(struct stv0367_state *state, u16 reg)
diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c
index 25bdf6e..f0377e2 100644
--- a/drivers/media/dvb-frontends/stv090x.c
+++ b/drivers/media/dvb-frontends/stv090x.c
@@ -761,7 +761,9 @@
static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 data)
{
- return stv090x_write_regs(state, reg, &data, 1);
+ u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+ return stv090x_write_regs(state, reg, &tmp, 1);
}
static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c
index c611ad2..924f16f 100644
--- a/drivers/media/dvb-frontends/stv6110x.c
+++ b/drivers/media/dvb-frontends/stv6110x.c
@@ -97,7 +97,9 @@
static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
{
- return stv6110x_write_regs(stv6110x, reg, &data, 1);
+ u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+ return stv6110x_write_regs(stv6110x, reg, &tmp, 1);
}
static int stv6110x_init(struct dvb_frontend *fe)
diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c
index a9f6bbe..103b9c8 100644
--- a/drivers/media/dvb-frontends/ts2020.c
+++ b/drivers/media/dvb-frontends/ts2020.c
@@ -369,7 +369,7 @@
gain2 = clamp_t(long, gain2, 0, 13);
v_agc = clamp_t(long, v_agc, 400, 1100);
- *_gain = -(gain1 * 2330 +
+ *_gain = -((__s64)gain1 * 2330 +
gain2 * 3500 +
v_agc * 24 / 10 * 10 +
10000);
@@ -387,7 +387,7 @@
gain3 = clamp_t(long, gain3, 0, 6);
v_agc = clamp_t(long, v_agc, 600, 1600);
- *_gain = -(gain1 * 2650 +
+ *_gain = -((__s64)gain1 * 2650 +
gain2 * 3380 +
gain3 * 2850 +
v_agc * 176 / 100 * 10 -
diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c
index f8c271b..0d2bef6 100644
--- a/drivers/media/dvb-frontends/zl10039.c
+++ b/drivers/media/dvb-frontends/zl10039.c
@@ -138,7 +138,9 @@
const enum zl10039_reg_addr reg,
const u8 val)
{
- return zl10039_write(state, reg, &val, 1);
+ const u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+ return zl10039_write(state, reg, &tmp, 1);
}
static int zl10039_init(struct dvb_frontend *fe)
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
index faee113..4b615b4 100644
--- a/drivers/media/i2c/s5k6aa.c
+++ b/drivers/media/i2c/s5k6aa.c
@@ -421,6 +421,7 @@
/**
* s5k6aa_configure_pixel_clock - apply ISP main clock/PLL configuration
+ * @s5k6aa: pointer to &struct s5k6aa describing the device
*
* Configure the internal ISP PLL for the required output frequency.
* Locking: called with s5k6aa.lock mutex held.
@@ -669,6 +670,7 @@
/**
* s5k6aa_configure_video_bus - configure the video output interface
+ * @s5k6aa: pointer to &struct s5k6aa describing the device
* @bus_type: video bus type: parallel or MIPI-CSI
* @nlanes: number of MIPI lanes to be used (MIPI-CSI only)
*
@@ -724,6 +726,8 @@
/**
* s5k6aa_set_prev_config - write user preview register set
+ * @s5k6aa: pointer to &struct s5k6aa describing the device
+ * @preset: s5kaa preset to be applied
*
* Configure output resolution and color fromat, pixel clock
* frequency range, device frame rate type and frame period range.
@@ -777,6 +781,7 @@
/**
* s5k6aa_initialize_isp - basic ISP MCU initialization
+ * @sd: pointer to V4L2 sub-device descriptor
*
* Configure AHB addresses for registers read/write; configure PLLs for
* required output pixel clock. The ISP power supply needs to be already
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 1e3a0dd..26d999c 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -193,57 +193,61 @@
}
}
+static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
+{
+ __le32 val = 0;
+
+ i2c_rd(sd, reg, (u8 __force *)&val, n);
+
+ return le32_to_cpu(val);
+}
+
+static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n)
+{
+ __le32 raw = cpu_to_le32(val);
+
+ i2c_wr(sd, reg, (u8 __force *)&raw, n);
+}
+
static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg)
{
- u8 val;
-
- i2c_rd(sd, reg, &val, 1);
-
- return val;
+ return i2c_rdreg(sd, reg, 1);
}
static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val)
{
- i2c_wr(sd, reg, &val, 1);
+ i2c_wrreg(sd, reg, val, 1);
}
static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg,
u8 mask, u8 val)
{
- i2c_wr8(sd, reg, (i2c_rd8(sd, reg) & mask) | val);
+ i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2);
}
static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg)
{
- u16 val;
-
- i2c_rd(sd, reg, (u8 *)&val, 2);
-
- return val;
+ return i2c_rdreg(sd, reg, 2);
}
static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val)
{
- i2c_wr(sd, reg, (u8 *)&val, 2);
+ i2c_wrreg(sd, reg, val, 2);
}
static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val)
{
- i2c_wr16(sd, reg, (i2c_rd16(sd, reg) & mask) | val);
+ i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2);
}
static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg)
{
- u32 val;
-
- i2c_rd(sd, reg, (u8 *)&val, 4);
-
- return val;
+ return i2c_rdreg(sd, reg, 4);
}
static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val)
{
- i2c_wr(sd, reg, (u8 *)&val, 4);
+ i2c_wrreg(sd, reg, val, 4);
}
/* --------------- STATUS --------------- */
@@ -1236,7 +1240,7 @@
reg->size = tc358743_get_reg_size(reg->reg);
- i2c_rd(sd, reg->reg, (u8 *)®->val, reg->size);
+ reg->val = i2c_rdreg(sd, reg->reg, reg->size);
return 0;
}
@@ -1262,7 +1266,7 @@
reg->reg == BCAPS)
return 0;
- i2c_wr(sd, (u16)reg->reg, (u8 *)®->val,
+ i2c_wrreg(sd, (u16)reg->reg, reg->val,
tc358743_get_reg_size(reg->reg));
return 0;
diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c
index 652a059..1ddf80f 100644
--- a/drivers/media/pci/tw5864/tw5864-video.c
+++ b/drivers/media/pci/tw5864/tw5864-video.c
@@ -708,6 +708,8 @@
static int tw5864_frameinterval_get(struct tw5864_input *input,
struct v4l2_fract *frameinterval)
{
+ struct tw5864_dev *dev = input->root;
+
switch (input->std) {
case STD_NTSC:
frameinterval->numerator = 1001;
@@ -719,8 +721,8 @@
frameinterval->denominator = 25;
break;
default:
- WARN(1, "tw5864_frameinterval_get requested for unknown std %d\n",
- input->std);
+ dev_warn(&dev->pci->dev, "tw5864_frameinterval_get requested for unknown std %d\n",
+ input->std);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf_api.h b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf_api.h
index 66c75f6..2b00a87 100644
--- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf_api.h
+++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -81,7 +81,7 @@
enum cam_cdm_id id;
void *userdata;
void (*cam_cdm_callback)(uint32_t handle, void *userdata,
- enum cam_cdm_cb_status status, uint32_t cookie);
+ enum cam_cdm_cb_status status, uint64_t cookie);
uint32_t base_array_cnt;
struct cam_soc_reg_map *base_array[CAM_SOC_MAX_BLOCK];
struct cam_hw_version cdm_version;
@@ -128,7 +128,7 @@
struct cam_cdm_bl_request {
int flag;
void *userdata;
- uint32_t cookie;
+ uint64_t cookie;
enum cam_cdm_bl_cmd_addr_type type;
uint32_t cmd_arrary_count;
struct cam_cdm_bl_cmd cmd[1];
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.c b/drivers/media/platform/msm/camera/cam_core/cam_context.c
index d1222aa..8beffc4 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.c
@@ -40,6 +40,7 @@
int cam_context_shutdown(struct cam_context *ctx)
{
int rc = 0;
+ int32_t ctx_hdl = ctx->dev_hdl;
if (ctx->state_machine[ctx->state].ioctl_ops.stop_dev) {
rc = ctx->state_machine[ctx->state].ioctl_ops.stop_dev(
@@ -54,6 +55,8 @@
CAM_ERR(CAM_CORE, "Error while dev release %d", rc);
}
+ if (!rc)
+ cam_destroy_device_hdl(ctx_hdl);
return rc;
}
@@ -224,6 +227,7 @@
struct cam_acquire_dev_cmd *cmd)
{
int rc;
+ int i;
if (!ctx->state_machine) {
CAM_ERR(CAM_CORE, "Context is not ready");
@@ -244,6 +248,17 @@
cmd->dev_handle, ctx->state);
rc = -EPROTO;
}
+
+ INIT_LIST_HEAD(&ctx->active_req_list);
+ INIT_LIST_HEAD(&ctx->wait_req_list);
+ INIT_LIST_HEAD(&ctx->pending_req_list);
+ INIT_LIST_HEAD(&ctx->free_req_list);
+
+ for (i = 0; i < ctx->req_size; i++) {
+ INIT_LIST_HEAD(&ctx->req_list[i].list);
+ list_add_tail(&ctx->req_list[i].list, &ctx->free_req_list);
+ }
+
mutex_unlock(&ctx->ctx_mutex);
return rc;
@@ -394,6 +409,8 @@
int cam_context_init(struct cam_context *ctx,
const char *dev_name,
+ uint64_t dev_id,
+ uint32_t ctx_id,
struct cam_req_mgr_kmd_ops *crm_node_intf,
struct cam_hw_mgr_intf *hw_mgr_intf,
struct cam_ctx_request *req_list,
@@ -417,6 +434,8 @@
spin_lock_init(&ctx->lock);
ctx->dev_name = dev_name;
+ ctx->dev_id = dev_id;
+ ctx->ctx_id = ctx_id;
ctx->ctx_crm_intf = NULL;
ctx->crm_ctx_intf = crm_node_intf;
ctx->hw_mgr_intf = hw_mgr_intf;
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 af92b7e..8324e78 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.h
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.h
@@ -147,6 +147,8 @@
* struct cam_context - camera context object for the subdevice node
*
* @dev_name: String giving name of device associated
+ * @dev_id: ID of device associated
+ * @ctx_id: ID for this context
* @list: Link list entry
* @sessoin_hdl: Session handle
* @dev_hdl: Device handle
@@ -174,6 +176,8 @@
*/
struct cam_context {
const char *dev_name;
+ uint64_t dev_id;
+ uint32_t ctx_id;
struct list_head list;
int32_t session_hdl;
int32_t dev_hdl;
@@ -376,6 +380,8 @@
*
* @ctx: Object pointer for cam_context
* @dev_name: String giving name of device associated
+ * @dev_id: ID of the device associated
+ * @ctx_id: ID for this context
* @crm_node_intf: Function table for crm to context interface
* @hw_mgr_intf: Function table for context to hw interface
* @req_list: Requests storage
@@ -384,6 +390,8 @@
*/
int cam_context_init(struct cam_context *ctx,
const char *dev_name,
+ uint64_t dev_id,
+ uint32_t ctx_id,
struct cam_req_mgr_kmd_ops *crm_node_intf,
struct cam_hw_mgr_intf *hw_mgr_intf,
struct cam_ctx_request *req_list,
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 8ea920d..85e9058 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
@@ -26,6 +26,9 @@
#include "cam_trace.h"
#include "cam_debug_util.h"
+static uint cam_debug_ctx_req_list;
+module_param(cam_debug_ctx_req_list, uint, 0644);
+
static inline int cam_context_validate_thread(void)
{
if (in_interrupt()) {
@@ -56,7 +59,8 @@
spin_lock(&ctx->lock);
if (list_empty(&ctx->active_req_list)) {
- CAM_ERR(CAM_CTXT, "no active request");
+ CAM_ERR(CAM_CTXT, "[%s][%d] no active request",
+ ctx->dev_name, ctx->ctx_id);
spin_unlock(&ctx->lock);
return -EIO;
}
@@ -66,14 +70,17 @@
trace_cam_buf_done("UTILS", ctx, req);
if (done->request_id != req->request_id) {
- CAM_ERR(CAM_CTXT, "mismatch: done req[%lld], active req[%lld]",
+ CAM_ERR(CAM_CTXT,
+ "[%s][%d] mismatch: done req[%lld], active req[%lld]",
+ ctx->dev_name, ctx->ctx_id,
done->request_id, req->request_id);
spin_unlock(&ctx->lock);
return -EIO;
}
if (!req->num_out_map_entries) {
- CAM_ERR(CAM_CTXT, "no output fence to signal");
+ CAM_ERR(CAM_CTXT, "[%s][%d] no output fence to signal",
+ ctx->dev_name, ctx->ctx_id);
spin_unlock(&ctx->lock);
return -EIO;
}
@@ -94,6 +101,11 @@
req->out_map_entries[j].sync_id = -1;
}
+ if (cam_debug_ctx_req_list & ctx->dev_id)
+ CAM_INFO(CAM_CTXT,
+ "[%s][%d] : Moving req[%llu] from active_list to free_list",
+ ctx->dev_name, ctx->ctx_id, req->request_id);
+
/*
* another thread may be adding/removing from free list,
* so hold the lock
@@ -114,7 +126,8 @@
struct cam_hw_config_args cfg;
if (!ctx->hw_mgr_intf) {
- CAM_ERR(CAM_CTXT, "HW interface is not ready");
+ CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+ ctx->dev_name, ctx->ctx_id);
rc = -EFAULT;
goto end;
}
@@ -124,7 +137,13 @@
list_add_tail(&req->list, &ctx->active_req_list);
spin_unlock(&ctx->lock);
+ if (cam_debug_ctx_req_list & ctx->dev_id)
+ CAM_INFO(CAM_CTXT,
+ "[%s][%d] : Moving req[%llu] from pending_list to active_list",
+ ctx->dev_name, ctx->ctx_id, req->request_id);
+
cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
+ cfg.request_id = req->request_id;
cfg.hw_update_entries = req->hw_update_entries;
cfg.num_hw_update_entries = req->num_hw_update_entries;
cfg.out_map_entries = req->out_map_entries;
@@ -135,7 +154,13 @@
if (rc) {
spin_lock(&ctx->lock);
list_del_init(&req->list);
+ list_add_tail(&req->list, &ctx->free_req_list);
spin_unlock(&ctx->lock);
+
+ if (cam_debug_ctx_req_list & ctx->dev_id)
+ CAM_INFO(CAM_CTXT,
+ "[%s][%d] : Moving req[%llu] from active_list to free_list",
+ ctx->dev_name, ctx->ctx_id, req->request_id);
}
end:
@@ -159,6 +184,11 @@
return;
ctx = req->ctx;
+ if (!ctx) {
+ CAM_ERR(CAM_CTXT, "Invalid ctx for req %llu", req->request_id);
+ return;
+ }
+
req->num_in_acked++;
if (req->num_in_acked == req->num_in_map_entries) {
apply.request_id = req->request_id;
@@ -174,8 +204,6 @@
CAM_DBG(CAM_CTXT, "fence error: %d", sync_obj);
flush_cmd.req_id = req->request_id;
cam_context_flush_req_to_hw(ctx, &flush_cmd);
- cam_context_putref(ctx);
- return;
}
mutex_lock(&ctx->sync_mutex);
@@ -190,6 +218,12 @@
list_del_init(&req->list);
list_add_tail(&req->list, &ctx->free_req_list);
spin_unlock(&ctx->lock);
+
+ if (cam_debug_ctx_req_list & ctx->dev_id)
+ CAM_INFO(CAM_CTXT,
+ "[%s][%d] : Moving req[%llu] from pending_list to free_list",
+ ctx->dev_name, ctx->ctx_id,
+ req->request_id);
}
}
cam_context_putref(ctx);
@@ -206,7 +240,8 @@
}
if ((!ctx->hw_mgr_intf) || (!ctx->hw_mgr_intf->hw_release)) {
- CAM_ERR(CAM_CTXT, "HW interface is not ready");
+ CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+ ctx->dev_name, ctx->ctx_id);
return -EINVAL;
}
@@ -241,7 +276,8 @@
}
if (!ctx->hw_mgr_intf) {
- CAM_ERR(CAM_CTXT, "HW interface is not ready");
+ CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+ ctx->dev_name, ctx->ctx_id);
rc = -EFAULT;
goto end;
}
@@ -258,7 +294,8 @@
spin_unlock(&ctx->lock);
if (!req) {
- CAM_ERR(CAM_CTXT, "No more request obj free");
+ CAM_ERR(CAM_CTXT, "[%s][%d] No more request obj free",
+ ctx->dev_name, ctx->ctx_id);
rc = -ENOMEM;
goto end;
}
@@ -273,7 +310,8 @@
(uint64_t *) &packet_addr,
&len);
if (rc != 0) {
- CAM_ERR(CAM_CTXT, "Can not get packet address");
+ CAM_ERR(CAM_CTXT, "[%s][%d] Can not get packet address",
+ ctx->dev_name, ctx->ctx_id);
rc = -EINVAL;
goto free_req;
}
@@ -295,7 +333,9 @@
rc = ctx->hw_mgr_intf->hw_prepare_update(
ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
if (rc != 0) {
- CAM_ERR(CAM_CTXT, "Prepare config packet failed in HW layer");
+ CAM_ERR(CAM_CTXT,
+ "[%s][%d] Prepare config packet failed in HW layer",
+ ctx->dev_name, ctx->ctx_id);
rc = -EFAULT;
goto free_req;
}
@@ -310,6 +350,12 @@
spin_lock(&ctx->lock);
list_add_tail(&req->list, &ctx->pending_req_list);
spin_unlock(&ctx->lock);
+
+ if (cam_debug_ctx_req_list & ctx->dev_id)
+ CAM_INFO(CAM_CTXT,
+ "[%s][%d] : Moving req[%llu] from free_list to pending_list",
+ ctx->dev_name, ctx->ctx_id, req->request_id);
+
for (i = 0; i < req->num_in_map_entries; i++) {
cam_context_getref(ctx);
rc = cam_sync_register_callback(
@@ -318,9 +364,21 @@
req->in_map_entries[i].sync_id);
if (rc) {
CAM_ERR(CAM_CTXT,
- "Failed register fence cb: %d ret = %d",
+ "[%s][%d] Failed register fence cb: %d ret = %d",
+ ctx->dev_name, ctx->ctx_id,
req->in_map_entries[i].sync_id, rc);
+ spin_lock(&ctx->lock);
+ list_del_init(&req->list);
+ spin_unlock(&ctx->lock);
+
+ if (cam_debug_ctx_req_list & ctx->dev_id)
+ CAM_INFO(CAM_CTXT,
+ "[%s][%d] : Moving req[%llu] from pending_list to free_list",
+ ctx->dev_name, ctx->ctx_id,
+ req->request_id);
+
cam_context_putref(ctx);
+
goto free_req;
}
CAM_DBG(CAM_CTXT, "register in fence cb: %d ret = %d",
@@ -355,7 +413,8 @@
}
if (!ctx->hw_mgr_intf) {
- CAM_ERR(CAM_CTXT, "HW interface is not ready");
+ CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+ ctx->dev_name, ctx->ctx_id);
rc = -EFAULT;
goto end;
}
@@ -365,14 +424,16 @@
cmd->resource_hdl);
if (cmd->num_resources > CAM_CTX_RES_MAX) {
- CAM_ERR(CAM_CTXT, "resource limit exceeded");
+ CAM_ERR(CAM_CTXT, "[%s][%d] resource limit exceeded",
+ ctx->dev_name, ctx->ctx_id);
rc = -ENOMEM;
goto end;
}
/* for now we only support user pointer */
if (cmd->handle_type != 1) {
- CAM_ERR(CAM_CTXT, "Only user pointer is supported");
+ CAM_ERR(CAM_CTXT, "[%s][%d] Only user pointer is supported",
+ ctx->dev_name, ctx->ctx_id);
rc = -EINVAL;
goto end;
}
@@ -387,7 +448,8 @@
rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv,
¶m);
if (rc != 0) {
- CAM_ERR(CAM_CTXT, "Acquire device failed");
+ CAM_ERR(CAM_CTXT, "[%s][%d] Acquire device failed",
+ ctx->dev_name, ctx->ctx_id);
goto end;
}
@@ -404,7 +466,8 @@
ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param);
if (ctx->dev_hdl <= 0) {
rc = -EFAULT;
- CAM_ERR(CAM_CTXT, "Can not create device handle");
+ CAM_ERR(CAM_CTXT, "[%s][%d] Can not create device handle",
+ ctx->dev_name, ctx->ctx_id);
goto free_hw;
}
cmd->dev_handle = ctx->dev_hdl;
@@ -430,7 +493,7 @@
uint32_t i;
int rc = 0;
- CAM_DBG(CAM_CTXT, "E: NRT flush ctx");
+ CAM_DBG(CAM_CTXT, "[%s] E: NRT flush ctx", ctx->dev_name);
/*
* flush pending requests, take the sync lock to synchronize with the
@@ -442,17 +505,30 @@
spin_lock(&ctx->lock);
list_splice_init(&ctx->pending_req_list, &temp_list);
spin_unlock(&ctx->lock);
+
+ if (cam_debug_ctx_req_list & ctx->dev_id)
+ CAM_INFO(CAM_CTXT,
+ "[%s][%d] : Moving all pending requests from pending_list to temp_list",
+ ctx->dev_name, ctx->ctx_id);
+
flush_args.num_req_pending = 0;
- while (!list_empty(&temp_list)) {
+ while (true) {
+ spin_lock(&ctx->lock);
+ if (list_empty(&temp_list)) {
+ spin_unlock(&ctx->lock);
+ break;
+ }
+
req = list_first_entry(&temp_list,
struct cam_ctx_request, list);
list_del_init(&req->list);
+ spin_unlock(&ctx->lock);
req->flushed = 1;
flush_args.flush_req_pending[flush_args.num_req_pending++] =
req->req_priv;
- for (i = 0; i < req->num_out_map_entries; i++)
+ for (i = 0; i < req->num_out_map_entries; i++) {
if (req->out_map_entries[i].sync_id != -1) {
rc = cam_sync_signal(
req->out_map_entries[i].sync_id,
@@ -466,6 +542,12 @@
break;
}
}
+ }
+
+ if (cam_debug_ctx_req_list & ctx->dev_id)
+ CAM_INFO(CAM_CTXT,
+ "[%s][%d] : Deleting req[%llu] from temp_list",
+ ctx->dev_name, ctx->ctx_id, req->request_id);
}
mutex_unlock(&ctx->sync_mutex);
@@ -492,10 +574,22 @@
INIT_LIST_HEAD(&ctx->active_req_list);
spin_unlock(&ctx->lock);
- while (!list_empty(&temp_list)) {
+ if (cam_debug_ctx_req_list & ctx->dev_id)
+ CAM_INFO(CAM_CTXT,
+ "[%s][%d] : Moving all requests from active_list to temp_list",
+ ctx->dev_name, ctx->ctx_id);
+
+ while (true) {
+ spin_lock(&ctx->lock);
+ if (list_empty(&temp_list)) {
+ spin_unlock(&ctx->lock);
+ break;
+ }
req = list_first_entry(&temp_list,
struct cam_ctx_request, list);
list_del_init(&req->list);
+ spin_unlock(&ctx->lock);
+
for (i = 0; i < req->num_out_map_entries; i++) {
if (req->out_map_entries[i].sync_id != -1) {
rc = cam_sync_signal(
@@ -517,9 +611,14 @@
list_add_tail(&req->list, &ctx->free_req_list);
spin_unlock(&ctx->lock);
req->ctx = NULL;
+
+ if (cam_debug_ctx_req_list & ctx->dev_id)
+ CAM_INFO(CAM_CTXT,
+ "[%s][%d] : Moving req[%llu] from temp_list to free_list",
+ ctx->dev_name, ctx->ctx_id, req->request_id);
}
- CAM_DBG(CAM_CTXT, "X: NRT flush ctx");
+ CAM_DBG(CAM_CTXT, "[%s] X: NRT flush ctx", ctx->dev_name);
return 0;
}
@@ -532,7 +631,7 @@
uint32_t i;
int rc = 0;
- CAM_DBG(CAM_CTXT, "E: NRT flush req");
+ CAM_DBG(CAM_CTXT, "[%s] E: NRT flush req", ctx->dev_name);
flush_args.num_req_pending = 0;
flush_args.num_req_active = 0;
@@ -542,6 +641,11 @@
if (req->request_id != cmd->req_id)
continue;
+ if (cam_debug_ctx_req_list & ctx->dev_id)
+ CAM_INFO(CAM_CTXT,
+ "[%s][%d] : Deleting req[%llu] from pending_list",
+ ctx->dev_name, ctx->ctx_id, req->request_id);
+
list_del_init(&req->list);
req->flushed = 1;
@@ -598,10 +702,16 @@
list_add_tail(&req->list, &ctx->free_req_list);
spin_unlock(&ctx->lock);
req->ctx = NULL;
+
+ if (cam_debug_ctx_req_list & ctx->dev_id)
+ CAM_INFO(CAM_CTXT,
+ "[%s][%d] : Moving req[%llu] from active_list to free_list",
+ ctx->dev_name, ctx->ctx_id,
+ req->request_id);
}
}
}
- CAM_DBG(CAM_CTXT, "X: NRT flush req");
+ CAM_DBG(CAM_CTXT, "[%s] X: NRT flush req", ctx->dev_name);
return 0;
}
@@ -619,7 +729,8 @@
}
if (!ctx->hw_mgr_intf) {
- CAM_ERR(CAM_CTXT, "HW interface is not ready");
+ CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+ ctx->dev_name, ctx->ctx_id);
rc = -EFAULT;
goto end;
}
@@ -630,7 +741,8 @@
rc = cam_context_flush_req_to_hw(ctx, cmd);
else {
rc = -EINVAL;
- CAM_ERR(CAM_CORE, "Invalid flush type %d", cmd->flush_type);
+ CAM_ERR(CAM_CORE, "[%s][%d] Invalid flush type %d",
+ ctx->dev_name, ctx->ctx_id, cmd->flush_type);
}
end:
@@ -650,14 +762,17 @@
}
if (!ctx->hw_mgr_intf) {
- CAM_ERR(CAM_CTXT, "HW interface is not ready");
+ CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+ ctx->dev_name, ctx->ctx_id);
rc = -EFAULT;
goto end;
}
if ((cmd->session_handle != ctx->session_hdl) ||
(cmd->dev_handle != ctx->dev_hdl)) {
- CAM_ERR(CAM_CTXT, "Invalid session hdl[%d], dev_handle[%d]",
+ CAM_ERR(CAM_CTXT,
+ "[%s][%d] Invalid session hdl[%d], dev_handle[%d]",
+ ctx->dev_name, ctx->ctx_id,
cmd->session_handle, cmd->dev_handle);
rc = -EPERM;
goto end;
@@ -669,7 +784,8 @@
&arg);
if (rc) {
/* HW failure. user need to clean up the resource */
- CAM_ERR(CAM_CTXT, "Start HW failed");
+ CAM_ERR(CAM_CTXT, "[%s][%d] Start HW failed",
+ ctx->dev_name, ctx->ctx_id);
goto end;
}
}
@@ -690,7 +806,8 @@
}
if (!ctx->hw_mgr_intf) {
- CAM_ERR(CAM_CTXT, "HW interface is not ready");
+ CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+ ctx->dev_name, ctx->ctx_id);
rc = -EFAULT;
goto end;
}
@@ -699,11 +816,9 @@
if (rc)
goto end;
- if (ctx->ctxt_to_hw_map) {
- rc = cam_context_flush_ctx_to_hw(ctx);
- if (rc)
- goto end;
- }
+ rc = cam_context_flush_ctx_to_hw(ctx);
+ if (rc)
+ goto end;
/* stop hw first */
if (ctx->hw_mgr_intf->hw_stop) {
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
index a90b3d9..4168ce6 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -123,10 +123,12 @@
* struct cam_hw_stop_args - Payload for stop command
*
* @ctxt_to_hw_map: HW context from the acquire
+ * @args: Arguments to pass for stop
*
*/
struct cam_hw_stop_args {
void *ctxt_to_hw_map;
+ void *args;
};
/**
@@ -170,6 +172,7 @@
* @out_map_entries: Out map info
* @num_out_map_entries: Number of out map entries
* @priv: Private pointer
+ * @request_id: Request ID
*
*/
struct cam_hw_config_args {
@@ -179,6 +182,7 @@
struct cam_hw_fence_map_entry *out_map_entries;
uint32_t num_out_map_entries;
void *priv;
+ uint64_t 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 4e9034e..a943680 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_node.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c
@@ -381,7 +381,6 @@
for (i = 0; i < node->ctx_size; i++) {
if (node->ctx_list[i].dev_hdl >= 0) {
cam_context_shutdown(&(node->ctx_list[i]));
- cam_destroy_device_hdl(node->ctx_list[i].dev_hdl);
cam_context_putref(&(node->ctx_list[i]));
}
}
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
index b04bc23..e7de207 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
@@ -543,10 +543,71 @@
return rc;
}
-static int cam_cpas_util_apply_client_axi_vote(
- struct cam_cpas *cpas_core, struct cam_cpas_private_soc *soc_private,
- struct cam_cpas_client *cpas_client, struct cam_axi_vote *axi_vote)
+static int cam_cpas_util_set_camnoc_axi_clk_rate(
+ struct cam_hw_info *cpas_hw)
{
+ struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
+ struct cam_cpas_private_soc *soc_private =
+ (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
+ int rc = 0;
+
+ CAM_DBG(CAM_CPAS, "control_camnoc_axi_clk=%d",
+ soc_private->control_camnoc_axi_clk);
+
+ if (soc_private->control_camnoc_axi_clk) {
+ struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
+ struct cam_cpas_axi_port *curr_axi_port = NULL;
+ struct cam_cpas_axi_port *temp_axi_port = NULL;
+ uint64_t required_camnoc_bw = 0;
+ int32_t clk_rate = 0;
+
+ list_for_each_entry_safe(curr_axi_port, temp_axi_port,
+ &cpas_core->axi_ports_list_head, sibling_port) {
+
+ if (curr_axi_port->consolidated_axi_vote.uncompressed_bw
+ > required_camnoc_bw)
+ required_camnoc_bw = curr_axi_port->
+ consolidated_axi_vote.uncompressed_bw;
+
+ CAM_DBG(CAM_CPAS, "[%s] : curr=%llu, overal=%llu",
+ curr_axi_port->axi_port_name,
+ curr_axi_port->consolidated_axi_vote.
+ uncompressed_bw,
+ required_camnoc_bw);
+ }
+
+ required_camnoc_bw += (required_camnoc_bw *
+ soc_private->camnoc_axi_clk_bw_margin) / 100;
+
+ if ((required_camnoc_bw > 0) &&
+ (required_camnoc_bw < CAM_CPAS_AXI_MIN_CAMNOC_IB_BW))
+ required_camnoc_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW;
+
+ clk_rate = required_camnoc_bw / soc_private->camnoc_bus_width;
+
+ CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d",
+ required_camnoc_bw, clk_rate);
+
+ rc = cam_soc_util_set_clk_rate(
+ soc_info->clk[soc_info->src_clk_idx],
+ soc_info->clk_name[soc_info->src_clk_idx],
+ clk_rate);
+ if (!rc)
+ CAM_ERR(CAM_CPAS,
+ "Failed in setting camnoc axi clk %llu %d %d",
+ required_camnoc_bw, clk_rate, rc);
+ }
+
+ return rc;
+}
+
+static int cam_cpas_util_apply_client_axi_vote(
+ struct cam_hw_info *cpas_hw,
+ struct cam_cpas_client *cpas_client,
+ struct cam_axi_vote *axi_vote)
+{
+ struct cam_cpas_private_soc *soc_private =
+ (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
struct cam_cpas_client *curr_client;
struct cam_cpas_client *temp_client;
struct cam_axi_vote req_axi_vote = *axi_vote;
@@ -587,6 +648,9 @@
if ((!soc_private->axi_camnoc_based) && (mnoc_bw < camnoc_bw))
mnoc_bw = camnoc_bw;
+ axi_port->consolidated_axi_vote.compressed_bw = mnoc_bw;
+ axi_port->consolidated_axi_vote.uncompressed_bw = camnoc_bw;
+
CAM_DBG(CAM_CPAS,
"axi[(%d, %d),(%d, %d)] : camnoc_bw[%llu], mnoc_bw[%llu]",
axi_port->mnoc_bus.src, axi_port->mnoc_bus.dst,
@@ -613,6 +677,14 @@
}
}
+ mutex_unlock(&axi_port->lock);
+
+ rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw);
+ if (rc)
+ CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc);
+
+ return rc;
+
unlock_axi_port:
mutex_unlock(&axi_port->lock);
return rc;
@@ -645,6 +717,7 @@
if (!CAM_CPAS_CLIENT_VALID(client_indx))
return -EINVAL;
+ mutex_lock(&cpas_hw->hw_mutex);
mutex_lock(&cpas_core->client_mutex[client_indx]);
if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) {
@@ -658,12 +731,12 @@
client_indx, axi_vote.compressed_bw,
axi_vote.uncompressed_bw);
- rc = cam_cpas_util_apply_client_axi_vote(cpas_core,
- cpas_hw->soc_info.soc_private,
+ rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
cpas_core->cpas_client[client_indx], &axi_vote);
unlock_client:
mutex_unlock(&cpas_core->client_mutex[client_indx]);
+ mutex_unlock(&cpas_hw->hw_mutex);
return rc;
}
@@ -897,8 +970,8 @@
"AXI client[%d] compressed_bw[%llu], uncompressed_bw[%llu]",
client_indx, axi_vote->compressed_bw,
axi_vote->uncompressed_bw);
- rc = cam_cpas_util_apply_client_axi_vote(cpas_core,
- cpas_hw->soc_info.soc_private, cpas_client, axi_vote);
+ rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
+ cpas_client, axi_vote);
if (rc)
goto done;
@@ -1040,8 +1113,8 @@
axi_vote.uncompressed_bw = 0;
axi_vote.compressed_bw = 0;
- rc = cam_cpas_util_apply_client_axi_vote(cpas_core,
- cpas_hw->soc_info.soc_private, cpas_client, &axi_vote);
+ rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
+ cpas_client, &axi_vote);
done:
mutex_unlock(&cpas_core->client_mutex[client_indx]);
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
index 05840bb..2e660b1 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
@@ -145,6 +145,7 @@
* @axi_port_node: Node representing this AXI Port
* @axi_port_mnoc_node: Node representing mnoc in this AXI Port
* @axi_port_camnoc_node: Node representing camnoc in this AXI Port
+ * @consolidated_axi_vote: Consolidated axi bw values for this AXI port
*
*/
struct cam_cpas_axi_port {
@@ -157,6 +158,7 @@
struct device_node *axi_port_node;
struct device_node *axi_port_mnoc_node;
struct device_node *axi_port_camnoc_node;
+ struct cam_axi_vote consolidated_axi_vote;
};
/**
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c
index b18af0a..8f9ec14 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c
@@ -44,6 +44,18 @@
return rc;
}
+
+ soc_private->hw_version = 0;
+ rc = of_property_read_u32(of_node,
+ "qcom,cpas-hw-ver", &soc_private->hw_version);
+ if (rc) {
+ CAM_ERR(CAM_CPAS, "device %s failed to read cpas-hw-ver",
+ pdev->name);
+ return rc;
+ }
+
+ CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_private->hw_version);
+
soc_private->client_id_based = of_property_read_bool(of_node,
"client-id-based");
@@ -93,6 +105,35 @@
soc_private->axi_camnoc_based = of_property_read_bool(of_node,
"client-bus-camnoc-based");
+ soc_private->control_camnoc_axi_clk = of_property_read_bool(of_node,
+ "control-camnoc-axi-clk");
+
+ if (soc_private->control_camnoc_axi_clk == true) {
+ rc = of_property_read_u32(of_node, "camnoc-bus-width",
+ &soc_private->camnoc_bus_width);
+ if (rc || (soc_private->camnoc_bus_width == 0)) {
+ CAM_ERR(CAM_CPAS, "Bus width not found rc=%d, %d",
+ rc, soc_private->camnoc_bus_width);
+ return rc;
+ }
+
+ rc = of_property_read_u32(of_node,
+ "camnoc-axi-clk-bw-margin-perc",
+ &soc_private->camnoc_axi_clk_bw_margin);
+
+ if (rc) {
+ /* this is not fatal, overwrite rc */
+ rc = 0;
+ soc_private->camnoc_axi_clk_bw_margin = 0;
+ }
+ }
+
+ CAM_DBG(CAM_CPAS,
+ "control_camnoc_axi_clk=%d, width=%d, margin=%d",
+ soc_private->control_camnoc_axi_clk,
+ soc_private->camnoc_bus_width,
+ soc_private->camnoc_axi_clk_bw_margin);
+
count = of_property_count_u32_elems(of_node, "vdd-corners");
if ((count > 0) && (count <= CAM_REGULATOR_LEVEL_MAX) &&
(of_property_count_strings(of_node, "vdd-corner-ahb-mapping") ==
@@ -140,6 +181,7 @@
irq_handler_t irq_handler, void *irq_data)
{
int rc = 0;
+ struct cam_cpas_private_soc *soc_private;
rc = cam_soc_util_get_dt_properties(soc_info);
if (rc) {
@@ -173,6 +215,12 @@
goto free_soc_private;
}
+ soc_private = soc_info->soc_private;
+ soc_private->soc_id = cam_soc_util_get_soc_id();
+ soc_private->hw_rev = cam_soc_util_get_hw_revision_node(soc_info);
+ CAM_DBG(CAM_CPAS, "soc id %d hw_rev %d",
+ soc_private->soc_id, soc_private->hw_rev);
+
return rc;
free_soc_private:
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h
index fe0187e..91e8d0c0 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h
@@ -17,7 +17,6 @@
#include "cam_cpas_hw.h"
#define CAM_REGULATOR_LEVEL_MAX 16
-
/**
* struct cam_cpas_vdd_ahb_mapping : Voltage to ahb level mapping
*
@@ -34,6 +33,7 @@
* struct cam_cpas_private_soc : CPAS private DT info
*
* @arch_compat: ARCH compatible string
+ * @hw_version: Camera HW version
* @client_id_based: Whether clients are id based
* @num_clients: Number of clients supported
* @client_name: Client names
@@ -42,10 +42,17 @@
* @axi_port_list_node : Node representing AXI Ports list
* @num_vdd_ahb_mapping : Number of vdd to ahb level mapping supported
* @vdd_ahb : AHB level mapping info for the supported vdd levels
+ * @soc_id : SOC id
+ * @hw_rev : Camera hw revision
+ * @control_camnoc_axi_clk : Whether CPAS driver need to set camnoc axi clk freq
+ * @camnoc_bus_width : CAMNOC Bus width
+ * @camnoc_axi_clk_bw_margin : BW Margin in percentage to add while calculating
+ * camnoc axi clock
*
*/
struct cam_cpas_private_soc {
const char *arch_compat;
+ uint32_t hw_version;
bool client_id_based;
uint32_t num_clients;
const char *client_name[CAM_CPAS_MAX_CLIENTS];
@@ -54,6 +61,11 @@
struct device_node *axi_port_list_node;
uint32_t num_vdd_ahb_mapping;
struct cam_cpas_vdd_ahb_mapping vdd_ahb[CAM_REGULATOR_LEVEL_MAX];
+ uint32_t soc_id;
+ uint32_t hw_rev;
+ bool control_camnoc_axi_clk;
+ uint32_t camnoc_bus_width;
+ uint32_t camnoc_axi_clk_bw_margin;
};
int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info,
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
index 0533ed8..9b703c0 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
@@ -21,6 +21,8 @@
#include "cam_cpas_soc.h"
#include "cpastop100.h"
#include "cpastop_v170_110.h"
+#include "cpastop_v175_100.h"
+#include "cpastop_v175_101.h"
struct cam_camnoc_info *camnoc_info;
@@ -114,6 +116,15 @@
return -EINVAL;
}
+ rc = cam_common_util_get_string_index(soc_info->mem_block_name,
+ soc_info->num_mem_block, "core_top_csr_tcsr", &index);
+ if ((rc == 0) && (index < num_reg_map)) {
+ regbase_index[CAM_CPAS_REG_CSR_TCSR] = index;
+ } else {
+ CAM_DBG(CAM_CPAS, "regbase not found for CAMNOC, rc=%d, %d %d",
+ rc, index, num_reg_map);
+ }
+
return 0;
}
@@ -456,6 +467,9 @@
static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw)
{
int i;
+ struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
+ struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
+ struct cam_cpas_private_soc *soc_private = soc_info->soc_private;
cam_cpastop_reset_irq(cpas_hw);
@@ -478,6 +492,29 @@
}
}
+ if ((soc_private && soc_private->soc_id == SDM670_SOC_ID) &&
+ (soc_private->hw_rev == SDM670_V1_1)) {
+
+ struct cam_cpas_reg *reg_info;
+ int tcsr_index;
+ void __iomem *mem_base;
+
+ reg_info = &camnoc_info->errata_wa_list->tcsr_reg.
+ tcsr_conn_box_spare_0;
+ tcsr_index = cpas_core->regbase_index[CAM_CPAS_REG_CSR_TCSR];
+ if (tcsr_index == -1) {
+ CAM_DBG(CAM_CPAS, "index in not initialized");
+ return 0;
+ }
+ mem_base = soc_info->reg_map[tcsr_index].mem_base;
+
+ reg_info->value = TCSR_CONN_SET;
+ cam_io_w_mb(reg_info->value, mem_base + reg_info->offset);
+ CAM_DBG(CAM_CPAS, "tcsr(0x%lx) value %d",
+ (unsigned long int)mem_base + reg_info->offset,
+ cam_io_r_mb(mem_base + reg_info->offset));
+ }
+
return 0;
}
@@ -489,6 +526,8 @@
int rc = 0;
struct cam_cpas_hw_errata_wa_list *errata_wa_list =
camnoc_info->errata_wa_list;
+ struct cam_cpas_private_soc *soc_private =
+ cpas_hw->soc_info.soc_private;
if (!errata_wa_list)
return 0;
@@ -512,36 +551,68 @@
}
}
+ if ((soc_private && soc_private->soc_id == SDM670_SOC_ID) &&
+ (soc_private->hw_rev == SDM670_V1_1)) {
+
+ struct cam_cpas_reg *reg_info;
+ int tcsr_index;
+ void __iomem *mem_base;
+
+ reg_info = &camnoc_info->errata_wa_list->tcsr_reg.
+ tcsr_conn_box_spare_0;
+ reg_info->value = TCSR_CONN_RESET;
+ tcsr_index = cpas_core->regbase_index[CAM_CPAS_REG_CSR_TCSR];
+ if (tcsr_index == -1) {
+ CAM_DBG(CAM_CPAS, "index in not initialized");
+ return 0;
+ }
+ mem_base = soc_info->reg_map[tcsr_index].mem_base;
+ cam_io_w_mb(reg_info->value, mem_base + reg_info->offset);
+ CAM_DBG(CAM_CPAS, "tcsr(0x%lx) value %d",
+ (unsigned long int)mem_base + reg_info->offset,
+ cam_io_r_mb(mem_base + reg_info->offset));
+ }
+
return rc;
}
static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw,
struct cam_cpas_hw_caps *hw_caps)
{
- if ((hw_caps->camera_version.major == 1) &&
- (hw_caps->camera_version.minor == 7) &&
- (hw_caps->camera_version.incr == 0)) {
- if ((hw_caps->cpas_version.major == 1) &&
- (hw_caps->cpas_version.minor == 0) &&
- (hw_caps->cpas_version.incr == 0)) {
- camnoc_info = &cam170_cpas100_camnoc_info;
- } else if ((hw_caps->cpas_version.major == 1) &&
- (hw_caps->cpas_version.minor == 1) &&
- (hw_caps->cpas_version.incr == 0)) {
- camnoc_info = &cam170_cpas110_camnoc_info;
- } else {
- CAM_ERR(CAM_CPAS, "CPAS Version not supported %d.%d.%d",
- hw_caps->cpas_version.major,
- hw_caps->cpas_version.minor,
- hw_caps->cpas_version.incr);
- return -EINVAL;
- }
- } else {
+ int rc = 0;
+ struct cam_cpas_private_soc *soc_private =
+ (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
+
+ CAM_DBG(CAM_CPAS,
+ "hw_version=0x%x Camera Version %d.%d.%d, cpas version %d.%d.%d",
+ soc_private->hw_version,
+ hw_caps->camera_version.major,
+ hw_caps->camera_version.minor,
+ hw_caps->camera_version.incr,
+ hw_caps->cpas_version.major,
+ hw_caps->cpas_version.minor,
+ hw_caps->cpas_version.incr);
+
+ switch (soc_private->hw_version) {
+ case CAM_CPAS_TITAN_170_V100:
+ camnoc_info = &cam170_cpas100_camnoc_info;
+ break;
+ case CAM_CPAS_TITAN_170_V110:
+ camnoc_info = &cam170_cpas110_camnoc_info;
+ break;
+ case CAM_CPAS_TITAN_175_V100:
+ camnoc_info = &cam175_cpas100_camnoc_info;
+ break;
+ case CAM_CPAS_TITAN_175_V101:
+ camnoc_info = &cam175_cpas101_camnoc_info;
+ break;
+ default:
CAM_ERR(CAM_CPAS, "Camera Version not supported %d.%d.%d",
hw_caps->camera_version.major,
hw_caps->camera_version.minor,
hw_caps->camera_version.incr);
- return -EINVAL;
+ rc = -EINVAL;
+ break;
}
return 0;
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
index 73f7e9b..080f6e6 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -162,14 +162,27 @@
};
/**
+ * struct cam_camnoc_tcsr_regs : Top control Status register
+ *
+ * @tcsr_conn_box_spare_0: spare register to select PriorityLvl
+ * for IFE0 and IFE1 (HW workaround for SDM670 1.1)
+ *
+ */
+struct cam_camnoc_tcsr_regs {
+ struct cam_cpas_reg tcsr_conn_box_spare_0;
+};
+
+/**
* struct cam_cpas_hw_errata_wa_list : List of HW Errata workaround info
*
* @camnoc_flush_slave_pending_trans: Errata workaround info for flushing
* camnoc slave pending transactions before turning off CPAS_TOP gdsc
+ * @tcsr_reg: HW workaround to select PriorityLvl for IFE0 and IFE(SDM670_1.1)
*
*/
struct cam_cpas_hw_errata_wa_list {
struct cam_cpas_hw_errata_wa camnoc_flush_slave_pending_trans;
+ struct cam_camnoc_tcsr_regs tcsr_reg;
};
/**
@@ -200,6 +213,7 @@
uint32_t errlog3_high;
};
+
/**
* struct cam_camnoc_info : Overall CAMNOC settings info
*
@@ -210,7 +224,6 @@
* @irq_err_size: Array size of IRQ Error settings
* @err_logger: Pointer to CAMNOC IRQ Error logger read registers
* @errata_wa_list: HW Errata workaround info
- *
*/
struct cam_camnoc_info {
struct cam_camnoc_specific *specific;
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
index 3c572f0..0c7c799 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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,8 @@
#define _CPASTOP_V170_110_H_
#define TEST_IRQ_ENABLE 0
+#define TCSR_CONN_RESET 0x0
+#define TCSR_CONN_SET 0x3
static struct cam_camnoc_irq_sbm cam_cpas110_irq_sbm = {
.sbm_enable = {
@@ -265,7 +267,7 @@
.access_type = CAM_REG_TYPE_READ_WRITE,
.masked_value = 0,
.offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */
- .value = 0x66665555,
+ .value = 0x66666666,
},
.urgency = {
.enable = true,
@@ -313,7 +315,7 @@
.access_type = CAM_REG_TYPE_READ_WRITE,
.masked_value = 0,
.offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */
- .value = 0x66665555,
+ .value = 0x66666666,
},
.urgency = {
.enable = true,
@@ -528,6 +530,14 @@
.value = 0, /* expected to be 0 */
},
},
+ .tcsr_reg = {
+ .tcsr_conn_box_spare_0 = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0xB3E4,
+ },
+ },
};
static struct cam_camnoc_info cam170_cpas110_camnoc_info = {
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v175_100.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v175_100.h
new file mode 100644
index 0000000..e2aad09
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v175_100.h
@@ -0,0 +1,545 @@
+/* Copyright (c) 2018, 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 _CPASTOP_V175_100_H_
+#define _CPASTOP_V175_100_H_
+
+#define TEST_IRQ_ENABLE 0
+
+static struct cam_camnoc_irq_sbm cam_cpas_v175_100_irq_sbm = {
+ .sbm_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x2040, /* SBM_FAULTINEN0_LOW */
+ .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/
+ 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */
+ 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */
+ 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */
+ 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */
+ 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */
+ (TEST_IRQ_ENABLE ?
+ 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */
+ 0x0),
+ },
+ .sbm_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */
+ },
+ .sbm_clear = {
+ .access_type = CAM_REG_TYPE_WRITE,
+ .enable = true,
+ .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */
+ .value = TEST_IRQ_ENABLE ? 0x6 : 0x2,
+ }
+};
+
+static struct cam_camnoc_irq_err
+ cam_cpas_v175_100_irq_err[] = {
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR,
+ .enable = true,
+ .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */
+ .value = 1,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */
+ },
+ .err_clear = {
+ .access_type = CAM_REG_TYPE_WRITE,
+ .enable = true,
+ .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR,
+ .enable = true,
+ .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */
+ .value = 1,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */
+ },
+ .err_clear = {
+ .access_type = CAM_REG_TYPE_WRITE,
+ .enable = true,
+ .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR,
+ .enable = true,
+ .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */
+ .value = 1,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */
+ },
+ .err_clear = {
+ .access_type = CAM_REG_TYPE_WRITE,
+ .enable = true,
+ .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR,
+ .enable = true,
+ .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */
+ .value = 1,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */
+ },
+ .err_clear = {
+ .access_type = CAM_REG_TYPE_WRITE,
+ .enable = true,
+ .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR,
+ .enable = true,
+ .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */
+ .value = 1,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x1190,
+ /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */
+ },
+ .err_clear = {
+ .access_type = CAM_REG_TYPE_WRITE,
+ .enable = true,
+ .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT,
+ .enable = true,
+ .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */
+ .value = 0x1,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */
+ },
+ .err_clear = {
+ .enable = false,
+ },
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1,
+ .enable = false,
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2,
+ .enable = false,
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST,
+ .enable = TEST_IRQ_ENABLE ? true : false,
+ .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */
+ .value = 0x5,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */
+ },
+ .err_clear = {
+ .enable = false,
+ },
+ },
+};
+
+static struct cam_camnoc_specific
+ cam_cpas_v175_100_camnoc_specific[] = {
+ {
+ .port_type = CAM_CAMNOC_CDM,
+ .enable = true,
+ .priority_lut_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */
+ .value = 0x22222222,
+ },
+ .priority_lut_high = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */
+ .value = 0x22222222,
+ },
+ .urgency = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 1,
+ .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */
+ .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */
+ .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */
+ .value = 0x2,
+ },
+ .danger_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */
+ .value = 0x0,
+ },
+ .safe_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */
+ .value = 0x0,
+ },
+ .ubwc_ctl = {
+ .enable = false,
+ },
+ },
+ {
+ .port_type = CAM_CAMNOC_IFE02,
+ .enable = true,
+ .priority_lut_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */
+ .value = 0x66666543,
+ },
+ .priority_lut_high = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */
+ .value = 0x66666666,
+ },
+ .urgency = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 1,
+ .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */
+ /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */
+ .mask = 0x70,
+ /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */
+ .shift = 0x4,
+ .value = 3,
+ },
+ .danger_lut = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */
+ .value = 0xFFFFFF00,
+ },
+ .safe_lut = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */
+ .value = 0x1,
+ },
+ .ubwc_ctl = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .port_type = CAM_CAMNOC_IFE13,
+ .enable = true,
+ .priority_lut_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */
+ .value = 0x66666543,
+ },
+ .priority_lut_high = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */
+ .value = 0x66666666,
+ },
+ .urgency = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 1,
+ .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */
+ /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */
+ .mask = 0x70,
+ /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */
+ .shift = 0x4,
+ .value = 3,
+ },
+ .danger_lut = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */
+ .value = 0xFFFFFF00,
+ },
+ .safe_lut = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */
+ .value = 0x1,
+ },
+ .ubwc_ctl = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ,
+ .enable = true,
+ .priority_lut_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */
+ .value = 0x33333333,
+ },
+ .priority_lut_high = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */
+ .value = 0x33333333,
+ },
+ .urgency = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 1,
+ .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */
+ /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */
+ .mask = 0x7,
+ /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */
+ .shift = 0x0,
+ .value = 3,
+ },
+ .danger_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */
+ .value = 0x0,
+ },
+ .safe_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */
+ .value = 0x0,
+ },
+ .ubwc_ctl = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE,
+ .enable = true,
+ .priority_lut_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */
+ .value = 0x33333333,
+ },
+ .priority_lut_high = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */
+ .value = 0x33333333,
+ },
+ .urgency = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 1,
+ .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */
+ /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */
+ .mask = 0x70,
+ /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */
+ .shift = 0x4,
+ .value = 3,
+ },
+ .danger_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */
+ .value = 0x0,
+ },
+ .safe_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */
+ .value = 0x0,
+ },
+ .ubwc_ctl = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .port_type = CAM_CAMNOC_JPEG,
+ .enable = true,
+ .priority_lut_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */
+ .value = 0x22222222,
+ },
+ .priority_lut_high = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */
+ .value = 0x22222222,
+ },
+ .urgency = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */
+ .value = 0x22,
+ },
+ .danger_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */
+ .value = 0x0,
+ },
+ .safe_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */
+ .value = 0x0,
+ },
+ .ubwc_ctl = {
+ .enable = false,
+ },
+ },
+ {
+ .port_type = CAM_CAMNOC_FD,
+ .enable = false,
+ },
+ {
+ .port_type = CAM_CAMNOC_ICP,
+ .enable = true,
+ .flag_out_set0_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_WRITE,
+ .masked_value = 0,
+ .offset = 0x2088,
+ .value = 0x100000,
+ },
+ },
+};
+
+static struct cam_camnoc_err_logger_info cam175_cpas100_err_logger_offsets = {
+ .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */
+ .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */
+ .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */
+ .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */
+ .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */
+ .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */
+ .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */
+ .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */
+ .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */
+ .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */
+};
+
+static struct cam_cpas_hw_errata_wa_list cam175_cpas100_errata_wa_list = {
+ .camnoc_flush_slave_pending_trans = {
+ .enable = false,
+ .data.reg_info = {
+ .access_type = CAM_REG_TYPE_READ,
+ .offset = 0x2100, /* SidebandManager_SenseIn0_Low */
+ .mask = 0xE0000, /* Bits 17, 18, 19 */
+ .value = 0, /* expected to be 0 */
+ },
+ },
+};
+
+static struct cam_camnoc_info cam175_cpas100_camnoc_info = {
+ .specific = &cam_cpas_v175_100_camnoc_specific[0],
+ .specific_size = sizeof(cam_cpas_v175_100_camnoc_specific) /
+ sizeof(cam_cpas_v175_100_camnoc_specific[0]),
+ .irq_sbm = &cam_cpas_v175_100_irq_sbm,
+ .irq_err = &cam_cpas_v175_100_irq_err[0],
+ .irq_err_size = sizeof(cam_cpas_v175_100_irq_err) /
+ sizeof(cam_cpas_v175_100_irq_err[0]),
+ .err_logger = &cam175_cpas100_err_logger_offsets,
+ .errata_wa_list = &cam175_cpas100_errata_wa_list,
+};
+
+#endif /* _CPASTOP_V175_100_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v175_101.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v175_101.h
new file mode 100644
index 0000000..e5e9673
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v175_101.h
@@ -0,0 +1,545 @@
+/* Copyright (c) 2018, 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 _CPASTOP_V175_101_H_
+#define _CPASTOP_V175_101_H_
+
+#define TEST_IRQ_ENABLE 0
+
+static struct cam_camnoc_irq_sbm cam_cpas_v175_101_irq_sbm = {
+ .sbm_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x2040, /* SBM_FAULTINEN0_LOW */
+ .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/
+ 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */
+ 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */
+ 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */
+ 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */
+ 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */
+ (TEST_IRQ_ENABLE ?
+ 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */
+ 0x0),
+ },
+ .sbm_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */
+ },
+ .sbm_clear = {
+ .access_type = CAM_REG_TYPE_WRITE,
+ .enable = true,
+ .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */
+ .value = TEST_IRQ_ENABLE ? 0x6 : 0x2,
+ }
+};
+
+static struct cam_camnoc_irq_err
+ cam_cpas_v175_101_irq_err[] = {
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR,
+ .enable = true,
+ .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */
+ .value = 1,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */
+ },
+ .err_clear = {
+ .access_type = CAM_REG_TYPE_WRITE,
+ .enable = true,
+ .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR,
+ .enable = true,
+ .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */
+ .value = 1,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */
+ },
+ .err_clear = {
+ .access_type = CAM_REG_TYPE_WRITE,
+ .enable = true,
+ .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR,
+ .enable = true,
+ .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */
+ .value = 1,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */
+ },
+ .err_clear = {
+ .access_type = CAM_REG_TYPE_WRITE,
+ .enable = true,
+ .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR,
+ .enable = true,
+ .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */
+ .value = 1,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */
+ },
+ .err_clear = {
+ .access_type = CAM_REG_TYPE_WRITE,
+ .enable = true,
+ .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR,
+ .enable = true,
+ .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */
+ .value = 1,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x1190,
+ /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */
+ },
+ .err_clear = {
+ .access_type = CAM_REG_TYPE_WRITE,
+ .enable = true,
+ .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT,
+ .enable = true,
+ .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */
+ .value = 0x1,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */
+ },
+ .err_clear = {
+ .enable = false,
+ },
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1,
+ .enable = false,
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2,
+ .enable = false,
+ },
+ {
+ .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST,
+ .enable = TEST_IRQ_ENABLE ? true : false,
+ .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */
+ .err_enable = {
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .enable = true,
+ .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */
+ .value = 0x5,
+ },
+ .err_status = {
+ .access_type = CAM_REG_TYPE_READ,
+ .enable = true,
+ .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */
+ },
+ .err_clear = {
+ .enable = false,
+ },
+ },
+};
+
+static struct cam_camnoc_specific
+ cam_cpas_v175_101_camnoc_specific[] = {
+ {
+ .port_type = CAM_CAMNOC_CDM,
+ .enable = true,
+ .priority_lut_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */
+ .value = 0x22222222,
+ },
+ .priority_lut_high = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */
+ .value = 0x22222222,
+ },
+ .urgency = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 1,
+ .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */
+ .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */
+ .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */
+ .value = 0x2,
+ },
+ .danger_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */
+ .value = 0x0,
+ },
+ .safe_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */
+ .value = 0x0,
+ },
+ .ubwc_ctl = {
+ .enable = false,
+ },
+ },
+ {
+ .port_type = CAM_CAMNOC_IFE02,
+ .enable = true,
+ .priority_lut_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */
+ .value = 0x66666543,
+ },
+ .priority_lut_high = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */
+ .value = 0x66666666,
+ },
+ .urgency = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 1,
+ .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */
+ /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */
+ .mask = 0x70,
+ /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */
+ .shift = 0x4,
+ .value = 3,
+ },
+ .danger_lut = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */
+ .value = 0xFFFFFF00,
+ },
+ .safe_lut = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */
+ .value = 0x1,
+ },
+ .ubwc_ctl = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .port_type = CAM_CAMNOC_IFE13,
+ .enable = true,
+ .priority_lut_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */
+ .value = 0x66666543,
+ },
+ .priority_lut_high = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */
+ .value = 0x66666666,
+ },
+ .urgency = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 1,
+ .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */
+ /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */
+ .mask = 0x70,
+ /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */
+ .shift = 0x4,
+ .value = 3,
+ },
+ .danger_lut = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */
+ .value = 0xFFFFFF00,
+ },
+ .safe_lut = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */
+ .value = 0x1,
+ },
+ .ubwc_ctl = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ,
+ .enable = true,
+ .priority_lut_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */
+ .value = 0x33333333,
+ },
+ .priority_lut_high = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */
+ .value = 0x33333333,
+ },
+ .urgency = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 1,
+ .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */
+ /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */
+ .mask = 0x7,
+ /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */
+ .shift = 0x0,
+ .value = 3,
+ },
+ .danger_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */
+ .value = 0x0,
+ },
+ .safe_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */
+ .value = 0x0,
+ },
+ .ubwc_ctl = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE,
+ .enable = true,
+ .priority_lut_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */
+ .value = 0x33333333,
+ },
+ .priority_lut_high = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */
+ .value = 0x33333333,
+ },
+ .urgency = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 1,
+ .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */
+ /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */
+ .mask = 0x70,
+ /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */
+ .shift = 0x4,
+ .value = 3,
+ },
+ .danger_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */
+ .value = 0x0,
+ },
+ .safe_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */
+ .value = 0x0,
+ },
+ .ubwc_ctl = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */
+ .value = 1,
+ },
+ },
+ {
+ .port_type = CAM_CAMNOC_JPEG,
+ .enable = true,
+ .priority_lut_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */
+ .value = 0x22222222,
+ },
+ .priority_lut_high = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */
+ .value = 0x22222222,
+ },
+ .urgency = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */
+ .value = 0x22,
+ },
+ .danger_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */
+ .value = 0x0,
+ },
+ .safe_lut = {
+ .enable = false,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */
+ .value = 0x0,
+ },
+ .ubwc_ctl = {
+ .enable = false,
+ },
+ },
+ {
+ .port_type = CAM_CAMNOC_FD,
+ .enable = false,
+ },
+ {
+ .port_type = CAM_CAMNOC_ICP,
+ .enable = true,
+ .flag_out_set0_low = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_WRITE,
+ .masked_value = 0,
+ .offset = 0x2088,
+ .value = 0x100000,
+ },
+ },
+};
+
+static struct cam_camnoc_err_logger_info cam175_cpas101_err_logger_offsets = {
+ .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */
+ .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */
+ .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */
+ .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */
+ .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */
+ .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */
+ .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */
+ .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */
+ .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */
+ .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */
+};
+
+static struct cam_cpas_hw_errata_wa_list cam175_cpas101_errata_wa_list = {
+ .camnoc_flush_slave_pending_trans = {
+ .enable = false,
+ .data.reg_info = {
+ .access_type = CAM_REG_TYPE_READ,
+ .offset = 0x2100, /* SidebandManager_SenseIn0_Low */
+ .mask = 0xE0000, /* Bits 17, 18, 19 */
+ .value = 0, /* expected to be 0 */
+ },
+ },
+};
+
+static struct cam_camnoc_info cam175_cpas101_camnoc_info = {
+ .specific = &cam_cpas_v175_101_camnoc_specific[0],
+ .specific_size = sizeof(cam_cpas_v175_101_camnoc_specific) /
+ sizeof(cam_cpas_v175_101_camnoc_specific[0]),
+ .irq_sbm = &cam_cpas_v175_101_irq_sbm,
+ .irq_err = &cam_cpas_v175_101_irq_err[0],
+ .irq_err_size = sizeof(cam_cpas_v175_101_irq_err) /
+ sizeof(cam_cpas_v175_101_irq_err[0]),
+ .err_logger = &cam175_cpas101_err_logger_offsets,
+ .errata_wa_list = &cam175_cpas101_errata_wa_list,
+};
+
+#endif /* _CPASTOP_V175_101_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
index c844ef7..d1492fe 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -32,6 +32,7 @@
enum cam_cpas_reg_base {
CAM_CPAS_REG_CPASTOP,
CAM_CPAS_REG_CAMNOC,
+ CAM_CPAS_REG_CSR_TCSR,
CAM_CPAS_REG_CAMSS,
CAM_CPAS_REG_MAX
};
diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c
index 04d65dd..99c509c 100644
--- a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c
+++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -211,7 +211,8 @@
int cam_fd_context_init(struct cam_fd_context *fd_ctx,
- struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf)
+ struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf,
+ uint32_t ctx_id)
{
int rc;
@@ -222,8 +223,8 @@
memset(fd_ctx, 0, sizeof(*fd_ctx));
- rc = cam_context_init(base_ctx, fd_dev_name, NULL, hw_intf,
- fd_ctx->req_base, CAM_CTX_REQ_MAX);
+ rc = cam_context_init(base_ctx, fd_dev_name, CAM_FD, ctx_id,
+ NULL, hw_intf, fd_ctx->req_base, CAM_CTX_REQ_MAX);
if (rc) {
CAM_ERR(CAM_FD, "Camera Context Base init failed, rc=%d", rc);
return rc;
diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.h b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.h
index 6aa5edb..a8b5d15 100644
--- a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.h
+++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -30,7 +30,8 @@
};
int cam_fd_context_init(struct cam_fd_context *fd_ctx,
- struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf);
+ struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf,
+ uint32_t ctx_id);
int cam_fd_context_deinit(struct cam_fd_context *ctx);
#endif /* _CAM_FD_CONTEXT_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c b/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c
index 260dcd8..3f01244 100644
--- a/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c
+++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -121,7 +121,7 @@
for (i = 0; i < CAM_CTX_MAX; i++) {
rc = cam_fd_context_init(&g_fd_dev.fd_ctx[i],
- &g_fd_dev.base_ctx[i], &node->hw_mgr_intf);
+ &g_fd_dev.base_ctx[i], &node->hw_mgr_intf, i);
if (rc) {
CAM_ERR(CAM_FD, "FD context init failed i=%d, rc=%d",
i, rc);
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
index 640c6f6..a18afc6 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -29,10 +29,10 @@
}
static void cam_fd_hw_util_cdm_callback(uint32_t handle, void *userdata,
- enum cam_cdm_cb_status status, uint32_t cookie)
+ enum cam_cdm_cb_status status, uint64_t cookie)
{
trace_cam_cdm_cb("FD", status);
- CAM_DBG(CAM_FD, "CDM hdl=%x, udata=%pK, status=%d, cookie=%d",
+ CAM_DBG(CAM_FD, "CDM hdl=%x, udata=%pK, status=%d, cookie=%llu",
handle, userdata, status, cookie);
}
@@ -1092,6 +1092,7 @@
CAM_ERR(CAM_FD, "Release cdm handle failed, handle=0x%x, rc=%d",
ctx_hw_private->cdm_handle, rc);
+ kfree(ctx_hw_private->cdm_cmd);
kfree(ctx_hw_private);
release_args->ctx_hw_private = NULL;
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c
index 803da76..6d9d330 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -22,6 +22,7 @@
#include "cam_fd_hw_core.h"
#include "cam_fd_hw_soc.h"
#include "cam_fd_hw_v41.h"
+#include "cam_fd_hw_v501.h"
static int cam_fd_hw_dev_probe(struct platform_device *pdev)
{
@@ -193,6 +194,10 @@
.compatible = "qcom,fd41",
.data = &cam_fd_wrapper120_core410_info,
},
+ {
+ .compatible = "qcom,fd501",
+ .data = &cam_fd_wrapper200_core501_info,
+ },
{}
};
MODULE_DEVICE_TABLE(of, cam_fd_hw_dt_match);
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h
index 70448bb..78257a5 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -63,7 +63,7 @@
CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE),
.qos_priority = 4,
.qos_priority_level = 4,
- .supported_modes = CAM_FD_MODE_FACEDETECTION | CAM_FD_MODE_PYRAMID,
+ .supported_modes = CAM_FD_MODE_FACEDETECTION,
.ro_mode_supported = true,
};
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h
new file mode 100644
index 0000000..44b9ab5
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2018, 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 _CAM_FD_HW_V501_H_
+#define _CAM_FD_HW_V501_H_
+
+static struct cam_fd_hw_static_info cam_fd_wrapper200_core501_info = {
+ .core_version = {
+ .major = 5,
+ .minor = 0,
+ .incr = 1,
+ },
+ .wrapper_version = {
+ .major = 2,
+ .minor = 0,
+ .incr = 0,
+ },
+ .core_regs = {
+ .version = 0x38,
+ .control = 0x0,
+ .result_cnt = 0x4,
+ .result_addr = 0x20,
+ .image_addr = 0x24,
+ .work_addr = 0x28,
+ .ro_mode = 0x34,
+ .results_reg_base = 0x400,
+ .raw_results_reg_base = 0x800,
+ },
+ .wrapper_regs = {
+ .wrapper_version = 0x0,
+ .cgc_disable = 0x4,
+ .hw_stop = 0x8,
+ .sw_reset = 0x10,
+ .vbif_req_priority = 0x20,
+ .vbif_priority_level = 0x24,
+ .vbif_done_status = 0x34,
+ .irq_mask = 0x50,
+ .irq_status = 0x54,
+ .irq_clear = 0x58,
+ },
+ .results = {
+ .max_faces = 35,
+ .per_face_entries = 4,
+ .raw_results_available = true,
+ .raw_results_entries = 512,
+ },
+ .enable_errata_wa = {
+ .single_irq_only = true,
+ .ro_mode_enable_always = true,
+ .ro_mode_results_invalid = true,
+ },
+ .irq_mask = CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE) |
+ CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE) |
+ CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE),
+ .qos_priority = 4,
+ .qos_priority_level = 4,
+ .supported_modes = CAM_FD_MODE_FACEDETECTION | CAM_FD_MODE_PYRAMID,
+ .ro_mode_supported = true,
+};
+
+#endif /* _CAM_FD_HW_V501_H_ */
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 d47350c..502c95d 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -177,7 +177,7 @@
};
int cam_icp_context_init(struct cam_icp_context *ctx,
- struct cam_hw_mgr_intf *hw_intf)
+ struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id)
{
int rc;
@@ -187,8 +187,8 @@
goto err;
}
- rc = cam_context_init(ctx->base, icp_dev_name, NULL, hw_intf,
- ctx->req_base, CAM_CTX_REQ_MAX);
+ rc = cam_context_init(ctx->base, icp_dev_name, CAM_ICP, ctx_id,
+ NULL, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX);
if (rc) {
CAM_ERR(CAM_ICP, "Camera Context Base init failed");
goto err;
diff --git a/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.h b/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.h
index 709fc56..0c3a360 100644
--- a/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.h
+++ b/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -35,9 +35,10 @@
* cam_icp_context_init() - ICP context init
* @ctx: Pointer to context
* @hw_intf: Pointer to ICP hardware interface
+ * @ctx_id: ID for this context
*/
int cam_icp_context_init(struct cam_icp_context *ctx,
- struct cam_hw_mgr_intf *hw_intf);
+ struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id);
/**
* cam_icp_context_deinit() - ICP context deinit
diff --git a/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c b/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c
index 51499de..4f91f73 100644
--- a/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c
+++ b/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -167,7 +167,7 @@
for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
g_icp_dev.ctx_icp[i].base = &g_icp_dev.ctx[i];
rc = cam_icp_context_init(&g_icp_dev.ctx_icp[i],
- hw_mgr_intf);
+ hw_mgr_intf, i);
if (rc) {
CAM_ERR(CAM_ICP, "ICP context init failed");
goto ctx_fail;
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
index 178e734..f556780 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
@@ -36,6 +36,7 @@
* @msg_q: message queue hfi memory for firmware to host communication
* @dbg_q: debug queue hfi memory for firmware debug information
* @sec_heap: secondary heap hfi memory for firmware
+ * @qdss: qdss mapped memory for fw
* @icp_base: icp base address
*/
struct hfi_mem_info {
@@ -45,6 +46,7 @@
struct hfi_mem dbg_q;
struct hfi_mem sec_heap;
struct hfi_mem shmem;
+ struct hfi_mem qdss;
void __iomem *icp_base;
};
@@ -113,9 +115,10 @@
void cam_hfi_deinit(void __iomem *icp_base);
/**
* hfi_set_debug_level() - set debug level
+ * @a5_dbg_type: 1 for debug_q & 2 for qdss
* @lvl: FW debug message level
*/
-int hfi_set_debug_level(uint32_t lvl);
+int hfi_set_debug_level(u64 a5_dbg_type, uint32_t lvl);
/**
* hfi_enable_ipe_bps_pc() - Enable interframe pc
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h
index 73663b3..2153cea 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h
@@ -41,6 +41,8 @@
#define HFI_REG_QTBL_PTR 0x58
#define HFI_REG_UNCACHED_HEAP_PTR 0x5C
#define HFI_REG_UNCACHED_HEAP_SIZE 0x60
+#define HFI_REG_QDSS_IOVA 0x6C
+#define HFI_REG_QDSS_IOVA_SIZE 0x70
/* end of ICP CSR registers */
/* flags for ICP CSR registers */
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h
index 84cc129..91190b6 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -184,11 +184,12 @@
* Section describes different modes (HFI_DEBUG_MODE_X)
* available to communicate the debug messages
*/
- /* Debug message output through the interface debug queue. */
+ /* Debug message output through the interface debug queue. */
#define HFI_DEBUG_MODE_QUEUE 0x00000001
/* Debug message output through QDSS. */
#define HFI_DEBUG_MODE_QDSS 0x00000002
-
+ /* Number of debug modes available. */
+#define NUM_HFI_DEBUG_MODE 0x00000002
#define HFI_DEBUG_MSG_LOW 0x00000001
#define HFI_DEBUG_MSG_MEDIUM 0x00000002
@@ -199,9 +200,6 @@
#define HFI_DEBUG_CFG_WFI 0x01000000
#define HFI_DEBUG_CFG_ARM9WD 0x10000000
-#define HFI_DEBUG_MODE_QUEUE 0x00000001
-#define HFI_DEBUG_MODE_QDSS 0x00000002
-
#define HFI_DEV_VERSION_MAX 0x5
/**
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index f95f8eb..b75719b 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -285,7 +285,7 @@
return 0;
}
-int hfi_set_debug_level(uint32_t lvl)
+int hfi_set_debug_level(u64 a5_dbg_type, uint32_t lvl)
{
uint8_t *prop;
struct hfi_cmd_prop *dbg_prop;
@@ -316,9 +316,9 @@
dbg_prop->num_prop = 1;
dbg_prop->prop_data[0] = HFI_PROP_SYS_DEBUG_CFG;
dbg_prop->prop_data[1] = lvl;
- dbg_prop->prop_data[2] = HFI_DEBUG_MODE_QUEUE;
-
+ dbg_prop->prop_data[2] = a5_dbg_type;
hfi_write_cmd(prop);
+
kfree(prop);
return 0;
@@ -538,6 +538,10 @@
icp_base + HFI_REG_UNCACHED_HEAP_PTR);
cam_io_w_mb((uint32_t)hfi_mem->sec_heap.len,
icp_base + HFI_REG_UNCACHED_HEAP_SIZE);
+ cam_io_w_mb((uint32_t)hfi_mem->qdss.iova,
+ icp_base + HFI_REG_QDSS_IOVA);
+ cam_io_w_mb((uint32_t)hfi_mem->qdss.len,
+ icp_base + HFI_REG_QDSS_IOVA_SIZE);
return rc;
}
@@ -715,6 +719,10 @@
icp_base + HFI_REG_UNCACHED_HEAP_SIZE);
cam_io_w_mb((uint32_t)ICP_INIT_REQUEST_SET,
icp_base + HFI_REG_HOST_ICP_INIT_REQUEST);
+ cam_io_w_mb((uint32_t)hfi_mem->qdss.iova,
+ icp_base + HFI_REG_QDSS_IOVA);
+ cam_io_w_mb((uint32_t)hfi_mem->qdss.len,
+ icp_base + HFI_REG_QDSS_IOVA_SIZE);
hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION);
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c
index aeec16c..4b5f22e 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -207,37 +207,38 @@
if (!core_info->fw_elf) {
CAM_ERR(CAM_ICP, "Invalid elf size");
- return -EINVAL;
+ rc = -EINVAL;
+ goto fw_download_failed;
}
fw_start = core_info->fw_elf->data;
rc = cam_icp_validate_fw(fw_start);
if (rc) {
CAM_ERR(CAM_ICP, "fw elf validation failed");
- return -EINVAL;
+ goto fw_download_failed;
}
rc = cam_icp_get_fw_size(fw_start, &fw_size);
if (rc) {
CAM_ERR(CAM_ICP, "unable to get fw size");
- return rc;
+ goto fw_download_failed;
}
if (core_info->fw_buf_len < fw_size) {
CAM_ERR(CAM_ICP, "mismatch in fw size: %u %llu",
fw_size, core_info->fw_buf_len);
- goto fw_alloc_failed;
+ rc = -EINVAL;
+ goto fw_download_failed;
}
rc = cam_icp_program_fw(fw_start, core_info);
if (rc) {
CAM_ERR(CAM_ICP, "fw program is failed");
- goto fw_program_failed;
+ goto fw_download_failed;
}
- return 0;
-fw_program_failed:
-fw_alloc_failed:
+fw_download_failed:
+ release_firmware(core_info->fw_elf);
return rc;
}
@@ -387,7 +388,6 @@
switch (cmd_type) {
case CAM_ICP_A5_CMD_FW_DOWNLOAD:
rc = cam_a5_download_fw(device_priv);
-
break;
case CAM_ICP_A5_CMD_SET_FW_BUF: {
struct cam_icp_a5_set_fw_buf_info *fw_buf_info = cmd_args;
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 5dfb1bc..c6c9b85 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
@@ -245,6 +245,38 @@
return 0;
}
+static bool cam_icp_frame_pending(struct cam_icp_hw_ctx_data *ctx_data)
+{
+ return !bitmap_empty(ctx_data->hfi_frame_process.bitmap,
+ CAM_FRAME_CMD_MAX);
+}
+
+static int cam_icp_ctx_timer_reset(struct cam_icp_hw_ctx_data *ctx_data)
+{
+ if (ctx_data && ctx_data->watch_dog) {
+ ctx_data->watch_dog_reset_counter++;
+ CAM_DBG(CAM_ICP, "reset timer : ctx_id = %d, counter=%d",
+ ctx_data->ctx_id, ctx_data->watch_dog_reset_counter);
+ crm_timer_reset(ctx_data->watch_dog);
+ }
+
+ return 0;
+}
+
+static void cam_icp_device_timer_reset(struct cam_icp_hw_mgr *hw_mgr,
+ int device_index)
+{
+ if ((device_index >= ICP_CLK_HW_MAX) || (!hw_mgr))
+ return;
+
+ if (hw_mgr->clk_info[device_index].watch_dog) {
+ CAM_DBG(CAM_ICP, "reset timer : device_index = %d",
+ device_index);
+ crm_timer_reset(hw_mgr->clk_info[device_index].watch_dog);
+ hw_mgr->clk_info[device_index].watch_dog_reset_counter++;
+ }
+}
+
static int32_t cam_icp_deinit_idle_clk(void *priv, void *data)
{
struct cam_icp_hw_mgr *hw_mgr = (struct cam_icp_hw_mgr *)priv;
@@ -259,6 +291,8 @@
struct cam_hw_intf *bps_dev_intf = NULL;
struct cam_hw_intf *dev_intf = NULL;
struct cam_a5_clk_update_cmd clk_upd_cmd;
+ int rc = 0;
+ bool busy = false;
ipe0_dev_intf = hw_mgr->ipe0_dev_intf;
ipe1_dev_intf = hw_mgr->ipe1_dev_intf;
@@ -268,19 +302,34 @@
clk_info->curr_clk = 0;
clk_info->over_clked = 0;
+ mutex_lock(&hw_mgr->hw_mgr_mutex);
+
for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
ctx_data = &hw_mgr->ctx_data[i];
mutex_lock(&ctx_data->ctx_mutex);
- if ((ctx_data->state != CAM_ICP_CTX_STATE_FREE) &&
+ if ((ctx_data->state == CAM_ICP_CTX_STATE_ACQUIRED) &&
(ICP_DEV_TYPE_TO_CLK_TYPE(ctx_data->
- icp_dev_acquire_info->dev_type) == clk_info->hw_type))
+ icp_dev_acquire_info->dev_type) == clk_info->hw_type)) {
+ busy = cam_icp_frame_pending(ctx_data);
+ if (busy) {
+ mutex_unlock(&ctx_data->ctx_mutex);
+ break;
+ }
cam_icp_ctx_clk_info_init(ctx_data);
+ }
mutex_unlock(&ctx_data->ctx_mutex);
}
+ if (busy) {
+ cam_icp_device_timer_reset(hw_mgr, clk_info->hw_type);
+ rc = -EBUSY;
+ goto done;
+ }
+
if ((!ipe0_dev_intf) || (!bps_dev_intf)) {
CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk");
- return -EINVAL;
+ rc = -EINVAL;
+ goto done;
}
if (clk_info->hw_type == ICP_CLK_HW_BPS) {
@@ -291,7 +340,7 @@
id = CAM_ICP_IPE_CMD_DISABLE_CLK;
} else {
CAM_ERR(CAM_ICP, "Error");
- return 0;
+ goto done;
}
CAM_DBG(CAM_ICP, "Disable %d", clk_info->hw_type);
@@ -308,7 +357,9 @@
&clk_upd_cmd,
sizeof(struct cam_a5_clk_update_cmd));
- return 0;
+done:
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ return rc;
}
static int32_t cam_icp_ctx_timer(void *priv, void *data)
@@ -339,6 +390,12 @@
return 0;
}
+ if (cam_icp_frame_pending(ctx_data)) {
+ cam_icp_ctx_timer_reset(ctx_data);
+ mutex_unlock(&ctx_data->ctx_mutex);
+ return -EBUSY;
+ }
+
CAM_DBG(CAM_ICP,
"E :ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u",
ctx_data->ctx_id,
@@ -380,8 +437,8 @@
ctx_data->clk_info.base_clk = 0;
clk_update.ahb_vote.type = CAM_VOTE_DYNAMIC;
- clk_update.ahb_vote.vote.freq = clk_info->curr_clk;
- clk_update.ahb_vote_valid = true;
+ clk_update.ahb_vote.vote.freq = 0;
+ clk_update.ahb_vote_valid = false;
clk_update.axi_vote.compressed_bw = clk_info->compressed_bw;
clk_update.axi_vote.uncompressed_bw = clk_info->uncompressed_bw;
clk_update.axi_vote_valid = true;
@@ -408,7 +465,7 @@
struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data;
spin_lock_irqsave(&icp_hw_mgr.hw_mgr_lock, flags);
- task = cam_req_mgr_workq_get_task(icp_hw_mgr.msg_work);
+ task = cam_req_mgr_workq_get_task(icp_hw_mgr.timer_work);
if (!task) {
CAM_ERR(CAM_ICP, "no empty task");
spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags);
@@ -432,7 +489,7 @@
struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data;
spin_lock_irqsave(&icp_hw_mgr.hw_mgr_lock, flags);
- task = cam_req_mgr_workq_get_task(icp_hw_mgr.msg_work);
+ task = cam_req_mgr_workq_get_task(icp_hw_mgr.timer_work);
if (!task) {
CAM_ERR(CAM_ICP, "no empty task");
spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags);
@@ -473,7 +530,7 @@
int rc = 0;
rc = crm_timer_init(&ctx_data->watch_dog,
- 2000, ctx_data, &cam_icp_ctx_timer_cb);
+ 200, ctx_data, &cam_icp_ctx_timer_cb);
if (rc)
CAM_ERR(CAM_ICP, "Failed to start timer");
@@ -533,30 +590,6 @@
}
}
-static int cam_icp_ctx_timer_reset(struct cam_icp_hw_ctx_data *ctx_data)
-{
- if (ctx_data && ctx_data->watch_dog) {
- ctx_data->watch_dog_reset_counter++;
- CAM_DBG(CAM_ICP, "reset timer : ctx_id = %d, counter=%d",
- ctx_data->ctx_id, ctx_data->watch_dog_reset_counter);
- crm_timer_reset(ctx_data->watch_dog);
- }
-
- return 0;
-}
-
-static void cam_icp_device_timer_reset(struct cam_icp_hw_mgr *hw_mgr,
- int device_index)
-{
- if ((device_index >= ICP_CLK_HW_MAX) || (!hw_mgr))
- return;
-
- if (hw_mgr->clk_info[device_index].watch_dog) {
- crm_timer_reset(hw_mgr->clk_info[device_index].watch_dog);
- hw_mgr->clk_info[device_index].watch_dog_reset_counter++;
- }
-}
-
static uint32_t cam_icp_mgr_calc_base_clk(uint32_t frame_cycles,
uint64_t budget)
{
@@ -639,7 +672,6 @@
* zero. If the clock is already at highest clock rate then
* no need to update the clock
*/
- mutex_lock(&hw_mgr->hw_mgr_mutex);
ctx_data->clk_info.base_clk = base_clk;
hw_mgr_clk_info->over_clked = 0;
if (clk_info->frame_cycles > ctx_data->clk_info.curr_fc) {
@@ -665,7 +697,6 @@
}
}
ctx_data->clk_info.curr_fc = clk_info->frame_cycles;
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
return rc;
}
@@ -731,10 +762,8 @@
ctx_data->clk_info.curr_fc = clk_info->frame_cycles;
ctx_data->clk_info.base_clk = base_clk;
- mutex_lock(&hw_mgr->hw_mgr_mutex);
cam_icp_calc_total_clk(hw_mgr, hw_mgr_clk_info,
ctx_data->icp_dev_acquire_info->dev_type);
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
/*
* Current clock is not always sum of base clocks, due to
@@ -752,7 +781,6 @@
over_clocked = cam_icp_is_over_clk(hw_mgr, ctx_data,
hw_mgr_clk_info);
- mutex_lock(&hw_mgr->hw_mgr_mutex);
if (hw_mgr_clk_info->curr_clk > hw_mgr_clk_info->base_clk &&
over_clocked) {
rc = cam_icp_update_clk_overclk_free(hw_mgr, ctx_data,
@@ -765,7 +793,6 @@
ctx_data, hw_mgr_clk_info->base_clk);
rc = true;
}
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
return rc;
}
@@ -775,12 +802,10 @@
if (icp_hw_mgr.icp_debug_clk < ICP_CLK_TURBO_HZ &&
icp_hw_mgr.icp_debug_clk &&
icp_hw_mgr.icp_debug_clk != hw_mgr_clk_info->curr_clk) {
- mutex_lock(&icp_hw_mgr.hw_mgr_mutex);
hw_mgr_clk_info->base_clk = icp_hw_mgr.icp_debug_clk;
hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_debug_clk;
hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_debug_clk;
hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_debug_clk;
- mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
CAM_DBG(CAM_ICP, "bc = %d cc = %d",
hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk);
return true;
@@ -792,12 +817,10 @@
static bool cam_icp_default_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info)
{
if (icp_hw_mgr.icp_default_clk != hw_mgr_clk_info->curr_clk) {
- mutex_lock(&icp_hw_mgr.hw_mgr_mutex);
hw_mgr_clk_info->base_clk = icp_hw_mgr.icp_default_clk;
hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_default_clk;
hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_default_clk;
hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_default_clk;
- mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
CAM_DBG(CAM_ICP, "bc = %d cc = %d",
hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk);
return true;
@@ -844,7 +867,6 @@
ctx->icp_dev_acquire_info->dev_type) ==
ICP_DEV_TYPE_TO_CLK_TYPE(
ctx_data->icp_dev_acquire_info->dev_type)) {
- mutex_lock(&hw_mgr->hw_mgr_mutex);
hw_mgr_clk_info->uncompressed_bw +=
ctx->clk_info.uncompressed_bw;
hw_mgr_clk_info->compressed_bw +=
@@ -852,7 +874,6 @@
CAM_DBG(CAM_ICP, "ubw = %lld, cbw = %lld",
hw_mgr_clk_info->uncompressed_bw,
hw_mgr_clk_info->compressed_bw);
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
}
}
@@ -1018,8 +1039,8 @@
}
clk_update.ahb_vote.type = CAM_VOTE_DYNAMIC;
- clk_update.ahb_vote.vote.freq = clk_info->curr_clk;
- clk_update.ahb_vote_valid = true;
+ clk_update.ahb_vote.vote.freq = 0;
+ clk_update.ahb_vote_valid = false;
clk_update.axi_vote.compressed_bw = clk_info->compressed_bw;
clk_update.axi_vote.uncompressed_bw = clk_info->uncompressed_bw;
clk_update.axi_vote_valid = true;
@@ -1244,6 +1265,23 @@
DEFINE_SIMPLE_ATTRIBUTE(cam_icp_debug_fs, cam_icp_get_a5_dbg_lvl,
cam_icp_set_a5_dbg_lvl, "%08llu");
+static int cam_icp_set_a5_dbg_type(void *data, u64 val)
+{
+ if (val <= NUM_HFI_DEBUG_MODE)
+ icp_hw_mgr.a5_debug_type = val;
+ return 0;
+}
+
+static int cam_icp_get_a5_dbg_type(void *data, u64 *val)
+{
+ *val = icp_hw_mgr.a5_debug_type;
+ return 0;
+}
+
+
+DEFINE_SIMPLE_ATTRIBUTE(cam_icp_debug_type_fs, cam_icp_get_a5_dbg_type,
+ cam_icp_set_a5_dbg_type, "%08llu");
+
static int cam_icp_hw_mgr_create_debugfs_entry(void)
{
int rc = 0;
@@ -1290,11 +1328,11 @@
goto err;
}
- if (!debugfs_create_bool("a5_debug_q",
+ if (!debugfs_create_file("a5_debug_type",
0644,
icp_hw_mgr.dentry,
- &icp_hw_mgr.a5_debug_q)) {
- CAM_ERR(CAM_ICP, "failed to create a5_debug_q\n");
+ NULL, &cam_icp_debug_type_fs)) {
+ CAM_ERR(CAM_ICP, "failed to create a5_debug_type\n");
rc = -ENOMEM;
goto err;
}
@@ -1352,7 +1390,7 @@
ctx_data->hfi_frame_process.in_resource[i]);
cam_sync_destroy(
ctx_data->hfi_frame_process.in_resource[i]);
- ctx_data->hfi_frame_process.in_free_resource[i] = 0;
+ ctx_data->hfi_frame_process.in_resource[i] = 0;
}
hfi_frame_process->fw_process_flag[i] = false;
clear_bit(i, ctx_data->hfi_frame_process.bitmap);
@@ -1366,7 +1404,7 @@
ctx_data->hfi_frame_process.in_free_resource[i]);
cam_sync_destroy(
ctx_data->hfi_frame_process.in_free_resource[i]);
- ctx_data->hfi_frame_process.in_resource[i] = 0;
+ ctx_data->hfi_frame_process.in_free_resource[i] = 0;
}
return 0;
@@ -1393,10 +1431,6 @@
CAM_DBG(CAM_ICP, "ctx : %pK, request_id :%lld",
(void *)ctx_data->context_priv, request_id);
- clk_type = ICP_DEV_TYPE_TO_CLK_TYPE(ctx_data->icp_dev_acquire_info->
- dev_type);
- cam_icp_device_timer_reset(&icp_hw_mgr, clk_type);
-
mutex_lock(&ctx_data->ctx_mutex);
cam_icp_ctx_timer_reset(ctx_data);
if (ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) {
@@ -1406,6 +1440,10 @@
return 0;
}
+ clk_type = ICP_DEV_TYPE_TO_CLK_TYPE(
+ ctx_data->icp_dev_acquire_info->dev_type);
+ cam_icp_device_timer_reset(&icp_hw_mgr, clk_type);
+
hfi_frame_process = &ctx_data->hfi_frame_process;
for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
if (hfi_frame_process->request_id[i] == request_id)
@@ -1449,8 +1487,6 @@
if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) {
CAM_ERR(CAM_ICP, "failed with error : %u",
ioconfig_ack->err_type);
- cam_icp_mgr_handle_frame_process(msg_ptr,
- ICP_FRAME_PROCESS_FAILURE);
return -EIO;
}
@@ -1774,10 +1810,14 @@
read_len = read_len << BYTE_WORD_SHIFT;
msg_ptr = (uint32_t *)icp_hw_mgr.msg_buf;
while (true) {
- rc = cam_icp_process_msg_pkt_type(hw_mgr, msg_ptr,
+ cam_icp_process_msg_pkt_type(hw_mgr, msg_ptr,
&msg_processed_len);
- if (rc)
- return rc;
+
+ if (!msg_processed_len) {
+ CAM_ERR(CAM_ICP, "Failed to read");
+ rc = -EINVAL;
+ break;
+ }
read_len -= msg_processed_len;
if (read_len > 0) {
@@ -1790,7 +1830,8 @@
}
}
- if (icp_hw_mgr.a5_debug_q)
+ if (icp_hw_mgr.a5_debug_type ==
+ HFI_DEBUG_MODE_QUEUE)
cam_icp_mgr_process_dbg_buf();
return rc;
@@ -1831,6 +1872,8 @@
rc = cam_mem_mgr_free_memory_region(&icp_hw_mgr.hfi_mem.sec_heap);
if (rc)
CAM_ERR(CAM_ICP, "failed to unreserve sec heap");
+
+ cam_smmu_dealloc_qdss(icp_hw_mgr.iommu_hdl);
cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.qtbl);
cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.cmd_q);
cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q);
@@ -1921,6 +1964,26 @@
return rc;
}
+static int cam_icp_allocate_qdss_mem(void)
+{
+ int rc;
+ size_t len;
+ dma_addr_t iova;
+
+ rc = cam_smmu_alloc_qdss(icp_hw_mgr.iommu_hdl,
+ &iova, &len);
+ if (rc)
+ return rc;
+
+ icp_hw_mgr.hfi_mem.qdss_buf.len = len;
+ icp_hw_mgr.hfi_mem.qdss_buf.iova = iova;
+ icp_hw_mgr.hfi_mem.qdss_buf.smmu_hdl = icp_hw_mgr.iommu_hdl;
+
+ CAM_DBG(CAM_ICP, "iova: %llx, len: %zu", iova, len);
+
+ return rc;
+}
+
static int cam_icp_allocate_hfi_mem(void)
{
int rc;
@@ -1939,6 +2002,12 @@
return rc;
}
+ rc = cam_icp_allocate_qdss_mem();
+ if (rc) {
+ CAM_ERR(CAM_ICP, "Unable to allocate qdss memory");
+ goto fw_alloc_failed;
+ }
+
rc = cam_icp_alloc_shared_mem(&icp_hw_mgr.hfi_mem.qtbl);
if (rc) {
CAM_ERR(CAM_ICP, "Unable to allocate qtbl memory");
@@ -1979,6 +2048,8 @@
cmd_q_alloc_failed:
cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.qtbl);
qtbl_alloc_failed:
+ cam_smmu_dealloc_qdss(icp_hw_mgr.iommu_hdl);
+fw_alloc_failed:
cam_smmu_dealloc_firmware(icp_hw_mgr.iommu_hdl);
return rc;
}
@@ -2067,6 +2138,37 @@
return 0;
}
+
+static int cam_icp_mgr_hw_close_u(void *hw_priv, void *hw_close_args)
+{
+ struct cam_icp_hw_mgr *hw_mgr = hw_priv;
+ int rc = 0;
+
+ if (!hw_mgr) {
+ CAM_ERR(CAM_ICP, "Null hw mgr");
+ return 0;
+ }
+
+ mutex_lock(&hw_mgr->hw_mgr_mutex);
+ rc = cam_icp_mgr_hw_close(hw_mgr, NULL);
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+ return rc;
+}
+
+static int cam_icp_mgr_hw_close_k(void *hw_priv, void *hw_close_args)
+{
+ struct cam_icp_hw_mgr *hw_mgr = hw_priv;
+
+ if (!hw_mgr) {
+ CAM_ERR(CAM_ICP, "Null hw mgr");
+ return 0;
+ }
+
+ return cam_icp_mgr_hw_close(hw_mgr, NULL);
+
+}
+
static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr)
{
int rc;
@@ -2085,7 +2187,7 @@
if (!hw_mgr->icp_pc_flag) {
cam_hfi_disable_cpu(
a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
- rc = cam_icp_mgr_hw_close(hw_mgr, NULL);
+ rc = cam_icp_mgr_hw_close_k(hw_mgr, NULL);
} else {
rc = cam_icp_mgr_send_pc_prep(hw_mgr);
cam_hfi_disable_cpu(
@@ -2140,6 +2242,9 @@
hfi_mem.shmem.iova = icp_hw_mgr.hfi_mem.shmem.iova_start;
hfi_mem.shmem.len = icp_hw_mgr.hfi_mem.shmem.iova_len;
+
+ hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova;
+ hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len;
return cam_hfi_resume(&hfi_mem,
a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base,
hw_mgr->a5_jtag_debug);
@@ -2195,7 +2300,6 @@
kfree(abort_cmd);
return rc;
}
-
CAM_DBG(CAM_ICP, "fw_handle = %x ctx_data = %pK",
ctx_data->fw_handle, ctx_data);
rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
@@ -2205,7 +2309,6 @@
CAM_ERR(CAM_ICP, "FW timeout/err in abort handle command");
}
- kfree(abort_cmd);
return rc;
}
@@ -2260,7 +2363,6 @@
kfree(destroy_cmd);
return rc;
}
-
CAM_DBG(CAM_ICP, "fw_handle = %x ctx_data = %pK",
ctx_data->fw_handle, ctx_data);
rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
@@ -2269,11 +2371,10 @@
rc = -ETIMEDOUT;
CAM_ERR(CAM_ICP, "FW response timeout: %d for %u",
rc, ctx_data->ctx_id);
- if (icp_hw_mgr.a5_debug_q)
+ if (icp_hw_mgr.a5_debug_type ==
+ HFI_DEBUG_MODE_QUEUE)
cam_icp_mgr_process_dbg_buf();
}
-
- kfree(destroy_cmd);
return rc;
}
@@ -2290,7 +2391,6 @@
if (hw_mgr->ctx_data[ctx_id].state !=
CAM_ICP_CTX_STATE_ACQUIRED) {
mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
CAM_DBG(CAM_ICP,
"ctx with id: %d not in right state to release: %d",
ctx_id, hw_mgr->ctx_data[ctx_id].state);
@@ -2360,16 +2460,13 @@
int rc = 0;
CAM_DBG(CAM_ICP, "E");
- mutex_lock(&hw_mgr->hw_mgr_mutex);
if (hw_mgr->fw_download == false) {
CAM_DBG(CAM_ICP, "hw mgr is already closed");
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
return 0;
}
a5_dev_intf = hw_mgr->a5_dev_intf;
if (!a5_dev_intf) {
CAM_DBG(CAM_ICP, "a5_dev_intf is NULL");
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
return -EINVAL;
}
a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
@@ -2397,7 +2494,7 @@
cam_icp_free_hfi_mem();
hw_mgr->fw_download = false;
hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
CAM_DBG(CAM_ICP, "Exit");
return rc;
}
@@ -2542,6 +2639,9 @@
hfi_mem.shmem.iova = icp_hw_mgr.hfi_mem.shmem.iova_start;
hfi_mem.shmem.len = icp_hw_mgr.hfi_mem.shmem.iova_len;
+ hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova;
+ hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len;
+
return cam_hfi_init(0, &hfi_mem,
a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base,
hw_mgr->a5_jtag_debug);
@@ -2580,6 +2680,35 @@
return rc;
}
+static int cam_icp_mgr_hw_open_u(void *hw_mgr_priv, void *download_fw_args)
+{
+ struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+ int rc = 0;
+
+ if (!hw_mgr) {
+ CAM_ERR(CAM_ICP, "Null hw mgr");
+ return 0;
+ }
+
+ mutex_lock(&hw_mgr->hw_mgr_mutex);
+ rc = cam_icp_mgr_hw_open(hw_mgr, download_fw_args);
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+ return rc;
+}
+
+static int cam_icp_mgr_hw_open_k(void *hw_mgr_priv, void *download_fw_args)
+{
+ struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+
+ if (!hw_mgr) {
+ CAM_ERR(CAM_ICP, "Null hw mgr");
+ return 0;
+ }
+
+ return cam_icp_mgr_hw_open(hw_mgr, download_fw_args);
+}
+
static int cam_icp_mgr_icp_resume(struct cam_icp_hw_mgr *hw_mgr)
{
int rc = 0;
@@ -2596,9 +2725,7 @@
if (hw_mgr->fw_download == false) {
CAM_DBG(CAM_ICP, "Downloading FW");
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
- rc = cam_icp_mgr_hw_open(hw_mgr, &downloadFromResume);
- mutex_lock(&hw_mgr->hw_mgr_mutex);
+ rc = cam_icp_mgr_hw_open_k(hw_mgr, &downloadFromResume);
CAM_DBG(CAM_ICP, "FW Download Done Exit");
return rc;
}
@@ -2631,17 +2758,14 @@
return -EINVAL;
}
- mutex_lock(&hw_mgr->hw_mgr_mutex);
if (hw_mgr->fw_download) {
CAM_DBG(CAM_ICP, "FW already downloaded");
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
return rc;
}
a5_dev_intf = hw_mgr->a5_dev_intf;
if (!a5_dev_intf) {
CAM_ERR(CAM_ICP, "a5_dev_intf is invalid");
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
return -EINVAL;
}
a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
@@ -2668,10 +2792,6 @@
hw_mgr->ctxt_cnt = 0;
hw_mgr->fw_download = true;
- if (icp_hw_mgr.a5_debug_q)
- hfi_set_debug_level(icp_hw_mgr.a5_dbg_lvl);
-
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
CAM_INFO(CAM_ICP, "FW download done successfully");
rc = cam_ipe_bps_deint(hw_mgr);
@@ -2703,7 +2823,6 @@
dev_init_fail:
cam_icp_free_hfi_mem();
alloc_hfi_mem_failed:
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
return rc;
}
@@ -2777,9 +2896,11 @@
}
ctx_data = config_args->ctxt_to_hw_map;
+ mutex_lock(&hw_mgr->hw_mgr_mutex);
mutex_lock(&ctx_data->ctx_mutex);
if (ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) {
mutex_unlock(&ctx_data->ctx_mutex);
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
CAM_ERR(CAM_ICP, "ctx id :%u is not in use",
ctx_data->ctx_id);
return -EINVAL;
@@ -2796,11 +2917,13 @@
CAM_DBG(CAM_ICP, "req_id = %lld %u",
req_id, ctx_data->ctx_id);
mutex_unlock(&ctx_data->ctx_mutex);
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
return 0;
config_err:
cam_icp_mgr_handle_config_err(config_args, ctx_data, idx);
mutex_unlock(&ctx_data->ctx_mutex);
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
return rc;
}
@@ -2839,8 +2962,23 @@
packet->header.op_code & 0xff);
return -EINVAL;
}
- CAM_DBG(CAM_ICP, "number of cmd/patch info: %u %u",
- packet->num_cmd_buf, packet->num_patches);
+
+ if (packet->num_io_configs > IPE_IO_IMAGES_MAX) {
+ CAM_ERR(CAM_ICP, "Invalid number of io configs: %d %d",
+ IPE_IO_IMAGES_MAX, packet->num_io_configs);
+ return -EINVAL;
+ }
+
+ if (packet->num_cmd_buf > CAM_ICP_CTX_MAX_CMD_BUFFERS) {
+ CAM_ERR(CAM_ICP, "Invalid number of cmd buffers: %d %d",
+ CAM_ICP_CTX_MAX_CMD_BUFFERS, packet->num_cmd_buf);
+ return -EINVAL;
+ }
+
+ CAM_DBG(CAM_ICP, "number of cmd/patch info: %u %u %u %u",
+ packet->num_cmd_buf,
+ packet->num_io_configs, IPE_IO_IMAGES_MAX,
+ packet->num_patches);
return 0;
}
@@ -3428,9 +3566,7 @@
rc = cam_icp_mgr_release_ctx(hw_mgr, ctx_id);
if (!hw_mgr->ctxt_cnt) {
CAM_DBG(CAM_ICP, "Last Release");
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
cam_icp_mgr_icp_power_collapse(hw_mgr);
- mutex_lock(&hw_mgr->hw_mgr_mutex);
cam_icp_hw_mgr_reset_clk_info(hw_mgr);
hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
rc = cam_ipe_bps_deint(hw_mgr);
@@ -3698,10 +3834,9 @@
mutex_lock(&ctx_data->ctx_mutex);
rc = cam_icp_get_acquire_info(hw_mgr, args, ctx_data);
- if (rc) {
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ if (rc)
goto acquire_info_failed;
- }
+
icp_dev_acquire_info = ctx_data->icp_dev_acquire_info;
rc = cam_mem_get_io_buf(
@@ -3710,7 +3845,6 @@
&io_buf_addr, &io_buf_size);
if (rc) {
CAM_ERR(CAM_ICP, "unable to get src buf info from io desc");
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
goto get_io_buf_failed;
}
@@ -3720,38 +3854,26 @@
if (!hw_mgr->ctxt_cnt) {
rc = cam_icp_clk_info_init(hw_mgr, ctx_data);
- if (rc) {
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ if (rc)
goto get_io_buf_failed;
- }
rc = cam_icp_mgr_icp_resume(hw_mgr);
- if (rc) {
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ if (rc)
goto get_io_buf_failed;
- }
- if (icp_hw_mgr.a5_debug_q)
- hfi_set_debug_level(icp_hw_mgr.a5_dbg_lvl);
+ if (icp_hw_mgr.a5_debug_type)
+ hfi_set_debug_level(icp_hw_mgr.a5_debug_type,
+ icp_hw_mgr.a5_dbg_lvl);
rc = cam_icp_send_ubwc_cfg(hw_mgr);
- if (rc) {
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ if (rc)
goto ubwc_cfg_failed;
- }
}
- if (!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt)
- cam_icp_device_timer_start(hw_mgr);
-
- cam_icp_ctx_timer_start(ctx_data);
rc = cam_icp_mgr_ipe_bps_resume(hw_mgr, ctx_data);
- if (rc) {
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ if (rc)
goto ipe_bps_resume_failed;
- }
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
rc = cam_icp_mgr_send_ping(ctx_data);
if (rc) {
@@ -3781,6 +3903,7 @@
kzalloc(bitmap_size, GFP_KERNEL);
if (!ctx_data->hfi_frame_process.bitmap)
goto ioconfig_failed;
+
ctx_data->hfi_frame_process.bits = bitmap_size * BITS_PER_BYTE;
hw_mgr->ctx_data[ctx_id].ctxt_event_cb = args->event_cb;
icp_dev_acquire_info->scratch_mem_size = ctx_data->scratch_mem_size;
@@ -3795,7 +3918,11 @@
CAM_DBG(CAM_ICP, "scratch size = %x fw_handle = %x",
(unsigned int)icp_dev_acquire_info->scratch_mem_size,
(unsigned int)ctx_data->fw_handle);
- mutex_lock(&hw_mgr->hw_mgr_mutex);
+ /* Start device timer*/
+ if (((hw_mgr->bps_ctxt_cnt == 1) || (hw_mgr->ipe_ctxt_cnt == 1)))
+ cam_icp_device_timer_start(hw_mgr);
+ /* Start context timer*/
+ cam_icp_ctx_timer_start(ctx_data);
hw_mgr->ctxt_cnt++;
mutex_unlock(&hw_mgr->hw_mgr_mutex);
CAM_DBG(CAM_ICP, "Acquire Done");
@@ -3811,7 +3938,6 @@
send_ping_failed:
cam_icp_mgr_ipe_bps_power_collapse(hw_mgr, ctx_data, 0);
ipe_bps_resume_failed:
- cam_icp_ctx_timer_stop(&hw_mgr->ctx_data[ctx_id]);
ubwc_cfg_failed:
if (!hw_mgr->ctxt_cnt)
cam_icp_mgr_icp_power_collapse(hw_mgr);
@@ -3821,6 +3947,7 @@
acquire_info_failed:
cam_icp_mgr_put_ctx(ctx_data);
mutex_unlock(&ctx_data->ctx_mutex);
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
return rc;
}
@@ -4003,17 +4130,24 @@
rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK,
&icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ);
if (rc) {
- CAM_ERR(CAM_ICP, "unable to create a worker");
+ CAM_ERR(CAM_ICP, "unable to create a command worker");
goto cmd_work_failed;
}
rc = cam_req_mgr_workq_create("icp_message_queue", ICP_WORKQ_NUM_TASK,
&icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ);
if (rc) {
- CAM_ERR(CAM_ICP, "unable to create a worker");
+ CAM_ERR(CAM_ICP, "unable to create a message worker");
goto msg_work_failed;
}
+ rc = cam_req_mgr_workq_create("icp_timer_queue", ICP_WORKQ_NUM_TASK,
+ &icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ);
+ if (rc) {
+ CAM_ERR(CAM_ICP, "unable to create a timer worker");
+ goto timer_work_failed;
+ }
+
icp_hw_mgr.cmd_work_data = (struct hfi_cmd_work_data *)
kzalloc(sizeof(struct hfi_cmd_work_data) * ICP_WORKQ_NUM_TASK,
GFP_KERNEL);
@@ -4026,9 +4160,15 @@
if (!icp_hw_mgr.msg_work_data)
goto msg_work_data_failed;
+ icp_hw_mgr.timer_work_data = (struct hfi_msg_work_data *)
+ kzalloc(sizeof(struct hfi_msg_work_data) * ICP_WORKQ_NUM_TASK,
+ GFP_KERNEL);
+ if (!icp_hw_mgr.timer_work_data)
+ goto timer_work_data_failed;
+
rc = cam_icp_hw_mgr_create_debugfs_entry();
if (rc)
- goto msg_work_data_failed;
+ goto debugfs_create_failed;
for (i = 0; i < ICP_WORKQ_NUM_TASK; i++)
icp_hw_mgr.msg_work->task.pool[i].payload =
@@ -4038,10 +4178,20 @@
icp_hw_mgr.cmd_work->task.pool[i].payload =
&icp_hw_mgr.cmd_work_data[i];
+ for (i = 0; i < ICP_WORKQ_NUM_TASK; i++)
+ icp_hw_mgr.timer_work->task.pool[i].payload =
+ &icp_hw_mgr.timer_work_data[i];
return 0;
+
+debugfs_create_failed:
+ kfree(icp_hw_mgr.timer_work_data);
+timer_work_data_failed:
+ kfree(icp_hw_mgr.msg_work_data);
msg_work_data_failed:
kfree(icp_hw_mgr.cmd_work_data);
cmd_work_data_failed:
+ cam_req_mgr_workq_destroy(&icp_hw_mgr.timer_work);
+timer_work_failed:
cam_req_mgr_workq_destroy(&icp_hw_mgr.msg_work);
msg_work_failed:
cam_req_mgr_workq_destroy(&icp_hw_mgr.cmd_work);
@@ -4069,8 +4219,8 @@
hw_mgr_intf->hw_release = cam_icp_mgr_release_hw;
hw_mgr_intf->hw_prepare_update = cam_icp_mgr_prepare_hw_update;
hw_mgr_intf->hw_config = cam_icp_mgr_config_hw;
- hw_mgr_intf->hw_open = cam_icp_mgr_hw_open;
- hw_mgr_intf->hw_close = cam_icp_mgr_hw_close;
+ hw_mgr_intf->hw_open = cam_icp_mgr_hw_open_u;
+ hw_mgr_intf->hw_close = cam_icp_mgr_hw_close_u;
hw_mgr_intf->hw_flush = cam_icp_mgr_hw_flush;
icp_hw_mgr.secure_mode = CAM_SECURE_MODE_NON_SECURE;
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index aac4a5e..c94550d 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -68,6 +68,8 @@
#define CAM_ICP_CTX_STATE_ACQUIRED 0x2
#define CAM_ICP_CTX_STATE_RELEASE 0x3
+#define CAM_ICP_CTX_MAX_CMD_BUFFERS 0x2
+
/**
* struct icp_hfi_mem_info
* @qtbl: Memory info of queue table
@@ -76,6 +78,7 @@
* @dbg_q: Memory info of debug queue
* @sec_heap: Memory info of secondary heap
* @fw_buf: Memory info of firmware
+ * @qdss_buf: Memory info of qdss
*/
struct icp_hfi_mem_info {
struct cam_mem_mgr_memory_desc qtbl;
@@ -84,6 +87,7 @@
struct cam_mem_mgr_memory_desc dbg_q;
struct cam_mem_mgr_memory_desc sec_heap;
struct cam_mem_mgr_memory_desc fw_buf;
+ struct cam_mem_mgr_memory_desc qdss_buf;
struct cam_smmu_region_info shmem;
};
@@ -253,11 +257,13 @@
* @hfi_mem: Memory for hfi
* @cmd_work: Work queue for hfi commands
* @msg_work: Work queue for hfi messages
+ * @timer_work: Work queue for timer watchdog
* @msg_buf: Buffer for message data from firmware
* @dbg_buf: Buffer for debug data from firmware
* @a5_complete: Completion info
* @cmd_work_data: Pointer to command work queue task
* @msg_work_data: Pointer to message work queue task
+ * @timer_work_data: Pointer to timer work queue task
* @ctxt_cnt: Active context count
* @ipe_ctxt_cnt: IPE Active context count
* @bps_ctxt_cnt: BPS Active context count
@@ -271,7 +277,7 @@
* @clk_info: Clock info of hardware
* @secure_mode: Flag to enable/disable secure camera
* @a5_jtag_debug: entry to enable A5 JTAG debugging
- * @a5_debug_q : entry to enable FW debug message
+ * @a5_debug_type : entry to enable FW debug message/qdss
* @a5_dbg_lvl : debug level set to FW.
* @ipe0_enable: Flag for IPE0
* @ipe1_enable: Flag for IPE1
@@ -298,11 +304,13 @@
struct icp_hfi_mem_info hfi_mem;
struct cam_req_mgr_core_workq *cmd_work;
struct cam_req_mgr_core_workq *msg_work;
+ struct cam_req_mgr_core_workq *timer_work;
uint32_t msg_buf[ICP_MSG_BUF_SIZE];
uint32_t dbg_buf[ICP_DBG_BUF_SIZE];
struct completion a5_complete;
struct hfi_cmd_work_data *cmd_work_data;
struct hfi_msg_work_data *msg_work_data;
+ struct hfi_msg_work_data *timer_work_data;
uint32_t ctxt_cnt;
uint32_t ipe_ctxt_cnt;
uint32_t bps_ctxt_cnt;
@@ -315,7 +323,7 @@
struct cam_icp_clk_info clk_info[ICP_CLK_HW_MAX];
bool secure_mode;
bool a5_jtag_debug;
- bool a5_debug_q;
+ u64 a5_debug_type;
u64 a5_dbg_lvl;
bool ipe0_enable;
bool ipe1_enable;
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 d62344d..8753bbb 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
@@ -1070,6 +1070,7 @@
req_isp->bubble_report = apply->report_if_bubble;
cfg.ctxt_to_hw_map = ctx_isp->hw_ctx;
+ cfg.request_id = req->request_id;
cfg.hw_update_entries = req_isp->cfg;
cfg.num_hw_update_entries = req_isp->num_cfg;
cfg.priv = &req_isp->hw_update_data;
@@ -1145,7 +1146,9 @@
struct cam_ctx_request *req;
struct cam_ctx_request *req_temp;
struct cam_isp_ctx_req *req_isp;
+ struct list_head flush_list;
+ INIT_LIST_HEAD(&flush_list);
spin_lock_bh(&ctx->lock);
if (list_empty(req_list)) {
spin_unlock_bh(&ctx->lock);
@@ -1154,11 +1157,22 @@
}
list_for_each_entry_safe(req, req_temp, req_list, list) {
- if ((flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ)
- && (req->request_id != flush_req->req_id))
- continue;
-
+ if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) {
+ if (req->request_id != flush_req->req_id) {
+ continue;
+ } else {
+ list_del_init(&req->list);
+ list_add_tail(&req->list, &flush_list);
+ cancel_req_id_found = 1;
+ break;
+ }
+ }
list_del_init(&req->list);
+ list_add_tail(&req->list, &flush_list);
+ }
+ spin_unlock_bh(&ctx->lock);
+
+ list_for_each_entry_safe(req, req_temp, &flush_list, list) {
req_isp = (struct cam_isp_ctx_req *) req->req_priv;
for (i = 0; i < req_isp->num_fence_map_out; i++) {
if (req_isp->fence_map_out[i].sync_id != -1) {
@@ -1174,15 +1188,10 @@
req_isp->fence_map_out[i].sync_id = -1;
}
}
+ spin_lock_bh(&ctx->lock);
list_add_tail(&req->list, &ctx->free_req_list);
-
- /* If flush request id found, exit the loop */
- if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) {
- cancel_req_id_found = 1;
- break;
- }
+ spin_unlock_bh(&ctx->lock);
}
- spin_unlock_bh(&ctx->lock);
if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ &&
!cancel_req_id_found)
@@ -2172,6 +2181,7 @@
}
arg.ctxt_to_hw_map = ctx_isp->hw_ctx;
+ arg.request_id = req->request_id;
arg.hw_update_entries = req_isp->cfg;
arg.num_hw_update_entries = req_isp->num_cfg;
arg.priv = &req_isp->hw_update_data;
@@ -2215,7 +2225,7 @@
}
static int __cam_isp_ctx_stop_dev_in_activated_unlock(
- struct cam_context *ctx)
+ struct cam_context *ctx, struct cam_start_stop_dev_cmd *stop_cmd)
{
int rc = 0;
uint32_t i;
@@ -2234,6 +2244,7 @@
/* stop hw first */
if (ctx_isp->hw_ctx) {
stop.ctxt_to_hw_map = ctx_isp->hw_ctx;
+ stop.args = stop_cmd;
ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv,
&stop);
}
@@ -2282,7 +2293,7 @@
{
int rc = 0;
- __cam_isp_ctx_stop_dev_in_activated_unlock(ctx);
+ __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, cmd);
ctx->state = CAM_CTX_ACQUIRED;
trace_cam_context_state("ISP", ctx);
return rc;
@@ -2293,7 +2304,7 @@
{
int rc = 0;
- rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx);
+ rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, NULL);
if (rc)
CAM_ERR(CAM_ISP, "Stop device failed rc=%d", rc);
@@ -2363,7 +2374,8 @@
CAM_WARN(CAM_ISP,
"Received unlink in activated state. It's unexpected");
- rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx);
+
+ rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, NULL);
if (rc)
CAM_WARN(CAM_ISP, "Stop device failed rc=%d", rc);
@@ -2498,7 +2510,8 @@
int cam_isp_context_init(struct cam_isp_context *ctx,
struct cam_context *ctx_base,
struct cam_req_mgr_kmd_ops *crm_node_intf,
- struct cam_hw_mgr_intf *hw_intf)
+ struct cam_hw_mgr_intf *hw_intf,
+ uint32_t ctx_id)
{
int rc = -1;
@@ -2527,8 +2540,8 @@
}
/* camera context setup */
- rc = cam_context_init(ctx_base, isp_dev_name, crm_node_intf, hw_intf,
- ctx->req_base, CAM_CTX_REQ_MAX);
+ rc = cam_context_init(ctx_base, isp_dev_name, CAM_ISP, ctx_id,
+ crm_node_intf, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX);
if (rc) {
CAM_ERR(CAM_ISP, "Camera Context Base init failed");
goto err;
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 f1f3137d..38ea58d 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
@@ -148,12 +148,14 @@
* @ctx: ISP context obj to be initialized
* @bridge_ops: Bridge call back funciton
* @hw_intf: ISP hw manager interface
+ * @ctx_id: ID for this context
*
*/
int cam_isp_context_init(struct cam_isp_context *ctx,
struct cam_context *ctx_base,
struct cam_req_mgr_kmd_ops *bridge_ops,
- struct cam_hw_mgr_intf *hw_intf);
+ struct cam_hw_mgr_intf *hw_intf,
+ uint32_t ctx_id);
/**
* cam_isp_context_deinit()
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c
index bcdba05..e775daa 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -104,7 +104,8 @@
rc = cam_isp_context_init(&g_isp_dev.ctx_isp[i],
&g_isp_dev.ctx[i],
&node->crm_node_intf,
- &node->hw_mgr_intf);
+ &node->hw_mgr_intf,
+ i);
if (rc) {
CAM_ERR(CAM_ISP, "ISP context init failed!");
goto unregister;
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 a6f1cf5..4628172 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
@@ -242,6 +242,7 @@
{
int i;
struct cam_hw_intf *hw_intf;
+ uint32_t dummy_args;
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!isp_hw_res->hw_res[i])
@@ -253,6 +254,12 @@
sizeof(struct cam_isp_resource_node));
else
CAM_ERR(CAM_ISP, "stop null");
+ if (hw_intf->hw_ops.process_cmd &&
+ isp_hw_res->res_type == CAM_IFE_HW_MGR_RES_IFE_OUT) {
+ hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
+ CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ,
+ &dummy_args, sizeof(dummy_args));
+ }
}
}
@@ -1089,7 +1096,7 @@
struct cam_ife_hw_mgr_res *cid_res;
struct cam_hw_intf *hw_intf;
struct cam_isp_out_port_info *out_port;
- uint32_t cid_res_id;
+ uint32_t cid_res_id;
struct cam_csid_hw_reserve_resource_args csid_acquire;
ife_hw_mgr = ife_ctx->hw_mgr;
@@ -1099,13 +1106,15 @@
if (!cam_ife_hw_mgr_is_rdi_res(out_port->res_type))
continue;
- /* get cid resource */
- rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res_id,
- cam_ife_hw_mgr_get_ife_csid_rdi_res_type(
- out_port->res_type));
- if (rc) {
- CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
- goto err;
+ /* get cid resource */
+ rc = cam_ife_mgr_acquire_cid_res(ife_ctx,
+ in_port, &cid_res_id,
+ cam_ife_hw_mgr_get_ife_csid_rdi_res_type(
+ out_port->res_type));
+ if (rc) {
+ CAM_ERR(CAM_ISP,
+ "Acquire IFE CID resource Failed");
+ goto err;
}
rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list,
@@ -1308,11 +1317,27 @@
}
void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata,
- enum cam_cdm_cb_status status, uint32_t cookie)
+ enum cam_cdm_cb_status status, uint64_t cookie)
{
- CAM_DBG(CAM_ISP,
- "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%d",
- handle, userdata, status, cookie);
+ struct cam_ife_hw_mgr_ctx *ctx = NULL;
+
+ if (!userdata) {
+ CAM_ERR(CAM_ISP, "Invalid args");
+ return;
+ }
+
+ ctx = userdata;
+
+ if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) {
+ complete(&ctx->config_done_complete);
+ CAM_DBG(CAM_ISP,
+ "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu",
+ handle, userdata, status, cookie);
+ } else {
+ CAM_WARN(CAM_ISP,
+ "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu",
+ handle, userdata, status, cookie);
+ }
}
/* entry function: acquire_hw */
@@ -1575,9 +1600,9 @@
cdm_cmd = ctx->cdm_cmd;
cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries;
cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE;
- cdm_cmd->flag = false;
- cdm_cmd->userdata = NULL;
- cdm_cmd->cookie = 0;
+ cdm_cmd->flag = true;
+ cdm_cmd->userdata = ctx;
+ cdm_cmd->cookie = cfg->request_id;
for (i = 0 ; i <= cfg->num_hw_update_entries; i++) {
cmd = (cfg->hw_update_entries + i);
@@ -1588,8 +1613,31 @@
CAM_DBG(CAM_ISP, "Submit to CDM");
rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd);
- if (rc)
+ if (rc) {
CAM_ERR(CAM_ISP, "Failed to apply the configs");
+ return rc;
+ }
+
+ if (cfg->request_id == 1) {
+ init_completion(&ctx->config_done_complete);
+ rc = wait_for_completion_timeout(
+ &ctx->config_done_complete,
+ msecs_to_jiffies(30));
+ if (rc <= 0) {
+ CAM_ERR(CAM_ISP,
+ "config done completion timeout for req_id=%llu rc = %d",
+ cfg->request_id, rc);
+ if (rc == 0)
+ rc = -ETIMEDOUT;
+ } else {
+ rc = 0;
+ CAM_DBG(CAM_ISP,
+ "config done Success for req_id=%llu",
+ cfg->request_id);
+ }
+
+ rc = 0;
+ }
} else {
CAM_ERR(CAM_ISP, "No commands to config");
}
@@ -1679,6 +1727,48 @@
return rc;
}
+static int cam_ife_mgr_bw_control(struct cam_ife_hw_mgr_ctx *ctx,
+ enum cam_vfe_bw_control_action action)
+{
+ struct cam_ife_hw_mgr_res *hw_mgr_res;
+ struct cam_hw_intf *hw_intf;
+ struct cam_vfe_bw_control_args bw_ctrl_args;
+ int rc = -EINVAL;
+ uint32_t i;
+
+ CAM_DBG(CAM_ISP, "Enter...ctx id:%d", ctx->ctx_index);
+
+ list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
+ for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+ if (!hw_mgr_res->hw_res[i])
+ continue;
+
+ hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+ if (hw_intf && hw_intf->hw_ops.process_cmd) {
+ bw_ctrl_args.node_res =
+ hw_mgr_res->hw_res[i];
+ bw_ctrl_args.action = action;
+
+ rc = hw_intf->hw_ops.process_cmd(
+ hw_intf->hw_priv,
+ CAM_ISP_HW_CMD_BW_CONTROL,
+ &bw_ctrl_args,
+ sizeof(struct cam_vfe_bw_control_args));
+ if (rc)
+ CAM_ERR(CAM_ISP, "BW Update failed");
+ } else
+ CAM_WARN(CAM_ISP, "NULL hw_intf!");
+ }
+ }
+
+ return rc;
+}
+
+static int cam_ife_mgr_pause_hw(struct cam_ife_hw_mgr_ctx *ctx)
+{
+ return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_EXCLUDE);
+}
+
/* entry function: stop_hw */
static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
{
@@ -1686,6 +1776,7 @@
struct cam_hw_stop_args *stop_args = stop_hw_args;
struct cam_ife_hw_mgr_res *hw_mgr_res;
struct cam_ife_hw_mgr_ctx *ctx;
+ enum cam_ife_csid_halt_cmd csid_halt_type;
uint32_t i, master_base_idx = 0;
if (!hw_mgr_priv || !stop_hw_args) {
@@ -1698,8 +1789,13 @@
return -EPERM;
}
- CAM_DBG(CAM_ISP, " Enter...ctx id:%d",
- ctx->ctx_index);
+ CAM_DBG(CAM_ISP, " Enter...ctx id:%d", ctx->ctx_index);
+
+ /* Set the csid halt command */
+ if (!stop_args->args)
+ csid_halt_type = CAM_CSID_HALT_IMMEDIATELY;
+ else
+ csid_halt_type = CAM_CSID_HALT_AT_FRAME_BOUNDARY;
/* Note:stop resource will remove the irq mask from the hardware */
@@ -1708,6 +1804,25 @@
return -EINVAL;
}
+ CAM_DBG(CAM_ISP, "Halting CSIDs");
+
+ if (cam_cdm_stream_off(ctx->cdm_handle))
+ CAM_ERR(CAM_ISP, "CDM stream off failed %d",
+ ctx->cdm_handle);
+ cam_tasklet_stop(ctx->common.tasklet_info);
+
+ CAM_DBG(CAM_ISP, "Going to stop IFE Mux");
+
+ /* IFE mux in resources */
+ list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
+ cam_ife_hw_mgr_stop_hw_res(hw_mgr_res);
+ }
+
+ CAM_DBG(CAM_ISP, "Going to stop IFE Out");
+
+ /* IFE out resources */
+ for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++)
+ cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]);
/* get master base index first */
for (i = 0; i < ctx->num_base; i++) {
if (ctx->base[i].split_id == CAM_ISP_HW_SPLIT_LEFT) {
@@ -1723,9 +1838,21 @@
if (i == ctx->num_base)
master_base_idx = ctx->base[0].idx;
+ /* Stop the master CIDs first */
+ cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
+ master_base_idx, csid_halt_type);
+
+ /* stop rest of the CIDs */
+ for (i = 0; i < ctx->num_base; i++) {
+ if (i == master_base_idx)
+ continue;
+ cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
+ ctx->base[i].idx, csid_halt_type);
+ }
+
/* Stop the master CSID path first */
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
- master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+ master_base_idx, csid_halt_type);
/* stop rest of the CSID paths */
for (i = 0; i < ctx->num_base; i++) {
@@ -1733,47 +1860,19 @@
continue;
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
- ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+ ctx->base[i].idx, csid_halt_type);
}
- /* Stop the master CIDs first */
- cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
- master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
-
- /* stop rest of the CIDs */
- for (i = 0; i < ctx->num_base; i++) {
- if (i == master_base_idx)
- continue;
- cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
- ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
- }
-
- if (cam_cdm_stream_off(ctx->cdm_handle))
- CAM_ERR(CAM_ISP, "CDM stream off failed %d",
- ctx->cdm_handle);
-
- /* IFE mux in resources */
- list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
- cam_ife_hw_mgr_stop_hw_res(hw_mgr_res);
- }
-
- /* IFE out resources */
- for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++)
- cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]);
-
- /* Update vote bandwidth should be done at the HW layer */
-
- cam_tasklet_stop(ctx->common.tasklet_info);
-
- /* Deinit IFE root node: do nothing */
/* Deinit IFE CID */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) {
+ CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CID\n", __func__);
cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res);
}
/* Deinit IFE CSID */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
+ CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CSID\n", __func__);
cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res);
}
@@ -1900,6 +1999,8 @@
{
int rc = -1;
struct cam_hw_config_args *start_args = start_hw_args;
+ struct cam_hw_stop_args stop_args;
+ struct cam_isp_stop_hw_method stop_hw_method;
struct cam_ife_hw_mgr_ctx *ctx;
struct cam_ife_hw_mgr_res *hw_mgr_res;
uint32_t i;
@@ -2065,7 +2166,10 @@
CAM_DBG(CAM_ISP, "Exit...(success)");
return 0;
err:
- cam_ife_mgr_stop_hw(hw_mgr_priv, start_hw_args);
+ stop_hw_method.hw_stop_cmd = CAM_CSID_HALT_IMMEDIATELY;
+ stop_args.ctxt_to_hw_map = start_args->ctxt_to_hw_map;
+ stop_args.args = (void *)(&stop_hw_method);
+ cam_ife_mgr_stop_hw(hw_mgr_priv, &stop_args);
CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc);
return rc;
}
@@ -2522,48 +2626,6 @@
return rc;
}
-static int cam_ife_mgr_bw_control(struct cam_ife_hw_mgr_ctx *ctx,
- enum cam_vfe_bw_control_action action)
-{
- struct cam_ife_hw_mgr_res *hw_mgr_res;
- struct cam_hw_intf *hw_intf;
- struct cam_vfe_bw_control_args bw_ctrl_args;
- int rc = -EINVAL;
- uint32_t i;
-
- CAM_DBG(CAM_ISP, "Enter...ctx id:%d", ctx->ctx_index);
-
- list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
- for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
- if (!hw_mgr_res->hw_res[i])
- continue;
-
- hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
- if (hw_intf && hw_intf->hw_ops.process_cmd) {
- bw_ctrl_args.node_res =
- hw_mgr_res->hw_res[i];
- bw_ctrl_args.action = action;
-
- rc = hw_intf->hw_ops.process_cmd(
- hw_intf->hw_priv,
- CAM_ISP_HW_CMD_BW_CONTROL,
- &bw_ctrl_args,
- sizeof(struct cam_vfe_bw_control_args));
- if (rc)
- CAM_ERR(CAM_ISP, "BW Update failed");
- } else
- CAM_WARN(CAM_ISP, "NULL hw_intf!");
- }
- }
-
- return rc;
-}
-
-static int cam_ife_mgr_pause_hw(struct cam_ife_hw_mgr_ctx *ctx)
-{
- return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_EXCLUDE);
-}
-
static int cam_ife_mgr_resume_hw(struct cam_ife_hw_mgr_ctx *ctx)
{
return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_INCLUDE);
@@ -2989,7 +3051,7 @@
void *handler_priv,
void *payload)
{
- int32_t error_status = CAM_ISP_HW_ERROR_NONE;
+ int32_t error_status;
uint32_t core_idx;
struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx;
struct cam_vfe_top_irq_evt_payload *evt_payload;
@@ -3010,15 +3072,15 @@
case CAM_ISP_HW_ERROR_OVERFLOW:
case CAM_ISP_HW_ERROR_P2I_ERROR:
case CAM_ISP_HW_ERROR_VIOLATION:
- CAM_DBG(CAM_ISP, "Enter: error_type (%d)", error_status);
+ CAM_ERR(CAM_ISP, "Enter: error_type (%d)", error_status);
error_event_data.error_type =
CAM_ISP_HW_ERROR_OVERFLOW;
cam_ife_hw_mgr_process_overflow(ife_hwr_mgr_ctx,
- &error_event_data,
- core_idx,
- &recovery_data);
+ &error_event_data,
+ core_idx,
+ &recovery_data);
/* Trigger for recovery */
recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW;
@@ -3028,7 +3090,7 @@
CAM_DBG(CAM_ISP, "None error (%d)", error_status);
}
- return error_status;
+ return 0;
}
/*
@@ -3093,6 +3155,15 @@
rup_status = hw_res->bottom_half_handler(
hw_res, evt_payload);
}
+
+ if (ife_src_res->is_dual_vfe) {
+ hw_res = ife_src_res->hw_res[0];
+ if (core_idx == hw_res->hw_intf->hw_idx) {
+ hw_res->bottom_half_handler(
+ hw_res, evt_payload);
+ }
+ }
+
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
break;
@@ -3108,13 +3179,6 @@
case CAM_ISP_HW_VFE_IN_RDI1:
case CAM_ISP_HW_VFE_IN_RDI2:
case CAM_ISP_HW_VFE_IN_RDI3:
- if (!ife_hwr_mgr_ctx->is_rdi_only_context)
- continue;
-
- /*
- * This is RDI only context, send Reg update and epoch
- * HW event to cam context
- */
hw_res = ife_src_res->hw_res[0];
if (!hw_res) {
@@ -3126,6 +3190,9 @@
rup_status = hw_res->bottom_half_handler(
hw_res, evt_payload);
+ if (!ife_hwr_mgr_ctx->is_rdi_only_context)
+ continue;
+
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
break;
if (!rup_status) {
@@ -3187,7 +3254,7 @@
(event_cnt[core_idx1] &&
(event_cnt[core_idx1] - event_cnt[core_idx0] > 1))) {
- CAM_WARN(CAM_ISP,
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
"One of the VFE cound not generate hw event %d",
hw_event_type);
rc = -1;
@@ -3327,8 +3394,6 @@
struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx,
struct cam_vfe_top_irq_evt_payload *evt_payload)
{
- struct cam_isp_hw_sof_event_data sof_done_event_data;
- cam_hw_event_cb_func ife_hwr_irq_sof_cb;
struct cam_isp_resource_node *hw_res_l = NULL;
struct cam_isp_resource_node *hw_res_r = NULL;
int32_t rc = -EINVAL;
@@ -3344,9 +3409,6 @@
CAM_DBG(CAM_ISP, "is_dual_vfe ? = %d",
isp_ife_camif_res->is_dual_vfe);
- ife_hwr_irq_sof_cb =
- ife_hwr_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_SOF];
-
switch (isp_ife_camif_res->is_dual_vfe) {
/* Handling Single VFE Scenario */
case 0:
@@ -3363,16 +3425,8 @@
evt_payload);
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
break;
- 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);
- }
+ if (!sof_status)
+ rc = 0;
}
break;
@@ -3424,15 +3478,6 @@
rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hwr_mgr_ctx,
core_index0, core_index1, evt_payload->evt_id);
- 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:
@@ -3442,14 +3487,13 @@
CAM_DBG(CAM_ISP, "Exit (sof_status = %d)", sof_status);
- return 0;
+ return rc;
}
static int cam_ife_hw_mgr_handle_sof(
void *handler_priv,
void *payload)
{
- int32_t rc = -EINVAL;
struct cam_isp_resource_node *hw_res = NULL;
struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx;
struct cam_vfe_top_irq_evt_payload *evt_payload;
@@ -3457,6 +3501,7 @@
cam_hw_event_cb_func ife_hw_irq_sof_cb;
struct cam_isp_hw_sof_event_data sof_done_event_data;
uint32_t sof_status = 0;
+ bool sof_sent = false;
CAM_DBG(CAM_ISP, "Enter");
@@ -3482,13 +3527,13 @@
case CAM_ISP_HW_VFE_IN_RDI1:
case CAM_ISP_HW_VFE_IN_RDI2:
case CAM_ISP_HW_VFE_IN_RDI3:
+ hw_res = ife_src_res->hw_res[0];
+ sof_status = hw_res->bottom_half_handler(
+ hw_res, evt_payload);
+
/* check if it is rdi only context */
if (ife_hw_mgr_ctx->is_rdi_only_context) {
- hw_res = ife_src_res->hw_res[0];
- sof_status = hw_res->bottom_half_handler(
- hw_res, evt_payload);
-
- if (!sof_status) {
+ if (!sof_status && !sof_sent) {
cam_ife_mgr_cmd_get_sof_timestamp(
ife_hw_mgr_ctx,
&sof_done_event_data.timestamp);
@@ -3499,16 +3544,30 @@
&sof_done_event_data);
CAM_DBG(CAM_ISP, "sof_status = %d",
sof_status);
+
+ sof_sent = true;
}
- /* this is RDI only context so exit from here */
- return 0;
}
break;
case CAM_ISP_HW_VFE_IN_CAMIF:
- rc = cam_ife_hw_mgr_process_camif_sof(ife_src_res,
- ife_hw_mgr_ctx, evt_payload);
+ sof_status = cam_ife_hw_mgr_process_camif_sof(
+ ife_src_res, ife_hw_mgr_ctx, evt_payload);
+ if (!sof_status && !sof_sent) {
+ cam_ife_mgr_cmd_get_sof_timestamp(
+ ife_hw_mgr_ctx,
+ &sof_done_event_data.timestamp);
+
+ ife_hw_irq_sof_cb(
+ ife_hw_mgr_ctx->common.cb_priv,
+ CAM_ISP_HW_EVENT_SOF,
+ &sof_done_event_data);
+ CAM_DBG(CAM_ISP, "sof_status = %d",
+ sof_status);
+
+ sof_sent = true;
+ }
break;
default:
CAM_ERR(CAM_ISP, "Invalid resource id :%d",
@@ -3825,7 +3884,7 @@
evt_payload = evt_payload_priv;
if (!handler_priv)
- goto put_payload;
+ return rc;
ife_hwr_mgr_ctx = (struct cam_ife_hw_mgr_ctx *)handler_priv;
@@ -3844,8 +3903,8 @@
*/
if (g_ife_hw_mgr.debug_cfg.enable_recovery) {
CAM_DBG(CAM_ISP, "IFE Mgr recovery is enabled");
- rc = cam_ife_hw_mgr_handle_camif_error(ife_hwr_mgr_ctx,
- evt_payload_priv);
+ rc = cam_ife_hw_mgr_handle_camif_error(ife_hwr_mgr_ctx,
+ evt_payload_priv);
} else {
CAM_DBG(CAM_ISP, "recovery is not enabled");
rc = 0;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
index c418a41..0e678b4 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
@@ -13,6 +13,7 @@
#ifndef _CAM_IFE_HW_MGR_H_
#define _CAM_IFE_HW_MGR_H_
+#include <linux/completion.h>
#include "cam_isp_hw_mgr.h"
#include "cam_vfe_hw_intf.h"
#include "cam_ife_csid_hw_intf.h"
@@ -121,6 +122,7 @@
* @overflow_pending flat to specify the overflow is pending for the
* context
* @is_rdi_only_context flag to specify the context has only rdi resource
+ * @config_done_complete indicator for configuration complete
*/
struct cam_ife_hw_mgr_ctx {
struct list_head list;
@@ -153,6 +155,7 @@
uint32_t eof_cnt[CAM_IFE_HW_NUM_MAX];
atomic_t overflow_pending;
uint32_t is_rdi_only_context;
+ struct completion config_done_complete;
};
/**
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 b632e77..24df4ce 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -431,11 +431,17 @@
irq_mask = cam_io_r_mb(controller->mem_base +
controller->irq_register_arr[i].
mask_reg_offset);
+ CAM_DBG(CAM_ISP, "irq_mask 0x%x before disable 0x%x",
+ controller->irq_register_arr[i].mask_reg_offset,
+ irq_mask);
irq_mask &= ~(evt_handler->evt_bit_mask_arr[i]);
cam_io_w_mb(irq_mask, controller->mem_base +
controller->irq_register_arr[i].
mask_reg_offset);
+ CAM_DBG(CAM_ISP, "irq_mask 0x%x after disable 0x%x",
+ controller->irq_register_arr[i].mask_reg_offset,
+ irq_mask);
/* Clear the IRQ bits of this handler */
cam_io_w_mb(evt_handler->evt_bit_mask_arr[i],
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 78336d2..2601190 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
@@ -51,6 +51,25 @@
};
/**
+ * enum cam_isp_hw_stop_cmd - Specify the stop command type
+ */
+enum cam_isp_hw_stop_cmd {
+ CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY,
+ CAM_ISP_HW_STOP_IMMEDIATELY,
+ CAM_ISP_HW_STOP_MAX,
+};
+
+/**
+ * struct cam_isp_stop_hw_method - hardware stop method
+ *
+ * @hw_stop_cmd: Hardware stop command type information
+ *
+ */
+struct cam_isp_stop_hw_method {
+ enum cam_isp_hw_stop_cmd hw_stop_cmd;
+};
+
+/**
* struct cam_isp_bw_config_internal - Internal Bandwidth configuration
*
* @usage_type: Usage type (Single/Dual)
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 ff0c91f..328aaaf 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
@@ -30,7 +30,7 @@
/* Timeout values in usec */
#define CAM_IFE_CSID_TIMEOUT_SLEEP_US 1000
-#define CAM_IFE_CSID_TIMEOUT_ALL_US 1000000
+#define CAM_IFE_CSID_TIMEOUT_ALL_US 100000
/*
* Constant Factors needed to change QTimer ticks to nanoseconds
@@ -355,8 +355,7 @@
struct cam_hw_soc_info *soc_info;
struct cam_ife_csid_reg_offset *csid_reg;
int rc = 0;
- uint32_t i, irq_mask_rx, irq_mask_ipp = 0,
- irq_mask_rdi[CAM_IFE_CSID_RDI_MAX];
+ uint32_t val = 0, i;
soc_info = &csid_hw->hw_info->soc_info;
csid_reg = csid_hw->csid_info->csid_reg;
@@ -373,19 +372,6 @@
init_completion(&csid_hw->csid_top_complete);
- /* Save interrupt mask registers values*/
- irq_mask_rx = cam_io_r_mb(soc_info->reg_map[0].mem_base +
- csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr);
-
- if (csid_reg->cmn_reg->no_pix)
- irq_mask_ipp = cam_io_r_mb(soc_info->reg_map[0].mem_base +
- csid_reg->ipp_reg->csid_ipp_irq_mask_addr);
-
- for (i = 0; i < csid_reg->cmn_reg->no_rdis; i++) {
- irq_mask_rdi[i] = cam_io_r_mb(soc_info->reg_map[0].mem_base +
- csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr);
- }
-
/* Mask all interrupts */
cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr);
@@ -448,17 +434,11 @@
rc = 0;
}
- /*restore all interrupt masks */
- cam_io_w_mb(irq_mask_rx, soc_info->reg_map[0].mem_base +
+ val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr);
-
- if (csid_reg->cmn_reg->no_pix)
- cam_io_w_mb(irq_mask_ipp, soc_info->reg_map[0].mem_base +
- csid_reg->ipp_reg->csid_ipp_irq_mask_addr);
-
- for (i = 0; i < csid_reg->cmn_reg->no_rdis; i++)
- cam_io_w_mb(irq_mask_rdi[i], soc_info->reg_map[0].mem_base +
- csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr);
+ if (val != 0)
+ CAM_ERR(CAM_ISP, "CSID:%d IRQ value after reset rc = %d",
+ csid_hw->hw_intf->hw_idx, val);
return rc;
}
@@ -1037,20 +1017,31 @@
static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw)
{
- int rc = 0;
+ int rc = -EINVAL;
struct cam_hw_soc_info *soc_info;
struct cam_ife_csid_reg_offset *csid_reg;
+ /* Check for refcount */
+ if (!csid_hw->hw_info->open_count) {
+ CAM_WARN(CAM_ISP, "Unbalanced disable_hw");
+ return rc;
+ }
/* Decrement ref Count */
- if (csid_hw->hw_info->open_count)
- csid_hw->hw_info->open_count--;
- if (csid_hw->hw_info->open_count)
+ csid_hw->hw_info->open_count--;
+
+ if (csid_hw->hw_info->open_count) {
+ rc = 0;
return rc;
+ }
soc_info = &csid_hw->hw_info->soc_info;
csid_reg = csid_hw->csid_info->csid_reg;
+ CAM_DBG(CAM_ISP, "%s:Calling Global Reset\n", __func__);
+ cam_ife_csid_global_reset(csid_hw);
+ CAM_DBG(CAM_ISP, "%s:Global Reset Done\n", __func__);
+
CAM_DBG(CAM_ISP, "CSID:%d De-init CSID HW",
csid_hw->hw_intf->hw_idx);
@@ -1509,7 +1500,6 @@
struct cam_isp_resource_node *res)
{
int rc = 0;
- uint32_t val = 0;
struct cam_ife_csid_reg_offset *csid_reg;
struct cam_hw_soc_info *soc_info;
@@ -1531,13 +1521,6 @@
rc = -EINVAL;
}
- /* Disable the IPP path */
- val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
- csid_reg->ipp_reg->csid_ipp_cfg0_addr);
- val &= ~(1 << csid_reg->cmn_reg->path_en_shift_val);
- cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
- csid_reg->ipp_reg->csid_ipp_cfg0_addr);
-
res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
return rc;
}
@@ -1608,7 +1591,6 @@
enum cam_ife_csid_halt_cmd stop_cmd)
{
int rc = 0;
- uint32_t val = 0;
struct cam_ife_csid_reg_offset *csid_reg;
struct cam_hw_soc_info *soc_info;
struct cam_ife_csid_path_cfg *path_data;
@@ -1654,19 +1636,8 @@
CAM_DBG(CAM_ISP, "CSID:%d res_id:%d",
csid_hw->hw_intf->hw_idx, res->res_id);
- if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER) {
- /* configure Halt */
- val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
- csid_reg->ipp_reg->csid_ipp_ctrl_addr);
- val &= ~0x3;
- val |= stop_cmd;
- cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
- csid_reg->ipp_reg->csid_ipp_ctrl_addr);
- } else if (path_data->sync_mode == CAM_ISP_HW_SYNC_NONE)
- cam_io_w_mb(stop_cmd, soc_info->reg_map[0].mem_base +
- csid_reg->ipp_reg->csid_ipp_ctrl_addr);
-
- /* For slave mode, halt command should take it from master */
+ cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
+ csid_reg->ipp_reg->csid_ipp_irq_mask_addr);
return rc;
}
@@ -1808,7 +1779,7 @@
struct cam_isp_resource_node *res)
{
int rc = 0;
- uint32_t val = 0, id;
+ uint32_t id;
struct cam_ife_csid_reg_offset *csid_reg;
struct cam_hw_soc_info *soc_info;
@@ -1825,13 +1796,6 @@
return -EINVAL;
}
- /* Disable the RDI path */
- val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
- csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr);
- val &= ~(1 << csid_reg->cmn_reg->path_en_shift_val);
- cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
- csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr);
-
res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
return rc;
}
@@ -1928,9 +1892,8 @@
CAM_DBG(CAM_ISP, "CSID:%d res_id:%d",
csid_hw->hw_intf->hw_idx, res->res_id);
- /*Halt the RDI path */
- cam_io_w_mb(stop_cmd, soc_info->reg_map[0].mem_base +
- csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr);
+ cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
+ csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr);
return rc;
}
@@ -2007,79 +1970,6 @@
return 0;
}
-static int cam_ife_csid_res_wait_for_halt(
- struct cam_ife_csid_hw *csid_hw,
- struct cam_isp_resource_node *res)
-{
- int rc = 0;
- uint32_t val = 0, id, status, path_status_reg;
- struct cam_ife_csid_reg_offset *csid_reg;
- struct cam_hw_soc_info *soc_info;
-
- csid_reg = csid_hw->csid_info->csid_reg;
- soc_info = &csid_hw->hw_info->soc_info;
-
- if (res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) {
- CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d Invalid res id%d",
- csid_hw->hw_intf->hw_idx, res->res_id);
- return -EINVAL;
- }
-
- if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW ||
- res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) {
- CAM_ERR_RATE_LIMIT(CAM_ISP,
- "CSID:%d Res:%d already in stopped state:%d",
- csid_hw->hw_intf->hw_idx,
- res->res_id, res->res_state);
- return rc;
- }
-
- if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) {
- CAM_ERR_RATE_LIMIT(CAM_ISP,
- "CSID:%d Res:%d Invalid state%d",
- csid_hw->hw_intf->hw_idx, res->res_id,
- res->res_state);
- return -EINVAL;
- }
-
- if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP)
- path_status_reg = csid_reg->ipp_reg->csid_ipp_status_addr;
- else
- path_status_reg = csid_reg->rdi_reg[res->res_id]->
- csid_rdi_status_addr;
-
- rc = readl_poll_timeout(soc_info->reg_map[0].mem_base +
- path_status_reg, status,
- (status == 1),
- CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US);
- if (rc < 0) {
- CAM_ERR(CAM_ISP, "Time out: Res id:%d Path has not halted",
- res->res_id);
- rc = -ETIMEDOUT;
- }
-
- /* Disable the interrupt */
- if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) {
- val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
- csid_reg->ipp_reg->csid_ipp_irq_mask_addr);
- val &= ~(CSID_PATH_INFO_INPUT_EOF | CSID_PATH_INFO_RST_DONE |
- CSID_PATH_ERROR_FIFO_OVERFLOW);
- cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
- csid_reg->ipp_reg->csid_ipp_irq_mask_addr);
- } else {
- id = res->res_id;
- val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
- csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr);
- val &= ~(CSID_PATH_INFO_INPUT_EOF | CSID_PATH_INFO_RST_DONE |
- CSID_PATH_ERROR_FIFO_OVERFLOW);
- cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
- csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr);
- }
- /* set state to init HW */
- res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
- return rc;
-}
-
static int cam_ife_csid_get_hw_caps(void *hw_priv,
void *get_hw_cap_args, uint32_t arg_size)
{
@@ -2300,7 +2190,6 @@
return rc;
}
-
static int cam_ife_csid_init_hw(void *hw_priv,
void *init_args, uint32_t arg_size)
{
@@ -2372,7 +2261,6 @@
rc = cam_ife_csid_reset_retain_sw_reg(csid_hw);
if (rc < 0) {
CAM_ERR(CAM_ISP, "CSID: Failed in SW reset");
- return rc;
}
if (rc)
@@ -2396,6 +2284,7 @@
return -EINVAL;
}
+ CAM_DBG(CAM_ISP, "Enter");
res = (struct cam_isp_resource_node *)deinit_args;
csid_hw_info = (struct cam_hw_info *)hw_priv;
csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info;
@@ -2410,9 +2299,11 @@
switch (res->res_type) {
case CAM_ISP_RESOURCE_CID:
+ CAM_DBG(CAM_ISP, "De-Init ife_csid");
rc = cam_ife_csid_disable_csi2(csid_hw, res);
break;
case CAM_ISP_RESOURCE_PIX_PATH:
+ CAM_DBG(CAM_ISP, "De-Init Pix Path: %d\n", res->res_id);
if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP)
rc = cam_ife_csid_deinit_ipp_path(csid_hw, res);
else
@@ -2427,7 +2318,9 @@
}
/* Disable CSID HW */
+ CAM_DBG(CAM_ISP, "Disabling CSID Hw\n");
cam_ife_csid_disable_hw(csid_hw);
+ CAM_DBG(CAM_ISP, "%s: Exit\n", __func__);
end:
mutex_unlock(&csid_hw->hw_info->hw_mutex);
@@ -2533,15 +2426,13 @@
}
}
- /*wait for the path to halt */
for (i = 0; i < csid_stop->num_res; i++) {
res = csid_stop->node_res[i];
- if (csid_stop->stop_cmd == CAM_CSID_HALT_AT_FRAME_BOUNDARY)
- rc = cam_ife_csid_res_wait_for_halt(csid_hw, res);
- else
- res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
+ res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
}
+ CAM_DBG(CAM_ISP, "%s: Exit\n", __func__);
+
return rc;
}
@@ -2594,35 +2485,8 @@
}
-static int cam_ife_csid_halt_device(
- struct cam_ife_csid_hw *csid_hw)
-{
- uint32_t i;
- int rc = 0;
- struct cam_isp_resource_node *res_node;
-
- res_node = &csid_hw->ipp_res;
- if (res_node->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) {
- rc = cam_ife_csid_disable_ipp_path(csid_hw,
- res_node, CAM_CSID_HALT_IMMEDIATELY);
- res_node->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
- }
-
- for (i = 0; i < CAM_IFE_CSID_RDI_MAX; i++) {
- res_node = &csid_hw->rdi_res[i];
- if (res_node->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) {
- rc = cam_ife_csid_disable_rdi_path(csid_hw,
- res_node, CAM_CSID_HALT_IMMEDIATELY);
- res_node->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
- }
- }
- return rc;
-}
-
-
irqreturn_t cam_ife_csid_irq(int irq_num, void *data)
{
- int rc = 0;
struct cam_ife_csid_hw *csid_hw;
struct cam_hw_soc_info *soc_info;
struct cam_ife_csid_reg_offset *csid_reg;
@@ -2696,52 +2560,22 @@
if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 0 over flow",
csid_hw->hw_intf->hw_idx);
- rc = cam_ife_csid_halt_device(csid_hw);
- if (rc) {
- CAM_ERR_RATE_LIMIT(CAM_ISP,
- "CSID:%d csid halt device fail rc = %d",
- csid_hw->hw_intf->hw_idx, rc);
- }
}
if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow",
csid_hw->hw_intf->hw_idx);
- rc = cam_ife_csid_halt_device(csid_hw);
- if (rc) {
- CAM_ERR_RATE_LIMIT(CAM_ISP,
- "CSID:%d csid halt device fail rc = %d",
- csid_hw->hw_intf->hw_idx, rc);
- }
}
if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow",
csid_hw->hw_intf->hw_idx);
- rc = cam_ife_csid_halt_device(csid_hw);
- if (rc) {
- CAM_ERR_RATE_LIMIT(CAM_ISP,
- "CSID:%d csid halt device fail rc = %d",
- csid_hw->hw_intf->hw_idx, rc);
- }
}
if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow",
csid_hw->hw_intf->hw_idx);
- rc = cam_ife_csid_halt_device(csid_hw);
- if (rc) {
- CAM_ERR_RATE_LIMIT(CAM_ISP,
- "CSID:%d csid halt device fail rc = %d",
- csid_hw->hw_intf->hw_idx, rc);
- }
}
if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER FLOW",
csid_hw->hw_intf->hw_idx);
- rc = cam_ife_csid_halt_device(csid_hw);
- if (rc) {
- CAM_ERR_RATE_LIMIT(CAM_ISP,
- "CSID:%d csid halt device fail rc = %d",
- csid_hw->hw_intf->hw_idx, rc);
- }
}
if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_EOT_RECEPTION",
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 4b546ea..681a47f 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
@@ -360,7 +360,6 @@
* @dt: Data type
* @cnt: Cid resource reference count.
* @tpg_set: Tpg used for this cid resource
- * @pixel_count: Pixel resource connected
*
*/
struct cam_ife_csid_cid_data {
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
index b9f6d77..c56c49f 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
@@ -93,6 +93,8 @@
CAM_ISP_HW_CMD_CLOCK_UPDATE,
CAM_ISP_HW_CMD_BW_UPDATE,
CAM_ISP_HW_CMD_BW_CONTROL,
+ CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ,
+ CAM_ISP_HW_CMD_GET_REG_DUMP,
CAM_ISP_HW_CMD_MAX,
};
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 8927d6a..05c3c61 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
@@ -49,6 +49,9 @@
CAM_VFE_IRQ_STATUS_COMP_OWRT = -2,
CAM_VFE_IRQ_STATUS_ERR = -1,
CAM_VFE_IRQ_STATUS_SUCCESS = 0,
+ CAM_VFE_IRQ_STATUS_OVERFLOW = 1,
+ CAM_VFE_IRQ_STATUS_P2I_ERROR = 2,
+ CAM_VFE_IRQ_STATUS_VIOLATION = 3,
CAM_VFE_IRQ_STATUS_MAX,
};
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 36ce652..ed728f5 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
@@ -106,7 +106,6 @@
struct cam_vfe_bus_irq_evt_payload evt_payload[
CAM_VFE_BUS_VER2_PAYLOAD_MAX];
struct list_head free_payload_list;
- spinlock_t spin_lock;
struct mutex bus_mutex;
uint32_t secure_mode;
uint32_t num_sec_out;
@@ -215,23 +214,16 @@
struct cam_vfe_bus_ver2_common_data *common_data,
struct cam_vfe_bus_irq_evt_payload **evt_payload)
{
- int rc;
-
- spin_lock(&common_data->spin_lock);
if (list_empty(&common_data->free_payload_list)) {
*evt_payload = NULL;
CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload");
- rc = -ENODEV;
- goto done;
+ 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);
- rc = 0;
-done:
- spin_unlock(&common_data->spin_lock);
- return rc;
+ return 0;
}
static enum cam_vfe_bus_comp_grp_id
@@ -262,7 +254,6 @@
struct cam_vfe_bus_ver2_common_data *common_data = NULL;
uint32_t *ife_irq_regs = NULL;
uint32_t status_reg0, status_reg1, status_reg2;
- unsigned long flags;
if (!core_info) {
CAM_ERR(CAM_ISP, "Invalid param core_info NULL");
@@ -285,14 +276,11 @@
}
common_data = core_info;
-
- spin_lock_irqsave(&common_data->spin_lock, flags);
list_add_tail(&(*evt_payload)->list,
&common_data->free_payload_list);
- spin_unlock_irqrestore(&common_data->spin_lock, flags);
-
*evt_payload = NULL;
+ CAM_DBG(CAM_ISP, "Done");
return 0;
}
@@ -1000,12 +988,11 @@
rsrc_data->height = 0;
rsrc_data->stride = 1;
rsrc_data->en_cfg = 0x3;
- } else if (rsrc_data->index == 9) {
+ } else if (rsrc_data->index == 9 || rsrc_data->index == 10) {
/* Write master 9 - Raw dump */
rsrc_data->width = rsrc_data->width * 2;
rsrc_data->stride = rsrc_data->width;
rsrc_data->en_cfg = 0x1;
-
/* LSB aligned */
rsrc_data->pack_fmt |= 0x10;
} else {
@@ -1112,7 +1099,12 @@
/* enable ubwc if needed*/
if (rsrc_data->en_ubwc) {
- cam_io_w_mb(0x1, common_data->mem_base +
+ int val = cam_io_r_mb(common_data->mem_base +
+ rsrc_data->hw_regs->ubwc_regs->mode_cfg);
+ CAM_DBG(CAM_ISP, "ubwc reg %d, res id %d",
+ val, rsrc_data->index);
+ val |= 0x1;
+ cam_io_w_mb(val, common_data->mem_base +
rsrc_data->hw_regs->ubwc_regs->mode_cfg);
}
@@ -1144,9 +1136,7 @@
rsrc_data->common_data;
/* Disble WM */
- cam_io_w_mb(0x0,
- common_data->mem_base + rsrc_data->hw_regs->cfg);
-
+ /* Disable all register access, reply on global reset */
CAM_DBG(CAM_ISP, "irq_enabled %d", rsrc_data->irq_enabled);
/* Unsubscribe IRQ */
if (rsrc_data->irq_enabled)
@@ -1154,10 +1144,6 @@
common_data->bus_irq_controller,
wm_res->irq_handle);
- /* Halt & Reset WM */
- cam_io_w_mb(BIT(rsrc_data->index),
- common_data->mem_base + common_data->common_reg->sw_reset);
-
wm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
rsrc_data->init_cfg_done = false;
rsrc_data->hfr_cfg_done = false;
@@ -1188,8 +1174,6 @@
rc = cam_vfe_bus_get_evt_payload(rsrc_data->common_data, &evt_payload);
if (rc) {
CAM_ERR_RATE_LIMIT(CAM_ISP,
- "No tasklet_cmd is free in queue");
- CAM_ERR_RATE_LIMIT(CAM_ISP,
"IRQ status_0 = 0x%x status_1 = 0x%x status_2 = 0x%x",
th_payload->evt_status_arr[0],
th_payload->evt_status_arr[1],
@@ -1601,7 +1585,6 @@
static int cam_vfe_bus_stop_comp_grp(struct cam_isp_resource_node *comp_grp)
{
int rc = 0;
- uint32_t addr_sync_cfg;
struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data =
comp_grp->res_priv;
struct cam_vfe_bus_ver2_common_data *common_data =
@@ -1617,51 +1600,6 @@
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);
- 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) {
-
- int dual_comp_grp = (rsrc_data->comp_grp_type -
- CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0);
-
- if (rsrc_data->is_master) {
- int intra_client_en = cam_io_r_mb(
- common_data->mem_base +
- common_data->common_reg->dual_master_comp_cfg);
-
- /*
- * 2 Bits per comp_grp. Hence left shift by
- * comp_grp * 2
- */
- intra_client_en &=
- ~(rsrc_data->intra_client_mask <<
- dual_comp_grp * 2);
-
- cam_io_w_mb(intra_client_en, common_data->mem_base +
- common_data->common_reg->dual_master_comp_cfg);
- }
-
- addr_sync_cfg = cam_io_r_mb(common_data->mem_base +
- common_data->common_reg->addr_sync_cfg);
- addr_sync_cfg &= ~(1 << dual_comp_grp);
- addr_sync_cfg &= ~(CAM_VFE_BUS_INTRA_CLIENT_MASK <<
- ((dual_comp_grp * 2) +
- CAM_VFE_BUS_ADDR_SYNC_INTRA_CLIENT_SHIFT));
- cam_io_w_mb(addr_sync_cfg, common_data->mem_base +
- common_data->common_reg->addr_sync_cfg);
-
- cam_io_w_mb(0, common_data->mem_base +
- rsrc_data->hw_regs->addr_sync_mask);
- common_data->addr_no_sync |= rsrc_data->composite_mask;
- cam_io_w_mb(common_data->addr_no_sync, common_data->mem_base +
- common_data->common_reg->addr_sync_no_sync);
- CAM_DBG(CAM_ISP, "addr_sync_cfg: 0x% addr_no_sync_cfg: 0x%x",
- addr_sync_cfg, common_data->addr_no_sync);
-
- }
-
comp_grp->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
return rc;
@@ -2208,6 +2146,7 @@
struct cam_isp_resource_node *vfe_out = handler_priv;
struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv;
+ CAM_DBG(CAM_ISP, "vfe_out %d", rsrc_data->out_type);
/*
* If this resource has Composite Group then we only handle
* Composite done. We acquire Composite if number of WM > 1.
@@ -2328,11 +2267,13 @@
struct cam_irq_th_payload *th_payload)
{
int i = 0;
- struct cam_vfe_bus_ver2_priv *bus_priv = th_payload->handler_priv;
+ struct cam_vfe_bus_ver2_priv *bus_priv =
+ th_payload->handler_priv;
CAM_ERR_RATE_LIMIT(CAM_ISP, "Bus Err IRQ");
for (i = 0; i < th_payload->num_registers; i++) {
- CAM_ERR_RATE_LIMIT(CAM_ISP, "IRQ_Status%d: 0x%x", i,
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "vfe:%d: IRQ_Status%d: 0x%x",
+ bus_priv->common_data.core_index, i,
th_payload->evt_status_arr[i]);
}
cam_irq_controller_disable_irq(bus_priv->common_data.bus_irq_controller,
@@ -2842,29 +2783,34 @@
void *deinit_hw_args, uint32_t arg_size)
{
struct cam_vfe_bus_ver2_priv *bus_priv = hw_priv;
- int rc;
+ int rc = 0;
- if (!bus_priv || (bus_priv->irq_handle <= 0) ||
- (bus_priv->error_irq_handle <= 0)) {
+ if (!bus_priv) {
CAM_ERR(CAM_ISP, "Error: Invalid args");
return -EINVAL;
}
- rc = cam_irq_controller_unsubscribe_irq(
- bus_priv->common_data.bus_irq_controller,
- bus_priv->error_irq_handle);
- if (rc)
- CAM_ERR(CAM_ISP, "Failed to unsubscribe error irq rc=%d", rc);
+ if (bus_priv->error_irq_handle) {
+ rc = cam_irq_controller_unsubscribe_irq(
+ bus_priv->common_data.bus_irq_controller,
+ bus_priv->error_irq_handle);
+ if (rc)
+ CAM_ERR(CAM_ISP,
+ "Failed to unsubscribe error irq rc=%d", rc);
- bus_priv->error_irq_handle = 0;
+ bus_priv->error_irq_handle = 0;
+ }
- rc = cam_irq_controller_unsubscribe_irq(
- bus_priv->common_data.vfe_irq_controller,
- bus_priv->irq_handle);
- if (rc)
- CAM_ERR(CAM_ISP, "Failed to unsubscribe irq rc=%d", rc);
+ if (bus_priv->irq_handle) {
+ rc = cam_irq_controller_unsubscribe_irq(
+ bus_priv->common_data.vfe_irq_controller,
+ bus_priv->irq_handle);
+ if (rc)
+ CAM_ERR(CAM_ISP,
+ "Failed to unsubscribe irq rc=%d", rc);
- bus_priv->irq_handle = 0;
+ bus_priv->irq_handle = 0;
+ }
return rc;
}
@@ -2880,6 +2826,7 @@
uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
{
int rc = -EINVAL;
+ struct cam_vfe_bus_ver2_priv *bus_priv;
if (!priv || !cmd_args) {
CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments");
@@ -2899,6 +2846,21 @@
case CAM_ISP_HW_CMD_STRIPE_UPDATE:
rc = cam_vfe_bus_update_stripe_cfg(priv, cmd_args, arg_size);
break;
+ case CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ:
+ bus_priv = (struct cam_vfe_bus_ver2_priv *) priv;
+ if (bus_priv->error_irq_handle) {
+ CAM_INFO(CAM_ISP, "Mask off bus error irq handler");
+ rc = cam_irq_controller_unsubscribe_irq(
+ bus_priv->common_data.bus_irq_controller,
+ bus_priv->error_irq_handle);
+ if (rc)
+ CAM_ERR(CAM_ISP,
+ "Failed to unsubscribe error irq rc=%d",
+ rc);
+
+ bus_priv->error_irq_handle = 0;
+ }
+ break;
default:
CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d",
cmd_type);
@@ -3001,7 +2963,6 @@
}
}
- spin_lock_init(&bus_priv->common_data.spin_lock);
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);
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 f427ab9..734cbdb 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -22,6 +22,7 @@
#include "cam_vfe_camif_ver2.h"
#include "cam_debug_util.h"
#include "cam_cdm_util.h"
+#include "cam_cpas_api.h"
struct cam_vfe_mux_camif_data {
void __iomem *mem_base;
@@ -234,12 +235,10 @@
CAM_DBG(CAM_ISP, "hw id:%d core_cfg val:%d", camif_res->hw_intf->hw_idx,
val);
- cam_io_w_mb(0x00400040, rsrc_data->mem_base +
- rsrc_data->camif_reg->camif_config);
- cam_io_w_mb(0x1, rsrc_data->mem_base +
- rsrc_data->camif_reg->line_skip_pattern);
- cam_io_w_mb(0x1, rsrc_data->mem_base +
- rsrc_data->camif_reg->pixel_skip_pattern);
+ /* disable the CGC for stats */
+ cam_io_w_mb(0xFFFFFFFF, rsrc_data->mem_base +
+ rsrc_data->common_reg->module_ctrl[
+ CAM_VFE_TOP_VER2_MODULE_STATS]->cgc_ovd);
/* epoch config with 20 line */
cam_io_w_mb(rsrc_data->reg_data->epoch_line_cfg,
@@ -255,6 +254,60 @@
return 0;
}
+static int cam_vfe_camif_reg_dump(
+ struct cam_isp_resource_node *camif_res)
+{
+ struct cam_vfe_mux_camif_data *camif_priv;
+ struct cam_vfe_soc_private *soc_private;
+ int rc = 0, i;
+ uint32_t val = 0;
+
+ if (!camif_res) {
+ CAM_ERR(CAM_ISP, "Error! Invalid input arguments");
+ return -EINVAL;
+ }
+
+ if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) ||
+ (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE))
+ return 0;
+
+ camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv;
+ soc_private = camif_priv->soc_info->soc_private;
+ for (i = 0xA3C; i <= 0xA90; i += 4) {
+ val = cam_io_r_mb(camif_priv->mem_base + i);
+ CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val);
+ }
+
+ for (i = 0xE0C; i <= 0xE3C; i += 4) {
+ val = cam_io_r_mb(camif_priv->mem_base + i);
+ CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val);
+ }
+
+ for (i = 0x2000; i <= 0x20B8; i += 4) {
+ val = cam_io_r_mb(camif_priv->mem_base + i);
+ CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val);
+ }
+
+ for (i = 0x2500; i <= 0x255C; i += 4) {
+ val = cam_io_r_mb(camif_priv->mem_base + i);
+ CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val);
+ }
+
+ for (i = 0x2600; i <= 0x265C; i += 4) {
+ val = cam_io_r_mb(camif_priv->mem_base + i);
+ CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val);
+ }
+
+ cam_cpas_reg_read(soc_private->cpas_handle,
+ CAM_CPAS_REG_CAMNOC, 0x420, true, &val);
+ CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val);
+
+ cam_cpas_reg_read(soc_private->cpas_handle,
+ CAM_CPAS_REG_CAMNOC, 0x820, true, &val);
+ CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val);
+
+ return rc;
+}
static int cam_vfe_camif_resource_stop(
struct cam_isp_resource_node *camif_res)
@@ -306,6 +359,9 @@
rc = cam_vfe_camif_get_reg_update(rsrc_node, cmd_args,
arg_size);
break;
+ case CAM_ISP_HW_CMD_GET_REG_DUMP:
+ rc = cam_vfe_camif_reg_dump(rsrc_node);
+ break;
default:
CAM_ERR(CAM_ISP,
"unsupported process command:%d", cmd_type);
@@ -331,8 +387,10 @@
uint32_t irq_status0;
uint32_t irq_status1;
- if (!handler_priv || !evt_payload_priv)
+ if (!handler_priv || !evt_payload_priv) {
+ CAM_ERR(CAM_ISP, "Invalid params");
return ret;
+ }
camif_node = handler_priv;
camif_priv = camif_node->res_priv;
@@ -372,6 +430,7 @@
if (irq_status1 & camif_priv->reg_data->error_irq_mask1) {
CAM_DBG(CAM_ISP, "Received ERROR\n");
ret = CAM_ISP_HW_ERROR_OVERFLOW;
+ cam_vfe_camif_reg_dump(camif_node);
} else {
ret = CAM_ISP_HW_ERROR_NONE;
}
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 50dca827..230698f 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -186,8 +186,10 @@
struct cam_vfe_top_irq_evt_payload *payload;
uint32_t irq_status0;
- if (!handler_priv || !evt_payload_priv)
+ if (!handler_priv || !evt_payload_priv) {
+ CAM_ERR(CAM_ISP, "Invalid params");
return ret;
+ }
rdi_node = handler_priv;
rdi_priv = rdi_node->res_priv;
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 f4aa5c3..976e6d2 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
@@ -34,13 +34,13 @@
struct cam_vfe_top_ver2_common_data common_data;
struct cam_isp_resource_node mux_rsrc[CAM_VFE_TOP_VER2_MUX_MAX];
unsigned long hw_clk_rate;
- enum cam_vfe_bw_control_action axi_vote_control[
- CAM_VFE_TOP_VER2_MUX_MAX];
struct cam_axi_vote to_be_applied_axi_vote;
struct cam_axi_vote applied_axi_vote;
uint32_t counter_to_update_axi_vote;
struct cam_axi_vote req_axi_vote[CAM_VFE_TOP_VER2_MUX_MAX];
unsigned long req_clk_rate[CAM_VFE_TOP_VER2_MUX_MAX];
+ enum cam_vfe_bw_control_action
+ axi_vote_control[CAM_VFE_TOP_VER2_MUX_MAX];
};
static int cam_vfe_top_mux_get_base(struct cam_vfe_top_ver2_priv *top_priv,
@@ -225,9 +225,11 @@
&top_priv->to_be_applied_axi_vote);
if (!rc) {
top_priv->applied_axi_vote.uncompressed_bw =
- top_priv->to_be_applied_axi_vote.uncompressed_bw;
+ top_priv->
+ to_be_applied_axi_vote.uncompressed_bw;
top_priv->applied_axi_vote.compressed_bw =
- top_priv->to_be_applied_axi_vote.compressed_bw;
+ top_priv->
+ to_be_applied_axi_vote.compressed_bw;
} else {
CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc);
}
@@ -273,7 +275,8 @@
}
if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
- CAM_DBG(CAM_ISP, "VFE:%d Not ready to set clocks yet :%d",
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "VFE:%d Not ready to set clocks yet :%d",
res->hw_intf->hw_idx,
hw_info->hw_state);
} else
@@ -321,7 +324,8 @@
}
if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
- CAM_DBG(CAM_ISP, "VFE:%d Not ready to set BW yet :%d",
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "VFE:%d Not ready to set BW yet :%d",
res->hw_intf->hw_idx,
hw_info->hw_state);
} else
@@ -364,7 +368,8 @@
}
if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
- CAM_DBG(CAM_ISP, "VFE:%d Not ready to set BW yet :%d",
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "VFE:%d Not ready to set BW yet :%d",
res->hw_intf->hw_idx,
hw_info->hw_state);
} else {
@@ -517,6 +522,7 @@
{
struct cam_vfe_top_ver2_priv *top_priv;
struct cam_isp_resource_node *mux_res;
+ struct cam_hw_info *hw_info = NULL;
int rc = 0;
if (!device_priv || !start_args) {
@@ -526,24 +532,33 @@
top_priv = (struct cam_vfe_top_ver2_priv *)device_priv;
mux_res = (struct cam_isp_resource_node *)start_args;
+ hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv;
- rc = cam_vfe_top_set_hw_clk_rate(top_priv);
- if (rc) {
- CAM_ERR(CAM_ISP, "set_hw_clk_rate failed, rc=%d", rc);
- return rc;
- }
+ if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) {
+ rc = cam_vfe_top_set_hw_clk_rate(top_priv);
+ if (rc) {
+ CAM_ERR(CAM_ISP,
+ "set_hw_clk_rate failed, rc=%d", rc);
+ return rc;
+ }
- rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
- if (rc) {
- CAM_ERR(CAM_ISP, "set_axi_bw_vote failed, rc=%d", rc);
- return rc;
- }
+ rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
+ if (rc) {
+ CAM_ERR(CAM_ISP,
+ "set_axi_bw_vote failed, rc=%d", rc);
+ return rc;
+ }
- if (mux_res->start) {
- rc = mux_res->start(mux_res);
+ if (mux_res->start) {
+ rc = mux_res->start(mux_res);
+ } else {
+ CAM_ERR(CAM_ISP,
+ "Invalid res id:%d", mux_res->res_id);
+ rc = -EINVAL;
+ }
} else {
- CAM_ERR(CAM_ISP, "Invalid res id:%d", mux_res->res_id);
- rc = -EINVAL;
+ CAM_ERR(CAM_ISP, "VFE HW not powered up");
+ rc = -EPERM;
}
return rc;
@@ -554,6 +569,7 @@
{
struct cam_vfe_top_ver2_priv *top_priv;
struct cam_isp_resource_node *mux_res;
+ struct cam_hw_info *hw_info = NULL;
int i, rc = 0;
if (!device_priv || !stop_args) {
@@ -563,6 +579,7 @@
top_priv = (struct cam_vfe_top_ver2_priv *)device_priv;
mux_res = (struct cam_isp_resource_node *)stop_args;
+ hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv;
if (mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF ||
(mux_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0 &&
@@ -585,16 +602,25 @@
}
}
- rc = cam_vfe_top_set_hw_clk_rate(top_priv);
- if (rc) {
- CAM_ERR(CAM_ISP, "set_hw_clk_rate failed, rc=%d", rc);
- return rc;
- }
+ if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) {
+ rc = cam_vfe_top_set_hw_clk_rate(top_priv);
+ if (rc) {
+ CAM_ERR(CAM_ISP,
+ "set_hw_clk_rate failed, rc=%d", rc);
+ return rc;
+ }
- rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
- if (rc) {
- CAM_ERR(CAM_ISP, "set_axi_bw_vote failed, rc=%d", rc);
- return rc;
+ top_priv->hw_clk_rate = 0;
+
+ rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
+ if (rc) {
+ CAM_ERR(CAM_ISP,
+ "set_axi_bw_vote failed, rc=%d", rc);
+ return rc;
+ }
+ } else {
+ CAM_ERR(CAM_ISP, "VFE HW not powered up");
+ rc = -EPERM;
}
}
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.c b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.c
index 1ccef0d..02334a4 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -121,7 +121,8 @@
int cam_jpeg_context_init(struct cam_jpeg_context *ctx,
struct cam_context *ctx_base,
- struct cam_hw_mgr_intf *hw_intf)
+ struct cam_hw_mgr_intf *hw_intf,
+ uint32_t ctx_id)
{
int rc;
int i;
@@ -139,8 +140,8 @@
for (i = 0; i < CAM_CTX_REQ_MAX; i++)
ctx->req_base[i].req_priv = ctx;
- rc = cam_context_init(ctx_base, jpeg_dev_name, NULL, hw_intf,
- ctx->req_base, CAM_CTX_REQ_MAX);
+ rc = cam_context_init(ctx_base, jpeg_dev_name, CAM_JPEG, ctx_id,
+ NULL, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX);
if (rc) {
CAM_ERR(CAM_JPEG, "Camera Context Base init failed");
goto err;
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.h b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.h
index 90ac5cf..1a40679 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.h
+++ b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -53,11 +53,13 @@
* @ctx: JPEG context obj to be initialized
* @ctx_base: Context base from cam_context
* @hw_intf: JPEG hw manager interface
+ * @ctx_id: ID for this context
*
*/
int cam_jpeg_context_init(struct cam_jpeg_context *ctx,
struct cam_context *ctx_base,
- struct cam_hw_mgr_intf *hw_intf);
+ struct cam_hw_mgr_intf *hw_intf,
+ uint32_t ctx_id);
/**
* cam_jpeg_context_deinit()
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c
index a400388..60feeac 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -98,7 +98,8 @@
for (i = 0; i < CAM_CTX_MAX; i++) {
rc = cam_jpeg_context_init(&g_jpeg_dev.ctx_jpeg[i],
&g_jpeg_dev.ctx[i],
- &node->hw_mgr_intf);
+ &node->hw_mgr_intf,
+ i);
if (rc) {
CAM_ERR(CAM_JPEG, "JPEG context init failed %d %d",
i, rc);
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
index 6e2e7e9..32f11a7 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -333,7 +333,6 @@
if (list_empty(&hw_mgr->hw_config_req_list)) {
CAM_DBG(CAM_JPEG, "no available request");
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
rc = -EFAULT;
goto end;
}
@@ -342,7 +341,6 @@
struct cam_jpeg_hw_cfg_req, list);
if (!p_cfg_req) {
CAM_ERR(CAM_JPEG, "no request");
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
rc = -EFAULT;
goto end;
}
@@ -353,13 +351,10 @@
list_del_init(&p_cfg_req->list);
} else {
CAM_DBG(CAM_JPEG, "Not dequeing, just return");
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
rc = -EFAULT;
goto end;
}
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
-
config_args = (struct cam_hw_config_args *)&p_cfg_req->hw_cfg_args;
request_id = task_data->request_id;
if (request_id != (uint64_t)config_args->priv) {
@@ -369,11 +364,11 @@
if (!config_args->num_hw_update_entries) {
CAM_ERR(CAM_JPEG, "No hw update enteries are available");
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
rc = -EINVAL;
goto end_unusedev;
}
- mutex_lock(&hw_mgr->hw_mgr_mutex);
ctx_data = (struct cam_jpeg_hw_ctx_data *)config_args->ctxt_to_hw_map;
if (!ctx_data->in_use) {
CAM_ERR(CAM_JPEG, "ctx is not in use");
@@ -381,7 +376,6 @@
rc = -EINVAL;
goto end_unusedev;
}
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
dev_type = ctx_data->jpeg_dev_acquire_info.dev_type;
@@ -483,9 +477,11 @@
goto end_callcb;
}
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
return rc;
end_callcb:
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
if (p_cfg_req) {
buf_data.num_handles = p_cfg_req->
hw_cfg_args.num_out_map_entries;
@@ -498,14 +494,14 @@
(uint64_t)p_cfg_req->hw_cfg_args.priv;
ctx_data->ctxt_event_cb(ctx_data->context_priv, 0, &buf_data);
}
+
end_unusedev:
mutex_lock(&hw_mgr->hw_mgr_mutex);
hw_mgr->device_in_use[p_cfg_req->dev_type][0] = false;
hw_mgr->dev_hw_cfg_args[p_cfg_req->dev_type][0] = NULL;
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
end:
-
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
return rc;
}
@@ -743,6 +739,9 @@
uint32_t dev_type;
struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL;
struct cam_jpeg_hw_cfg_req *cfg_req = NULL, *req_temp = NULL;
+ struct cam_jpeg_set_irq_cb irq_cb;
+
+ CAM_DBG(CAM_JPEG, "E: JPEG flush ctx");
if (!hw_mgr || !ctx_data) {
CAM_ERR(CAM_JPEG, "Invalid args");
@@ -757,6 +756,30 @@
if ((struct cam_jpeg_hw_ctx_data *)p_cfg_req->
hw_cfg_args.ctxt_to_hw_map == ctx_data) {
/* stop reset Unregister CB and deinit */
+ irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb;
+ irq_cb.data = NULL;
+ irq_cb.b_set_cb = false;
+ if (hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) {
+ rc = hw_mgr->devices[dev_type][0]->
+ hw_ops.process_cmd(
+ hw_mgr->devices[dev_type][0]->hw_priv,
+ CAM_JPEG_CMD_SET_IRQ_CB,
+ &irq_cb, sizeof(irq_cb));
+ if (rc)
+ CAM_ERR(CAM_JPEG,
+ "CMD_SET_IRQ_CB failed %d", rc);
+
+ } else {
+ CAM_ERR(CAM_JPEG, "process_cmd null ");
+ }
+ rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd(
+ hw_mgr->devices[dev_type][0]->hw_priv,
+ CAM_JPEG_CMD_SET_IRQ_CB,
+ &irq_cb, sizeof(irq_cb));
+ if (rc)
+ CAM_ERR(CAM_JPEG,
+ "CMD_SET_IRQ_CB failed %d", rc);
+
if (hw_mgr->devices[dev_type][0]->hw_ops.stop) {
rc = hw_mgr->devices[dev_type][0]->hw_ops.stop(
hw_mgr->devices[dev_type][0]->hw_priv,
@@ -765,7 +788,19 @@
CAM_ERR(CAM_JPEG, "stop fail %d", rc);
} else {
CAM_ERR(CAM_JPEG, "op stop null ");
- rc = -EINVAL;
+ }
+
+ if (hw_mgr->devices[dev_type][0]->hw_ops.deinit) {
+ rc = hw_mgr->devices[dev_type][0]
+ ->hw_ops.deinit(
+ hw_mgr->devices[dev_type][0]->hw_priv,
+ NULL, 0);
+ if (rc)
+ CAM_ERR(CAM_JPEG,
+ "Failed to Deinit %d HW",
+ dev_type);
+ } else {
+ CAM_ERR(CAM_JPEG, "op deinit null");
}
}
@@ -783,6 +818,8 @@
list_del_init(&cfg_req->list);
}
+ CAM_DBG(CAM_JPEG, "X: JPEG flush ctx with rc: %d", rc);
+
return rc;
}
@@ -795,6 +832,8 @@
struct cam_jpeg_hw_cfg_req *cfg_req, *req_temp;
int64_t request_id;
+ CAM_DBG(CAM_JPEG, "E: JPEG flush req");
+
if (!hw_mgr || !ctx_data || !flush_args) {
CAM_ERR(CAM_JPEG, "Invalid args");
return -EINVAL;
@@ -816,6 +855,8 @@
list_del_init(&cfg_req->list);
}
+ CAM_DBG(CAM_JPEG, "X: JPEG flush req");
+
return 0;
}
@@ -924,6 +965,7 @@
if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 0) {
mutex_unlock(&hw_mgr->hw_mgr_mutex);
CAM_ERR(CAM_JPEG, "Error Unbalanced deinit");
+ kfree(ctx_data->cdm_cmd);
return -EFAULT;
}
@@ -943,9 +985,12 @@
rc = cam_jpeg_mgr_release_ctx(hw_mgr, ctx_data);
if (rc) {
mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ CAM_ERR(CAM_JPEG, "JPEG release ctx failed");
+ kfree(ctx_data->cdm_cmd);
return -EINVAL;
}
+ kfree(ctx_data->cdm_cmd);
CAM_DBG(CAM_JPEG, "handle %llu", ctx_data);
return rc;
@@ -999,7 +1044,7 @@
sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL);
if (!ctx_data->cdm_cmd) {
rc = -ENOMEM;
- goto acq_cdm_hdl_failed;
+ goto jpeg_release_ctx;
}
mutex_lock(&ctx_data->ctx_mutex);
@@ -1046,20 +1091,8 @@
hw_mgr->cdm_info[dev_type][0].ref_cnt++;
}
- ctx_data->cdm_cmd_chbase =
- kzalloc(((sizeof(struct cam_cdm_bl_request)) +
- (2 * sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL);
- if (!ctx_data->cdm_cmd_chbase) {
- rc = -ENOMEM;
- goto start_cdm_hdl_failed;
- }
size = hw_mgr->cdm_info[dev_type][0].
cdm_ops->cdm_required_size_changebase();
- ctx_data->cmd_chbase_buf_addr = kzalloc(size*4, GFP_KERNEL);
- if (!ctx_data->cdm_cmd_chbase) {
- rc = -ENOMEM;
- goto start_cdm_hdl_failed;
- }
if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 1)
if (cam_cdm_stream_on(
@@ -1101,6 +1134,7 @@
hw_mgr->cdm_info[dev_type][0].ref_cnt--;
acq_cdm_hdl_failed:
kfree(ctx_data->cdm_cmd);
+jpeg_release_ctx:
cam_jpeg_mgr_release_ctx(hw_mgr, ctx_data);
mutex_unlock(&hw_mgr->hw_mgr_mutex);
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h
index dce47d2..5e10167 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -95,8 +95,6 @@
* @in_use: Flag for context usage
* @wait_complete: Completion info
* @cdm_cmd: Cdm cmd submitted for that context.
- * @cdm_cmd_chbase: Change base cdm command from context
- * @cmd_chbase_buf_addr : Change base cmd buf address
*/
struct cam_jpeg_hw_ctx_data {
void *context_priv;
@@ -106,8 +104,6 @@
bool in_use;
struct completion wait_complete;
struct cam_cdm_bl_request *cdm_cmd;
- struct cam_cdm_bl_request *cdm_cmd_chbase;
- uint32_t *cmd_chbase_buf_addr;
};
/**
diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c
index 1ab3143..3d0266d 100644
--- a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c
+++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -16,6 +16,8 @@
#include "cam_debug_util.h"
#include "cam_lrme_context.h"
+static const char lrme_dev_name[] = "lrme";
+
static int __cam_lrme_ctx_acquire_dev_in_available(struct cam_context *ctx,
struct cam_acquire_dev_cmd *cmd)
{
@@ -208,7 +210,7 @@
int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx,
struct cam_context *base_ctx,
struct cam_hw_mgr_intf *hw_intf,
- uint64_t index)
+ uint32_t index)
{
int rc = 0;
@@ -221,8 +223,8 @@
memset(lrme_ctx, 0, sizeof(*lrme_ctx));
- rc = cam_context_init(base_ctx, "lrme", NULL, hw_intf,
- lrme_ctx->req_base, CAM_CTX_REQ_MAX);
+ rc = cam_context_init(base_ctx, lrme_dev_name, CAM_LRME, index,
+ NULL, hw_intf, lrme_ctx->req_base, CAM_CTX_REQ_MAX);
if (rc) {
CAM_ERR(CAM_LRME, "Failed to init context");
return rc;
diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h
index 882f7ac..4c705c1 100644
--- a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h
+++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -35,7 +35,7 @@
int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx,
struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf,
- uint64_t index);
+ uint32_t index);
int cam_lrme_context_deinit(struct cam_lrme_context *lrme_ctx);
#endif /* _CAM_LRME_CONTEXT_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
index f514139..86c2039 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
@@ -2,9 +2,9 @@
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 \
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_core.o\
+ cam_req_mgr_dev.o \
cam_req_mgr_util.o \
- cam_req_mgr_core.o \
cam_req_mgr_workq.o \
cam_mem_mgr.o \
cam_req_mgr_timer.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 02f03ea..643b0afc 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
@@ -377,7 +377,8 @@
heap_id = ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID);
ion_flag |= ION_FLAG_SECURE | ION_FLAG_CP_CAMERA;
} else {
- heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
+ heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID) |
+ ION_HEAP(ION_CAMERA_HEAP_ID);
}
if (cmd->flags & CAM_MEM_FLAG_CACHE)
@@ -947,7 +948,8 @@
else
ion_flag &= ~ION_FLAG_CACHED;
- heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
+ heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID) |
+ ION_HEAP(ION_CAMERA_HEAP_ID);
rc = cam_mem_util_get_dma_buf(inp->size,
inp->align,
@@ -1111,7 +1113,8 @@
return -EINVAL;
}
- heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
+ heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID) |
+ ION_HEAP(ION_CAMERA_HEAP_ID);
rc = cam_mem_util_get_dma_buf(inp->size,
inp->align,
heap_id,
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 3100f91..e66d21d 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
@@ -25,6 +25,22 @@
static struct cam_req_mgr_core_device *g_crm_core_dev;
+void cam_req_mgr_handle_core_shutdown(void)
+{
+ struct cam_req_mgr_core_session *session;
+ struct cam_req_mgr_core_session *tsession;
+ struct cam_req_mgr_session_info ses_info;
+
+ if (!list_empty(&g_crm_core_dev->session_head)) {
+ list_for_each_entry_safe(session, tsession,
+ &g_crm_core_dev->session_head, entry) {
+ ses_info.session_hdl =
+ session->session_hdl;
+ cam_req_mgr_destroy_session(&ses_info);
+ }
+ }
+}
+
static int __cam_req_mgr_setup_payload(struct cam_req_mgr_core_workq *workq)
{
int32_t i = 0;
@@ -183,20 +199,14 @@
tbl->skip_traverse, traverse_data->in_q->slot[curr_idx].status,
traverse_data->in_q->slot[curr_idx].skip_idx);
- if (tbl->inject_delay > 0 && (traverse_data->validate_only == false)) {
+ if ((tbl->inject_delay > 0) &&
+ (traverse_data->self_link == true)) {
CAM_DBG(CAM_CRM, "Injecting Delay of one frame");
+ apply_data[tbl->pd].req_id = -1;
tbl->inject_delay--;
/* This pd table is not ready to proceed with asked idx */
SET_FAILURE_BIT(traverse_data->result, tbl->pd);
- apply_data[tbl->pd].req_id = -1;
- if (tbl->next) {
- __cam_req_mgr_dec_idx(&next_idx, tbl->pd_delta,
- tbl->num_slots);
- traverse_data->idx = next_idx;
- traverse_data->tbl = tbl->next;
- rc = __cam_req_mgr_traverse(traverse_data);
- }
- return rc;
+ return -EAGAIN;
}
/* Check if req is ready or in skip mode or pd tbl is in skip mode */
@@ -212,14 +222,21 @@
}
if (rc >= 0) {
SET_SUCCESS_BIT(traverse_data->result, tbl->pd);
+
if (traverse_data->validate_only == false) {
apply_data[tbl->pd].pd = tbl->pd;
apply_data[tbl->pd].req_id =
- CRM_GET_REQ_ID(traverse_data->in_q,
- curr_idx);
+ CRM_GET_REQ_ID(
+ traverse_data->in_q, curr_idx);
apply_data[tbl->pd].idx = curr_idx;
- /* If traverse is success dec traverse skip */
+ CAM_DBG(CAM_CRM, "req_id: %d with pd of %d",
+ apply_data[tbl->pd].req_id,
+ apply_data[tbl->pd].pd);
+ /*
+ * If traverse is successful decrement
+ * traverse skip
+ */
if (tbl->skip_traverse > 0) {
apply_data[tbl->pd].req_id = -1;
tbl->skip_traverse--;
@@ -231,20 +248,8 @@
}
} else {
/* This pd table is not ready to proceed with asked idx */
- if (tbl->slot[curr_idx].state == CRM_REQ_STATE_APPLIED)
- SET_SUCCESS_BIT(traverse_data->result, tbl->pd);
- else
- SET_FAILURE_BIT(traverse_data->result, tbl->pd);
-
- apply_data[tbl->pd].req_id = -1;
- if (tbl->next) {
- __cam_req_mgr_dec_idx(&next_idx, tbl->pd_delta,
- tbl->num_slots);
- traverse_data->idx = next_idx;
- traverse_data->tbl = tbl->next;
- rc = __cam_req_mgr_traverse(traverse_data);
- }
- return rc;
+ SET_FAILURE_BIT(traverse_data->result, tbl->pd);
+ return -EAGAIN;
}
return 0;
}
@@ -439,8 +444,8 @@
trace_cam_req_mgr_apply_request(link, &apply_req, dev);
apply_req.trigger_point = trigger;
- CAM_DBG(CAM_CRM, "SEND: pd %d req_id %lld",
- pd, apply_req.request_id);
+ CAM_DBG(CAM_CRM, "SEND: link_hdl: %x pd %d req_id %lld",
+ link->link_hdl, pd, apply_req.request_id);
if (dev->ops && dev->ops->apply_req) {
rc = dev->ops->apply_req(&apply_req);
if (rc < 0)
@@ -468,20 +473,20 @@
/**
* __cam_req_mgr_check_link_is_ready()
*
- * @brief : traverse through all request tables and see if
- * all devices are ready to apply request settings
- * @link : pointer to link whose input queue and req tbl are
- * traversed through
- * @idx : index within input request queue
+ * @brief : traverse through all request tables and see if all devices are
+ * ready to apply request settings.
+ * @link : pointer to link whose input queue and req tbl are
+ * traversed through
+ * @idx : index within input request queue
* @validate_only : Whether to validate only and/or update settings
- * @result : Holds the value that indicates which of the pd
- * tables have a req that is ready to be applied
+ * @self_link : To indicate whether the validation is for the given link or
+ * other sync link
*
* @return : 0 for success, negative for failure
*
*/
static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link,
- int32_t idx, bool validate_only, int *result)
+ int32_t idx, bool validate_only, bool self_link)
{
int rc;
struct cam_req_mgr_traverse traverse_data;
@@ -491,10 +496,10 @@
in_q = link->req.in_q;
apply_data = link->req.apply_data;
+
if (validate_only == false) {
memset(apply_data, 0,
- sizeof(struct cam_req_mgr_apply) *
- CAM_PIPELINE_DELAY_MAX);
+ sizeof(struct cam_req_mgr_apply) * CAM_PIPELINE_DELAY_MAX);
}
traverse_data.apply_data = apply_data;
@@ -503,27 +508,28 @@
traverse_data.in_q = in_q;
traverse_data.result = 0;
traverse_data.validate_only = validate_only;
+ traverse_data.self_link = self_link;
/*
* Traverse through all pd tables, if result is success,
* apply the settings
*/
rc = __cam_req_mgr_traverse(&traverse_data);
- CAM_DBG(CAM_CRM, "SOF: idx %d result %x pd_mask %x rc %d",
- idx, traverse_data.result, link->pd_mask, rc);
+ CAM_DBG(CAM_CRM,
+ "SOF: idx %d self_link %d validate %d result %x pd_mask %x rc %d",
+ idx, traverse_data.self_link, traverse_data.validate_only,
+ traverse_data.result, link->pd_mask, rc);
- if (!traverse_data.result)
- return -EAGAIN;
-
- if (!rc) {
+ if (!rc && traverse_data.result == link->pd_mask) {
CAM_DBG(CAM_CRM,
"APPLY: link_hdl= %x idx= %d, req_id= %lld :%lld :%lld",
link->link_hdl, idx,
- apply_data[2].req_id, apply_data[1].req_id,
+ apply_data[2].req_id,
+ apply_data[1].req_id,
apply_data[0].req_id);
- }
+ } else
+ rc = -EAGAIN;
- *result = traverse_data.result;
return rc;
}
@@ -574,6 +580,11 @@
link->sof_counter = -1;
link->sync_link->sof_counter = -1;
link->frame_skip_flag = false;
+
+ CAM_DBG(CAM_CRM,
+ "link_hdl %x self_counter %lld other_counter %lld frame_skip_lag %d",
+ link->link_hdl, link->sof_counter,
+ link->sync_link->sof_counter, link->frame_skip_flag);
}
/**
@@ -592,6 +603,11 @@
link->sof_counter++;
link->sync_self_ref = link->sof_counter -
link->sync_link->sof_counter;
+
+ CAM_DBG(CAM_CRM,
+ "link_hdl %x self_counter %lld other_counter %lld",
+ link->link_hdl, link->sof_counter,
+ link->sync_link->sof_counter);
}
/**
@@ -609,6 +625,11 @@
link->sof_counter = (MAX_SYNC_COUNT -
(link->sync_link->sof_counter));
link->sync_link->sof_counter = 0;
+
+ CAM_DBG(CAM_CRM,
+ "link_hdl %x self_counter %lld sync_link_hdl %x other_counter %lld",
+ link->link_hdl, link->sof_counter,
+ link->sync_link->link_hdl, link->sync_link->sof_counter);
}
/**
@@ -632,12 +653,18 @@
__cam_req_mgr_wrap_sof_cnt(link);
sync_diff = link->sof_counter - sync_link->sof_counter;
- if (sync_diff != link->sync_self_ref) {
+
+ CAM_DBG(CAM_CRM,
+ "link[%x] self_counter=%lld other_counter=%lld diff=%lld sync_self_ref=%lld",
+ link->link_hdl, link->sof_counter,
+ sync_link->sof_counter, sync_diff, link->sync_self_ref);
+
+ if (sync_diff > SYNC_LINK_SOF_CNT_MAX_LMT) {
link->sync_link->frame_skip_flag = true;
CAM_WARN(CAM_CRM,
- "Detected anomaly, skip link:%d, self=%lld, other=%lld",
+ "Detected anomaly, skip link_hdl %x self_counter=%lld other_counter=%lld sync_self_ref=%lld",
link->link_hdl, link->sof_counter,
- sync_link->sof_counter);
+ sync_link->sof_counter, link->sync_self_ref);
rc = -EPERM;
}
@@ -652,16 +679,12 @@
* @link : pointer to link whose input queue and req tbl are
* traversed through
* @slot : pointer to the current slot being processed
- * @result : Holds the value that indicates which of the pd
- * tables have a req that is ready to be applied
- *
* @return : 0 for success, negative for failure
*
*/
static int __cam_req_mgr_process_sync_req(
struct cam_req_mgr_core_link *link,
- struct cam_req_mgr_slot *slot,
- int *result)
+ struct cam_req_mgr_slot *slot)
{
struct cam_req_mgr_core_link *sync_link = NULL;
int64_t req_id = 0;
@@ -674,11 +697,27 @@
sync_link = link->sync_link;
req_id = slot->req_id;
+
+ CAM_DBG(CAM_CRM,
+ "link_hdl %x req %lld sync_self_ref %lld sof_counter %lld frame_skip_flag %d sync_link_self_ref %lld",
+ link->link_hdl, req_id, link->sync_self_ref, link->sof_counter,
+ link->frame_skip_flag, link->sync_link->sync_self_ref);
+
+ if (sync_link->sync_link_sof_skip) {
+ CAM_DBG(CAM_CRM,
+ "No req applied on corresponding SOF on sync link: %x",
+ sync_link->link_hdl);
+ sync_link->sync_link_sof_skip = false;
+ /*It is to manage compensate inject delay for each pd*/
+ __cam_req_mgr_check_link_is_ready(link, slot->idx, true, true);
+ return -EINVAL;
+ }
+
if (link->sof_counter == -1) {
__cam_req_mgr_sof_cnt_initialize(link);
- } else if (link->frame_skip_flag &&
+ } else if ((link->frame_skip_flag) &&
(sync_link->sync_self_ref != -1)) {
- CAM_DBG(CAM_CRM, "Link[%x] Req[%lld] Resetting values",
+ CAM_DBG(CAM_CRM, "Link[%x] Req[%lld] Resetting values ",
link->link_hdl, req_id);
__cam_req_mgr_reset_sof_cnt(link);
__cam_req_mgr_sof_cnt_initialize(link);
@@ -686,19 +725,21 @@
link->sof_counter++;
}
- rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true, result);
+ rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true, true);
if (rc) {
CAM_DBG(CAM_CRM,
"Req: %lld [My link]not available link: %x, rc=%d",
req_id, link->link_hdl, rc);
+ link->sync_link_sof_skip = true;
goto failure;
}
sync_slot_idx = __cam_req_mgr_find_slot_for_req(
sync_link->req.in_q, req_id);
+
if (sync_slot_idx != -1) {
rc = __cam_req_mgr_check_link_is_ready(
- sync_link, sync_slot_idx, true, result);
+ sync_link, sync_slot_idx, true, false);
CAM_DBG(CAM_CRM, "sync_slot_idx=%d, status=%d, rc=%d",
sync_slot_idx,
sync_link->req.in_q->slot[sync_slot_idx].status,
@@ -709,8 +750,8 @@
}
if ((sync_slot_idx != -1) &&
- ((sync_link->req.in_q->slot[sync_slot_idx].status ==
- CRM_SLOT_STATUS_REQ_APPLIED) || (rc == 0))) {
+ ((sync_link->req.in_q->slot[sync_slot_idx].status ==
+ CRM_SLOT_STATUS_REQ_APPLIED) || (rc == 0))) {
rc = __cam_req_mgr_validate_sof_cnt(link, sync_link);
if (rc) {
CAM_DBG(CAM_CRM,
@@ -718,13 +759,27 @@
req_id, sync_link->link_hdl);
goto failure;
}
- __cam_req_mgr_check_link_is_ready(link, slot->idx, false,
- result);
+
+ CAM_DBG(CAM_CRM,
+ "Req: %lld ready to apply on link: %x [validation successful]",
+ req_id, link->link_hdl);
+ /*
+ * At this point all validation is successfully done
+ * and we can proceed to apply the given request.
+ * Ideally the next call should return success.
+ */
+ rc = __cam_req_mgr_check_link_is_ready(link,
+ slot->idx, false, true);
+
+ if (rc) {
+ CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc);
+ }
} else {
CAM_DBG(CAM_CRM,
"Req: %lld [Other link] not ready to apply on link: %x",
req_id, sync_link->link_hdl);
rc = -EPERM;
+ link->sync_link_sof_skip = true;
goto failure;
}
@@ -736,41 +791,6 @@
}
/**
- * __cam_req_mgr_reset_pd_tables()
- *
- * @brief : resets pd tables based on req getting applied on
- * from a particular pd table
- * @link : pointer to link whose input queue and req tbl are
- * traversed through
- * @slot : Pointer to the current slot
- * @result : indicates request of which pd table was successfully
- * processed
- *
- */
-static void __cam_req_mgr_reset_pd_tables(
- struct cam_req_mgr_core_link *link,
- struct cam_req_mgr_slot *slot,
- int result)
-{
- int pd_set_bit = 0;
- int curr_idx = slot->idx;
- int no_tables = link->req.num_tbl;
- int max_pd_delay = link->max_delay;
- struct cam_req_mgr_req_tbl *tbl = link->req.l_tbl;
- struct cam_req_mgr_req_queue *in_q = link->req.in_q;
-
- while (no_tables) {
- pd_set_bit = (result & (1 << max_pd_delay));
- if (pd_set_bit)
- tbl->slot[curr_idx].state = CRM_REQ_STATE_APPLIED;
- max_pd_delay--;
- no_tables--;
- tbl = tbl->next;
- __cam_req_mgr_dec_idx(&curr_idx, 1, in_q->num_slots);
- }
-}
-
-/**
* __cam_req_mgr_process_req()
*
* @brief : processes read index in request queue and traverse through table
@@ -783,7 +803,7 @@
static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link,
uint32_t trigger)
{
- int rc = 0, idx, result = 0;
+ int rc = 0, idx;
struct cam_req_mgr_slot *slot = NULL;
struct cam_req_mgr_req_queue *in_q;
struct cam_req_mgr_core_session *session;
@@ -798,9 +818,9 @@
* - if in applied_state, somthign wrong.
* - if in no_req state, no new req
*/
- CAM_DBG(CAM_CRM, "SOF Req[%lld] idx %d req_status %d",
+ CAM_DBG(CAM_CRM, "SOF Req[%lld] idx %d req_status %d link_hdl %x",
in_q->slot[in_q->rd_idx].req_id, in_q->rd_idx,
- in_q->slot[in_q->rd_idx].status);
+ in_q->slot[in_q->rd_idx].status, link->link_hdl);
slot = &in_q->slot[in_q->rd_idx];
if (slot->status == CRM_SLOT_STATUS_NO_REQ) {
@@ -809,8 +829,8 @@
goto error;
}
- if (trigger != CAM_TRIGGER_POINT_SOF &&
- trigger != CAM_TRIGGER_POINT_EOF)
+ if ((trigger != CAM_TRIGGER_POINT_SOF) &&
+ (trigger != CAM_TRIGGER_POINT_EOF))
goto error;
if ((trigger == CAM_TRIGGER_POINT_EOF) &&
@@ -829,11 +849,10 @@
}
if (slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)
- rc = __cam_req_mgr_process_sync_req(link, slot,
- &result);
+ rc = __cam_req_mgr_process_sync_req(link, slot);
else
rc = __cam_req_mgr_check_link_is_ready(link,
- slot->idx, false, &result);
+ slot->idx, false, true);
if (rc < 0) {
/*
@@ -865,10 +884,10 @@
/* Apply req failed retry at next sof */
slot->status = CRM_SLOT_STATUS_REQ_PENDING;
} else {
- CAM_DBG(CAM_CRM, "Applied req[%lld] on link[%x] success",
- slot->req_id, link->link_hdl);
link->trigger_mask |= trigger;
+ CAM_DBG(CAM_CRM, "Applied req[%lld] on link[%x] success",
+ slot->req_id, link->link_hdl);
spin_lock_bh(&link->link_state_spin_lock);
if (link->state == CAM_CRM_LINK_STATE_ERR) {
CAM_WARN(CAM_CRM, "Err recovery done idx %d",
@@ -877,31 +896,25 @@
}
spin_unlock_bh(&link->link_state_spin_lock);
- if (link->trigger_mask == link->subscribe_event) {
- if (result == link->pd_mask) {
- slot->status = CRM_SLOT_STATUS_REQ_APPLIED;
- CAM_DBG(CAM_CRM, "req %d is applied on link %d",
- slot->req_id, link->link_hdl);
- idx = in_q->rd_idx;
- __cam_req_mgr_dec_idx(
- &idx, link->max_delay + 1,
- in_q->num_slots);
- __cam_req_mgr_reset_req_slot(link, idx);
- } else {
- CAM_DBG(CAM_CRM,
- "Req:%lld not applied on all devices",
- slot->req_id);
- __cam_req_mgr_reset_pd_tables(link, slot,
- result);
- slot->status = CRM_SLOT_STATUS_REQ_PENDING;
- }
+ if (link->sync_link_sof_skip)
+ link->sync_link_sof_skip = false;
+ if (link->trigger_mask == link->subscribe_event) {
+ slot->status = CRM_SLOT_STATUS_REQ_APPLIED;
link->trigger_mask = 0;
+ CAM_DBG(CAM_CRM, "req %d is applied on link %x",
+ slot->req_id,
+ link->link_hdl);
+ idx = in_q->rd_idx;
+ __cam_req_mgr_dec_idx(
+ &idx, link->max_delay + 1,
+ in_q->num_slots);
+ __cam_req_mgr_reset_req_slot(link, idx);
}
}
+
mutex_unlock(&session->lock);
return rc;
-
error:
mutex_unlock(&session->lock);
return rc;
@@ -1138,8 +1151,9 @@
* @brief : Cleans up the mem allocated while linking
* @link : pointer to link, mem associated with this link is freed
*
+ * @return : returns if unlink for any device was success or failure
*/
-static void __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
+static int __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
{
int32_t i = 0;
struct cam_req_mgr_connected_device *dev;
@@ -1160,8 +1174,8 @@
rc = dev->ops->link_setup(&link_data);
if (rc)
CAM_ERR(CAM_CRM,
- "Unlink failed dev_hdl 0x%x rc=%d",
- dev->dev_hdl, rc);
+ "Unlink failed dev_hdl %d",
+ dev->dev_hdl);
}
dev->dev_hdl = 0;
dev->parent = NULL;
@@ -1176,6 +1190,8 @@
link->pd_mask = 0;
link->num_devs = 0;
link->max_delay = 0;
+
+ return rc;
}
/**
@@ -1238,6 +1254,9 @@
/* Loop through and find a free index */
for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
if (!session->links[i]) {
+ CAM_DBG(CAM_CRM,
+ "Free link index %d found, num_links=%d",
+ i, session->num_links);
session->links[i] = link;
break;
}
@@ -1442,9 +1461,9 @@
if (device->ops && device->ops->flush_req)
rc = device->ops->flush_req(&flush_req);
}
+ complete(&link->workq_comp);
mutex_unlock(&link->req.lock);
- complete(&link->workq_comp);
end:
return rc;
}
@@ -1476,13 +1495,12 @@
link = (struct cam_req_mgr_core_link *)priv;
task_data = (struct crm_task_payload *)data;
sched_req = (struct cam_req_mgr_sched_request *)&task_data->u;
- CAM_DBG(CAM_CRM, "link_hdl %x req_id %lld sync_mode %d",
- sched_req->link_hdl,
- sched_req->req_id,
- sched_req->sync_mode);
-
in_q = link->req.in_q;
+ CAM_DBG(CAM_CRM, "link_hdl %x req_id %lld at slot %d sync_mode %d",
+ sched_req->link_hdl, sched_req->req_id,
+ in_q->wr_idx, sched_req->sync_mode);
+
mutex_lock(&link->req.lock);
slot = &in_q->slot[in_q->wr_idx];
@@ -1490,9 +1508,6 @@
slot->status != CRM_SLOT_STATUS_REQ_APPLIED)
CAM_WARN(CAM_CRM, "in_q overwrite %d", slot->status);
- CAM_DBG(CAM_CRM, "sched_req %lld at slot %d sync_mode %d",
- sched_req->req_id, in_q->wr_idx, sched_req->sync_mode);
-
slot->status = CRM_SLOT_STATUS_REQ_ADDED;
slot->req_id = sched_req->req_id;
slot->sync_mode = sched_req->sync_mode;
@@ -1875,9 +1890,9 @@
rc = -EPERM;
goto end;
}
+ crm_timer_reset(link->watchdog);
spin_unlock_bh(&link->link_state_spin_lock);
- crm_timer_reset(link->watchdog);
task = cam_req_mgr_workq_get_task(link->workq);
if (!task) {
CAM_ERR(CAM_CRM, "no empty task req_id %lld", err_info->req_id);
@@ -1938,9 +1953,9 @@
rc = -EPERM;
goto end;
}
+ crm_timer_reset(link->watchdog);
spin_unlock_bh(&link->link_state_spin_lock);
- crm_timer_reset(link->watchdog);
task = cam_req_mgr_workq_get_task(link->workq);
if (!task) {
CAM_ERR(CAM_CRM, "no empty task frame %lld",
@@ -2109,22 +2124,6 @@
return rc;
}
-void cam_req_mgr_handle_core_shutdown(void)
-{
- struct cam_req_mgr_core_session *session;
- struct cam_req_mgr_core_session *tsession;
- struct cam_req_mgr_session_info ses_info;
-
- if (!list_empty(&g_crm_core_dev->session_head)) {
- list_for_each_entry_safe(session, tsession,
- &g_crm_core_dev->session_head, entry) {
- ses_info.session_hdl =
- session->session_hdl;
- cam_req_mgr_destroy_session(&ses_info);
- }
- }
-}
-
/* IOCTLs handling section */
int cam_req_mgr_create_session(
struct cam_req_mgr_session_info *ses_info)
@@ -2185,6 +2184,9 @@
mutex_lock(&link->lock);
spin_lock_bh(&link->link_state_spin_lock);
link->state = CAM_CRM_LINK_STATE_IDLE;
+
+ /* Destroy timer of link */
+ crm_timer_exit(&link->watchdog);
spin_unlock_bh(&link->link_state_spin_lock);
__cam_req_mgr_print_req_tbl(&link->req);
@@ -2192,13 +2194,14 @@
kfree(link->workq->task.pool[0].payload);
link->workq->task.pool[0].payload = NULL;
- /* Destroy workq and timer of link */
- crm_timer_exit(&link->watchdog);
-
+ /* Destroy workq of link */
cam_req_mgr_workq_destroy(&link->workq);
/* Cleanup request tables and unlink devices */
- __cam_req_mgr_destroy_link_info(link);
+ rc = __cam_req_mgr_destroy_link_info(link);
+ if (rc)
+ CAM_ERR(CAM_CORE,
+ "Unlink for all devices was not successful");
/* Free memory holding data of linked devs */
__cam_req_mgr_destroy_subdev(link->l_dev);
@@ -2504,6 +2507,7 @@
}
mutex_lock(&cam_session->lock);
+
CAM_DBG(CAM_CRM, "link handles %x %x",
sync_info->link_hdls[0], sync_info->link_hdls[1]);
@@ -2525,11 +2529,13 @@
link1->sof_counter = -1;
link1->sync_self_ref = -1;
link1->frame_skip_flag = false;
+ link1->sync_link_sof_skip = false;
link1->sync_link = link2;
link2->sof_counter = -1;
link2->sync_self_ref = -1;
link2->frame_skip_flag = false;
+ link2->sync_link_sof_skip = false;
link2->sync_link = link1;
cam_session->sync_mode = sync_info->sync_mode;
@@ -2660,7 +2666,9 @@
}
} else if (control->ops == CAM_REQ_MGR_LINK_DEACTIVATE) {
/* Destroy SOF watchdog timer */
+ spin_lock_bh(&link->link_state_spin_lock);
crm_timer_exit(&link->watchdog);
+ spin_unlock_bh(&link->link_state_spin_lock);
/* notify nodes */
for (j = 0; j < link->num_devs; j++) {
dev = &link->l_dev[j];
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
index 4511a5d..e15b3b0 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -32,6 +32,8 @@
#define MAX_SYNC_COUNT 65535
+#define SYNC_LINK_SOF_CNT_MAX_LMT 1
+
/**
* enum crm_workq_task_type
* @codes: to identify which type of task is present
@@ -79,14 +81,12 @@
* EMPTY : indicates req slot is empty
* PENDING : indicates req slot is waiting for reqs from all devs
* READY : indicates req slot is ready to be sent to devs
- * APPLIED : indicates req slot is already sent to devs
* INVALID : indicates req slot is not in valid state
*/
enum crm_req_state {
CRM_REQ_STATE_EMPTY,
CRM_REQ_STATE_PENDING,
CRM_REQ_STATE_READY,
- CRM_REQ_STATE_APPLIED,
CRM_REQ_STATE_INVALID,
};
@@ -132,6 +132,8 @@
* @apply_data : pointer which various tables will update during traverse
* @in_q : input request queue pointer
* @validate_only : Whether to validate only and/or update settings
+ * @self_link : To indicate whether the check is for the given link or the
+ * other sync link
*/
struct cam_req_mgr_traverse {
int32_t idx;
@@ -140,6 +142,7 @@
struct cam_req_mgr_apply *apply_data;
struct cam_req_mgr_req_queue *in_q;
bool validate_only;
+ bool self_link;
};
/**
@@ -295,6 +298,9 @@
* @sync_self_ref : reference sync count against which the difference
* between sync_counts for a given link is checked
* @frame_skip_flag : flag that determines if a frame needs to be skipped
+ * @sync_link_sof_skip : flag determines if a pkt is not available for a given
+ * frame in a particular link skip corresponding
+ * frame in sync link as well.
*
*/
struct cam_req_mgr_core_link {
@@ -317,6 +323,7 @@
int64_t sof_counter;
int64_t sync_self_ref;
bool frame_skip_flag;
+ bool sync_link_sof_skip;
};
/**
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
index e4944d0..9a93feb 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -25,10 +25,12 @@
#include "cam_subdev.h"
#include "cam_mem_mgr.h"
#include "cam_debug_util.h"
+#include <linux/slub_def.h>
#define CAM_REQ_MGR_EVENT_MAX 30
static struct cam_req_mgr_device g_dev;
+struct kmem_cache *g_cam_req_mgr_timer_cachep;
static int cam_media_device_setup(struct device *dev)
{
@@ -635,6 +637,19 @@
g_dev.state = true;
+ if (g_cam_req_mgr_timer_cachep == NULL) {
+ g_cam_req_mgr_timer_cachep = kmem_cache_create("crm_timer",
+ sizeof(struct cam_req_mgr_timer), 64,
+ SLAB_CONSISTENCY_CHECKS | SLAB_RED_ZONE |
+ SLAB_POISON | SLAB_STORE_USER, NULL);
+ if (!g_cam_req_mgr_timer_cachep)
+ CAM_ERR(CAM_CRM,
+ "Failed to create kmem_cache for crm_timer");
+ else
+ CAM_DBG(CAM_CRM, "Name : %s",
+ g_cam_req_mgr_timer_cachep->name);
+ }
+
return rc;
req_mgr_core_fail:
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h
index 45ebc69..1ca6cc5 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.c
index 2189202..124b336 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -53,9 +53,18 @@
CAM_DBG(CAM_CRM, "init timer %d %pK", expires, *timer);
if (*timer == NULL) {
- crm_timer = (struct cam_req_mgr_timer *)
- kzalloc(sizeof(struct cam_req_mgr_timer), GFP_KERNEL);
- if (!crm_timer) {
+ if (g_cam_req_mgr_timer_cachep) {
+ crm_timer = (struct cam_req_mgr_timer *)
+ kmem_cache_alloc(
+ g_cam_req_mgr_timer_cachep,
+ __GFP_ZERO | GFP_KERNEL);
+ if (!crm_timer) {
+ ret = -ENOMEM;
+ goto end;
+ }
+ }
+
+ else {
ret = -ENOMEM;
goto end;
}
@@ -80,10 +89,11 @@
}
void crm_timer_exit(struct cam_req_mgr_timer **crm_timer)
{
- CAM_DBG(CAM_CRM, "destroy timer %pK", *crm_timer);
+ CAM_DBG(CAM_CRM, "destroy timer %pK @ %pK", *crm_timer, crm_timer);
if (*crm_timer) {
del_timer_sync(&(*crm_timer)->sys_timer);
- kfree(*crm_timer);
+ if (g_cam_req_mgr_timer_cachep)
+ kmem_cache_free(g_cam_req_mgr_timer_cachep, *crm_timer);
*crm_timer = NULL;
}
}
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.h
index 4d600ee..b3e473a 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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,6 @@
* @timer : timer pointer which will be freed
*/
void crm_timer_exit(struct cam_req_mgr_timer **timer);
+
+extern struct kmem_cache *g_cam_req_mgr_timer_cachep;
#endif
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
index f357941..dda04f8 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -296,7 +296,7 @@
idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl);
if (idx >= CAM_REQ_MGR_MAX_HANDLES) {
- CAM_ERR(CAM_CRM, "Invalid idx");
+ CAM_ERR(CAM_CRM, "Invalid idx %d", idx);
goto destroy_hdl_fail;
}
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
index c48a391..966b573 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -98,8 +98,10 @@
static void cam_req_mgr_process_workq(struct work_struct *w)
{
struct cam_req_mgr_core_workq *workq = NULL;
- struct crm_workq_task *task, *task_save;
+ struct crm_workq_task *task;
int32_t i = CRM_TASK_PRIORITY_0;
+ unsigned long flags = 0;
+
if (!w) {
CAM_ERR(CAM_CRM, "NULL task pointer can not schedule");
return;
@@ -108,15 +110,19 @@
container_of(w, struct cam_req_mgr_core_workq, work);
while (i < CRM_TASK_PRIORITY_MAX) {
- if (!list_empty(&workq->task.process_head[i])) {
- list_for_each_entry_safe(task, task_save,
- &workq->task.process_head[i], entry) {
- atomic_sub(1, &workq->task.pending_cnt);
- cam_req_mgr_process_task(task);
- }
+ WORKQ_ACQUIRE_LOCK(workq, flags);
+ while (!list_empty(&workq->task.process_head[i])) {
+ task = list_first_entry(&workq->task.process_head[i],
+ struct crm_workq_task, entry);
+ atomic_sub(1, &workq->task.pending_cnt);
+ list_del_init(&task->entry);
+ WORKQ_RELEASE_LOCK(workq, flags);
+ cam_req_mgr_process_task(task);
CAM_DBG(CAM_CRM, "processed task %pK free_cnt %d",
task, atomic_read(&workq->task.free_cnt));
+ WORKQ_ACQUIRE_LOCK(workq, flags);
}
+ WORKQ_RELEASE_LOCK(workq, flags);
i++;
}
}
@@ -267,6 +273,7 @@
destroy_workqueue((*crm_workq)->job);
(*crm_workq)->job = NULL;
}
+ kfree((*crm_workq)->task.pool);
kfree(*crm_workq);
*crm_workq = NULL;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
index 9a711ec..b975418 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -87,6 +87,7 @@
struct cam_hw_soc_info *soc_info =
&cci_dev->soc_info;
void __iomem *base = soc_info->reg_map[0].mem_base;
+ unsigned long flags;
read_val = cam_io_r_mb(base +
CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset);
@@ -110,12 +111,16 @@
CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
reg_val = 1 << ((master * 2) + queue);
CAM_DBG(CAM_CCI, "CCI_QUEUE_START_ADDR");
+ spin_lock_irqsave(
+ &cci_dev->cci_master_info[master].lock_q[queue], flags);
atomic_set(&cci_dev->cci_master_info[master].
done_pending[queue], 1);
cam_io_w_mb(reg_val, base +
CCI_QUEUE_START_ADDR);
CAM_DBG(CAM_CCI, "wait_for_completion_timeout");
atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
+ spin_unlock_irqrestore(
+ &cci_dev->cci_master_info[master].lock_q[queue], flags);
rc = wait_for_completion_timeout(&cci_dev->
cci_master_info[master].report_q[queue], CCI_TIMEOUT);
if (rc <= 0) {
@@ -183,45 +188,46 @@
uint32_t read_val = 0;
uint32_t i = 0;
uint32_t reg_offset = 0;
+ void __iomem *base = cci_dev->soc_info.reg_map[0].mem_base;
/* CCI Top Registers */
- CAM_DBG(CAM_CCI, "****CCI TOP Registers ****");
+ CAM_INFO(CAM_CCI, "****CCI TOP Registers ****");
for (i = 0; i < DEBUG_TOP_REG_COUNT; i++) {
reg_offset = DEBUG_TOP_REG_START + i * 4;
- read_val = cam_io_r_mb(cci_dev->base + reg_offset);
- CAM_DBG(CAM_CCI, "offset = 0x%X value = 0x%X",
+ read_val = cam_io_r_mb(base + reg_offset);
+ CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X",
reg_offset, read_val);
}
/* CCI Master registers */
- CAM_DBG(CAM_CCI, "****CCI MASTER %d Registers ****",
+ CAM_INFO(CAM_CCI, "****CCI MASTER %d Registers ****",
master);
for (i = 0; i < DEBUG_MASTER_REG_COUNT; i++) {
if (i == 6)
continue;
reg_offset = DEBUG_MASTER_REG_START + master*0x100 + i * 4;
- read_val = cam_io_r_mb(cci_dev->base + reg_offset);
- CAM_DBG(CAM_CCI, "offset = 0x%X value = 0x%X",
+ read_val = cam_io_r_mb(base + reg_offset);
+ CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X",
reg_offset, read_val);
}
/* CCI Master Queue registers */
- CAM_DBG(CAM_CCI, " **** CCI MASTER%d QUEUE%d Registers ****",
+ CAM_INFO(CAM_CCI, " **** CCI MASTER%d QUEUE%d Registers ****",
master, queue);
for (i = 0; i < DEBUG_MASTER_QUEUE_REG_COUNT; i++) {
reg_offset = DEBUG_MASTER_QUEUE_REG_START + master*0x200 +
queue*0x100 + i * 4;
- read_val = cam_io_r_mb(cci_dev->base + reg_offset);
- CAM_DBG(CAM_CCI, "offset = 0x%X value = 0x%X",
+ read_val = cam_io_r_mb(base + reg_offset);
+ CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X",
reg_offset, read_val);
}
/* CCI Interrupt registers */
- CAM_DBG(CAM_CCI, " ****CCI Interrupt Registers ****");
+ CAM_INFO(CAM_CCI, " ****CCI Interrupt Registers ****");
for (i = 0; i < DEBUG_INTR_REG_COUNT; i++) {
reg_offset = DEBUG_INTR_REG_START + i * 4;
- read_val = cam_io_r_mb(cci_dev->base + reg_offset);
- CAM_DBG(CAM_CCI, "offset = 0x%X value = 0x%X",
+ read_val = cam_io_r_mb(base + reg_offset);
+ CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X",
reg_offset, read_val);
}
}
@@ -289,6 +295,7 @@
enum cci_i2c_master_t master,
enum cci_i2c_queue_t queue)
{
+ unsigned long flags;
struct cam_hw_soc_info *soc_info =
&cci_dev->soc_info;
void __iomem *base = soc_info->reg_map[0].mem_base;
@@ -296,8 +303,12 @@
uint32_t reg_val = 1 << ((master * 2) + queue);
cam_cci_load_report_cmd(cci_dev, master, queue);
+ spin_lock_irqsave(
+ &cci_dev->cci_master_info[master].lock_q[queue], flags);
atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
atomic_set(&cci_dev->cci_master_info[master].done_pending[queue], 1);
+ spin_unlock_irqrestore(
+ &cci_dev->cci_master_info[master].lock_q[queue], flags);
cam_io_w_mb(reg_val, base +
CCI_QUEUE_START_ADDR);
@@ -309,8 +320,13 @@
enum cci_i2c_queue_t queue)
{
int32_t rc = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 0) {
+ spin_unlock_irqrestore(
+ &cci_dev->cci_master_info[master].lock_q[queue], flags);
rc = cam_cci_lock_queue(cci_dev, master, queue, 0);
if (rc < 0) {
CAM_ERR(CAM_CCI, "failed rc: %d", rc);
@@ -324,6 +340,8 @@
} else {
atomic_set(&cci_dev->cci_master_info[master].
done_pending[queue], 1);
+ spin_unlock_irqrestore(
+ &cci_dev->cci_master_info[master].lock_q[queue], flags);
rc = cam_cci_wait(cci_dev, master, queue);
if (rc < 0) {
CAM_ERR(CAM_CCI, "failed rc %d", rc);
@@ -371,13 +389,18 @@
&cci_dev->soc_info;
void __iomem *base = soc_info->reg_map[0].mem_base;
uint32_t reg_val = 1 << ((master * 2) + queue);
+ unsigned long flags;
+ spin_lock_irqsave(&cci_dev->cci_master_info[master].lock_q[queue],
+ flags);
if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 0) {
cam_cci_load_report_cmd(cci_dev, master, queue);
atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
cam_io_w_mb(reg_val, base +
CCI_QUEUE_START_ADDR);
}
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[master].lock_q[queue],
+ flags);
}
static int32_t cam_cci_process_full_q(struct cci_device *cci_dev,
@@ -385,16 +408,24 @@
enum cci_i2c_queue_t queue)
{
int32_t rc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cci_dev->cci_master_info[master].lock_q[queue],
+ flags);
if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 1) {
atomic_set(&cci_dev->cci_master_info[master].
done_pending[queue], 1);
+ spin_unlock_irqrestore(
+ &cci_dev->cci_master_info[master].lock_q[queue], flags);
rc = cam_cci_wait(cci_dev, master, queue);
if (rc < 0) {
CAM_ERR(CAM_CCI, "failed rc %d", rc);
return rc;
}
} else {
+ spin_unlock_irqrestore(
+ &cci_dev->cci_master_info[master].lock_q[queue], flags);
rc = cam_cci_wait_report_cmd(cci_dev, master, queue);
if (rc < 0) {
CAM_ERR(CAM_CCI, "failed rc %d", rc);
@@ -442,6 +473,10 @@
if (cmd->reg_addr + 1 ==
(cmd+1)->reg_addr) {
len += data_len;
+ if (len > cci_dev->payload_size) {
+ len = len - data_len;
+ break;
+ }
(*pack)++;
} else {
break;
@@ -598,6 +633,7 @@
struct cam_hw_soc_info *soc_info =
&cci_dev->soc_info;
void __iomem *base = soc_info->reg_map[0].mem_base;
+ unsigned long flags;
if (i2c_cmd == NULL) {
CAM_ERR(CAM_CCI, "Failed: i2c cmd is NULL");
@@ -640,7 +676,11 @@
cam_io_w_mb(val, base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
reg_offset);
+ spin_lock_irqsave(&cci_dev->cci_master_info[master].lock_q[queue],
+ flags);
atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 0);
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[master].lock_q[queue],
+ flags);
max_queue_size = cci_dev->cci_i2c_queue_info[master][queue].
max_queue_size;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
index ed91250..8fb2468 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -64,6 +64,7 @@
struct cam_hw_soc_info *soc_info =
&cci_dev->soc_info;
void __iomem *base = soc_info->reg_map[0].mem_base;
+ unsigned long flags;
irq = cam_io_r_mb(base + CCI_IRQ_STATUS_0_ADDR);
cam_io_w_mb(irq, base + CCI_IRQ_CLEAR_0_ADDR);
@@ -91,23 +92,35 @@
struct cam_cci_master_info *cci_master_info;
cci_master_info = &cci_dev->cci_master_info[MASTER_0];
+ spin_lock_irqsave(
+ &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_0],
+ flags);
atomic_set(&cci_master_info->q_free[QUEUE_0], 0);
cci_master_info->status = 0;
if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) {
complete(&cci_master_info->report_q[QUEUE_0]);
atomic_set(&cci_master_info->done_pending[QUEUE_0], 0);
}
+ spin_unlock_irqrestore(
+ &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_0],
+ flags);
}
if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK) {
struct cam_cci_master_info *cci_master_info;
cci_master_info = &cci_dev->cci_master_info[MASTER_0];
+ spin_lock_irqsave(
+ &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_1],
+ flags);
atomic_set(&cci_master_info->q_free[QUEUE_1], 0);
cci_master_info->status = 0;
if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) {
complete(&cci_master_info->report_q[QUEUE_1]);
atomic_set(&cci_master_info->done_pending[QUEUE_1], 0);
}
+ spin_unlock_irqrestore(
+ &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_1],
+ flags);
}
if (irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) {
cci_dev->cci_master_info[MASTER_1].status = 0;
@@ -117,23 +130,35 @@
struct cam_cci_master_info *cci_master_info;
cci_master_info = &cci_dev->cci_master_info[MASTER_1];
+ spin_lock_irqsave(
+ &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_0],
+ flags);
atomic_set(&cci_master_info->q_free[QUEUE_0], 0);
cci_master_info->status = 0;
if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) {
complete(&cci_master_info->report_q[QUEUE_0]);
atomic_set(&cci_master_info->done_pending[QUEUE_0], 0);
}
+ spin_unlock_irqrestore(
+ &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_0],
+ flags);
}
if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK) {
struct cam_cci_master_info *cci_master_info;
cci_master_info = &cci_dev->cci_master_info[MASTER_1];
+ spin_lock_irqsave(
+ &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_1],
+ flags);
atomic_set(&cci_master_info->q_free[QUEUE_1], 0);
cci_master_info->status = 0;
if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) {
complete(&cci_master_info->report_q[QUEUE_1]);
atomic_set(&cci_master_info->done_pending[QUEUE_1], 0);
}
+ spin_unlock_irqrestore(
+ &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_1],
+ flags);
}
if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) {
cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h
index d0ee0f6..d25964e 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -144,6 +144,7 @@
struct mutex mutex_q[NUM_QUEUES];
struct completion report_q[NUM_QUEUES];
atomic_t done_pending[NUM_QUEUES];
+ spinlock_t lock_q[NUM_QUEUES];
};
struct cam_cci_clk_params_t {
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c
index cf7a65f..14737f9 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -198,7 +198,9 @@
mutex_init(&new_cci_dev->cci_master_info[i].mutex_q[j]);
init_completion(&new_cci_dev->
cci_master_info[i].report_q[j]);
- }
+ spin_lock_init(
+ &new_cci_dev->cci_master_info[i].lock_q[j]);
+ }
}
}
@@ -390,7 +392,6 @@
cci_dev->cci_state = CCI_STATE_DISABLED;
cci_dev->cycles_per_us = 0;
- soc_info->src_clk_idx = 0;
cam_cpas_stop(cci_dev->cpas_handle);
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 262e49c..4f30f56 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -71,9 +71,9 @@
csiphy_reset_reg[i].reg_addr);
usleep_range(csiphy_dev->ctrl_reg->
- csiphy_reset_reg[i].delay * 100,
+ csiphy_reset_reg[i].delay * 1000,
csiphy_dev->ctrl_reg->
- csiphy_reset_reg[i].delay * 100 + 1000);
+ csiphy_reset_reg[i].delay * 1000 + 10);
}
}
@@ -285,6 +285,10 @@
csiphybase +
csiphy_dev->ctrl_reg->
csiphy_common_reg[i].reg_addr);
+ usleep_range(csiphy_dev->ctrl_reg->
+ csiphy_common_reg[i].delay*1000,
+ csiphy_dev->ctrl_reg->
+ csiphy_common_reg[i].delay*1000 + 10);
break;
case CSIPHY_DEFAULT_PARAMS:
cam_io_w_mb(csiphy_dev->ctrl_reg->
@@ -292,6 +296,10 @@
csiphybase +
csiphy_dev->ctrl_reg->
csiphy_common_reg[i].reg_addr);
+ usleep_range(csiphy_dev->ctrl_reg->
+ csiphy_common_reg[i].delay*1000,
+ csiphy_dev->ctrl_reg->
+ csiphy_common_reg[i].delay*1000 + 10);
break;
default:
break;
@@ -506,6 +514,13 @@
bridge_params.media_entity_flag = 0;
bridge_params.priv = csiphy_dev;
+ if (csiphy_acq_params.combo_mode >= 2) {
+ CAM_ERR(CAM_CSIPHY, "Invalid combo_mode %d",
+ csiphy_acq_params.combo_mode);
+ rc = -EINVAL;
+ goto release_mutex;
+ }
+
csiphy_acq_dev.device_handle =
cam_create_device_hdl(&bridge_params);
csiphy_dev->bridge_intf.
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h
index 2977834..3f743fc 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -19,8 +19,8 @@
.mipi_csiphy_interrupt_status0_addr = 0x8B0,
.mipi_csiphy_interrupt_clear0_addr = 0x858,
.mipi_csiphy_glbl_irq_cmd_addr = 0x828,
- .csiphy_common_array_size = 3,
- .csiphy_reset_array_size = 3,
+ .csiphy_common_array_size = 5,
+ .csiphy_reset_array_size = 5,
.csiphy_2ph_config_array_size = 14,
.csiphy_3ph_config_array_size = 19,
};
@@ -29,12 +29,16 @@
{0x0814, 0x00, 0x00, CSIPHY_LANE_ENABLE},
{0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS},
+ {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS},
+ {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
};
struct csiphy_reg_t csiphy_reset_reg_1_0[] = {
- {0x0814, 0x00, 0x50, CSIPHY_LANE_ENABLE},
+ {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE},
{0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+ {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS},
+ {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
};
struct csiphy_reg_t csiphy_irq_reg_1_0[] = {
@@ -148,7 +152,7 @@
{0x0008, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
{0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
- {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+ {0x0060, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
},
{
@@ -164,7 +168,7 @@
{0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS},
- {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+ {0x0760, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
},
{
@@ -179,7 +183,7 @@
{0x0208, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
{0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
- {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+ {0x0260, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
},
{
@@ -194,7 +198,7 @@
{0x0408, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
{0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
- {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+ {0x0460, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
},
{
@@ -210,7 +214,7 @@
{0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS},
- {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+ {0x0660, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
{0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
},
};
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
index 23d25a4..e7110b8 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -271,8 +271,8 @@
static int delete_req(struct cam_flash_ctrl *fctrl, uint64_t req_id)
{
int i = 0;
- int frame_offset = 0;
struct cam_flash_frame_setting *flash_data = NULL;
+ uint64_t top = 0, del_req_id = 0;
if (req_id == 0) {
flash_data = &fctrl->nrt_info;
@@ -288,14 +288,52 @@
is_settings_valid = false;
}
} else {
- frame_offset = (req_id + MAX_PER_FRAME_ARRAY -
- CAM_FLASH_PIPELINE_DELAY) % 8;
- flash_data = &fctrl->per_frame[frame_offset];
- if (req_id > flash_data->cmn_attr.request_id) {
- flash_data->cmn_attr.request_id = 0;
- flash_data->cmn_attr.is_settings_valid = false;
- for (i = 0; i < flash_data->cmn_attr.count; i++)
- flash_data->led_current_ma[i] = 0;
+ for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) {
+ flash_data = &fctrl->per_frame[i];
+ if (req_id >= flash_data->cmn_attr.request_id &&
+ flash_data->cmn_attr.is_settings_valid
+ == 1) {
+ if (top < flash_data->cmn_attr.request_id) {
+ del_req_id = top;
+ top = flash_data->cmn_attr.request_id;
+ } else if (top >
+ flash_data->cmn_attr.request_id &&
+ del_req_id <
+ flash_data->cmn_attr.request_id) {
+ del_req_id =
+ flash_data->cmn_attr.request_id;
+ }
+ }
+ }
+
+ if (top < req_id) {
+ if ((((top % MAX_PER_FRAME_ARRAY) - (req_id %
+ MAX_PER_FRAME_ARRAY)) >= BATCH_SIZE_MAX) ||
+ (((top % MAX_PER_FRAME_ARRAY) - (req_id %
+ MAX_PER_FRAME_ARRAY)) <= -BATCH_SIZE_MAX))
+ del_req_id = req_id;
+ }
+
+ if (!del_req_id)
+ return 0;
+
+ CAM_DBG(CAM_FLASH, "top: %llu, del_req_id:%llu",
+ top, del_req_id);
+
+ for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) {
+ flash_data = &fctrl->per_frame[i];
+ if ((del_req_id ==
+ flash_data->cmn_attr.request_id) &&
+ (flash_data->cmn_attr.
+ is_settings_valid == 1)) {
+ CAM_DBG(CAM_FLASH, "Deleting request[%d] %llu",
+ i, flash_data->cmn_attr.request_id);
+ flash_data->cmn_attr.request_id = 0;
+ flash_data->cmn_attr.is_settings_valid = false;
+ flash_data->opcode = 0;
+ for (i = 0; i < flash_data->cmn_attr.count; i++)
+ flash_data->led_current_ma[i] = 0;
+ }
}
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
index 085bcf6..6120e02 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -41,6 +41,8 @@
CAM_ERR(CAM_FLASH,
"Cannot apply Acquire dev: Prev state: %d",
fctrl->flash_state);
+ rc = -EINVAL;
+ goto release_mutex;
}
if (fctrl->bridge_intf.device_hdl != -1) {
@@ -161,6 +163,8 @@
CAM_WARN(CAM_FLASH,
"Cannot apply Stop dev: Prev state is: %d",
fctrl->flash_state);
+ rc = -EINVAL;
+ goto release_mutex;
}
rc = cam_flash_stop_dev(fctrl);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
index db80584..3a0a6d6 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -299,6 +299,7 @@
uint16_t total_bytes = 0;
uint8_t *ptr = NULL;
int32_t rc = 0, cnt;
+ uint32_t fw_size;
const struct firmware *fw = NULL;
const char *fw_name_prog = NULL;
const char *fw_name_coeff = NULL;
@@ -306,6 +307,7 @@
char name_coeff[32] = {0};
struct device *dev = &(o_ctrl->pdev->dev);
struct cam_sensor_i2c_reg_setting i2c_reg_setting;
+ struct page *page = NULL;
if (!o_ctrl) {
CAM_ERR(CAM_OIS, "Invalid Args");
@@ -331,15 +333,20 @@
i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
i2c_reg_setting.size = total_bytes;
- i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *)
- kzalloc(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes,
- GFP_KERNEL);
- if (!i2c_reg_setting.reg_setting) {
+ i2c_reg_setting.delay = 0;
+ fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) *
+ total_bytes) >> PAGE_SHIFT;
+ page = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)),
+ fw_size, 0);
+ if (!page) {
CAM_ERR(CAM_OIS, "Failed in allocating i2c_array");
release_firmware(fw);
return -ENOMEM;
}
+ i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *)(
+ page_address(page));
+
for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes;
cnt++, ptr++) {
i2c_reg_setting.reg_setting[cnt].reg_addr =
@@ -355,7 +362,10 @@
CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc);
goto release_firmware;
}
- kfree(i2c_reg_setting.reg_setting);
+ cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)),
+ page, fw_size);
+ page = NULL;
+ fw_size = 0;
release_firmware(fw);
rc = request_firmware(&fw, fw_name_coeff, dev);
@@ -368,15 +378,20 @@
i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
i2c_reg_setting.size = total_bytes;
- i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *)
- kzalloc(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes,
- GFP_KERNEL);
- if (!i2c_reg_setting.reg_setting) {
+ i2c_reg_setting.delay = 0;
+ fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) *
+ total_bytes) >> PAGE_SHIFT;
+ page = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)),
+ fw_size, 0);
+ if (!page) {
CAM_ERR(CAM_OIS, "Failed in allocating i2c_array");
release_firmware(fw);
return -ENOMEM;
}
+ i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *)(
+ page_address(page));
+
for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes;
cnt++, ptr++) {
i2c_reg_setting.reg_setting[cnt].reg_addr =
@@ -392,7 +407,8 @@
CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc);
release_firmware:
- kfree(i2c_reg_setting.reg_setting);
+ cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)),
+ page, fw_size);
release_firmware(fw);
return rc;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.h
index 516ac88..d6f0ec5 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -12,6 +12,8 @@
#ifndef _CAM_OIS_CORE_H_
#define _CAM_OIS_CORE_H_
+#include <linux/cma.h>
+#include <linux/dma-contiguous.h>
#include "cam_ois_dev.h"
/**
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 d5bb1b0..5a1b67c 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
@@ -161,12 +161,20 @@
break;
}
case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON: {
+ if (s_ctrl->streamon_count > 0)
+ return 0;
+
+ s_ctrl->streamon_count = s_ctrl->streamon_count + 1;
i2c_reg_settings = &i2c_data->streamon_settings;
i2c_reg_settings->request_id = 0;
i2c_reg_settings->is_settings_valid = 1;
break;
}
case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF: {
+ if (s_ctrl->streamoff_count > 0)
+ return 0;
+
+ s_ctrl->streamoff_count = s_ctrl->streamoff_count + 1;
i2c_reg_settings = &i2c_data->streamoff_settings;
i2c_reg_settings->request_id = 0;
i2c_reg_settings->is_settings_valid = 1;
@@ -185,8 +193,9 @@
&i2c_data->
per_frame[csl_packet->header.request_id %
MAX_PER_FRAME_ARRAY];
- CAM_DBG(CAM_SENSOR, "Received Packet: %lld",
- csl_packet->header.request_id % MAX_PER_FRAME_ARRAY);
+ CAM_DBG(CAM_SENSOR, "Received Packet: %lld req: %lld",
+ csl_packet->header.request_id % MAX_PER_FRAME_ARRAY,
+ csl_packet->header.request_id);
if (i2c_reg_settings->is_settings_valid == 1) {
CAM_ERR(CAM_SENSOR,
"Already some pkt in offset req : %lld",
@@ -514,6 +523,8 @@
kfree(power_info->power_setting);
kfree(power_info->power_down_setting);
+ s_ctrl->streamon_count = 0;
+ s_ctrl->streamoff_count = 0;
s_ctrl->sensor_state = CAM_SENSOR_INIT;
}
@@ -714,6 +725,9 @@
}
s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
+ CAM_INFO(CAM_SENSOR,
+ "CAM_ACQUIRE_DEV Success, sensor_id:0x%x",
+ s_ctrl->sensordata->slave_info.sensor_id);
}
break;
case CAM_RELEASE_DEV: {
@@ -751,6 +765,11 @@
s_ctrl->bridge_intf.session_hdl = -1;
s_ctrl->sensor_state = CAM_SENSOR_INIT;
+ CAM_INFO(CAM_SENSOR,
+ "CAM_RELEASE_DEV Success, sensor_id:0x%x",
+ s_ctrl->sensordata->slave_info.sensor_id);
+ s_ctrl->streamon_count = 0;
+ s_ctrl->streamoff_count = 0;
}
break;
case CAM_QUERY_CAP: {
@@ -786,6 +805,9 @@
}
}
s_ctrl->sensor_state = CAM_SENSOR_START;
+ CAM_INFO(CAM_SENSOR,
+ "CAM_START_DEV Success, sensor_id:0x%x",
+ s_ctrl->sensordata->slave_info.sensor_id);
}
break;
case CAM_STOP_DEV: {
@@ -809,6 +831,9 @@
cam_sensor_release_resource(s_ctrl);
s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
+ CAM_INFO(CAM_SENSOR,
+ "CAM_STOP_DEV Success, sensor_id:0x%x",
+ s_ctrl->sensordata->slave_info.sensor_id);
}
break;
case CAM_CONFIG_DEV: {
@@ -986,7 +1011,8 @@
int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl,
int64_t req_id, enum cam_sensor_packet_opcodes opcode)
{
- int rc = 0, offset, del_req_id;
+ int rc = 0, offset, i;
+ uint64_t top = 0, del_req_id = 0;
struct i2c_settings_array *i2c_set = NULL;
struct i2c_settings_list *i2c_list;
@@ -1049,21 +1075,46 @@
"Invalid/NOP request to apply: %lld", req_id);
}
- del_req_id = (req_id + MAX_PER_FRAME_ARRAY -
- MAX_SYSTEM_PIPELINE_DELAY) % MAX_PER_FRAME_ARRAY;
- CAM_DBG(CAM_SENSOR, "Deleting the Request: %d", del_req_id);
-
- if ((req_id >
- s_ctrl->i2c_data.per_frame[del_req_id].request_id) &&
- (s_ctrl->i2c_data.per_frame[del_req_id].
+ /* Change the logic dynamically */
+ for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) {
+ if ((req_id >=
+ s_ctrl->i2c_data.per_frame[i].request_id) &&
+ (top <
+ s_ctrl->i2c_data.per_frame[i].request_id) &&
+ (s_ctrl->i2c_data.per_frame[i].
is_settings_valid == 1)) {
- s_ctrl->i2c_data.per_frame[del_req_id].request_id = 0;
- rc = delete_request(
- &(s_ctrl->i2c_data.per_frame[del_req_id]));
- if (rc < 0)
- CAM_ERR(CAM_SENSOR,
- "Delete request Fail:%d rc:%d",
- del_req_id, rc);
+ del_req_id = top;
+ top = s_ctrl->i2c_data.per_frame[i].request_id;
+ }
+ }
+
+ if (top < req_id) {
+ if ((((top % MAX_PER_FRAME_ARRAY) - (req_id %
+ MAX_PER_FRAME_ARRAY)) >= BATCH_SIZE_MAX) ||
+ (((top % MAX_PER_FRAME_ARRAY) - (req_id %
+ MAX_PER_FRAME_ARRAY)) <= -BATCH_SIZE_MAX))
+ del_req_id = req_id;
+ }
+
+ if (!del_req_id)
+ return rc;
+
+ CAM_DBG(CAM_SENSOR, "top: %llu, del_req_id:%llu",
+ top, del_req_id);
+
+ for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) {
+ if ((del_req_id >
+ s_ctrl->i2c_data.per_frame[i].request_id) &&
+ (s_ctrl->i2c_data.per_frame[i].
+ is_settings_valid == 1)) {
+ s_ctrl->i2c_data.per_frame[i].request_id = 0;
+ rc = delete_request(
+ &(s_ctrl->i2c_data.per_frame[i]));
+ if (rc < 0)
+ CAM_ERR(CAM_SENSOR,
+ "Delete request Fail:%lld rc:%d",
+ del_req_id, rc);
+ }
}
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h
index 624ea29..cc6070c 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -90,6 +90,8 @@
* @sensor_info: Sensor query cap structure
* @bridge_intf: Bridge interface structure
* @device_name: Sensor device structure
+ * @streamon_count: Count to hold the number of times stream on called
+ * @streamoff_count: Count to hold the number of times stream off called
*/
struct cam_sensor_ctrl_t {
struct platform_device *pdev;
@@ -109,6 +111,8 @@
struct cam_sensor_query_cap sensor_info;
struct intf_params bridge_intf;
char device_name[20];
+ uint32_t streamon_count;
+ uint32_t streamoff_count;
};
#endif /* _CAM_SENSOR_DEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
index 131b0ae..626b263 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -112,31 +112,49 @@
{
int32_t rc = -EINVAL;
struct spi_device *spi = client->spi_client->spi_master;
+ struct device *dev = NULL;
char *ctx = NULL, *crx = NULL;
uint32_t len, hlen;
uint8_t retries = client->spi_client->retries;
+ uint32_t txr = 0, rxr = 0;
+ struct page *page_tx = NULL, *page_rx = NULL;
hlen = cam_camera_spi_get_hlen(inst);
len = hlen + num_byte;
+ dev = &(spi->dev);
+
+ if (!dev) {
+ CAM_ERR(CAM_SENSOR, "Invalid arguments");
+ return -EINVAL;
+ }
if (tx) {
ctx = tx;
} else {
- ctx = kzalloc(len, GFP_KERNEL | GFP_DMA);
- if (!ctx)
+ txr = PAGE_ALIGN(len) >> PAGE_SHIFT;
+ page_tx = cma_alloc(dev_get_cma_area(dev),
+ txr, 0);
+ if (!page_tx)
return -ENOMEM;
+
+ ctx = page_address(page_tx);
}
if (num_byte) {
if (rx) {
crx = rx;
} else {
- crx = kzalloc(len, GFP_KERNEL | GFP_DMA);
- if (!crx) {
+ rxr = PAGE_ALIGN(len) >> PAGE_SHIFT;
+ page_rx = cma_alloc(dev_get_cma_area(dev),
+ rxr, 0);
+ if (!page_rx) {
if (!tx)
- kfree(ctx);
+ cma_release(dev_get_cma_area(dev),
+ page_tx, txr);
+
return -ENOMEM;
}
+ crx = page_address(page_rx);
}
} else {
crx = NULL;
@@ -157,9 +175,9 @@
out:
if (!tx)
- kfree(ctx);
+ cma_release(dev_get_cma_area(dev), page_tx, txr);
if (!rx)
- kfree(crx);
+ cma_release(dev_get_cma_area(dev), page_rx, rxr);
return rc;
}
@@ -468,6 +486,63 @@
return rc;
}
+int32_t cam_spi_write_seq(struct camera_io_master *client,
+ uint32_t addr, uint8_t *data,
+ enum camera_sensor_i2c_type addr_type, uint32_t num_byte)
+{
+ struct cam_camera_spi_inst *pg =
+ &client->spi_client->cmd_tbl.page_program;
+ const uint32_t page_size = client->spi_client->page_size;
+ uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len;
+ uint16_t len;
+ uint32_t cur_len, end;
+ char *tx, *pdata = data;
+ int rc = -EINVAL;
+
+ if ((addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) ||
+ (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID))
+ return rc;
+ /* single page write */
+ if ((addr % page_size) + num_byte <= page_size) {
+ len = header_len + num_byte;
+ tx = kmalloc(len, GFP_KERNEL | GFP_DMA);
+ if (!tx)
+ goto NOMEM;
+ rc = cam_spi_page_program(client, addr, data, addr_type,
+ num_byte, tx);
+ if (rc < 0)
+ goto ERROR;
+ goto OUT;
+ }
+ /* multi page write */
+ len = header_len + page_size;
+ tx = kmalloc(len, GFP_KERNEL | GFP_DMA);
+ if (!tx)
+ goto NOMEM;
+ while (num_byte) {
+ end = min(page_size, (addr % page_size) + num_byte);
+ cur_len = end - (addr % page_size);
+ CAM_ERR(CAM_SENSOR, "Addr: 0x%x curr_len: 0x%x pgSize: %d",
+ addr, cur_len, page_size);
+ rc = cam_spi_page_program(client, addr, pdata, addr_type,
+ cur_len, tx);
+ if (rc < 0)
+ goto ERROR;
+ addr += cur_len;
+ pdata += cur_len;
+ num_byte -= cur_len;
+ }
+ goto OUT;
+NOMEM:
+ pr_err("%s: memory allocation failed\n", __func__);
+ return -ENOMEM;
+ERROR:
+ pr_err("%s: error write\n", __func__);
+OUT:
+ kfree(tx);
+ return rc;
+}
+
int cam_spi_write_table(struct camera_io_master *client,
struct cam_sensor_i2c_reg_setting *write_setting)
{
@@ -508,3 +583,35 @@
addr_type = client_addr_type;
return rc;
}
+
+int cam_spi_erase(struct camera_io_master *client,
+ uint32_t addr, enum camera_sensor_i2c_type addr_type,
+ uint32_t size) {
+ struct cam_camera_spi_inst *se = &client->spi_client->cmd_tbl.erase;
+ int rc = 0;
+ uint32_t cur;
+ uint32_t end = addr + size;
+ uint32_t erase_size = client->spi_client->erase_size;
+
+ end = addr + size;
+ for (cur = rounddown(addr, erase_size); cur < end; cur += erase_size) {
+ CAM_ERR(CAM_SENSOR, "%s: erasing 0x%x size: %d\n",
+ __func__, cur, erase_size);
+ rc = cam_spi_write_enable(client, addr_type);
+ if (rc < 0)
+ return rc;
+ rc = cam_spi_tx_helper(client, se, cur, NULL, addr_type, 0,
+ NULL, NULL);
+ if (rc < 0) {
+ CAM_ERR(CAM_SENSOR, "%s: erase failed\n", __func__);
+ return rc;
+ }
+ rc = cam_spi_wait(client, se, addr_type);
+ if (rc < 0) {
+ CAM_ERR(CAM_SENSOR, "%s: erase timedout\n", __func__);
+ return rc;
+ }
+ }
+
+ return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h
index ec1bede..8ce45d8 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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,8 @@
#define _CAM_SENSOR_SPI_H_
#include <linux/spi/spi.h>
+#include <linux/cma.h>
+#include <linux/dma-contiguous.h>
#include <media/cam_sensor.h>
#include "cam_sensor_i2c.h"
@@ -99,4 +101,12 @@
int cam_spi_write_table(struct camera_io_master *client,
struct cam_sensor_i2c_reg_setting *write_setting);
+int cam_spi_erase(struct camera_io_master *client,
+ uint32_t addr, enum camera_sensor_i2c_type addr_type,
+ uint32_t size);
+
+int32_t cam_spi_write_seq(struct camera_io_master *client,
+ uint32_t addr, uint8_t *data,
+ enum camera_sensor_i2c_type addr_type, uint32_t num_byte);
+
#endif
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
index 622dae6..fddff38 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
@@ -27,6 +27,7 @@
#define MAX_POWER_CONFIG 12
#define MAX_PER_FRAME_ARRAY 32
+#define BATCH_SIZE_MAX 16
#define CAM_SENSOR_NAME "cam-sensor"
#define CAM_ACTUATOR_NAME "cam-actuator"
@@ -318,6 +319,9 @@
CAMERA_1,
CAMERA_2,
CAMERA_3,
+ CAMERA_4,
+ CAMERA_5,
+ CAMERA_6,
MAX_CAMERAS,
};
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
index 82ba24f..f9b846b 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -147,7 +147,7 @@
sizeof(uint32_t);
(*byte_cnt) += sizeof(struct cam_cmd_conditional_wait);
- (*offset) += 1;
+ *offset = 1;
*list_ptr = &(i2c_list->list);
return rc;
@@ -191,7 +191,7 @@
i2c_list->i2c_settings.
reg_setting[cnt].data_mask = 0;
}
- (*offset) += cnt;
+ *offset = cnt;
*list = &(i2c_list->list);
return rc;
@@ -246,7 +246,7 @@
i2c_list->i2c_settings.
reg_setting[cnt].data_mask = 0;
}
- (*offset) += cnt;
+ *offset = cnt;
*list = &(i2c_list->list);
return rc;
@@ -1349,7 +1349,8 @@
rc = msm_cam_sensor_handle_reg_gpio(
power_setting->seq_type,
- gpio_num_info, 1);
+ gpio_num_info,
+ (int) power_setting->config_val);
if (rc < 0) {
CAM_ERR(CAM_SENSOR,
"Error in handling VREG GPIO");
@@ -1476,6 +1477,9 @@
power_setting->data[0] =
soc_info->rgltr[vreg_idx];
+ regulator_put(
+ soc_info->rgltr[vreg_idx]);
+ soc_info->rgltr[vreg_idx] = NULL;
}
else
CAM_ERR(CAM_SENSOR, "seq_val:%d > num_vreg: %d",
@@ -1575,8 +1579,12 @@
soc_info->rgltr_op_mode[j],
soc_info->rgltr_delay[j]);
- ps->data[0] =
- soc_info->rgltr[j];
+ ps->data[0] =
+ soc_info->rgltr[j];
+
+ regulator_put(
+ soc_info->rgltr[j]);
+ soc_info->rgltr[j] = NULL;
}
}
}
@@ -1667,6 +1675,10 @@
ps->data[0] =
soc_info->rgltr[ps->seq_val];
+
+ regulator_put(
+ soc_info->rgltr[ps->seq_val]);
+ soc_info->rgltr[ps->seq_val] = NULL;
}
else
CAM_ERR(CAM_SENSOR,
diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
index e04c6b9..0d03df0 100644
--- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
@@ -106,8 +106,11 @@
uint8_t shared_support;
uint8_t io_support;
uint8_t secheap_support;
+ uint8_t qdss_support;
+ dma_addr_t qdss_phy_addr;
bool is_fw_allocated;
bool is_secheap_allocated;
+ bool is_qdss_allocated;
struct scratch_mapping scratch_map;
struct gen_pool *shared_mem_pool;
@@ -117,6 +120,7 @@
struct cam_smmu_region_info shared_info;
struct cam_smmu_region_info io_info;
struct cam_smmu_region_info secheap_info;
+ struct cam_smmu_region_info qdss_info;
struct secheap_buf_info secheap_buf;
struct list_head smmu_buf_list;
@@ -176,6 +180,8 @@
size_t len;
};
+static const char *qdss_region_name = "qdss";
+
static struct cam_iommu_cb_set iommu_cb_set;
static enum dma_data_direction cam_smmu_translate_dir(
@@ -1158,6 +1164,136 @@
}
EXPORT_SYMBOL(cam_smmu_dealloc_firmware);
+int cam_smmu_alloc_qdss(int32_t smmu_hdl,
+ dma_addr_t *iova,
+ size_t *len)
+{
+ int rc;
+ int32_t idx;
+ size_t qdss_len = 0;
+ size_t qdss_start = 0;
+ dma_addr_t qdss_phy_addr;
+ struct iommu_domain *domain;
+
+ if (!iova || !len || (smmu_hdl == HANDLE_INIT)) {
+ CAM_ERR(CAM_SMMU, "Error: Input args are invalid");
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ CAM_ERR(CAM_SMMU,
+ "Error: handle or index invalid. idx = %d hdl = %x",
+ idx, smmu_hdl);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].qdss_support) {
+ CAM_ERR(CAM_SMMU,
+ "QDSS memory not supported for this SMMU handle");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].is_qdss_allocated) {
+ CAM_ERR(CAM_SMMU, "Trying to allocate twice");
+ rc = -ENOMEM;
+ goto unlock_and_end;
+ }
+
+ qdss_len = iommu_cb_set.cb_info[idx].qdss_info.iova_len;
+ qdss_start = iommu_cb_set.cb_info[idx].qdss_info.iova_start;
+ qdss_phy_addr = iommu_cb_set.cb_info[idx].qdss_phy_addr;
+ CAM_DBG(CAM_SMMU, "QDSS area len from DT = %zu", qdss_len);
+
+ domain = iommu_cb_set.cb_info[idx].mapping->domain;
+ rc = iommu_map(domain,
+ qdss_start,
+ qdss_phy_addr,
+ qdss_len,
+ IOMMU_READ|IOMMU_WRITE);
+
+ if (rc) {
+ CAM_ERR(CAM_SMMU, "Failed to map QDSS into IOMMU");
+ goto unlock_and_end;
+ }
+
+ iommu_cb_set.cb_info[idx].is_qdss_allocated = true;
+
+ *iova = iommu_cb_set.cb_info[idx].qdss_info.iova_start;
+ *len = qdss_len;
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+
+ return rc;
+
+unlock_and_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+end:
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_alloc_qdss);
+
+int cam_smmu_dealloc_qdss(int32_t smmu_hdl)
+{
+ int rc = 0;
+ int32_t idx;
+ size_t qdss_len = 0;
+ size_t qdss_start = 0;
+ struct iommu_domain *domain;
+ size_t unmapped = 0;
+
+ if (smmu_hdl == HANDLE_INIT) {
+ CAM_ERR(CAM_SMMU, "Error: Invalid handle");
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ CAM_ERR(CAM_SMMU,
+ "Error: handle or index invalid. idx = %d hdl = %x",
+ idx, smmu_hdl);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].qdss_support) {
+ CAM_ERR(CAM_SMMU,
+ "QDSS memory not supported for this SMMU handle");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (!iommu_cb_set.cb_info[idx].is_qdss_allocated) {
+ CAM_ERR(CAM_SMMU,
+ "Trying to deallocate qdss that is not allocated");
+ rc = -ENOMEM;
+ goto unlock_and_end;
+ }
+
+ qdss_len = iommu_cb_set.cb_info[idx].qdss_info.iova_len;
+ qdss_start = iommu_cb_set.cb_info[idx].qdss_info.iova_start;
+ domain = iommu_cb_set.cb_info[idx].mapping->domain;
+ unmapped = iommu_unmap(domain, qdss_start, qdss_len);
+
+ if (unmapped != qdss_len) {
+ CAM_ERR(CAM_SMMU, "Only %zu unmapped out of total %zu",
+ unmapped,
+ qdss_len);
+ rc = -EINVAL;
+ }
+
+ iommu_cb_set.cb_info[idx].is_qdss_allocated = false;
+
+unlock_and_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+end:
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_dealloc_qdss);
+
int cam_smmu_get_region_info(int32_t smmu_hdl,
enum cam_smmu_region_id region_id,
struct cam_smmu_region_info *region_info)
@@ -3009,6 +3145,7 @@
uint32_t region_start;
uint32_t region_len;
uint32_t region_id;
+ uint32_t qdss_region_phy_addr = 0;
num_regions++;
rc = of_property_read_string(child_node,
@@ -3043,6 +3180,17 @@
return -EINVAL;
}
+ if (strcmp(region_name, qdss_region_name) == 0) {
+ rc = of_property_read_u32(child_node,
+ "qdss-phy-addr", &qdss_region_phy_addr);
+ if (rc < 0) {
+ of_node_put(mem_map_node);
+ CAM_ERR(CAM_SMMU,
+ "Failed to read qdss phy addr");
+ return -EINVAL;
+ }
+ }
+
switch (region_id) {
case CAM_SMMU_REGION_FIRMWARE:
cb->firmware_support = 1;
@@ -3069,6 +3217,12 @@
cb->secheap_info.iova_start = region_start;
cb->secheap_info.iova_len = region_len;
break;
+ case CAM_SMMU_REGION_QDSS:
+ cb->qdss_support = 1;
+ cb->qdss_info.iova_start = region_start;
+ cb->qdss_info.iova_len = region_len;
+ cb->qdss_phy_addr = qdss_region_phy_addr;
+ break;
default:
CAM_ERR(CAM_SMMU,
"Incorrect region id present in DT file: %d",
diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h
index b062258..254e382 100644
--- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h
@@ -46,7 +46,8 @@
CAM_SMMU_REGION_SHARED,
CAM_SMMU_REGION_SCRATCH,
CAM_SMMU_REGION_IO,
- CAM_SMMU_REGION_SECHEAP
+ CAM_SMMU_REGION_SECHEAP,
+ CAM_SMMU_REGION_QDSS
};
/**
@@ -345,4 +346,26 @@
*/
int cam_smmu_release_sec_heap(int32_t smmu_hdl);
+/**
+ * @brief Allocates qdss for context bank
+ *
+ * @param smmu_hdl: SMMU handle identifying context bank
+ * @param iova: IOVA address of allocated qdss
+ * @param len: Length of allocated qdss memory
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_alloc_qdss(int32_t smmu_hdl,
+ dma_addr_t *iova,
+ size_t *len);
+
+/**
+ * @brief Deallocates qdss memory for context bank
+ *
+ * @param smmu_hdl: SMMU handle identifying the context bank
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_dealloc_qdss(int32_t smmu_hdl);
+
#endif /* _CAM_SMMU_API_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
index 3d230af..d625a20 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -90,8 +90,9 @@
}
/* Trigger callback if sync object is already in SIGNALED state */
- if (row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS ||
- row->state == CAM_SYNC_STATE_SIGNALED_ERROR) {
+ if ((row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS ||
+ row->state == CAM_SYNC_STATE_SIGNALED_ERROR) &&
+ (!row->remaining)) {
sync_cb->callback_func = cb_func;
sync_cb->cb_data = userdata;
sync_cb->sync_obj = sync_obj;
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 0b1896f..d0a13ab 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
@@ -15,8 +15,62 @@
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
+#include <soc/qcom/socinfo.h>
#include "cam_soc_util.h"
#include "cam_debug_util.h"
+#include <linux/nvmem-consumer.h>
+
+uint32_t cam_soc_util_get_soc_id(void)
+{
+ return socinfo_get_id();
+}
+#if defined(CONFIG_NVMEM) && defined(CONFIG_QCOM_QFPROM)
+uint32_t cam_soc_util_get_hw_revision_node(struct cam_hw_soc_info *soc_info)
+{
+ struct nvmem_cell *cell;
+ ssize_t len;
+ uint32_t *buf, hw_rev;
+ struct platform_device *pdev;
+
+ pdev = soc_info->pdev;
+ /* read the soc hw revision and select revision node */
+ cell = nvmem_cell_get(&pdev->dev, "minor_rev");
+ if (IS_ERR_OR_NULL(cell)) {
+ if (PTR_ERR(cell) == -EPROBE_DEFER) {
+ CAM_ERR(CAM_UTIL, "Err to get nvmem cell: ret=%ld",
+ PTR_ERR(cell));
+ return -EINVAL;
+ }
+ CAM_ERR(CAM_UTIL, "No DTS entry");
+ return 0;
+ }
+
+ if (PTR_ERR(cell) == -ENOENT) {
+ CAM_DBG(CAM_UTIL, "nvme cell not found");
+ return 0;
+ }
+
+ buf = nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+
+ if (IS_ERR_OR_NULL(buf)) {
+ CAM_ERR(CAM_UTIL, "Unable to read nvmem cell: ret=%ld",
+ PTR_ERR(buf));
+ return -EINVAL;
+ }
+
+ CAM_DBG(CAM_UTIL, "hw_rev = %u", *buf);
+ hw_rev = (*buf >> 28) & 0x3;
+ kfree(buf);
+
+ return hw_rev;
+}
+#else
+uint32_t cam_soc_util_get_hw_revision_node(struct cam_hw_soc_info *soc_info)
+{
+ return 0;
+}
+#endif
int cam_soc_util_get_level_from_string(const char *string,
enum cam_vote_level *level)
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
index 4b57d54..1f2d46d 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -40,6 +40,11 @@
/* maximum number of device clock */
#define CAM_SOC_MAX_CLK 32
+/* soc id */
+#define SDM670_SOC_ID 336
+
+/* Minor Version */
+#define SDM670_V1_1 0x1
/**
* enum cam_vote_level - Enum for voting level
*
@@ -615,5 +620,23 @@
int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info,
enum cam_vote_level clk_level);
+/**
+ * cam_soc_util_get_soc_id()
+ *
+ * @brief: Read soc id
+ *
+ * @return SOC id
+ */
+uint32_t cam_soc_util_get_soc_id(void);
+/**
+ * cam_soc_util_get_hw_revision_node()
+ *
+ * @brief: Camera HW ID
+ *
+ * @soc_info: Device soc information
+ *
+ * @return HW id
+ */
+uint32_t cam_soc_util_get_hw_revision_node(struct cam_hw_soc_info *soc_info);
#endif /* _CAM_SOC_UTIL_H_ */
diff --git a/drivers/media/platform/msm/camera_v2/Makefile b/drivers/media/platform/msm/camera_v2/Makefile
index cdb0468..4348d44 100644
--- a/drivers/media/platform/msm/camera_v2/Makefile
+++ b/drivers/media/platform/msm/camera_v2/Makefile
@@ -1,7 +1,7 @@
ccflags-y += -Idrivers/media/platform/msm/camera_v2
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor
ccflags-y += -Idrivers/media/platform/msm/camera_v2/codecs
-ccflags-y += -Idrivers/media/platform/msm/camera_v2/isps
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/isp
ccflags-y += -Idrivers/media/platform/msm/camera_v2/pproc
ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2
ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 0efbd1b..01ee5d4 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -917,9 +917,7 @@
rc = media_entity_pads_init(&pvdev->vdev->entity, 0, NULL);
if (WARN_ON(rc < 0))
goto entity_fail;
- pvdev->vdev->entity.function = MEDIA_ENT_F_IO_V4L;
- //TODO: Use entity.name in from userspcae to find device.
- //pvdev->vdev->entity.group_id = QCAMERA_VNODE_GROUP_ID;
+ pvdev->vdev->entity.function = QCAMERA_VNODE_GROUP_ID;
#endif
v4l2_dev->notify = NULL;
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
index 36e3752..08c8575 100644
--- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
+++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
@@ -1390,7 +1390,7 @@
virt_len, &iova);
if (rc < 0) {
- pr_err("Could not find valid iova for scratch buffer");
+ pr_err("Could not find valid iova for scratch buffer\n");
goto err_iommu_map;
}
@@ -2118,7 +2118,7 @@
/* set the name of the context bank */
property = of_get_property(dev->of_node, "iommus", &cnt);
cnt /= 4;
- for (i = 0, j = 0; i < cnt; i = i + 2, j++) {
+ for (i = 0, j = 0; i < cnt; i = i + 3, j++) {
rc = of_property_read_u32_index(dev->of_node,
"iommus", i + 1, &cb->sids[j]);
if (rc < 0)
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c
index 3c38f12..2eb00eb 100644
--- a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c
+++ b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c
@@ -710,7 +710,7 @@
CDBG("name : %s, enable : %d\n", tmp->name, mode);
if (mode) {
rc = regulator_set_mode(tmp->vdd,
- REGULATOR_MODE_FAST);
+ REGULATOR_MODE_NORMAL);
if (rc < 0) {
pr_err("regulator enable failed %d\n",
i);
diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c
index 009b4cd..9a212825 100644
--- a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c
+++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c
@@ -408,14 +408,14 @@
return -EINVAL;
}
- if (cam_vreg == NULL) {
- pr_err("%s:%d cam_vreg sequence invalid\n", __func__, __LINE__);
- return -EINVAL;
- }
-
if (!num_vreg_seq)
num_vreg_seq = num_vreg;
+ if ((cam_vreg == NULL) && num_vreg_seq) {
+ pr_err("%s:%d cam_vreg NULL\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
if (config) {
for (i = 0; i < num_vreg_seq; i++) {
if (vreg_seq) {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index 7af9a3e..cfe8054 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -693,7 +693,7 @@
spin_lock_init(&req_history_lock);
spin_lock_init(&vfe_dev->completion_lock);
media_entity_pads_init(&vfe_dev->subdev.sd.entity, 0, NULL);
- vfe_dev->subdev.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ vfe_dev->subdev.sd.entity.function = MSM_CAMERA_SUBDEV_VFE;
//vfe_dev->subdev.sd.entity.group_id = MSM_CAMERA_SUBDEV_VFE;
vfe_dev->subdev.sd.entity.name = pdev->name;
vfe_dev->subdev.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x2;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index cc1ef7a..f560e83 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -19,9 +19,6 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/delay.h>
-#ifdef CONFIG_MSM_AVTIMER
-#include <linux/avtimer_kernel.h>
-#endif
#include <media/v4l2-subdev.h>
#include <media/msmb_isp.h>
#include <linux/msm-bus.h>
@@ -156,9 +153,11 @@
struct msm_isp_timestamp *ts);
void (*process_axi_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
+ uint32_t pingpong_status,
struct msm_isp_timestamp *ts);
void (*process_stats_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
+ uint32_t pingpong_status,
struct msm_isp_timestamp *ts);
void (*config_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
@@ -597,6 +596,7 @@
struct list_head list;
uint32_t vfeInterruptStatus0;
uint32_t vfeInterruptStatus1;
+ uint32_t vfe_pingpong_status;
struct msm_isp_timestamp ts;
uint8_t cmd_used;
struct vfe_device *vfe_dev;
@@ -858,8 +858,6 @@
struct platform_device *child_list[VFE_SD_HW_MAX];
struct msm_vfe_common_subdev *common_sd;
};
-
int vfe_hw_probe(struct platform_device *pdev);
void msm_isp_update_last_overflow_ab_ib(struct vfe_device *vfe_dev);
-
#endif
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index de7d9ed..269d563 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -199,7 +199,7 @@
if (rc < 0 || !ds_entries) {
pr_err("%s: NO D/S entries found\n", __func__);
} else {
- ds_settings = kcalloc(qos_entries, sizeof(uint32_t),
+ ds_settings = kcalloc(ds_entries, sizeof(uint32_t),
GFP_KERNEL);
if (!ds_settings)
return -ENOMEM;
@@ -1106,8 +1106,10 @@
fe_cfg->stream_id);
vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
+ mutex_lock(&vfe_dev->buf_mgr->lock);
rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
+ mutex_unlock(&vfe_dev->buf_mgr->lock);
if (rc < 0 || !buf) {
pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
__func__, rc, buf);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
index bc0a31f..a9ff454 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
@@ -891,8 +891,11 @@
vfe_dev->buf_mgr, fe_cfg->session_id,
fe_cfg->stream_id);
vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
+
+ mutex_lock(&vfe_dev->buf_mgr->lock);
rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
+ mutex_unlock(&vfe_dev->buf_mgr->lock);
if (rc < 0) {
pr_err("%s: No fetch buffer\n", __func__);
return -EINVAL;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
index b319738..0239fe7 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
@@ -830,8 +830,10 @@
fe_cfg->stream_id);
vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
+ mutex_lock(&vfe_dev->buf_mgr->lock);
rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
+ mutex_unlock(&vfe_dev->buf_mgr->lock);
if (rc < 0 || !buf) {
pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
__func__, rc, buf);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
index e03f76f..410689f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
@@ -566,6 +566,7 @@
void msm_vfe47_read_and_clear_irq_status(struct vfe_device *vfe_dev,
uint32_t *irq_status0, uint32_t *irq_status1)
{
+ uint32_t count = 0;
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x6C);
*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x70);
/* Mask off bits that are not enabled */
@@ -574,6 +575,14 @@
msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x58);
*irq_status0 &= vfe_dev->irq0_mask;
*irq_status1 &= vfe_dev->irq1_mask;
+ /* check if status register is cleared if not clear again*/
+ while (*irq_status0 &&
+ (*irq_status0 & msm_camera_io_r(vfe_dev->vfe_base + 0x6C)) &&
+ (count < MAX_RECOVERY_THRESHOLD)) {
+ msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x64);
+ msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x58);
+ count++;
+ }
if (*irq_status1 & (1 << 0)) {
vfe_dev->error_info.camif_status =
@@ -1151,8 +1160,10 @@
fe_cfg->stream_id);
vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
+ mutex_lock(&vfe_dev->buf_mgr->lock);
rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
+ mutex_unlock(&vfe_dev->buf_mgr->lock);
if (rc < 0 || !buf) {
pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
__func__, rc, buf);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 0b7bb8d..5b1a804 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -20,6 +20,9 @@
#define HANDLE_TO_IDX(handle) (handle & 0xFF)
#define ISP_SOF_DEBUG_COUNT 0
+#ifdef CONFIG_MSM_AVTIMER
+static struct avtimer_fptr_t avtimer_func;
+#endif
static void msm_isp_reload_ping_pong_offset(
struct msm_vfe_axi_stream *stream_info);
@@ -935,8 +938,12 @@
}
if (frame_src == VFE_PIX_0) {
- vfe_dev->isp_page->kernel_sofid =
- vfe_dev->axi_data.src_info[frame_src].frame_id;
+ if (vfe_dev->isp_page == NULL)
+ pr_err("Invalid ISP PAGE");
+ else
+ vfe_dev->isp_page->kernel_sofid =
+ vfe_dev->axi_data.src_info[frame_src].frame_id;
+
if (!src_info->frame_id &&
!src_info->reg_update_frame_id &&
((src_info->frame_id -
@@ -1178,10 +1185,34 @@
}
#ifdef CONFIG_MSM_AVTIMER
+/**
+ * msm_isp_set_avtimer_fptr() - Set avtimer function pointer
+ * @avtimer: struct of type avtimer_fptr_t to hold function pointer.
+ *
+ * Initialize the function pointers sent by the avtimer driver
+ *
+ */
+void msm_isp_set_avtimer_fptr(struct avtimer_fptr_t avtimer)
+{
+ avtimer_func.fptr_avtimer_open = avtimer.fptr_avtimer_open;
+ avtimer_func.fptr_avtimer_enable = avtimer.fptr_avtimer_enable;
+ avtimer_func.fptr_avtimer_get_time = avtimer.fptr_avtimer_get_time;
+}
+EXPORT_SYMBOL(msm_isp_set_avtimer_fptr);
+
void msm_isp_start_avtimer(void)
{
- avcs_core_open();
- avcs_core_disable_power_collapse(1);
+ if (avtimer_func.fptr_avtimer_open &&
+ avtimer_func.fptr_avtimer_enable) {
+ avtimer_func.fptr_avtimer_open();
+ avtimer_func.fptr_avtimer_enable(1);
+ }
+}
+void msm_isp_stop_avtimer(void)
+{
+ if (avtimer_func.fptr_avtimer_enable) {
+ avtimer_func.fptr_avtimer_enable(0);
+ }
}
void msm_isp_get_avtimer_ts(
@@ -1191,19 +1222,21 @@
uint32_t avtimer_usec = 0;
uint64_t avtimer_tick = 0;
- rc = avcs_core_query_timer(&avtimer_tick);
- if (rc < 0) {
- pr_err_ratelimited("%s: Error: Invalid AVTimer Tick, rc=%d\n",
- __func__, rc);
- /* In case of error return zero AVTimer Tick Value */
- time_stamp->vt_time.tv_sec = 0;
- time_stamp->vt_time.tv_usec = 0;
- } else {
- avtimer_usec = do_div(avtimer_tick, USEC_PER_SEC);
- time_stamp->vt_time.tv_sec = (uint32_t)(avtimer_tick);
- time_stamp->vt_time.tv_usec = avtimer_usec;
- pr_debug("%s: AVTimer TS = %u:%u\n", __func__,
- (uint32_t)(avtimer_tick), avtimer_usec);
+ if (avtimer_func.fptr_avtimer_get_time) {
+ rc = avtimer_func.fptr_avtimer_get_time(&avtimer_tick);
+ if (rc < 0) {
+ pr_err_ratelimited("%s: Error: Invalid AVTimer Tick, rc=%d\n",
+ __func__, rc);
+ /* In case of error return zero AVTimer Tick Value */
+ time_stamp->vt_time.tv_sec = 0;
+ time_stamp->vt_time.tv_usec = 0;
+ } else {
+ avtimer_usec = do_div(avtimer_tick, USEC_PER_SEC);
+ time_stamp->vt_time.tv_sec = (uint32_t)(avtimer_tick);
+ time_stamp->vt_time.tv_usec = avtimer_usec;
+ pr_debug("%s: AVTimer TS = %u:%u\n", __func__,
+ (uint32_t)(avtimer_tick), avtimer_usec);
+ }
}
}
#else
@@ -1215,10 +1248,14 @@
void msm_isp_get_avtimer_ts(
struct msm_isp_timestamp *time_stamp)
{
- pr_err_ratelimited("%s: Error: AVTimer driver not available\n",
+ struct timespec ts;
+
+ pr_debug("%s: AVTimer driver not available using system time\n",
__func__);
- time_stamp->vt_time.tv_sec = 0;
- time_stamp->vt_time.tv_usec = 0;
+
+ get_monotonic_boottime(&ts);
+ time_stamp->vt_time.tv_sec = ts.tv_sec;
+ time_stamp->vt_time.tv_usec = ts.tv_nsec/1000;
}
#endif
@@ -3744,13 +3781,6 @@
unsigned long flags;
int vfe_idx;
- if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[
- SRC_TO_INTF(stream_info->stream_src)])) {
- pr_err("%s: Update in progress for vfe %d intf %d\n",
- __func__, vfe_dev->pdev->id,
- SRC_TO_INTF(stream_info->stream_src));
- return -EINVAL;
- }
spin_lock_irqsave(&stream_info->lock, flags);
if (stream_info->state != ACTIVE) {
spin_unlock_irqrestore(&stream_info->lock, flags);
@@ -4263,11 +4293,11 @@
void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
- struct msm_isp_timestamp *ts)
+ uint32_t pingpong_status, struct msm_isp_timestamp *ts)
{
int i, rc = 0;
uint32_t comp_mask = 0, wm_mask = 0;
- uint32_t pingpong_status, stream_idx;
+ uint32_t stream_idx;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_composite_info *comp_info;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
@@ -4281,8 +4311,6 @@
return;
ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0);
- pingpong_status =
- vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(vfe_dev);
for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) {
rc = 0;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
index c0ba7ab..d27834f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
@@ -28,6 +28,7 @@
int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg);
void msm_isp_start_avtimer(void);
+void msm_isp_stop_avtimer(void);
void msm_isp_get_avtimer_ts(struct msm_isp_timestamp *time_stamp);
int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg);
@@ -55,7 +56,7 @@
void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
- struct msm_isp_timestamp *ts);
+ uint32_t pingpong_status, struct msm_isp_timestamp *ts);
void msm_isp_axi_disable_all_wm(struct vfe_device *vfe_dev);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index 98be3dd..0d7a1e0 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -257,13 +257,12 @@
static int32_t msm_isp_stats_configure(struct vfe_device *vfe_dev,
uint32_t stats_irq_mask, struct msm_isp_timestamp *ts,
- bool is_composite)
+ uint32_t pingpong_status, bool is_composite)
{
int i, rc = 0;
struct msm_isp_event_data buf_event;
struct msm_isp_stats_event *stats_event = &buf_event.u.stats;
struct msm_vfe_stats_stream *stream_info = NULL;
- uint32_t pingpong_status;
uint32_t comp_stats_type_mask = 0;
int result = 0;
@@ -272,8 +271,6 @@
buf_event.mono_timestamp = ts->buf_time;
buf_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
- pingpong_status = vfe_dev->hw_info->
- vfe_ops.stats_ops.get_pingpong_status(vfe_dev);
for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) {
if (!(stats_irq_mask & (1 << i)))
@@ -310,7 +307,7 @@
void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
- struct msm_isp_timestamp *ts)
+ uint32_t pingpong_status, struct msm_isp_timestamp *ts)
{
int j, rc;
uint32_t atomic_stats_mask = 0;
@@ -338,7 +335,7 @@
/* Process non-composite irq */
if (stats_irq_mask) {
rc = msm_isp_stats_configure(vfe_dev, stats_irq_mask, ts,
- comp_flag);
+ pingpong_status, comp_flag);
}
/* Process composite irq */
@@ -351,7 +348,7 @@
&vfe_dev->stats_data.stats_comp_mask[j]);
rc = msm_isp_stats_configure(vfe_dev, atomic_stats_mask,
- ts, !comp_flag);
+ ts, pingpong_status, !comp_flag);
}
}
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
index 9d5ae8c..52df59f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2016, 2018 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
@@ -17,7 +17,7 @@
void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
- struct msm_isp_timestamp *ts);
+ uint32_t pingpong_status, struct msm_isp_timestamp *ts);
int msm_isp_stats_create_stream(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream_request_cmd *stream_req_cmd,
struct msm_vfe_stats_stream *stream_info);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 9959f70..99dc054 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -2073,7 +2073,8 @@
}
static void msm_isp_enqueue_tasklet_cmd(struct vfe_device *vfe_dev,
- uint32_t irq_status0, uint32_t irq_status1)
+ uint32_t irq_status0, uint32_t irq_status1,
+ uint32_t ping_pong_status)
{
unsigned long flags;
struct msm_vfe_tasklet_queue_cmd *queue_cmd = NULL;
@@ -2095,8 +2096,8 @@
atomic_add(1, &vfe_dev->irq_cnt);
queue_cmd->vfeInterruptStatus0 = irq_status0;
queue_cmd->vfeInterruptStatus1 = irq_status1;
+ queue_cmd->vfe_pingpong_status = ping_pong_status;
msm_isp_get_timestamp(&queue_cmd->ts, vfe_dev);
-
queue_cmd->cmd_used = 1;
queue_cmd->vfe_dev = vfe_dev;
@@ -2110,7 +2111,7 @@
irqreturn_t msm_isp_process_irq(int irq_num, void *data)
{
struct vfe_device *vfe_dev = (struct vfe_device *) data;
- uint32_t irq_status0, irq_status1;
+ uint32_t irq_status0, irq_status1, ping_pong_status;
uint32_t error_mask0, error_mask1;
vfe_dev->hw_info->vfe_ops.irq_ops.
@@ -2121,6 +2122,8 @@
__func__, vfe_dev->pdev->id);
return IRQ_HANDLED;
}
+ ping_pong_status = vfe_dev->hw_info->vfe_ops.axi_ops.
+ get_pingpong_status(vfe_dev);
if (vfe_dev->hw_info->vfe_ops.irq_ops.preprocess_camif_irq) {
vfe_dev->hw_info->vfe_ops.irq_ops.preprocess_camif_irq(
vfe_dev, irq_status0);
@@ -2148,7 +2151,8 @@
return IRQ_HANDLED;
}
msm_isp_prepare_irq_debug_info(vfe_dev, irq_status0, irq_status1);
- msm_isp_enqueue_tasklet_cmd(vfe_dev, irq_status0, irq_status1);
+ msm_isp_enqueue_tasklet_cmd(vfe_dev, irq_status0, irq_status1,
+ ping_pong_status);
return IRQ_HANDLED;
}
@@ -2161,7 +2165,7 @@
struct msm_vfe_irq_ops *irq_ops;
struct msm_vfe_tasklet_queue_cmd *queue_cmd;
struct msm_isp_timestamp ts;
- uint32_t irq_status0, irq_status1;
+ uint32_t irq_status0, irq_status1, pingpong_status;
while (1) {
spin_lock_irqsave(&tasklet->tasklet_lock, flags);
@@ -2177,6 +2181,7 @@
queue_cmd->vfe_dev = NULL;
irq_status0 = queue_cmd->vfeInterruptStatus0;
irq_status1 = queue_cmd->vfeInterruptStatus1;
+ pingpong_status = queue_cmd->vfe_pingpong_status;
ts = queue_cmd->ts;
spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
if (vfe_dev->vfe_open_cnt == 0) {
@@ -2201,9 +2206,11 @@
}
msm_isp_process_error_info(vfe_dev);
irq_ops->process_stats_irq(vfe_dev,
- irq_status0, irq_status1, &ts);
+ irq_status0, irq_status1,
+ pingpong_status, &ts);
irq_ops->process_axi_irq(vfe_dev,
- irq_status0, irq_status1, &ts);
+ irq_status0, irq_status1,
+ pingpong_status, &ts);
irq_ops->process_camif_irq(vfe_dev,
irq_status0, irq_status1, &ts);
irq_ops->process_reg_update(vfe_dev,
@@ -2348,7 +2355,7 @@
#ifdef CONFIG_MSM_AVTIMER
static void msm_isp_end_avtimer(void)
{
- avcs_core_disable_power_collapse(0);
+ msm_isp_stop_avtimer();
}
#else
static void msm_isp_end_avtimer(void)
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c
index 55e2646..dc316b1 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c
@@ -816,9 +816,13 @@
static int msm_jpegdma_reqbufs(struct file *file,
void *fh, struct v4l2_requestbuffers *req)
{
+ int ret = 0;
struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
- return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, req);
+ mutex_lock(&ctx->lock);
+ ret = v4l2_m2m_reqbufs(file, ctx->m2m_ctx, req);
+ mutex_unlock(&ctx->lock);
+ return ret;
}
/*
@@ -925,11 +929,11 @@
{
struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
int ret;
-
+ mutex_lock(&ctx->lock);
ret = v4l2_m2m_streamoff(file, ctx->m2m_ctx, buf_type);
if (ret < 0)
dev_err(ctx->jdma_device->dev, "Stream off fails\n");
-
+ mutex_unlock(&ctx->lock);
return ret;
}
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c
index 702be49..627d72c 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c
@@ -79,8 +79,10 @@
*/
static inline long long jpegdma_do_div(long long num, long long den)
{
- do_div(num, den);
- return num;
+ uint64_t n = (uint64_t) num;
+
+ do_div(n, (uint32_t)den);
+ return n;
}
/*
@@ -919,7 +921,7 @@
static int msm_jpegdma_hw_calc_config(struct msm_jpegdma_size_config *size_cfg,
struct msm_jpegdma_plane *plane)
{
- u64 scale_hor, scale_ver, phase;
+ u64 scale_hor, scale_ver, phase = 0;
u64 in_width, in_height;
u64 out_width, out_height;
struct msm_jpegdma_config *config;
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 121e42a5..d52d8bc 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -350,8 +350,11 @@
return -EINVAL;
rc = v4l2_device_register_subdev(msm_v4l2_dev, sd);
- if (rc < 0)
+ if (rc < 0) {
+ pr_err("v4l2_device_register_subdev: failed for %s", sd->name);
+ WARN_ON(1);
return rc;
+ }
/* Register a device node for every subdev marked with the
* V4L2_SUBDEV_FL_HAS_DEVNODE flag.
@@ -1303,7 +1306,7 @@
uint64_t seq_num = 0;
int ret;
- if (copy_from_user(lbuf, buf, sizeof(lbuf)))
+ if (copy_from_user(lbuf, buf, sizeof(lbuf) - 1))
return -EFAULT;
ret = kstrtoull(lbuf, 0, &seq_num);
@@ -1366,8 +1369,7 @@
0, NULL)) < 0))
goto entity_fail;
- pvdev->vdev->entity.function = MEDIA_ENT_F_IO_V4L;
- //pvdev->vdev->entity.group_id = QCAMERA_VNODE_GROUP_ID;
+ pvdev->vdev->entity.function = QCAMERA_VNODE_GROUP_ID;
#endif
msm_v4l2_dev->notify = msm_sd_notify;
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 8a91c3e..e350096 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -857,9 +857,8 @@
v4l2_set_subdevdata(&msm_buf_mngr_dev->subdev.sd, msm_buf_mngr_dev);
media_entity_pads_init(&msm_buf_mngr_dev->subdev.sd.entity, 0, NULL);
- msm_buf_mngr_dev->subdev.sd.entity.function = MEDIA_ENT_F_IO_V4L;
- //msm_buf_mngr_dev->subdev.sd.entity.group_id =
- // MSM_CAMERA_SUBDEV_BUF_MNGR;
+ msm_buf_mngr_dev->subdev.sd.entity.function =
+ MSM_CAMERA_SUBDEV_BUF_MNGR;
msm_buf_mngr_dev->subdev.sd.internal_ops =
&msm_generic_buf_mngr_subdev_internal_ops;
msm_buf_mngr_dev->subdev.close_seq = MSM_SD_CLOSE_4TH_CATEGORY;
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
index 1322707..87e0172 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
@@ -399,7 +399,7 @@
static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id,
unsigned int stream_id, uint32_t sequence,
- struct timeval *ts, uint32_t reserved)
+ struct timeval *ts, uint32_t buf_type)
{
unsigned long flags, rl_flags;
struct msm_vb2_buffer *msm_vb2;
@@ -441,7 +441,10 @@
/* put buf before buf done */
if (msm_vb2->in_freeq) {
vb2_v4l2_buf->sequence = sequence;
- //vb2_v4l2_buf->timestamp = *ts;
+ vb2_v4l2_buf->timecode.type = buf_type;
+ vb2_v4l2_buf->vb2_buf.timestamp =
+ ((u64)ts->tv_sec * 1000000 +
+ ts->tv_usec) * 1000;
vb2_buffer_done(&vb2_v4l2_buf->vb2_buf,
VB2_BUF_STATE_DONE);
msm_vb2->in_freeq = 0;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 6fd9c4d..70bb3f2 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -4579,15 +4579,6 @@
}
}
- if (of_find_property(pdev->dev.of_node, "qcom,cpp-cx-ipeak", NULL)) {
- cpp_dev->cpp_cx_ipeak = cx_ipeak_register(
- pdev->dev.of_node, "qcom,cpp-cx-ipeak");
- if (cpp_dev->cpp_cx_ipeak)
- CPP_DBG("Cx ipeak Registration Successful ");
- else
- pr_err("Cx ipeak Registration Unsuccessful");
- }
-
rc = msm_camera_get_reset_info(pdev,
&cpp_dev->micro_iface_reset);
if (rc < 0) {
@@ -4596,7 +4587,6 @@
__func__);
goto get_reg_err;
}
-
rc = msm_camera_get_regulator_info(pdev, &cpp_dev->cpp_vdd,
&cpp_dev->num_reg);
if (rc < 0) {
@@ -4625,7 +4615,7 @@
goto bus_de_init;
media_entity_pads_init(&cpp_dev->msm_sd.sd.entity, 0, NULL);
- cpp_dev->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ cpp_dev->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_CPP;
cpp_dev->msm_sd.sd.entity.name = pdev->name;
cpp_dev->msm_sd.close_seq = MSM_SD_CLOSE_3RD_CATEGORY;
msm_sd_register(&cpp_dev->msm_sd);
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c
index d733d2a..64f3104 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c
@@ -83,67 +83,37 @@
return -EINVAL;
}
-static int cpp_get_clk_freq_tbl_dt(struct cpp_device *cpp_dev)
+static int cpp_get_clk_freq_tbl(struct clk *clk, struct cpp_hw_info *hw_info,
+ uint32_t min_clk_rate)
{
- uint32_t i, count, min_clk_rate;
+ uint32_t i;
uint32_t idx = 0;
- struct device_node *of_node;
- uint32_t *rates;
- int32_t rc = 0;
- struct cpp_hw_info *hw_info;
+ signed long freq_tbl_entry = 0;
- if (cpp_dev == NULL) {
+ if ((clk == NULL) || (hw_info == NULL) || (clk->ops == NULL) ||
+ (clk->ops->list_rate == NULL)) {
pr_err("Bad parameter\n");
- rc = -EINVAL;
- goto err;
+ return -EINVAL;
}
- of_node = cpp_dev->pdev->dev.of_node;
- min_clk_rate = cpp_dev->min_clk_rate;
- hw_info = &cpp_dev->hw_info;
-
- if ((hw_info == NULL) || (of_node == NULL)) {
- pr_err("Invalid hw_info %pK or ofnode %pK\n", hw_info, of_node);
- rc = -EINVAL;
- goto err;
-
- }
- count = of_property_count_u32_elems(of_node, "qcom,src-clock-rates");
- if ((count == 0) || (count > MAX_FREQ_TBL)) {
- pr_err("Clock count is invalid\n");
- rc = -EINVAL;
- goto err;
- }
-
- rates = devm_kcalloc(&cpp_dev->pdev->dev, count, sizeof(uint32_t),
- GFP_KERNEL);
- if (!rates) {
- rc = -ENOMEM;
- goto err;
- }
-
- rc = of_property_read_u32_array(of_node, "qcom,src-clock-rates",
- rates, count);
- if (rc) {
- rc = -EINVAL;
- goto mem_free;
- }
-
- for (i = 0; i < count; i++) {
- pr_debug("entry=%d\n", rates[i]);
- if (rates[i] >= min_clk_rate) {
- hw_info->freq_tbl[idx++] = rates[i];
- pr_debug("tbl[%d]=%d\n", idx-1, rates[i]);
+ for (i = 0; i < MAX_FREQ_TBL; i++) {
+ freq_tbl_entry = clk->ops->list_rate(clk, i);
+ pr_debug("entry=%ld\n", freq_tbl_entry);
+ if (freq_tbl_entry >= 0) {
+ if (freq_tbl_entry >= min_clk_rate) {
+ hw_info->freq_tbl[idx++] = freq_tbl_entry;
+ pr_debug("tbl[%d]=%ld\n", idx-1,
+ freq_tbl_entry);
+ }
+ } else {
+ pr_debug("freq table returned invalid entry/end %ld\n",
+ freq_tbl_entry);
+ break;
}
}
-
- pr_debug("%s: idx %d\n", __func__, idx);
+ pr_debug("%s: idx %d", __func__, idx);
hw_info->freq_tbl_count = idx;
-
-mem_free:
- devm_kfree(&cpp_dev->pdev->dev, rates);
-err:
- return rc;
+ return 0;
}
int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev)
@@ -192,7 +162,8 @@
rc = msm_cpp_core_clk_idx;
return rc;
}
- rc = cpp_get_clk_freq_tbl_dt(cpp_dev);
+ rc = cpp_get_clk_freq_tbl(cpp_dev->cpp_clk[msm_cpp_core_clk_idx],
+ &cpp_dev->hw_info, cpp_dev->min_clk_rate);
if (rc < 0) {
pr_err("%s: fail to get frequency table\n", __func__);
return rc;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index 295e203..625a0db 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -57,6 +57,11 @@
CDBG("Enter\n");
+ if (a_ctrl->i2c_reg_tbl == NULL) {
+ pr_err("failed. i2c reg table is NULL");
+ return -EFAULT;
+ }
+
if (a_ctrl->curr_step_pos != 0) {
a_ctrl->i2c_tbl_index = 0;
a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
@@ -99,7 +104,7 @@
}
if (a_ctrl->i2c_reg_tbl == NULL) {
- pr_err("failed. i2c reg tabl is NULL");
+ pr_err("failed. i2c reg table is NULL");
return;
}
@@ -526,6 +531,11 @@
CDBG("Enter\n");
+ if (a_ctrl->i2c_reg_tbl == NULL) {
+ pr_err("failed. i2c reg table is NULL");
+ return -EFAULT;
+ }
+
if (copy_from_user(&ringing_params_kernel,
&(move_params->ringing_params[0]),
sizeof(struct damping_params_t))) {
@@ -599,6 +609,10 @@
pr_err("Invalid direction = %d\n", dir);
return -EFAULT;
}
+ if (a_ctrl->i2c_reg_tbl == NULL) {
+ pr_err("failed. i2c reg table is NULL");
+ return -EFAULT;
+ }
if (dest_step_pos > a_ctrl->total_steps) {
pr_err("Step pos greater than total steps = %d\n",
dest_step_pos);
@@ -719,6 +733,10 @@
pr_err("Invalid direction = %d\n", dir);
return -EFAULT;
}
+ if (a_ctrl->i2c_reg_tbl == NULL) {
+ pr_err("failed. i2c reg table is NULL");
+ return -EFAULT;
+ }
if (dest_step_pos > a_ctrl->total_steps) {
pr_err("Step pos greater than total steps = %d\n",
dest_step_pos);
@@ -1182,7 +1200,8 @@
}
if (!a_ctrl || !a_ctrl->func_tbl ||
- !a_ctrl->func_tbl->actuator_parse_i2c_params) {
+ !a_ctrl->func_tbl->actuator_parse_i2c_params ||
+ !a_ctrl->i2c_reg_tbl) {
pr_err("failed. NULL actuator pointers.");
return -EFAULT;
}
@@ -1294,12 +1313,10 @@
a_ctrl->region_size = set_info->af_tuning_params.region_size;
a_ctrl->pwd_step = set_info->af_tuning_params.pwd_step;
- a_ctrl->total_steps = set_info->af_tuning_params.total_steps;
if (copy_from_user(&a_ctrl->region_params,
(void __user *)set_info->af_tuning_params.region_params,
a_ctrl->region_size * sizeof(struct region_params_t))) {
- a_ctrl->total_steps = 0;
pr_err("Error copying region_params\n");
return -EFAULT;
}
@@ -1341,6 +1358,7 @@
return -ENOMEM;
}
+ a_ctrl->total_steps = set_info->af_tuning_params.total_steps;
if (copy_from_user(&a_ctrl->reg_tbl,
(void __user *)set_info->actuator_params.reg_tbl_params,
a_ctrl->reg_tbl_size *
@@ -1895,7 +1913,7 @@
act_ctrl_t->msm_sd.sd.internal_ops = &msm_actuator_internal_ops;
act_ctrl_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
media_entity_pads_init(&act_ctrl_t->msm_sd.sd.entity, 0, NULL);
- act_ctrl_t->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ act_ctrl_t->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_ACTUATOR;
act_ctrl_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
msm_sd_register(&act_ctrl_t->msm_sd);
msm_cam_copy_v4l2_subdev_fops(&msm_actuator_v4l2_subdev_fops);
@@ -2007,7 +2025,7 @@
snprintf(msm_actuator_t->msm_sd.sd.name,
ARRAY_SIZE(msm_actuator_t->msm_sd.sd.name), "msm_actuator");
media_entity_pads_init(&msm_actuator_t->msm_sd.sd.entity, 0, NULL);
- msm_actuator_t->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ msm_actuator_t->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_ACTUATOR;
msm_actuator_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
msm_sd_register(&msm_actuator_t->msm_sd);
msm_actuator_t->actuator_state = ACT_DISABLE_STATE;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index 0f4bd88..b67af9c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -2095,11 +2095,11 @@
return -ENOMEM;
}
v4l2_subdev_init(&new_cci_dev->msm_sd.sd, &msm_cci_subdev_ops);
- new_cci_dev->msm_sd.sd.internal_ops = &msm_cci_internal_ops;
snprintf(new_cci_dev->msm_sd.sd.name,
ARRAY_SIZE(new_cci_dev->msm_sd.sd.name), "msm_cci");
v4l2_set_subdevdata(&new_cci_dev->msm_sd.sd, new_cci_dev);
platform_set_drvdata(pdev, &new_cci_dev->msm_sd.sd);
+
CDBG("%s sd %pK\n", __func__, &new_cci_dev->msm_sd.sd);
if (pdev->dev.of_node)
of_property_read_u32((&pdev->dev)->of_node,
@@ -2141,6 +2141,13 @@
}
msm_camera_enable_irq(new_cci_dev->irq, false);
+
+ new_cci_dev->pdev = pdev;
+ new_cci_dev->msm_sd.sd.internal_ops = &msm_cci_internal_ops;
+ new_cci_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ media_entity_pads_init(&new_cci_dev->msm_sd.sd.entity, 0, NULL);
+ new_cci_dev->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_CCI;
+ new_cci_dev->msm_sd.sd.entity.name = new_cci_dev->msm_sd.sd.name;
new_cci_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6;
msm_sd_register(&new_cci_dev->msm_sd);
new_cci_dev->pdev = pdev;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 057472a..ba32526 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -1008,6 +1008,8 @@
if (!new_csid_dev)
return -ENOMEM;
+ CDBG("%s: csid_probe entry\n", __func__);
+
new_csid_dev->csid_3p_enabled = 0;
new_csid_dev->ctrl_reg = NULL;
new_csid_dev->ctrl_reg = kzalloc(sizeof(struct csid_ctrl_t),
@@ -1088,7 +1090,7 @@
snprintf(new_csid_dev->msm_sd.sd.name,
ARRAY_SIZE(new_csid_dev->msm_sd.sd.name), "msm_csid");
media_entity_pads_init(&new_csid_dev->msm_sd.sd.entity, 0, NULL);
- new_csid_dev->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ new_csid_dev->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_CSID;
new_csid_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x5;
msm_sd_register(&new_csid_dev->msm_sd);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index 04f7732..edf022e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -1743,7 +1743,7 @@
snprintf(new_csiphy_dev->msm_sd.sd.name,
ARRAY_SIZE(new_csiphy_dev->msm_sd.sd.name), "msm_csiphy");
media_entity_pads_init(&new_csiphy_dev->msm_sd.sd.entity, 0, NULL);
- new_csiphy_dev->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ new_csiphy_dev->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_CSIPHY;
new_csiphy_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x4;
msm_sd_register(&new_csiphy_dev->msm_sd);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 30a3113..cd16236 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -847,7 +847,7 @@
e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops;
e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
media_entity_pads_init(&e_ctrl->msm_sd.sd.entity, 0, NULL);
- e_ctrl->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ e_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_EEPROM;
msm_sd_register(&e_ctrl->msm_sd);
CDBG("%s success result=%d X\n", __func__, rc);
return rc;
@@ -1215,7 +1215,7 @@
e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops;
e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
media_entity_pads_init(&e_ctrl->msm_sd.sd.entity, 0, NULL);
- e_ctrl->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ e_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_EEPROM;
msm_sd_register(&e_ctrl->msm_sd);
e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1;
CDBG("%s success result=%d supported=%x X\n", __func__, rc,
@@ -1755,7 +1755,7 @@
snprintf(e_ctrl->msm_sd.sd.name,
ARRAY_SIZE(e_ctrl->msm_sd.sd.name), "msm_eeprom");
media_entity_pads_init(&e_ctrl->msm_sd.sd.entity, 0, NULL);
- e_ctrl->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ e_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_EEPROM;
msm_sd_register(&e_ctrl->msm_sd);
#ifdef CONFIG_COMPAT
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
index b26fee4..656b1ca 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
@@ -1314,7 +1314,7 @@
ARRAY_SIZE(flash_ctrl->msm_sd.sd.name),
"msm_camera_flash");
media_entity_pads_init(&flash_ctrl->msm_sd.sd.entity, 0, NULL);
- flash_ctrl->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ flash_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_FLASH;
flash_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
msm_sd_register(&flash_ctrl->msm_sd);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ir_cut/msm_ir_cut.c b/drivers/media/platform/msm/camera_v2/sensor/ir_cut/msm_ir_cut.c
index 165f0c3..002a9b9 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ir_cut/msm_ir_cut.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ir_cut/msm_ir_cut.c
@@ -601,7 +601,7 @@
ARRAY_SIZE(ir_cut_ctrl->msm_sd.sd.name),
"msm_camera_ir_cut");
media_entity_pads_init(&ir_cut_ctrl->msm_sd.sd.entity, 0, NULL);
- ir_cut_ctrl->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ ir_cut_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_IR_CUT;
ir_cut_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
msm_sd_register(&ir_cut_ctrl->msm_sd);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ir_led/msm_ir_led.c b/drivers/media/platform/msm/camera_v2/sensor/ir_led/msm_ir_led.c
index 00ce821..2beca58 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ir_led/msm_ir_led.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ir_led/msm_ir_led.c
@@ -398,7 +398,7 @@
ARRAY_SIZE(ir_led_ctrl->msm_sd.sd.name),
"msm_camera_ir_led");
media_entity_pads_init(&ir_led_ctrl->msm_sd.sd.entity, 0, NULL);
- ir_led_ctrl->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ ir_led_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_IR_LED;
ir_led_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
msm_sd_register(&ir_led_ctrl->msm_sd);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.c b/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.c
index d30fc95..ee695d8 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.c
@@ -515,11 +515,7 @@
ARRAY_SIZE(laser_led_ctrl->msm_sd.sd.name),
"msm_camera_laser_led");
media_entity_pads_init(&laser_led_ctrl->msm_sd.sd.entity, 0, NULL);
- laser_led_ctrl->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
- /*
- * laser_led_ctrl->msm_sd.sd.entity.group_id
- * = MSM_CAMERA_SUBDEV_LASER_LED;
- */
+ laser_led_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_LASER_LED;
laser_led_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
msm_sd_register(&laser_led_ctrl->msm_sd);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
index 80149a9..0b0f98a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
@@ -104,7 +104,7 @@
v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, client);
s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
media_entity_pads_init(&s_ctrl->msm_sd.sd.entity, 0, NULL);
- s_ctrl->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ s_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_SENSOR;
s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name;
s_ctrl->sensordata->sensor_info->session_id = session_id;
s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3;
@@ -148,7 +148,7 @@
v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, s_ctrl->pdev);
s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
media_entity_pads_init(&s_ctrl->msm_sd.sd.entity, 0, NULL);
- s_ctrl->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ s_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_SENSOR;
s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name;
s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3;
rc = msm_sd_register(&s_ctrl->msm_sd);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c
index b9fafc8..acab45e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c
@@ -187,7 +187,7 @@
s_init->msm_sd.sd.internal_ops = &msm_sensor_init_internal_ops;
s_init->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
media_entity_pads_init(&s_init->msm_sd.sd.entity, 0, NULL);
- s_init->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ s_init->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_SENSOR_INIT;
s_init->msm_sd.sd.entity.name = s_init->msm_sd.sd.name;
s_init->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6;
ret = msm_sd_register(&s_init->msm_sd);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c
index 2253eee..0e17b7d 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c
@@ -830,7 +830,7 @@
ois_ctrl_t->msm_sd.sd.internal_ops = &msm_ois_internal_ops;
ois_ctrl_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
media_entity_pads_init(&ois_ctrl_t->msm_sd.sd.entity, 0, NULL);
- ois_ctrl_t->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ ois_ctrl_t->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_OIS;
ois_ctrl_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
msm_sd_register(&ois_ctrl_t->msm_sd);
ois_ctrl_t->ois_state = OIS_DISABLE_STATE;
@@ -1032,7 +1032,7 @@
snprintf(msm_ois_t->msm_sd.sd.name,
ARRAY_SIZE(msm_ois_t->msm_sd.sd.name), "msm_ois");
media_entity_pads_init(&msm_ois_t->msm_sd.sd.entity, 0, NULL);
- msm_ois_t->msm_sd.sd.entity.function = MEDIA_ENT_F_IO_V4L;
+ msm_ois_t->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_OIS;
msm_ois_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
msm_sd_register(&msm_ois_t->msm_sd);
msm_ois_t->ois_state = OIS_DISABLE_STATE;
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 9d92acf..6dac1ed 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
@@ -217,12 +217,18 @@
SDEROT_DBG("w:%d h:%d fps:%d pixfmt:%8.8x yuv:%d res:%llu rd:%d\n",
width, height, fps, pixfmt, is_yuv, res, is_rd);
+ if (!is_yuv)
+ goto exit;
+
+ /*
+ * If (total_source_pixels <= 62208000 && YUV) -> RD/WROT=2 //1080p30
+ * If (total_source_pixels <= 124416000 && YUV) -> RD/WROT=4 //1080p60
+ * If (total_source_pixels <= 2160p && YUV && FPS <= 30) -> RD/WROT = 32
+ */
if (res <= (RES_1080p * 30))
ot_lim = 2;
else if (res <= (RES_1080p * 60))
ot_lim = 4;
- else if (res <= (RES_UHD * 30))
- ot_lim = 8;
exit:
SDEROT_DBG("ot_lim=%d\n", ot_lim);
@@ -252,6 +258,8 @@
val &= (0xFF << bit_off);
val = val >> bit_off;
+ SDEROT_EVTLOG(val, ot_lim);
+
if (val == ot_lim)
ot_lim = 0;
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 3636aa1..e3a5cc7 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -806,7 +806,7 @@
pkt->offset = input_frame->offset;
pkt->alloc_len = input_frame->alloc_len;
pkt->filled_len = input_frame->filled_len;
- pkt->input_tag = input_frame->clnt_data;
+ pkt->input_tag = input_frame->input_tag;
pkt->packet_buffer = (u32)input_frame->device_addr;
trace_msm_v4l2_vidc_buffer_event_start("ETB",
@@ -841,7 +841,7 @@
pkt->offset = input_frame->offset;
pkt->alloc_len = input_frame->alloc_len;
pkt->filled_len = input_frame->filled_len;
- pkt->input_tag = input_frame->clnt_data;
+ pkt->input_tag = input_frame->input_tag;
pkt->packet_buffer = (u32)input_frame->device_addr;
pkt->extra_data_buffer = (u32)input_frame->extradata_addr;
@@ -877,6 +877,7 @@
return -EINVAL;
pkt->packet_buffer = (u32)output_frame->device_addr;
+ pkt->output_tag = output_frame->output_tag;
pkt->extra_data_buffer = (u32)output_frame->extradata_addr;
pkt->alloc_len = output_frame->alloc_len;
pkt->filled_len = output_frame->filled_len;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 44cc7dc..cef5396 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -115,6 +115,7 @@
struct hfi_pic_struct *pic_struct;
struct hfi_buffer_requirements *buf_req;
struct hfi_index_extradata_input_crop_payload *crop_info;
+ struct hfi_dpb_counts *dpb_counts;
u32 entropy_mode = 0;
u8 *data_ptr;
int prop_id;
@@ -215,6 +216,23 @@
data_ptr +=
sizeof(struct hfi_pic_struct);
break;
+ case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS:
+ data_ptr = data_ptr + sizeof(u32);
+ dpb_counts = (struct hfi_dpb_counts *) data_ptr;
+ event_notify.max_dpb_count =
+ dpb_counts->max_dpb_count;
+ event_notify.max_ref_count =
+ dpb_counts->max_ref_count;
+ event_notify.max_dec_buffering =
+ dpb_counts->max_dec_buffering;
+ dprintk(VIDC_DBG,
+ "DPB Counts: dpb %d ref %d buff %d\n",
+ dpb_counts->max_dpb_count,
+ dpb_counts->max_ref_count,
+ dpb_counts->max_dec_buffering);
+ data_ptr +=
+ sizeof(struct hfi_pic_struct);
+ break;
case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE:
data_ptr = data_ptr + sizeof(u32);
colour_info =
@@ -312,6 +330,7 @@
event_notify.hal_event_type = HAL_EVENT_RELEASE_BUFFER_REFERENCE;
event_notify.packet_buffer = data->packet_buffer;
event_notify.extra_data_buffer = data->extra_data_buffer;
+ event_notify.output_tag = data->output_tag;
info->response_type = HAL_SESSION_EVENT_CHANGE;
info->response.event = event_notify;
@@ -856,6 +875,36 @@
return 0;
}
+static int copy_nal_stream_format_caps_to_sessions(u32 nal_stream_format_value,
+ struct msm_vidc_capability *capabilities, u32 num_sessions,
+ u32 codecs, u32 domain) {
+ u32 i = 0;
+ struct msm_vidc_capability *capability;
+ u32 sess_codec;
+ u32 sess_domain;
+
+ for (i = 0; i < num_sessions; i++) {
+ sess_codec = 0;
+ sess_domain = 0;
+ capability = &capabilities[i];
+
+ if (capability->codec)
+ sess_codec =
+ vidc_get_hfi_codec(capability->codec);
+ if (capability->domain)
+ sess_domain =
+ vidc_get_hfi_domain(capability->domain);
+
+ if (!(sess_codec & codecs && sess_domain & domain))
+ continue;
+
+ capability->nal_stream_format.nal_stream_format_supported =
+ nal_stream_format_value;
+ }
+
+ return 0;
+}
+
static enum vidc_status hfi_parse_init_done_properties(
struct msm_vidc_capability *capabilities,
u32 num_sessions, u8 *data_ptr, u32 num_properties,
@@ -984,6 +1033,15 @@
}
case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED:
{
+ struct hfi_nal_stream_format_supported *prop =
+ (struct hfi_nal_stream_format_supported *)
+ (data_ptr + next_offset);
+
+ copy_nal_stream_format_caps_to_sessions(
+ prop->nal_stream_format_supported,
+ capabilities, num_sessions,
+ codecs, domain);
+
next_offset +=
sizeof(struct hfi_nal_stream_format_supported);
num_properties--;
@@ -1358,7 +1416,7 @@
data_done.session_id = (void *)(uintptr_t)pkt->session_id;
data_done.status = hfi_map_err_status(pkt->error_type);
data_done.size = sizeof(struct msm_vidc_cb_data_done);
- data_done.clnt_data = pkt->input_tag;
+ data_done.input_done.input_tag = pkt->input_tag;
data_done.input_done.recon_stats.buffer_index =
pkt->ubwc_cr_stats.frame_index;
memcpy(&data_done.input_done.recon_stats.ubwc_stats_info,
@@ -1490,7 +1548,9 @@
data_done.output_done.frame_height = pkt->frame_height;
data_done.output_done.start_x_coord = pkt->start_x_coord;
data_done.output_done.start_y_coord = pkt->start_y_coord;
- data_done.output_done.input_tag1 = pkt->input_tag;
+ data_done.output_done.input_tag = pkt->input_tag;
+ data_done.output_done.input_tag1 = pkt->input_tag2;
+ data_done.output_done.output_tag = pkt->output_tag;
data_done.output_done.picture_type = pkt->picture_type;
data_done.output_done.packet_buffer1 = pkt->packet_buffer;
data_done.output_done.extra_data_buffer =
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index e627ee4..be24f8d 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -164,6 +164,15 @@
"Unlimited"
};
+static const char *const mpeg_video_stream_format[] = {
+ "NAL Format Start Codes",
+ "NAL Format One NAL Per Buffer",
+ "NAL Format One Byte Length",
+ "NAL Format Two Byte Length",
+ "NAL Format Four Byte Length",
+ NULL
+};
+
static struct msm_vidc_ctrl msm_venc_ctrls[] = {
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD,
@@ -1197,7 +1206,22 @@
.step = 1,
.qmenu = NULL,
},
-
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT,
+ .name = "NAL Format",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH)
+ ),
+ .qmenu = mpeg_video_stream_format,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -1358,6 +1382,7 @@
struct hal_vui_timing_info vui_timing_info = {0};
enum hal_iframesize_type iframesize_type = HAL_IFRAMESIZE_TYPE_DEFAULT;
u32 color_primaries, custom_matrix;
+ struct hal_nal_stream_format_select stream_format;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
@@ -2211,6 +2236,13 @@
vui_timing_info.time_scale = NSEC_PER_SEC;
break;
}
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
+ {
+ property_id = HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
+ stream_format.nal_stream_format_select = BIT(ctrl->val);
+ pdata = &stream_format;
+ break;
+ }
case V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE:
case V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT:
case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_WIDTH:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index e7ae579..f077e3b 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -495,6 +495,7 @@
struct msm_vidc_inst *inst = instance;
int rc = 0, i = 0;
struct buf_queue *q = NULL;
+ struct vidc_tag_data tag_data;
u32 cr = 0;
if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst)) {
@@ -523,6 +524,12 @@
b->m.planes[0].reserved[3], b->m.planes[0].reserved[4]);
}
+ tag_data.index = b->index;
+ tag_data.type = b->type;
+ tag_data.input_tag = b->m.planes[0].reserved[5];
+ tag_data.output_tag = b->m.planes[0].reserved[6];
+ msm_comm_store_tags(inst, &tag_data);
+
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
dprintk(VIDC_ERR,
@@ -545,6 +552,7 @@
struct msm_vidc_inst *inst = instance;
int rc = 0, i = 0;
struct buf_queue *q = NULL;
+ struct vidc_tag_data tag_data;
if (!inst || !b || !valid_v4l2_buffer(b, inst)) {
dprintk(VIDC_ERR, "%s: invalid params, inst %pK\n",
@@ -582,6 +590,13 @@
&b->m.planes[0].reserved[4]);
}
+ tag_data.index = b->index;
+ tag_data.type = b->type;
+
+ msm_comm_fetch_tags(inst, &tag_data);
+ b->m.planes[0].reserved[5] = tag_data.input_tag;
+ b->m.planes[0].reserved[6] = tag_data.output_tag;
+
return rc;
}
EXPORT_SYMBOL(msm_vidc_dqbuf);
@@ -1523,6 +1538,11 @@
case V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION:
ctrl->val = inst->capability.tme_version;
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
+ ctrl->val =
+ inst->capability.nal_stream_format.
+ nal_stream_format_supported;
+ break;
default:
/*
* Other controls aren't really volatile, shouldn't need to
@@ -1618,6 +1638,7 @@
INIT_MSM_VIDC_LIST(&inst->scratchbufs);
INIT_MSM_VIDC_LIST(&inst->freqs);
INIT_MSM_VIDC_LIST(&inst->input_crs);
+ INIT_MSM_VIDC_LIST(&inst->buffer_tags);
INIT_MSM_VIDC_LIST(&inst->persistbufs);
INIT_MSM_VIDC_LIST(&inst->pending_getpropq);
INIT_MSM_VIDC_LIST(&inst->outputbufs);
@@ -1734,6 +1755,7 @@
DEINIT_MSM_VIDC_LIST(&inst->eosbufs);
DEINIT_MSM_VIDC_LIST(&inst->freqs);
DEINIT_MSM_VIDC_LIST(&inst->input_crs);
+ DEINIT_MSM_VIDC_LIST(&inst->buffer_tags);
DEINIT_MSM_VIDC_LIST(&inst->etb_data);
DEINIT_MSM_VIDC_LIST(&inst->fbd_data);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 4be087f..0f74c7c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -1018,9 +1018,10 @@
rc_mode = msm_comm_g_ctrl_for_id(inst,
V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL);
if (rc_mode == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR ||
- rc_mode ==
- V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR)
- pdata.video_work_mode = VIDC_WORK_MODE_2;
+ rc_mode == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR ||
+ rc_mode == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR ||
+ rc_mode == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR)
+ pdata.video_work_mode = VIDC_WORK_MODE_2;
} else {
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index a6af12a..7d9bbed 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1586,7 +1586,7 @@
}
static void msm_vidc_queue_rbr_event(struct msm_vidc_inst *inst,
- int fd, u32 offset)
+ int fd, u32 offset, u32 output_tag)
{
struct v4l2_event buf_event = {0};
u32 *ptr;
@@ -1595,6 +1595,7 @@
ptr = (u32 *)buf_event.u.data;
ptr[0] = fd;
ptr[1] = offset;
+ ptr[2] = output_tag;
v4l2_event_queue_fh(&inst->event_handler, &buf_event);
}
@@ -1643,6 +1644,7 @@
planes[0] = event_notify->packet_buffer;
planes[1] = event_notify->extra_data_buffer;
mbuf = msm_comm_get_buffer_using_device_planes(inst, planes);
+ mbuf->output_tag = event_notify->output_tag;
if (!mbuf || !kref_get_mbuf(inst, mbuf)) {
dprintk(VIDC_ERR,
"%s: data_addr %x, extradata_addr %x not found\n",
@@ -1709,6 +1711,9 @@
ptr[10] = msm_comm_get_v4l2_level(
inst->fmts[OUTPUT_PORT].fourcc,
event_notify->level);
+ ptr[11] = event_notify->max_dpb_count;
+ ptr[12] = event_notify->max_ref_count;
+ ptr[13] = event_notify->max_dec_buffering;
dprintk(VIDC_DBG,
"Event payload: height = %d width = %d profile = %d level = %d\n",
@@ -2375,6 +2380,7 @@
struct msm_vidc_inst *inst;
struct vidc_hal_ebd *empty_buf_done;
struct vb2_v4l2_buffer *vbuf;
+ struct vidc_tag_data tag_data;
u32 planes[VIDEO_MAX_PLANES] = {0};
u32 extra_idx = 0, i;
@@ -2455,6 +2461,14 @@
}
mutex_unlock(&inst->registeredbufs.lock);
+ tag_data.index = vb->index;
+ tag_data.input_tag = empty_buf_done->input_tag;
+ tag_data.output_tag = empty_buf_done->output_tag;
+ tag_data.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+
+ msm_comm_store_tags(inst, &tag_data);
+
+
update_recon_stats(inst, &empty_buf_done->recon_stats);
msm_vidc_clear_freq_entry(inst, mbuf->smem[0].device_addr);
/*
@@ -2520,6 +2534,7 @@
struct vb2_buffer *vb, *vb2;
struct vidc_hal_fbd *fill_buf_done;
struct vb2_v4l2_buffer *vbuf;
+ struct vidc_tag_data tag_data;
enum hal_buffer buffer_type;
u64 time_usec = 0;
u32 planes[VIDEO_MAX_PLANES] = {0};
@@ -2603,6 +2618,13 @@
fill_buf_done->mark_data, fill_buf_done->mark_target);
}
+ tag_data.index = vb->index;
+ tag_data.input_tag = fill_buf_done->input_tag;
+ tag_data.output_tag = fill_buf_done->output_tag;
+ tag_data.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+
+ msm_comm_store_tags(inst, &tag_data);
+
extra_idx = EXTRADATA_IDX(inst->bufq[CAPTURE_PORT].num_planes);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES)
vb->planes[extra_idx].bytesused = vb->planes[extra_idx].length;
@@ -2623,6 +2645,8 @@
mbuf->vvb.flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT)
mbuf->vvb.flags |= V4L2_QCOM_BUF_DATA_CORRUPT;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_ENDOFSUBFRAME)
+ mbuf->vvb.flags |= V4L2_QCOM_BUF_END_OF_SUBFRAME;
switch (fill_buf_done->picture_type) {
case HAL_PICTURE_IDR:
mbuf->vvb.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
@@ -3824,7 +3848,6 @@
list_for_each_entry_safe(binfo, temp, &inst->eosbufs.list, list) {
data.alloc_len = binfo->smem.size;
data.device_addr = binfo->smem.device_addr;
- data.clnt_data = data.device_addr;
data.buffer_type = HAL_BUFFER_INPUT;
data.filled_len = 0;
data.offset = 0;
@@ -3976,6 +3999,7 @@
int extra_idx;
struct vb2_buffer *vb;
struct vb2_v4l2_buffer *vbuf;
+ struct vidc_tag_data tag_data;
if (!inst || !mbuf || !data) {
dprintk(VIDC_ERR, "%s: invalid params %pK %pK %pK\n",
@@ -3993,7 +4017,6 @@
data->device_addr = mbuf->smem[0].device_addr;
data->timestamp = time_usec;
data->flags = 0;
- data->clnt_data = data->device_addr;
if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
data->buffer_type = HAL_BUFFER_INPUT;
@@ -4021,6 +4044,14 @@
data->buffer_type = msm_comm_get_hal_output_buffer(inst);
}
+ tag_data.index = vb->index;
+ tag_data.type = vb->type;
+
+ msm_comm_fetch_tags(inst, &tag_data);
+ data->input_tag = tag_data.input_tag;
+ data->output_tag = tag_data.output_tag;
+
+
extra_idx = EXTRADATA_IDX(vb->num_planes);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
data->extradata_addr = mbuf->smem[extra_idx].device_addr;
@@ -6605,7 +6636,8 @@
/* send RBR event to client */
msm_vidc_queue_rbr_event(inst,
mbuf->vvb.vb2_buf.planes[0].m.fd,
- mbuf->vvb.vb2_buf.planes[0].data_offset);
+ mbuf->vvb.vb2_buf.planes[0].data_offset,
+ mbuf->output_tag);
/* clear RBR_PENDING flag */
mbuf->flags &= ~MSM_VIDC_FLAG_RBR_PENDING;
@@ -6742,6 +6774,90 @@
return ret;
}
+void msm_comm_free_buffer_tags(struct msm_vidc_inst *inst)
+{
+ struct vidc_tag_data *temp, *next;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid params %pK\n",
+ __func__, inst);
+ return;
+ }
+
+ mutex_lock(&inst->buffer_tags.lock);
+ list_for_each_entry_safe(temp, next, &inst->buffer_tags.list, list) {
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ INIT_LIST_HEAD(&inst->buffer_tags.list);
+ mutex_unlock(&inst->buffer_tags.lock);
+}
+
+void msm_comm_store_tags(struct msm_vidc_inst *inst,
+ struct vidc_tag_data *tag_data)
+{
+
+ struct vidc_tag_data *temp, *next;
+ struct vidc_tag_data *pdata = NULL;
+ bool found = false;
+
+ if (!inst || !tag_data) {
+ dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n",
+ __func__, inst, tag_data);
+ return;
+ }
+
+
+ mutex_lock(&inst->buffer_tags.lock);
+ list_for_each_entry_safe(temp, next, &inst->buffer_tags.list, list) {
+ if (temp->index == tag_data->index &&
+ temp->type == tag_data->type) {
+ temp->input_tag = tag_data->input_tag;
+ temp->output_tag = tag_data->output_tag;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dprintk(VIDC_WARN, "%s: malloc failure.\n", __func__);
+ goto exit;
+ }
+ pdata->input_tag = tag_data->input_tag;
+ pdata->output_tag = tag_data->output_tag;
+ pdata->index = tag_data->index;
+ pdata->type = tag_data->type;
+ list_add_tail(&pdata->list, &inst->buffer_tags.list);
+ }
+
+exit:
+ mutex_unlock(&inst->buffer_tags.lock);
+}
+
+void msm_comm_fetch_tags(struct msm_vidc_inst *inst,
+ struct vidc_tag_data *tag_data)
+{
+ struct vidc_tag_data *temp, *next;
+
+ if (!inst || !tag_data) {
+ dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n",
+ __func__, inst, tag_data);
+ return;
+ }
+ mutex_lock(&inst->buffer_tags.lock);
+ list_for_each_entry_safe(temp, next, &inst->buffer_tags.list, list) {
+ if (temp->index == tag_data->index &&
+ temp->type == tag_data->type) {
+ tag_data->input_tag = temp->input_tag;
+ tag_data->output_tag = temp->output_tag;
+ break;
+ }
+ }
+ mutex_unlock(&inst->buffer_tags.lock);
+}
+
void msm_comm_store_mark_data(struct msm_vidc_list *data_list,
u32 index, u32 mark_data, u32 mark_target)
{
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index fa9cdee..c13242a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -150,6 +150,11 @@
u32 *planes, u32 i);
bool msm_comm_compare_device_planes(struct msm_vidc_buffer *mbuf,
u32 *planes);
+void msm_comm_store_tags(struct msm_vidc_inst *inst,
+ struct vidc_tag_data *tag_data);
+void msm_comm_fetch_tags(struct msm_vidc_inst *inst,
+ struct vidc_tag_data *tag_data);
+void msm_comm_free_buffer_tags(struct msm_vidc_inst *inst);
int msm_comm_qbuf_cache_operations(struct msm_vidc_inst *inst,
struct v4l2_buffer *b);
int msm_comm_dqbuf_cache_operations(struct msm_vidc_inst *inst,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 90253fd..60cdd18 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -152,6 +152,14 @@
u32 input_cr;
};
+struct vidc_tag_data {
+ struct list_head list;
+ u32 index;
+ u32 type;
+ u32 input_tag;
+ u32 output_tag;
+};
+
struct recon_buf {
struct list_head list;
u32 buffer_index;
@@ -373,6 +381,7 @@
struct buf_queue bufq[MAX_PORT_NUM];
struct msm_vidc_list freqs;
struct msm_vidc_list input_crs;
+ struct msm_vidc_list buffer_tags;
struct msm_vidc_list scratchbufs;
struct msm_vidc_list persistbufs;
struct msm_vidc_list pending_getpropq;
@@ -453,6 +462,7 @@
struct msm_smem smem[VIDEO_MAX_PLANES];
struct vb2_v4l2_buffer vvb;
enum msm_vidc_flags flags;
+ u32 output_tag;
};
void msm_comm_handle_thermal_event(void);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
index c84490f..cb581b7 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, 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
@@ -179,7 +179,7 @@
},
{
.key = "qcom,max-hw-load",
- .value = 1944000,
+ .value = 2009280,
},
{
.key = "qcom,max-hq-mbs-per-frame",
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 2d9f3f1..9290c48 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -954,6 +954,8 @@
u32 filled_len;
u32 mark_target;
u32 mark_data;
+ u32 input_tag;
+ u32 output_tag;
u32 clnt_data;
u32 extradata_size;
};
@@ -1148,6 +1150,8 @@
u32 mark_data;
u32 stats;
u32 offset;
+ u32 input_tag;
+ u32 output_tag;
u32 alloc_len;
u32 filled_len;
enum hal_picture picture_type;
@@ -1174,6 +1178,7 @@
u32 start_y_coord;
u32 input_tag;
u32 input_tag1;
+ u32 output_tag;
enum hal_picture picture_type;
u32 packet_buffer1;
u32 extra_data_buffer;
@@ -1291,12 +1296,16 @@
u32 hal_event_type;
u32 packet_buffer;
u32 extra_data_buffer;
+ u32 output_tag;
u32 pic_struct;
u32 colour_space;
u32 profile;
u32 level;
u32 entropy_mode;
u32 capture_buf_count;
+ u32 max_dpb_count;
+ u32 max_ref_count;
+ u32 max_dec_buffering;
struct hal_index_extradata_input_crop_payload crop_data;
};
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index ea8cf1a..7615736 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -256,6 +256,8 @@
(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x009)
#define HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE \
(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x00A)
+#define HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS \
+ (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x00B)
#define HFI_PROPERTY_CONFIG_VDEC_COMMON_START \
@@ -543,6 +545,12 @@
u32 level;
};
+struct hfi_dpb_counts {
+ u32 max_dpb_count;
+ u32 max_ref_count;
+ u32 max_dec_buffering;
+};
+
struct hfi_profile_level_supported {
u32 profile_count;
struct hfi_profile_level rg_profile_level[1];
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vdec.c b/drivers/media/platform/msm/vidc_3x/msm_vdec.c
index b0f639a..04bdd65 100644
--- a/drivers/media/platform/msm/vidc_3x/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc_3x/msm_vdec.c
@@ -2491,6 +2491,11 @@
break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
+ if (!temp_ctrl) {
+ dprintk(VIDC_ERR,
+ "failed to get control\n");
+ return -EINVAL;
+ }
property_id =
HAL_PARAM_PROFILE_LEVEL_CURRENT;
profile_level.profile = vdec_v4l2_to_hal(ctrl->id,
@@ -2502,6 +2507,11 @@
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
+ if (!temp_ctrl) {
+ dprintk(VIDC_ERR,
+ "failed to get control\n");
+ return -EINVAL;
+ }
property_id =
HAL_PARAM_PROFILE_LEVEL_CURRENT;
profile_level.level = vdec_v4l2_to_hal(ctrl->id,
diff --git a/drivers/media/platform/msm/vidc_3x/msm_venc.c b/drivers/media/platform/msm/vidc_3x/msm_venc.c
index 50ec4bd..a728b69 100644
--- a/drivers/media/platform/msm/vidc_3x/msm_venc.c
+++ b/drivers/media/platform/msm/vidc_3x/msm_venc.c
@@ -2320,6 +2320,11 @@
switch (inst->fmts[CAPTURE_PORT].fourcc) {
case V4L2_PIX_FMT_VP8:
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MAX_QP);
+ if (!temp_ctrl) {
+ dprintk(VIDC_ERR,
+ "failed to get control");
+ return -EINVAL;
+ }
max = temp_ctrl->maximum;
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MIN_QP);
min = temp_ctrl->minimum;
@@ -2329,6 +2334,11 @@
case V4L2_PIX_FMT_H263:
case V4L2_PIX_FMT_MPEG4:
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP);
+ if (!temp_ctrl) {
+ dprintk(VIDC_ERR,
+ "failed to get control");
+ return -EINVAL;
+ }
max = temp_ctrl->maximum;
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP);
min = temp_ctrl->minimum;
@@ -2338,6 +2348,11 @@
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_HEVC:
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MAX_QP);
+ if (!temp_ctrl) {
+ dprintk(VIDC_ERR,
+ "failed to get control");
+ return -EINVAL;
+ }
max = temp_ctrl->maximum;
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MIN_QP);
min = temp_ctrl->minimum;
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc.c b/drivers/media/platform/msm/vidc_3x/msm_vidc.c
index 7b22511..983e600c 100644
--- a/drivers/media/platform/msm/vidc_3x/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc.c
@@ -81,16 +81,24 @@
int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
{
+ int rc = -EINVAL;
struct msm_vidc_inst *inst = instance;
if (!inst || !cap)
return -EINVAL;
if (inst->session_type == MSM_VIDC_DECODER)
- return msm_vdec_querycap(instance, cap);
+ rc = msm_vdec_querycap(instance, cap);
else if (inst->session_type == MSM_VIDC_ENCODER)
- return msm_venc_querycap(instance, cap);
- return -EINVAL;
+ rc = msm_venc_querycap(instance, cap);
+ else
+ goto exit;
+ if (!rc) {
+ cap->device_caps = cap->capabilities;
+ cap->capabilities |= V4L2_CAP_DEVICE_CAPS;
+ }
+exit:
+ return rc;
}
EXPORT_SYMBOL(msm_vidc_querycap);
@@ -940,6 +948,15 @@
b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
b->m.planes[i].reserved[0] = buffer_info->fd[i];
b->m.planes[i].reserved[1] = buffer_info->buff_off[i];
+
+ b->m.planes[i].reserved[2] = buffer_info->crop_data.nLeft;
+ b->m.planes[i].reserved[3] = buffer_info->crop_data.nTop;
+ b->m.planes[i].reserved[4] = buffer_info->crop_data.nWidth;
+ b->m.planes[i].reserved[5] = buffer_info->crop_data.nHeight;
+ b->m.planes[i].reserved[6] =
+ buffer_info->crop_data.width_height[0];
+ b->m.planes[i].reserved[7] =
+ buffer_info->crop_data.width_height[1];
if (!(inst->flags & VIDC_SECURE) && !b->m.planes[i].m.userptr) {
dprintk(VIDC_ERR,
"%s: Failed to find user virtual address, %#lx, %d, %d\n",
@@ -1067,6 +1084,7 @@
q->ops = msm_venc_get_vb2q_ops();
q->mem_ops = &msm_vidc_vb2_mem_ops;
q->drv_priv = inst;
+ q->allow_zero_bytesused = 1;
return vb2_queue_init(q);
}
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
index 395ea58..4dcb3b1 100644
--- a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
@@ -2005,6 +2005,7 @@
int64_t time_usec = 0;
static int first_enc_frame = 1;
struct vb2_v4l2_buffer *vbuf = NULL;
+ struct buffer_info *buffer_info = NULL;
if (!response) {
dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
@@ -2046,6 +2047,26 @@
"fbd:Overflow bytesused = %d; length = %d\n",
vb->planes[0].bytesused,
vb->planes[0].length);
+
+ buffer_info = device_to_uvaddr(&inst->registeredbufs,
+ fill_buf_done->packet_buffer1);
+
+ if (!buffer_info) {
+ dprintk(VIDC_ERR,
+ "%s buffer not found in registered list\n",
+ __func__);
+ return;
+ }
+
+ buffer_info->crop_data.nLeft = fill_buf_done->start_x_coord;
+ buffer_info->crop_data.nTop = fill_buf_done->start_y_coord;
+ buffer_info->crop_data.nWidth = fill_buf_done->frame_width;
+ buffer_info->crop_data.nHeight = fill_buf_done->frame_height;
+ buffer_info->crop_data.width_height[0] =
+ inst->prop.width[CAPTURE_PORT];
+ buffer_info->crop_data.width_height[1] =
+ inst->prop.height[CAPTURE_PORT];
+
if (!(fill_buf_done->flags1 &
HAL_BUFFERFLAG_TIMESTAMPINVALID)) {
time_usec = fill_buf_done->timestamp_hi;
@@ -3553,7 +3574,7 @@
static void populate_frame_data(struct vidc_frame_data *data,
const struct vb2_buffer *vb, struct msm_vidc_inst *inst)
{
- int64_t time_usec;
+ u64 time_usec;
int extra_idx;
enum v4l2_buf_type type = vb->type;
enum vidc_ports port = type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
@@ -5192,7 +5213,7 @@
int msm_vidc_comm_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
{
u32 property_id = 0;
- u64 us_per_frame = 0;
+ u64 us_per_frame = 0, fps_u64 = 0;
void *pdata;
int rc = 0, fps = 0;
struct hal_frame_rate frame_rate;
@@ -5230,8 +5251,9 @@
goto exit;
}
- fps = USEC_PER_SEC;
- do_div(fps, us_per_frame);
+ fps_u64 = USEC_PER_SEC;
+ do_div(fps_u64, us_per_frame);
+ fps = fps_u64;
if (fps % 15 == 14 || fps % 24 == 23)
fps = fps + 1;
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h
index 177e09c..93368f6 100644
--- a/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h
@@ -328,6 +328,14 @@
int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst);
void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
+struct crop_info {
+ u32 nLeft;
+ u32 nTop;
+ u32 nWidth;
+ u32 nHeight;
+ u32 width_height[MAX_PORT_NUM];
+};
+
struct buffer_info {
struct list_head list;
int type;
@@ -347,6 +355,7 @@
bool mapped[VIDEO_MAX_PLANES];
int same_fd_ref[VIDEO_MAX_PLANES];
struct timeval timestamp;
+ struct crop_info crop_data;
};
struct buffer_info *device_to_uvaddr(struct msm_vidc_list *buf_list,
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c
index f77252d..d29c248 100644
--- a/drivers/media/platform/soc_camera/soc_scale_crop.c
+++ b/drivers/media/platform/soc_camera/soc_scale_crop.c
@@ -418,3 +418,7 @@
mf->height = soc_camera_shift_scale(rect->height, shift, scale_v);
}
EXPORT_SYMBOL(soc_camera_calc_client_output);
+
+MODULE_DESCRIPTION("soc-camera scaling-cropping functions");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c
index 08dca40..006dac6 100644
--- a/drivers/media/tuners/r820t.c
+++ b/drivers/media/tuners/r820t.c
@@ -396,9 +396,11 @@
return 0;
}
-static int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val)
+static inline int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val)
{
- return r820t_write(priv, reg, &val, 1);
+ u8 tmp = val; /* work around GCC PR81715 with asan-stack=1 */
+
+ return r820t_write(priv, reg, &tmp, 1);
}
static int r820t_read_cache_reg(struct r820t_priv *priv, int reg)
@@ -411,17 +413,18 @@
return -EINVAL;
}
-static int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val,
+static inline int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val,
u8 bit_mask)
{
+ u8 tmp = val;
int rc = r820t_read_cache_reg(priv, reg);
if (rc < 0)
return rc;
- val = (rc & ~bit_mask) | (val & bit_mask);
+ tmp = (rc & ~bit_mask) | (tmp & bit_mask);
- return r820t_write(priv, reg, &val, 1);
+ return r820t_write(priv, reg, &tmp, 1);
}
static int r820t_read(struct r820t_priv *priv, u8 reg, u8 *val, int len)
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index 0e8fb89..5c4aa24 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -504,18 +504,23 @@
static int lme2510_return_status(struct dvb_usb_device *d)
{
- int ret = 0;
+ int ret;
u8 *data;
- data = kzalloc(10, GFP_KERNEL);
+ data = kzalloc(6, GFP_KERNEL);
if (!data)
return -ENOMEM;
- ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
- 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
- info("Firmware Status: %x (%x)", ret , data[2]);
+ ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+ 0x06, 0x80, 0x0302, 0x00,
+ data, 0x6, 200);
+ if (ret != 6)
+ ret = -EINVAL;
+ else
+ ret = data[2];
- ret = (ret < 0) ? -ENODEV : data[2];
+ info("Firmware Status: %6ph", data);
+
kfree(data);
return ret;
}
@@ -1079,8 +1084,6 @@
if (adap->fe[0]) {
info("FE Found M88RS2000");
- dvb_attach(ts2020_attach, adap->fe[0], &ts2020_config,
- &d->i2c_adap);
st->i2c_tuner_gate_w = 5;
st->i2c_tuner_gate_r = 5;
st->i2c_tuner_addr = 0x60;
@@ -1146,17 +1149,18 @@
ret = st->tuner_config;
break;
case TUNER_RS2000:
- ret = st->tuner_config;
+ if (dvb_attach(ts2020_attach, adap->fe[0],
+ &ts2020_config, &d->i2c_adap))
+ ret = st->tuner_config;
break;
default:
break;
}
- if (ret)
+ if (ret) {
info("TUN Found %s tuner", tun_msg[ret]);
- else {
- info("TUN No tuner found --- resetting device");
- lme_coldreset(d);
+ } else {
+ info("TUN No tuner found");
return -ENODEV;
}
@@ -1200,6 +1204,7 @@
static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
{
struct lme2510_state *st = d->priv;
+ int status;
usb_reset_configuration(d->udev);
@@ -1208,12 +1213,16 @@
st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware;
- if (lme2510_return_status(d) == 0x44) {
+ status = lme2510_return_status(d);
+ if (status == 0x44) {
*name = lme_firmware_switch(d, 0);
return COLD;
}
- return 0;
+ if (status != 0x47)
+ return -EINVAL;
+
+ return WARM;
}
static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index 9fd43a3..b20f03d 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -820,6 +820,8 @@
case XC2028_RESET_CLK:
deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg);
break;
+ case XC2028_I2C_FLUSH:
+ break;
default:
deb_info("%s: unknown command %d, arg %d\n", __func__,
command, arg);
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index caa5540..2868766 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -431,6 +431,7 @@
state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
break;
case XC2028_RESET_CLK:
+ case XC2028_I2C_FLUSH:
break;
default:
err("%s: unknown command %d, arg %d\n", __func__,
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index d917b0a..aa131cf 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -11,7 +11,7 @@
select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT
- select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT
---help---
This is a video4linux driver for Empia 28xx based TV cards.
diff --git a/drivers/media/usb/go7007/Kconfig b/drivers/media/usb/go7007/Kconfig
index 95a3af6..af1d024 100644
--- a/drivers/media/usb/go7007/Kconfig
+++ b/drivers/media/usb/go7007/Kconfig
@@ -11,7 +11,7 @@
select VIDEO_TW2804 if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_TW9903 if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_TW9906 if MEDIA_SUBDRV_AUTOSELECT
- select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT
select VIDEO_UDA1342 if MEDIA_SUBDRV_AUTOSELECT
---help---
This is a video4linux driver for the WIS GO7007 MPEG
diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index a61d8fd..a20b60a 100644
--- a/drivers/media/usb/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -295,7 +295,7 @@
/* register v4l2_device early so it can be used for printks */
if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
dev_err(&interface->dev, "v4l2_device_register failed\n");
- goto error;
+ goto error_free_dev;
}
mutex_init(&dev->io_mutex);
@@ -304,7 +304,7 @@
dev->usbc_buf = kmalloc(64, GFP_KERNEL);
if (!dev->usbc_buf) {
v4l2_err(&dev->v4l2_dev, "Out of memory\n");
- goto error;
+ goto error_v4l2_unregister;
}
init_waitqueue_head(&dev->wait_buffer);
@@ -342,13 +342,13 @@
}
if (!dev->bulk_in_endpointAddr) {
v4l2_err(&dev->v4l2_dev, "Could not find bulk-in endpoint\n");
- goto error;
+ goto error_put_usb;
}
/* init the device */
if (hdpvr_device_init(dev)) {
v4l2_err(&dev->v4l2_dev, "device init failed\n");
- goto error;
+ goto error_put_usb;
}
mutex_lock(&dev->io_mutex);
@@ -356,7 +356,7 @@
mutex_unlock(&dev->io_mutex);
v4l2_err(&dev->v4l2_dev,
"allocating transfer buffers failed\n");
- goto error;
+ goto error_put_usb;
}
mutex_unlock(&dev->io_mutex);
@@ -364,7 +364,7 @@
retval = hdpvr_register_i2c_adapter(dev);
if (retval < 0) {
v4l2_err(&dev->v4l2_dev, "i2c adapter register failed\n");
- goto error;
+ goto error_free_buffers;
}
client = hdpvr_register_ir_rx_i2c(dev);
@@ -397,13 +397,17 @@
reg_fail:
#if IS_ENABLED(CONFIG_I2C)
i2c_del_adapter(&dev->i2c_adapter);
+error_free_buffers:
#endif
+ hdpvr_free_buffers(dev);
+error_put_usb:
+ usb_put_dev(dev->udev);
+ kfree(dev->usbc_buf);
+error_v4l2_unregister:
+ v4l2_device_unregister(&dev->v4l2_dev);
+error_free_dev:
+ kfree(dev);
error:
- if (dev) {
- flush_work(&dev->worker);
- /* this frees allocated memory */
- hdpvr_delete(dev);
- }
return retval;
}
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index f37d64c..9eaab98 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -18,8 +18,18 @@
#include <linux/videodev2.h>
#include <linux/v4l2-subdev.h>
#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-ioctl.h>
+/* Use the same argument order as copy_in_user */
+#define assign_in_user(to, from) \
+({ \
+ typeof(*from) __assign_tmp; \
+ \
+ get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \
+})
+
static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret = -ENOIOCTLCMD;
@@ -33,157 +43,88 @@
struct v4l2_clip32 {
struct v4l2_rect c;
- compat_caddr_t next;
+ compat_caddr_t next;
};
struct v4l2_window32 {
struct v4l2_rect w;
- __u32 field; /* enum v4l2_field */
+ __u32 field; /* enum v4l2_field */
__u32 chromakey;
compat_caddr_t clips; /* actually struct v4l2_clip32 * */
__u32 clipcount;
compat_caddr_t bitmap;
+ __u8 global_alpha;
};
static int get_v4l2_window32(struct v4l2_window __user *kp,
- struct v4l2_window32 __user *up)
+ struct v4l2_window32 __user *up,
+ void __user *aux_buf, u32 aux_space)
{
- u32 clipcount = 0;
+ struct v4l2_clip32 __user *uclips;
+ struct v4l2_clip __user *kclips;
+ compat_caddr_t p;
+ u32 clipcount;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
- !access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_window)) ||
- copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
- copy_in_user(&kp->field, &up->field, sizeof(up->field)) ||
- copy_in_user(&kp->chromakey, &up->chromakey,
- sizeof(up->chromakey)) ||
- copy_in_user(&kp->clipcount, &up->clipcount,
- sizeof(up->clipcount)))
- return -EFAULT;
- if (get_user(clipcount, &kp->clipcount))
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
+ assign_in_user(&kp->field, &up->field) ||
+ assign_in_user(&kp->chromakey, &up->chromakey) ||
+ assign_in_user(&kp->global_alpha, &up->global_alpha) ||
+ get_user(clipcount, &up->clipcount) ||
+ put_user(clipcount, &kp->clipcount))
return -EFAULT;
if (clipcount > 2048)
return -EINVAL;
- if (clipcount) {
- struct v4l2_clip32 __user *uclips;
- struct v4l2_clip __user *kclips;
- int n = clipcount;
- compat_caddr_t p;
+ if (!clipcount)
+ return put_user(NULL, &kp->clips);
- if (get_user(p, &up->clips))
+ if (get_user(p, &up->clips))
+ return -EFAULT;
+ uclips = compat_ptr(p);
+ if (aux_space < clipcount * sizeof(*kclips))
+ return -EFAULT;
+ kclips = aux_buf;
+ if (put_user(kclips, &kp->clips))
+ return -EFAULT;
+
+ while (clipcount--) {
+ if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
return -EFAULT;
- uclips = compat_ptr(p);
- kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
- if (put_user(kclips, &kp->clips))
+ if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next))
return -EFAULT;
- while (--n >= 0) {
- if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
- return -EFAULT;
- if (put_user(n ? kclips + 1 : NULL, &kclips->next))
- return -EFAULT;
- uclips += 1;
- kclips += 1;
- }
- } else {
- if (put_user(NULL, &kp->clips))
- return -EFAULT;
+ uclips++;
+ kclips++;
}
return 0;
}
static int put_v4l2_window32(struct v4l2_window __user *kp,
- struct v4l2_window32 __user *up)
+ struct v4l2_window32 __user *up)
{
- if (copy_in_user(&up->w, &kp->w, sizeof(up->w)) ||
- copy_in_user(&up->field, &kp->field, sizeof(up->field)) ||
- copy_in_user(&up->chromakey, &kp->chromakey,
- sizeof(up->chromakey)) ||
- copy_in_user(&up->clipcount, &kp->clipcount,
- sizeof(up->clipcount)))
- return -EFAULT;
- return 0;
-}
+ struct v4l2_clip __user *kclips = kp->clips;
+ struct v4l2_clip32 __user *uclips;
+ compat_caddr_t p;
+ u32 clipcount;
-static inline int get_v4l2_pix_format(struct v4l2_pix_format __user *kp,
- struct v4l2_pix_format __user *up)
-{
- if (copy_in_user(kp, up, sizeof(struct v4l2_pix_format)))
+ if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) ||
+ assign_in_user(&up->field, &kp->field) ||
+ assign_in_user(&up->chromakey, &kp->chromakey) ||
+ assign_in_user(&up->global_alpha, &kp->global_alpha) ||
+ get_user(clipcount, &kp->clipcount) ||
+ put_user(clipcount, &up->clipcount))
return -EFAULT;
- return 0;
-}
+ if (!clipcount)
+ return 0;
-static inline int get_v4l2_pix_format_mplane(
- struct v4l2_pix_format_mplane __user *kp,
- struct v4l2_pix_format_mplane __user *up)
-{
- if (copy_in_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
+ if (get_user(p, &up->clips))
return -EFAULT;
- return 0;
-}
-
-static inline int put_v4l2_pix_format(struct v4l2_pix_format __user *kp,
- struct v4l2_pix_format __user *up)
-{
- if (copy_in_user(up, kp, sizeof(struct v4l2_pix_format)))
- return -EFAULT;
- return 0;
-}
-
-static inline int put_v4l2_pix_format_mplane(
- struct v4l2_pix_format_mplane __user *kp,
- struct v4l2_pix_format_mplane __user *up)
-{
- if (copy_in_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
- return -EFAULT;
- return 0;
-}
-
-static inline int get_v4l2_vbi_format(struct v4l2_vbi_format __user *kp,
- struct v4l2_vbi_format __user *up)
-{
- if (copy_in_user(kp, up, sizeof(struct v4l2_vbi_format)))
- return -EFAULT;
- return 0;
-}
-
-static inline int put_v4l2_vbi_format(struct v4l2_vbi_format __user *kp,
- struct v4l2_vbi_format __user *up)
-{
- if (copy_in_user(up, kp, sizeof(struct v4l2_vbi_format)))
- return -EFAULT;
- return 0;
-}
-
-static inline int get_v4l2_sliced_vbi_format(
- struct v4l2_sliced_vbi_format __user *kp,
- struct v4l2_sliced_vbi_format __user *up)
-{
- if (copy_in_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
- return -EFAULT;
- return 0;
-}
-
-static inline int put_v4l2_sliced_vbi_format(
- struct v4l2_sliced_vbi_format __user *kp,
- struct v4l2_sliced_vbi_format __user *up)
-{
- if (copy_in_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
- return -EFAULT;
- return 0;
-}
-
-static inline int get_v4l2_sdr_format(struct v4l2_sdr_format __user *kp,
- struct v4l2_sdr_format __user *up)
-{
- if (copy_in_user(kp, up, sizeof(struct v4l2_sdr_format)))
- return -EFAULT;
- return 0;
-}
-
-static inline int put_v4l2_sdr_format(struct v4l2_sdr_format __user *kp,
- struct v4l2_sdr_format __user *up)
-{
- if (copy_in_user(up, kp, sizeof(struct v4l2_sdr_format)))
- return -EFAULT;
+ uclips = compat_ptr(p);
+ while (clipcount--) {
+ if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
+ return -EFAULT;
+ uclips++;
+ kclips++;
+ }
return 0;
}
@@ -217,120 +158,158 @@
__u32 reserved[8];
};
-static int __get_v4l2_format32(struct v4l2_format __user *kp,
- struct v4l2_format32 __user *up)
+static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
{
u32 type;
- if (copy_in_user(&kp->type, &up->type, sizeof(up->type)))
+ if (get_user(type, &up->type))
return -EFAULT;
- if (get_user(type, &kp->type))
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
+ u32 clipcount;
+
+ if (get_user(clipcount, &up->fmt.win.clipcount))
+ return -EFAULT;
+ if (clipcount > 2048)
+ return -EINVAL;
+ *size = clipcount * sizeof(struct v4l2_clip);
+ return 0;
+ }
+ default:
+ *size = 0;
+ return 0;
+ }
+}
+
+static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
+{
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)))
return -EFAULT;
+ return __bufsize_v4l2_format(up, size);
+}
+
+static int __get_v4l2_format32(struct v4l2_format __user *kp,
+ struct v4l2_format32 __user *up,
+ void __user *aux_buf, u32 aux_space)
+{
+ u32 type;
+
+ if (get_user(type, &up->type) || put_user(type, &kp->type))
+ return -EFAULT;
+
switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+ return copy_in_user(&kp->fmt.pix, &up->fmt.pix,
+ sizeof(kp->fmt.pix)) ? -EFAULT : 0;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
- &up->fmt.pix_mp);
+ return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
+ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
- return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+ return get_v4l2_window32(&kp->fmt.win, &up->fmt.win,
+ aux_buf, aux_space);
case V4L2_BUF_TYPE_VBI_CAPTURE:
case V4L2_BUF_TYPE_VBI_OUTPUT:
- return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+ return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi,
+ sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
- return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+ return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced,
+ sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
case V4L2_BUF_TYPE_SDR_CAPTURE:
case V4L2_BUF_TYPE_SDR_OUTPUT:
- return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
+ return copy_in_user(&kp->fmt.sdr, &up->fmt.sdr,
+ sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
default:
- pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
- kp->type);
return -EINVAL;
}
}
static int get_v4l2_format32(struct v4l2_format __user *kp,
- struct v4l2_format32 __user *up)
+ struct v4l2_format32 __user *up,
+ void __user *aux_buf, u32 aux_space)
{
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
- !access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_format)))
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)))
return -EFAULT;
- return __get_v4l2_format32(kp, up);
+ return __get_v4l2_format32(kp, up, aux_buf, aux_space);
+}
+
+static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up,
+ u32 *size)
+{
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+ return -EFAULT;
+ return __bufsize_v4l2_format(&up->format, size);
}
static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
- struct v4l2_create_buffers32 __user *up)
+ struct v4l2_create_buffers32 __user *up,
+ void __user *aux_buf, u32 aux_space)
{
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
- !access_ok(VERIFY_WRITE, kp,
- sizeof(struct v4l2_create_buffers)) ||
- copy_in_user(kp, up,
- offsetof(struct v4l2_create_buffers32, format)))
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ copy_in_user(kp, up,
+ offsetof(struct v4l2_create_buffers32, format)))
return -EFAULT;
- return __get_v4l2_format32(&kp->format, &up->format);
+ return __get_v4l2_format32(&kp->format, &up->format,
+ aux_buf, aux_space);
}
static int __put_v4l2_format32(struct v4l2_format __user *kp,
- struct v4l2_format32 __user *up)
+ struct v4l2_format32 __user *up)
{
u32 type;
- if (copy_in_user(&up->type, &kp->type, sizeof(up->type)))
- return -EFAULT;
-
if (get_user(type, &kp->type))
return -EFAULT;
switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+ return copy_in_user(&up->fmt.pix, &kp->fmt.pix,
+ sizeof(kp->fmt.pix)) ? -EFAULT : 0;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
- &up->fmt.pix_mp);
+ return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
+ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
case V4L2_BUF_TYPE_VBI_CAPTURE:
case V4L2_BUF_TYPE_VBI_OUTPUT:
- return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+ return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi,
+ sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
- return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+ return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced,
+ sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
case V4L2_BUF_TYPE_SDR_CAPTURE:
case V4L2_BUF_TYPE_SDR_OUTPUT:
- return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
+ return copy_in_user(&up->fmt.sdr, &kp->fmt.sdr,
+ sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
default:
- pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
- kp->type);
return -EINVAL;
}
}
static int put_v4l2_format32(struct v4l2_format __user *kp,
- struct v4l2_format32 __user *up)
+ struct v4l2_format32 __user *up)
{
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
- !access_ok(VERIFY_READ, kp, sizeof(struct v4l2_format)))
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
return -EFAULT;
return __put_v4l2_format32(kp, up);
}
static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
- struct v4l2_create_buffers32 __user *up)
+ struct v4l2_create_buffers32 __user *up)
{
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
- !access_ok(VERIFY_READ, kp,
- sizeof(struct v4l2_create_buffers)) ||
- copy_in_user(up, kp,
- offsetof(struct v4l2_create_buffers32, format)) ||
- copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ copy_in_user(up, kp,
+ offsetof(struct v4l2_create_buffers32, format)) ||
+ copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
return -EFAULT;
return __put_v4l2_format32(&kp->format, &up->format);
}
@@ -345,30 +324,27 @@
};
static int get_v4l2_standard32(struct v4l2_standard __user *kp,
- struct v4l2_standard32 __user *up)
+ struct v4l2_standard32 __user *up)
{
/* other fields are not set by the user, nor used by the driver */
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
- !access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_standard)) ||
- copy_in_user(&kp->index, &up->index, sizeof(up->index)))
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ assign_in_user(&kp->index, &up->index))
return -EFAULT;
return 0;
}
static int put_v4l2_standard32(struct v4l2_standard __user *kp,
- struct v4l2_standard32 __user *up)
+ struct v4l2_standard32 __user *up)
{
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
- !access_ok(VERIFY_READ, kp, sizeof(struct v4l2_standard)) ||
- copy_in_user(&up->index, &kp->index, sizeof(up->index)) ||
- copy_in_user(&up->id, &kp->id, sizeof(up->id)) ||
- copy_in_user(up->name, kp->name, 24) ||
- copy_in_user(&up->frameperiod, &kp->frameperiod,
- sizeof(up->frameperiod)) ||
- copy_in_user(&up->framelines, &kp->framelines,
- sizeof(up->framelines)) ||
- copy_in_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
- return -EFAULT;
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ assign_in_user(&up->index, &kp->index) ||
+ assign_in_user(&up->id, &kp->id) ||
+ copy_in_user(up->name, kp->name, sizeof(up->name)) ||
+ copy_in_user(&up->frameperiod, &kp->frameperiod,
+ sizeof(up->frameperiod)) ||
+ assign_in_user(&up->framelines, &kp->framelines) ||
+ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+ return -EFAULT;
return 0;
}
@@ -407,160 +383,192 @@
__u32 reserved;
};
-static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
- enum v4l2_memory memory)
+static int get_v4l2_plane32(struct v4l2_plane __user *up,
+ struct v4l2_plane32 __user *up32,
+ enum v4l2_memory memory)
{
- void __user *up_pln;
- compat_long_t p;
+ compat_ulong_t p;
if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
- copy_in_user(&up->data_offset, &up32->data_offset,
- sizeof(__u32)) ||
- copy_in_user(up->reserved, up32->reserved,
- sizeof(up->reserved)) ||
- copy_in_user(&up->length, &up32->length,
- sizeof(__u32)))
+ copy_in_user(&up->data_offset, &up32->data_offset,
+ sizeof(up->data_offset)) ||
+ copy_in_user(up->reserved, up32->reserved,
+ sizeof(up->reserved)) ||
+ copy_in_user(&up->length, &up32->length,
+ sizeof(up->length)))
return -EFAULT;
- if (memory == V4L2_MEMORY_USERPTR) {
- if (get_user(p, &up32->m.userptr))
- return -EFAULT;
- up_pln = compat_ptr(p);
- if (put_user((unsigned long)up_pln, &up->m.userptr))
- return -EFAULT;
- } else if (memory == V4L2_MEMORY_DMABUF) {
- if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int)))
- return -EFAULT;
- } else {
+ switch (memory) {
+ case V4L2_MEMORY_MMAP:
+ case V4L2_MEMORY_OVERLAY:
if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
- sizeof(__u32)))
+ sizeof(up32->m.mem_offset)))
return -EFAULT;
+ break;
+ case V4L2_MEMORY_USERPTR:
+ if (get_user(p, &up32->m.userptr) ||
+ put_user((unsigned long)compat_ptr(p), &up->m.userptr))
+ return -EFAULT;
+ break;
+ case V4L2_MEMORY_DMABUF:
+ if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd)))
+ return -EFAULT;
+ break;
}
return 0;
}
-static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
- enum v4l2_memory memory)
+static int put_v4l2_plane32(struct v4l2_plane __user *up,
+ struct v4l2_plane32 __user *up32,
+ enum v4l2_memory memory)
{
+ unsigned long p;
+
if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
- copy_in_user(&up32->data_offset, &up->data_offset,
- sizeof(__u32)) ||
- copy_in_user(up32->reserved, up->reserved,
- sizeof(up32->reserved)))
+ copy_in_user(&up32->data_offset, &up->data_offset,
+ sizeof(up->data_offset)) ||
+ copy_in_user(up32->reserved, up->reserved,
+ sizeof(up32->reserved)))
return -EFAULT;
- /* For MMAP, driver might've set up the offset, so copy it back.
- * USERPTR stays the same (was userspace-provided), so no copying. */
- if (memory == V4L2_MEMORY_MMAP)
+ switch (memory) {
+ case V4L2_MEMORY_MMAP:
+ case V4L2_MEMORY_OVERLAY:
if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
- sizeof(__u32)))
+ sizeof(up->m.mem_offset)))
return -EFAULT;
- /* For DMABUF, driver might've set up the fd, so copy it back. */
- if (memory == V4L2_MEMORY_DMABUF)
- if (copy_in_user(&up32->m.fd, &up->m.fd,
- sizeof(int)))
+ break;
+ case V4L2_MEMORY_USERPTR:
+ if (get_user(p, &up->m.userptr) ||
+ put_user((compat_ulong_t)ptr_to_compat((__force void *)p),
+ &up32->m.userptr))
return -EFAULT;
+ break;
+ case V4L2_MEMORY_DMABUF:
+ if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd)))
+ return -EFAULT;
+ break;
+ }
return 0;
}
-static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
- struct v4l2_buffer32 __user *up)
+static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size)
{
+ u32 type;
+ u32 length;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ get_user(type, &up->type) ||
+ get_user(length, &up->length))
+ return -EFAULT;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ if (length > VIDEO_MAX_PLANES)
+ return -EINVAL;
+
+ /*
+ * We don't really care if userspace decides to kill itself
+ * by passing a very big length value
+ */
+ *size = length * sizeof(struct v4l2_plane);
+ } else {
+ *size = 0;
+ }
+ return 0;
+}
+
+static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
+ struct v4l2_buffer32 __user *up,
+ void __user *aux_buf, u32 aux_space)
+{
+ u32 type;
+ u32 length;
+ enum v4l2_memory memory;
struct v4l2_plane32 __user *uplane32;
struct v4l2_plane __user *uplane;
compat_caddr_t p;
- int num_planes;
- struct timeval time;
- u32 plane_count, memory, type;
int ret;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
- !access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_buffer)) ||
- copy_in_user(&kp->index, &up->index, sizeof(up->index)) ||
- copy_in_user(&kp->type, &up->type, sizeof(up->type)) ||
- copy_in_user(&kp->flags, &up->flags, sizeof(up->flags)) ||
- copy_in_user(&kp->memory, &up->memory, sizeof(up->memory)) ||
- copy_in_user(&kp->length, &up->length, sizeof(up->length)))
- return -EFAULT;
-
- if (get_user(type, &kp->type))
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ assign_in_user(&kp->index, &up->index) ||
+ get_user(type, &up->type) ||
+ put_user(type, &kp->type) ||
+ assign_in_user(&kp->flags, &up->flags) ||
+ get_user(memory, &up->memory) ||
+ put_user(memory, &kp->memory) ||
+ get_user(length, &up->length) ||
+ put_user(length, &kp->length))
return -EFAULT;
+
if (V4L2_TYPE_IS_OUTPUT(type))
- if (copy_in_user(&kp->bytesused, &up->bytesused,
- sizeof(up->bytesused)) ||
- copy_in_user(&kp->field, &up->field,
- sizeof(up->field)) ||
- get_user(time.tv_sec, &up->timestamp.tv_sec) ||
- get_user(time.tv_usec, &up->timestamp.tv_usec) ||
- put_user(time.tv_sec, &kp->timestamp.tv_sec) ||
- put_user(time.tv_usec, &kp->timestamp.tv_usec))
+ if (assign_in_user(&kp->bytesused, &up->bytesused) ||
+ assign_in_user(&kp->field, &up->field) ||
+ assign_in_user(&kp->timestamp.tv_sec,
+ &up->timestamp.tv_sec) ||
+ assign_in_user(&kp->timestamp.tv_usec,
+ &up->timestamp.tv_usec))
return -EFAULT;
- if (get_user(memory, &kp->memory))
- return -EFAULT;
if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
- if (get_user(plane_count, &kp->length))
- return -EFAULT;
- num_planes = plane_count;
+ u32 num_planes = length;
+
if (num_planes == 0) {
- if (put_user(NULL, &kp->m.planes))
- return -EFAULT;
- /* num_planes == 0 is legal, e.g. when userspace doesn't
- * need planes array on DQBUF*/
- return 0;
+ /*
+ * num_planes == 0 is legal, e.g. when userspace doesn't
+ * need planes array on DQBUF
+ */
+ return put_user(NULL, &kp->m.planes);
}
+ if (num_planes > VIDEO_MAX_PLANES)
+ return -EINVAL;
if (get_user(p, &up->m.planes))
return -EFAULT;
uplane32 = compat_ptr(p);
if (!access_ok(VERIFY_READ, uplane32,
- num_planes * sizeof(struct v4l2_plane32)))
+ num_planes * sizeof(*uplane32)))
return -EFAULT;
- /* We don't really care if userspace decides to kill itself
- * by passing a very big num_planes value */
- uplane = compat_alloc_user_space(num_planes *
- sizeof(struct v4l2_plane));
- if (put_user(uplane, &kp->m.planes))
+ /*
+ * We don't really care if userspace decides to kill itself
+ * by passing a very big num_planes value
+ */
+ if (aux_space < num_planes * sizeof(*uplane))
return -EFAULT;
- while (--num_planes >= 0) {
+ uplane = aux_buf;
+ if (put_user((__force struct v4l2_plane *)uplane,
+ &kp->m.planes))
+ return -EFAULT;
+
+ while (num_planes--) {
ret = get_v4l2_plane32(uplane, uplane32, memory);
if (ret)
return ret;
- ++uplane;
- ++uplane32;
+ uplane++;
+ uplane32++;
}
} else {
switch (memory) {
case V4L2_MEMORY_MMAP:
- if (copy_in_user(&kp->m.offset, &up->m.offset,
- sizeof(up->m.offset)))
- return -EFAULT;
- break;
- case V4L2_MEMORY_USERPTR:
- {
- compat_long_t tmp;
- unsigned long userptr;
-
- if (get_user(tmp, &up->m.userptr))
- return -EFAULT;
-
- userptr = (unsigned long)compat_ptr(tmp);
- put_user(userptr, &kp->m.userptr);
- }
- break;
case V4L2_MEMORY_OVERLAY:
- if (copy_in_user(&kp->m.offset, &up->m.offset,
- sizeof(up->m.offset)))
+ if (assign_in_user(&kp->m.offset, &up->m.offset))
return -EFAULT;
break;
+ case V4L2_MEMORY_USERPTR: {
+ compat_ulong_t userptr;
+
+ if (get_user(userptr, &up->m.userptr) ||
+ put_user((unsigned long)compat_ptr(userptr),
+ &kp->m.userptr))
+ return -EFAULT;
+ break;
+ }
case V4L2_MEMORY_DMABUF:
- if (copy_in_user(&kp->m.fd, &up->m.fd,
- sizeof(up->m.fd)))
+ if (assign_in_user(&kp->m.fd, &up->m.fd))
return -EFAULT;
break;
}
@@ -570,59 +578,50 @@
}
static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
- struct v4l2_buffer32 __user *up)
+ struct v4l2_buffer32 __user *up)
{
+ u32 type;
+ u32 length;
+ enum v4l2_memory memory;
struct v4l2_plane32 __user *uplane32;
struct v4l2_plane __user *uplane;
compat_caddr_t p;
- int num_planes;
int ret;
- struct timeval time;
- u32 memory, type, length;
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
- !access_ok(VERIFY_READ, kp, sizeof(struct v4l2_buffer)) ||
- copy_in_user(&up->index, &kp->index, sizeof(up->index)) ||
- copy_in_user(&up->type, &kp->type, sizeof(up->type)) ||
- copy_in_user(&up->flags, &kp->flags, sizeof(up->flags)) ||
- copy_in_user(&up->memory, &kp->memory, sizeof(up->memory)))
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ assign_in_user(&up->index, &kp->index) ||
+ get_user(type, &kp->type) ||
+ put_user(type, &up->type) ||
+ assign_in_user(&up->flags, &kp->flags) ||
+ get_user(memory, &kp->memory) ||
+ put_user(memory, &up->memory))
return -EFAULT;
- if (copy_in_user(&up->bytesused, &kp->bytesused,
- sizeof(up->bytesused)) ||
- copy_in_user(&up->field, &kp->field, sizeof(up->field)) ||
- get_user(time.tv_sec, &kp->timestamp.tv_sec) ||
- get_user(time.tv_usec, &kp->timestamp.tv_usec) ||
- put_user(time.tv_sec, &up->timestamp.tv_sec) ||
- put_user(time.tv_usec, &up->timestamp.tv_usec) ||
- copy_in_user(&up->timecode, &kp->timecode,
- sizeof(struct v4l2_timecode)) ||
- copy_in_user(&up->sequence, &kp->sequence,
- sizeof(up->sequence)) ||
- copy_in_user(&up->reserved2, &kp->reserved2,
- sizeof(up->reserved2)) ||
- copy_in_user(&up->reserved, &kp->reserved,
- sizeof(up->reserved)) ||
- copy_in_user(&up->length, &kp->length, sizeof(up->length)))
+ if (assign_in_user(&up->bytesused, &kp->bytesused) ||
+ assign_in_user(&up->field, &kp->field) ||
+ assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
+ assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
+ copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
+ assign_in_user(&up->sequence, &kp->sequence) ||
+ assign_in_user(&up->reserved2, &kp->reserved2) ||
+ assign_in_user(&up->reserved, &kp->reserved) ||
+ get_user(length, &kp->length) ||
+ put_user(length, &up->length))
return -EFAULT;
- if (get_user(type, &kp->type) ||
- get_user(memory, &kp->memory) ||
- get_user(length, &kp->length))
- return -EINVAL;
-
if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
- num_planes = length;
+ u32 num_planes = length;
+
if (num_planes == 0)
return 0;
- if (get_user(uplane, &kp->m.planes))
+ if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes)))
return -EFAULT;
if (get_user(p, &up->m.planes))
return -EFAULT;
uplane32 = compat_ptr(p);
- while (--num_planes >= 0) {
+ while (num_planes--) {
ret = put_v4l2_plane32(uplane, uplane32, memory);
if (ret)
return ret;
@@ -632,23 +631,16 @@
} else {
switch (memory) {
case V4L2_MEMORY_MMAP:
- if (copy_in_user(&up->m.offset, &kp->m.offset,
- sizeof(up->m.offset)))
+ case V4L2_MEMORY_OVERLAY:
+ if (assign_in_user(&up->m.offset, &kp->m.offset))
return -EFAULT;
break;
case V4L2_MEMORY_USERPTR:
- if (copy_in_user(&up->m.userptr, &kp->m.userptr,
- sizeof(up->m.userptr)))
- return -EFAULT;
- break;
- case V4L2_MEMORY_OVERLAY:
- if (copy_in_user(&up->m.offset, &kp->m.offset,
- sizeof(up->m.offset)))
+ if (assign_in_user(&up->m.userptr, &kp->m.userptr))
return -EFAULT;
break;
case V4L2_MEMORY_DMABUF:
- if (copy_in_user(&up->m.fd, &kp->m.fd,
- sizeof(up->m.fd)))
+ if (assign_in_user(&up->m.fd, &kp->m.fd))
return -EFAULT;
break;
}
@@ -660,7 +652,7 @@
struct v4l2_framebuffer32 {
__u32 capability;
__u32 flags;
- compat_caddr_t base;
+ compat_caddr_t base;
struct {
__u32 width;
__u32 height;
@@ -674,39 +666,32 @@
};
static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
- struct v4l2_framebuffer32 __user *up)
+ struct v4l2_framebuffer32 __user *up)
{
- u32 tmp;
+ compat_caddr_t tmp;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
- !access_ok(VERIFY_WRITE, kp,
- sizeof(struct v4l2_framebuffer)) ||
- get_user(tmp, &up->base) ||
- put_user(compat_ptr(tmp), &kp->base) ||
- copy_in_user(&kp->capability, &up->capability,
- sizeof(up->capability)) ||
- copy_in_user(&kp->flags, &up->flags, sizeof(up->flags)) ||
- copy_in_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
- return -EFAULT;
-
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ get_user(tmp, &up->base) ||
+ put_user((__force void *)compat_ptr(tmp), &kp->base) ||
+ assign_in_user(&kp->capability, &up->capability) ||
+ assign_in_user(&kp->flags, &up->flags) ||
+ copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
+ return -EFAULT;
return 0;
}
static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
- struct v4l2_framebuffer32 __user *up)
+ struct v4l2_framebuffer32 __user *up)
{
- unsigned long base;
+ void *base;
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
- !access_ok(VERIFY_READ, kp,
- sizeof(struct v4l2_framebuffer)) ||
- copy_from_user(&base, &kp->base, sizeof(base)) ||
- put_user((u32)base, &up->base) ||
- copy_in_user(&up->capability, &kp->capability,
- sizeof(up->capability)) ||
- copy_in_user(&up->flags, &kp->flags, sizeof(up->flags)) ||
- copy_in_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
- return -EFAULT;
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ get_user(base, &kp->base) ||
+ put_user(ptr_to_compat(base), &up->base) ||
+ assign_in_user(&up->capability, &kp->capability) ||
+ assign_in_user(&up->flags, &kp->flags) ||
+ copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt)))
+ return -EFAULT;
return 0;
}
@@ -718,23 +703,26 @@
__u32 tuner; /* Associated tuner */
compat_u64 std;
__u32 status;
- __u32 reserved[4];
+ __u32 capabilities;
+ __u32 reserved[3];
};
-/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
- Otherwise it is identical to the 32-bit version. */
+/*
+ * The 64-bit v4l2_input struct has extra padding at the end of the struct.
+ * Otherwise it is identical to the 32-bit version.
+ */
static inline int get_v4l2_input32(struct v4l2_input __user *kp,
- struct v4l2_input32 __user *up)
+ struct v4l2_input32 __user *up)
{
- if (copy_in_user(kp, up, sizeof(struct v4l2_input32)))
+ if (copy_in_user(kp, up, sizeof(*up)))
return -EFAULT;
return 0;
}
static inline int put_v4l2_input32(struct v4l2_input __user *kp,
- struct v4l2_input32 __user *up)
+ struct v4l2_input32 __user *up)
{
- if (copy_in_user(up, kp, sizeof(struct v4l2_input32)))
+ if (copy_in_user(up, kp, sizeof(*up)))
return -EFAULT;
return 0;
}
@@ -758,70 +746,95 @@
};
} __attribute__ ((packed));
-/* The following function really belong in v4l2-common, but that causes
- a circular dependency between modules. We need to think about this, but
- for now this will do. */
-
-/* Return non-zero if this control is a pointer type. Currently only
- type STRING is a pointer type. */
-static inline int ctrl_is_pointer(u32 id)
+/* Return true if this control is a pointer type. */
+static inline bool ctrl_is_pointer(struct file *file, u32 id)
{
- switch (id) {
- case V4L2_CID_RDS_TX_PS_NAME:
- case V4L2_CID_RDS_TX_RADIO_TEXT:
- return 1;
- default:
- return 0;
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_fh *fh = NULL;
+ struct v4l2_ctrl_handler *hdl = NULL;
+ struct v4l2_query_ext_ctrl qec = { id };
+ const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
+
+ if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
+ fh = file->private_data;
+
+ if (fh && fh->ctrl_handler)
+ hdl = fh->ctrl_handler;
+ else if (vdev->ctrl_handler)
+ hdl = vdev->ctrl_handler;
+
+ if (hdl) {
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
+
+ return ctrl && ctrl->is_ptr;
}
+
+ if (!ops || !ops->vidioc_query_ext_ctrl)
+ return false;
+
+ return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
+ (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
}
-static int get_v4l2_ext_controls32(struct v4l2_ext_controls __user *kp,
- struct v4l2_ext_controls32 __user *up)
+static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up,
+ u32 *size)
+{
+ u32 count;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ get_user(count, &up->count))
+ return -EFAULT;
+ if (count > V4L2_CID_MAX_CTRLS)
+ return -EINVAL;
+ *size = count * sizeof(struct v4l2_ext_control);
+ return 0;
+}
+
+static int get_v4l2_ext_controls32(struct file *file,
+ struct v4l2_ext_controls __user *kp,
+ struct v4l2_ext_controls32 __user *up,
+ void __user *aux_buf, u32 aux_space)
{
struct v4l2_ext_control32 __user *ucontrols;
struct v4l2_ext_control __user *kcontrols;
- int n;
- compat_caddr_t p;
u32 count;
+ u32 n;
+ compat_caddr_t p;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
- !access_ok(VERIFY_WRITE, kp,
- sizeof(struct v4l2_ext_controls)) ||
- copy_in_user(&kp->which, &up->which,
- sizeof(up->which)) ||
- copy_in_user(&kp->count, &up->count, sizeof(up->count)) ||
- copy_in_user(&kp->error_idx, &up->error_idx,
- sizeof(up->error_idx)) ||
- copy_in_user(kp->reserved, up->reserved,
- sizeof(up->reserved)))
- return -EFAULT;
-
- if (get_user(count, &kp->count))
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ assign_in_user(&kp->which, &up->which) ||
+ get_user(count, &up->count) ||
+ put_user(count, &kp->count) ||
+ assign_in_user(&kp->error_idx, &up->error_idx) ||
+ copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
return -EFAULT;
- n = count;
- if (n == 0) {
- if (put_user(NULL, &kp->controls))
- return -EINVAL;
- return 0;
- }
+
+ if (count == 0)
+ return put_user(NULL, &kp->controls);
+ if (count > V4L2_CID_MAX_CTRLS)
+ return -EINVAL;
if (get_user(p, &up->controls))
return -EFAULT;
ucontrols = compat_ptr(p);
- if (!access_ok(VERIFY_READ, ucontrols,
- n * sizeof(struct v4l2_ext_control32)))
+ if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols)))
return -EFAULT;
- kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
- if (put_user(kcontrols, &kp->controls))
+ if (aux_space < count * sizeof(*kcontrols))
+ return -EFAULT;
+ kcontrols = aux_buf;
+ if (put_user((__force struct v4l2_ext_control *)kcontrols,
+ &kp->controls))
return -EFAULT;
- while (--n >= 0) {
+ for (n = 0; n < count; n++) {
u32 id;
if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
return -EFAULT;
+
if (get_user(id, &kcontrols->id))
return -EFAULT;
- if (ctrl_is_pointer(id)) {
+
+ if (ctrl_is_pointer(file, id)) {
void __user *s;
if (get_user(p, &ucontrols->string))
@@ -836,53 +849,55 @@
return 0;
}
-static int put_v4l2_ext_controls32(struct v4l2_ext_controls __user *kp,
- struct v4l2_ext_controls32 __user *up)
+static int put_v4l2_ext_controls32(struct file *file,
+ struct v4l2_ext_controls __user *kp,
+ struct v4l2_ext_controls32 __user *up)
{
struct v4l2_ext_control32 __user *ucontrols;
struct v4l2_ext_control __user *kcontrols;
- int n;
u32 count;
+ u32 n;
compat_caddr_t p;
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
- !access_ok(VERIFY_READ, kp,
- sizeof(struct v4l2_ext_controls)) ||
- copy_in_user(&up->which, &kp->which,
- sizeof(up->which)) ||
- copy_in_user(&up->count, &kp->count,
- sizeof(up->count)) ||
- copy_in_user(&up->error_idx, &kp->error_idx,
- sizeof(up->error_idx)) ||
- copy_in_user(up->reserved, kp->reserved,
- sizeof(up->reserved)) ||
- get_user(count, &kp->count) ||
- get_user(kcontrols, &kp->controls))
- return -EFAULT;
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ assign_in_user(&up->which, &kp->which) ||
+ get_user(count, &kp->count) ||
+ put_user(count, &up->count) ||
+ assign_in_user(&up->error_idx, &kp->error_idx) ||
+ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) ||
+ get_user(kcontrols, &kp->controls))
+ return -EFAULT;
+
if (!count)
return 0;
-
- n = count;
if (get_user(p, &up->controls))
return -EFAULT;
ucontrols = compat_ptr(p);
- if (!access_ok(VERIFY_WRITE, ucontrols,
- n * sizeof(struct v4l2_ext_control32)))
+ if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols)))
return -EFAULT;
- while (--n >= 0) {
- unsigned size = sizeof(*ucontrols);
+ for (n = 0; n < count; n++) {
+ unsigned int size = sizeof(*ucontrols);
u32 id;
- if (get_user(id, &kcontrols->id))
+ if (get_user(id, &kcontrols->id) ||
+ put_user(id, &ucontrols->id) ||
+ assign_in_user(&ucontrols->size, &kcontrols->size) ||
+ copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
+ sizeof(ucontrols->reserved2)))
return -EFAULT;
- /* Do not modify the pointer when copying a pointer control.
- The contents of the pointer was changed, not the pointer
- itself. */
- if (ctrl_is_pointer(id))
+
+ /*
+ * Do not modify the pointer when copying a pointer control.
+ * The contents of the pointer was changed, not the pointer
+ * itself.
+ */
+ if (ctrl_is_pointer(file, id))
size -= sizeof(ucontrols->value64);
+
if (copy_in_user(ucontrols, kcontrols, size))
return -EFAULT;
+
ucontrols++;
kcontrols++;
}
@@ -903,22 +918,18 @@
};
static int put_v4l2_event32(struct v4l2_event __user *kp,
- struct v4l2_event32 __user *up)
+ struct v4l2_event32 __user *up)
{
- struct timespec ts;
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
- !access_ok(VERIFY_READ, kp, sizeof(struct v4l2_event)) ||
- copy_in_user(&up->type, &kp->type, sizeof(up->type)) ||
- copy_in_user(&up->u, &kp->u, sizeof(up->u)) ||
- copy_in_user(&up->pending, &kp->pending,
- sizeof(up->pending)) ||
- copy_in_user(&up->sequence, &kp->sequence,
- sizeof(up->sequence)) ||
- copy_from_user(&ts, &kp->timestamp, sizeof(ts)) ||
- compat_put_timespec(&ts, &up->timestamp) ||
- copy_in_user(&up->id, &kp->id, sizeof(up->id)) ||
- copy_in_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
- return -EFAULT;
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ assign_in_user(&up->type, &kp->type) ||
+ copy_in_user(&up->u, &kp->u, sizeof(kp->u)) ||
+ assign_in_user(&up->pending, &kp->pending) ||
+ assign_in_user(&up->sequence, &kp->sequence) ||
+ assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
+ assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) ||
+ assign_in_user(&up->id, &kp->id) ||
+ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+ return -EFAULT;
return 0;
}
@@ -931,39 +942,34 @@
};
static int get_v4l2_edid32(struct v4l2_edid __user *kp,
- struct v4l2_edid32 __user *up)
+ struct v4l2_edid32 __user *up)
{
- u32 tmp;
+ compat_uptr_t tmp;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) ||
- !access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_edid)) ||
- copy_in_user(&kp->pad, &up->pad, sizeof(up->pad)) ||
- copy_in_user(&kp->start_block, &up->start_block,
- sizeof(up->start_block)) ||
- copy_in_user(&kp->blocks, &up->blocks, sizeof(up->blocks)) ||
- get_user(tmp, &up->edid) ||
- put_user(compat_ptr(tmp), &kp->edid) ||
- copy_in_user(kp->reserved, up->reserved,
- sizeof(kp->reserved)))
- return -EFAULT;
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ assign_in_user(&kp->pad, &up->pad) ||
+ assign_in_user(&kp->start_block, &up->start_block) ||
+ assign_in_user(&kp->blocks, &up->blocks) ||
+ get_user(tmp, &up->edid) ||
+ put_user(compat_ptr(tmp), &kp->edid) ||
+ copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+ return -EFAULT;
return 0;
}
static int put_v4l2_edid32(struct v4l2_edid __user *kp,
- struct v4l2_edid32 __user *up)
+ struct v4l2_edid32 __user *up)
{
- unsigned long ptr;
+ void *edid;
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
- !access_ok(VERIFY_READ, kp, sizeof(struct v4l2_edid)) ||
- copy_in_user(&up->pad, &kp->pad, sizeof(up->pad)) ||
- copy_in_user(&up->start_block, &kp->start_block,
- sizeof(up->start_block)) ||
- copy_in_user(&up->blocks, &kp->blocks, sizeof(up->blocks)) ||
- copy_from_user(&ptr, &kp->edid, sizeof(ptr)) ||
- put_user((u32)ptr, &up->edid) ||
- copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
- return -EFAULT;
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ assign_in_user(&up->pad, &kp->pad) ||
+ assign_in_user(&up->start_block, &kp->start_block) ||
+ assign_in_user(&up->blocks, &kp->blocks) ||
+ get_user(edid, &kp->edid) ||
+ put_user(ptr_to_compat(edid), &up->edid) ||
+ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+ return -EFAULT;
return 0;
}
@@ -979,7 +985,7 @@
#define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32)
#define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32)
#define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32)
-#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
+#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
#define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32)
#define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32)
#define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32)
@@ -995,30 +1001,26 @@
#define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32)
#define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32)
+static int alloc_userspace(unsigned int size, u32 aux_space,
+ void __user **up_native)
+{
+ *up_native = compat_alloc_user_space(size + aux_space);
+ if (!*up_native)
+ return -ENOMEM;
+ if (clear_user(*up_native, size))
+ return -EFAULT;
+ return 0;
+}
+
static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- union {
- struct v4l2_format v2f;
- struct v4l2_buffer v2b;
- struct v4l2_framebuffer v2fb;
- struct v4l2_input v2i;
- struct v4l2_standard v2s;
- struct v4l2_ext_controls v2ecs;
- struct v4l2_event v2ev;
- struct v4l2_create_buffers v2crt;
- struct v4l2_edid v2edid;
- unsigned long vx;
- int vi;
- } *karg;
void __user *up = compat_ptr(arg);
+ void __user *up_native = NULL;
+ void __user *aux_buf;
+ u32 aux_space;
int compatible_arg = 1;
long err = 0;
- karg = compat_alloc_user_space(sizeof(*karg));
- if (karg == NULL) {
- return -EFAULT;
- }
-
/* First, convert the command. */
switch (cmd) {
case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
@@ -1054,31 +1056,52 @@
case VIDIOC_STREAMOFF:
case VIDIOC_S_INPUT:
case VIDIOC_S_OUTPUT:
- err = copy_in_user(&karg->vi, (s32 __user *)up,
- sizeof(karg->vi));
+ err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
+ if (!err && assign_in_user((unsigned int __user *)up_native,
+ (compat_uint_t __user *)up))
+ err = -EFAULT;
compatible_arg = 0;
break;
case VIDIOC_G_INPUT:
case VIDIOC_G_OUTPUT:
+ err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
compatible_arg = 0;
break;
case VIDIOC_G_EDID:
case VIDIOC_S_EDID:
- err = get_v4l2_edid32(&karg->v2edid, up);
+ err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native);
+ if (!err)
+ err = get_v4l2_edid32(up_native, up);
compatible_arg = 0;
break;
case VIDIOC_G_FMT:
case VIDIOC_S_FMT:
case VIDIOC_TRY_FMT:
- err = get_v4l2_format32(&karg->v2f, up);
+ err = bufsize_v4l2_format(up, &aux_space);
+ if (!err)
+ err = alloc_userspace(sizeof(struct v4l2_format),
+ aux_space, &up_native);
+ if (!err) {
+ aux_buf = up_native + sizeof(struct v4l2_format);
+ err = get_v4l2_format32(up_native, up,
+ aux_buf, aux_space);
+ }
compatible_arg = 0;
break;
case VIDIOC_CREATE_BUFS:
- err = get_v4l2_create32(&karg->v2crt, up);
+ err = bufsize_v4l2_create(up, &aux_space);
+ if (!err)
+ err = alloc_userspace(sizeof(struct v4l2_create_buffers),
+ aux_space, &up_native);
+ if (!err) {
+ aux_buf = up_native + sizeof(struct v4l2_create_buffers);
+ err = get_v4l2_create32(up_native, up,
+ aux_buf, aux_space);
+ }
compatible_arg = 0;
break;
@@ -1086,36 +1109,63 @@
case VIDIOC_QUERYBUF:
case VIDIOC_QBUF:
case VIDIOC_DQBUF:
- err = get_v4l2_buffer32(&karg->v2b, up);
+ err = bufsize_v4l2_buffer(up, &aux_space);
+ if (!err)
+ err = alloc_userspace(sizeof(struct v4l2_buffer),
+ aux_space, &up_native);
+ if (!err) {
+ aux_buf = up_native + sizeof(struct v4l2_buffer);
+ err = get_v4l2_buffer32(up_native, up,
+ aux_buf, aux_space);
+ }
compatible_arg = 0;
break;
case VIDIOC_S_FBUF:
- err = get_v4l2_framebuffer32(&karg->v2fb, up);
+ err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
+ &up_native);
+ if (!err)
+ err = get_v4l2_framebuffer32(up_native, up);
compatible_arg = 0;
break;
case VIDIOC_G_FBUF:
+ err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
+ &up_native);
compatible_arg = 0;
break;
case VIDIOC_ENUMSTD:
- err = get_v4l2_standard32(&karg->v2s, up);
+ err = alloc_userspace(sizeof(struct v4l2_standard), 0,
+ &up_native);
+ if (!err)
+ err = get_v4l2_standard32(up_native, up);
compatible_arg = 0;
break;
case VIDIOC_ENUMINPUT:
- err = get_v4l2_input32(&karg->v2i, up);
+ err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native);
+ if (!err)
+ err = get_v4l2_input32(up_native, up);
compatible_arg = 0;
break;
case VIDIOC_G_EXT_CTRLS:
case VIDIOC_S_EXT_CTRLS:
case VIDIOC_TRY_EXT_CTRLS:
- err = get_v4l2_ext_controls32(&karg->v2ecs, up);
+ err = bufsize_v4l2_ext_controls(up, &aux_space);
+ if (!err)
+ err = alloc_userspace(sizeof(struct v4l2_ext_controls),
+ aux_space, &up_native);
+ if (!err) {
+ aux_buf = up_native + sizeof(struct v4l2_ext_controls);
+ err = get_v4l2_ext_controls32(file, up_native, up,
+ aux_buf, aux_space);
+ }
compatible_arg = 0;
break;
case VIDIOC_DQEVENT:
+ err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native);
compatible_arg = 0;
break;
}
@@ -1124,18 +1174,26 @@
if (compatible_arg)
err = native_ioctl(file, cmd, (unsigned long)up);
- else {
- err = native_ioctl(file, cmd, (unsigned long)karg);
- }
+ else
+ err = native_ioctl(file, cmd, (unsigned long)up_native);
- /* Special case: even after an error we need to put the
- results back for these ioctls since the error_idx will
- contain information on which control failed. */
+ if (err == -ENOTTY)
+ return err;
+
+ /*
+ * Special case: even after an error we need to put the
+ * results back for these ioctls since the error_idx will
+ * contain information on which control failed.
+ */
switch (cmd) {
case VIDIOC_G_EXT_CTRLS:
case VIDIOC_S_EXT_CTRLS:
case VIDIOC_TRY_EXT_CTRLS:
- if (put_v4l2_ext_controls32(&karg->v2ecs, up))
+ if (put_v4l2_ext_controls32(file, up_native, up))
+ err = -EFAULT;
+ break;
+ case VIDIOC_S_EDID:
+ if (put_v4l2_edid32(up_native, up))
err = -EFAULT;
break;
}
@@ -1147,44 +1205,46 @@
case VIDIOC_S_OUTPUT:
case VIDIOC_G_INPUT:
case VIDIOC_G_OUTPUT:
- err = copy_in_user(up, &karg->vi, sizeof(s32));
+ if (assign_in_user((compat_uint_t __user *)up,
+ ((unsigned int __user *)up_native)))
+ err = -EFAULT;
break;
case VIDIOC_G_FBUF:
- err = put_v4l2_framebuffer32(&karg->v2fb, up);
+ err = put_v4l2_framebuffer32(up_native, up);
break;
case VIDIOC_DQEVENT:
- err = put_v4l2_event32(&karg->v2ev, up);
+ err = put_v4l2_event32(up_native, up);
break;
case VIDIOC_G_EDID:
- case VIDIOC_S_EDID:
- err = put_v4l2_edid32(&karg->v2edid, up);
+ err = put_v4l2_edid32(up_native, up);
break;
case VIDIOC_G_FMT:
case VIDIOC_S_FMT:
case VIDIOC_TRY_FMT:
- err = put_v4l2_format32(&karg->v2f, up);
+ err = put_v4l2_format32(up_native, up);
break;
case VIDIOC_CREATE_BUFS:
- err = put_v4l2_create32(&karg->v2crt, up);
+ err = put_v4l2_create32(up_native, up);
break;
+ case VIDIOC_PREPARE_BUF:
case VIDIOC_QUERYBUF:
case VIDIOC_QBUF:
case VIDIOC_DQBUF:
- err = put_v4l2_buffer32(&karg->v2b, up);
+ err = put_v4l2_buffer32(up_native, up);
break;
case VIDIOC_ENUMSTD:
- err = put_v4l2_standard32(&karg->v2s, up);
+ err = put_v4l2_standard32(up_native, up);
break;
case VIDIOC_ENUMINPUT:
- err = put_v4l2_input32(&karg->v2i, up);
+ err = put_v4l2_input32(up_native, up);
break;
}
return err;
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 98e5e3b..fa14101 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -307,6 +307,7 @@
static const char * const header_mode[] = {
"Separate Buffer",
"Joined With 1st Frame",
+ "Joined with I Frame",
NULL,
};
static const char * const multi_slice[] = {
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 0e48938..e2e23ff 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1371,6 +1371,12 @@
descr = "VP9"; break;
case V4L2_PIX_FMT_TME:
descr = "TME"; break;
+ case V4L2_PIX_FMT_HEVC_HYBRID:
+ descr = "HEVC Hybrid"; break;
+ case V4L2_PIX_FMT_DIVX_311:
+ descr = "DIVX311"; break;
+ case V4L2_PIX_FMT_DIVX:
+ descr = "DIVX"; break;
default:
WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
if (fmt->description[0])
@@ -2946,8 +2952,11 @@
/* Handles IOCTL */
err = func(file, cmd, parg);
- if (err == -ENOIOCTLCMD)
+ if (err == -ENOTTY || err == -ENOIOCTLCMD) {
err = -ENOTTY;
+ goto out;
+ }
+
if (err == 0) {
if (cmd == VIDIOC_DQBUF)
trace_v4l2_dqbuf(video_devdata(file)->minor, parg);
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 744001a..fb07ce4 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -49,7 +49,8 @@
obj-$(CONFIG_SRAM) += sram.o
obj-y += mic/
obj-$(CONFIG_GENWQE) += genwqe/
-obj-$(CONFIG_HDCP_QSEECOM) += hdcp.o
+obj-$(CONFIG_HDCP_QSEECOM) += hdcp_qseecom.o
+obj-$(CONFIG_HDCP_QSEECOM) += msm_hdcp.o
obj-$(CONFIG_QSEECOM) += qseecom.o
obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp_qseecom.c
similarity index 87%
rename from drivers/misc/hdcp.c
rename to drivers/misc/hdcp_qseecom.c
index a86d9f1..6ce3776 100644
--- a/drivers/misc/hdcp.c
+++ b/drivers/misc/hdcp_qseecom.c
@@ -38,8 +38,6 @@
#include "qseecom_kernel.h"
-#define CLASS_NAME "hdcp"
-#define DRIVER_NAME "msm_hdcp"
#define TZAPP_NAME "hdcp2p2"
#define HDCP1_APP_NAME "hdcp1"
#define QSEECOM_SBUFF_SIZE 0x1000
@@ -509,21 +507,6 @@
const char *msg_name;
};
-struct msm_hdcp_mgr {
- struct platform_device *pdev;
- dev_t dev_num;
- struct cdev cdev;
- struct class *class;
- struct device *device;
- struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
- u32 tp_msgid;
- void *client_ctx;
- struct hdcp_lib_handle *handle;
-};
-
-static struct msm_hdcp_mgr *hdcp_drv_mgr;
-static struct hdcp_lib_handle *drv_client_handle;
-
static void hdcp_lib_clean(struct hdcp_lib_handle *handle);
static void hdcp_lib_init(struct hdcp_lib_handle *handle);
static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle);
@@ -751,7 +734,7 @@
QSEECOM_ALIGN(sizeof
(struct hdcp_set_hw_key_rsp)));
- if ((rc < 0) || (rsp_buf->status < 0)) {
+ if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS)) {
pr_err("qseecom cmd failed with err = %d status = %d\n",
rc, rsp_buf->status);
rc = -EINVAL;
@@ -1125,7 +1108,7 @@
(struct
hdcp_lib_session_deinit_rsp)));
- if ((rc < 0) || (rsp_buf->status < 0) ||
+ if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
(rsp_buf->commandid != HDCP_SESSION_DEINIT)) {
pr_err("qseecom cmd failed with err = %d status = %d\n",
rc, rsp_buf->status);
@@ -1231,7 +1214,7 @@
QSEECOM_ALIGN(sizeof
(struct hdcp_deinit_rsp)));
- if ((rc < 0) || (rsp_buf->status < 0) ||
+ if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
(rsp_buf->commandid != HDCP_TXMTR_DEINIT)) {
pr_err("qseecom cmd failed with err = %d status = %d\n",
rc, rsp_buf->status);
@@ -1285,7 +1268,7 @@
if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
(rsp_buf->commandid != HDCP_TXMTR_START_AUTHENTICATE) ||
- (rsp_buf->msglen <= 0) || (rsp_buf->message == NULL)) {
+ (rsp_buf->msglen == 0) || (rsp_buf->message == NULL)) {
pr_err("qseecom cmd failed with err = %d, status = %d\n",
rc, rsp_buf->status);
rc = -EINVAL;
@@ -1352,9 +1335,10 @@
(struct
hdcp_query_stream_type_rsp)));
- if ((rc < 0) || (rsp_buf->status < 0) || (rsp_buf->msglen <= 0) ||
- (rsp_buf->commandid != HDCP_TXMTR_QUERY_STREAM_TYPE) ||
- (rsp_buf->msg == NULL)) {
+ if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+ (rsp_buf->msglen == 0) ||
+ (rsp_buf->commandid != HDCP_TXMTR_QUERY_STREAM_TYPE) ||
+ (rsp_buf->msg == NULL)) {
pr_err("qseecom cmd failed with err=%d status=%d\n",
rc, rsp_buf->status);
rc = -EINVAL;
@@ -1851,7 +1835,7 @@
mutex_lock(&handle->msg_lock);
msglen = handle->last_msg_recvd_len;
- if (msglen <= 0) {
+ if (msglen == 0) {
pr_err("invalid msg len\n");
mutex_unlock(&handle->msg_lock);
rc = -EINVAL;
@@ -1937,9 +1921,10 @@
goto exit;
}
- if ((rc < 0) || (rsp_buf->status != 0) || (rsp_buf->msglen <= 0) ||
- (rsp_buf->commandid != HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE) ||
- (rsp_buf->msg == NULL)) {
+ if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+ (rsp_buf->msglen == 0) ||
+ (rsp_buf->commandid != HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE) ||
+ (rsp_buf->msg == NULL)) {
pr_err("qseecom cmd failed with err=%d status=%d\n",
rc, rsp_buf->status);
rc = -EINVAL;
@@ -2089,14 +2074,10 @@
}
/* copy bytes into msb and lsb */
- *aksv_msb = key_set_rsp->ksv[0] << 24;
- *aksv_msb |= key_set_rsp->ksv[1] << 16;
- *aksv_msb |= key_set_rsp->ksv[2] << 8;
- *aksv_msb |= key_set_rsp->ksv[3];
- *aksv_lsb = key_set_rsp->ksv[4] << 24;
- *aksv_lsb |= key_set_rsp->ksv[5] << 16;
- *aksv_lsb |= key_set_rsp->ksv[6] << 8;
- *aksv_lsb |= key_set_rsp->ksv[7];
+ *aksv_msb = key_set_rsp->ksv[0] << 24 | key_set_rsp->ksv[1] << 16 |
+ key_set_rsp->ksv[2] << 8 | key_set_rsp->ksv[3];
+ *aksv_lsb = key_set_rsp->ksv[4] << 24 | key_set_rsp->ksv[5] << 16 |
+ key_set_rsp->ksv[6] << 8 | key_set_rsp->ksv[7];
return 0;
}
@@ -2217,23 +2198,6 @@
*data->hdcp_ctx = handle;
- /* Cache the client ctx to be used later if
- * Misc HDCP driver probe happens later than
- * SDE driver probe hence caching it to
- * be used later.
- */
- drv_client_handle = handle;
-
- /* if misc HDCP driver probe happens earlier
- * than SDE driver probe store the client
- * handle to be used to sysfs notifications.
- */
-
- if (hdcp_drv_mgr && !hdcp_drv_mgr->handle) {
- if (drv_client_handle)
- hdcp_drv_mgr->handle = drv_client_handle;
- }
-
handle->thread = kthread_run(kthread_worker_fn,
&handle->worker, "hdcp_tz_lib");
@@ -2274,287 +2238,3 @@
}
EXPORT_SYMBOL(hdcp_library_deregister);
-void hdcp1_notify_topology(void)
-{
- char *envp[4];
- char *a;
- char *b;
-
- if (!hdcp_drv_mgr) {
- pr_err("invalid input\n");
- return;
- }
-
- a = kzalloc(SZ_16, GFP_KERNEL);
-
- if (!a)
- return;
-
- b = kzalloc(SZ_16, GFP_KERNEL);
-
- if (!b) {
- kfree(a);
- return;
- }
-
- envp[0] = "HDCP_MGR_EVENT=MSG_READY";
- envp[1] = a;
- envp[2] = b;
- envp[3] = NULL;
-
- snprintf(envp[1], 16, "%d", (int)DOWN_CHECK_TOPOLOGY);
- snprintf(envp[2], 16, "%d", (int)HDCP_V1_TX);
-
- kobject_uevent_env(&hdcp_drv_mgr->device->kobj, KOBJ_CHANGE, envp);
- kfree(a);
- kfree(b);
-}
-
-static ssize_t msm_hdcp_1x_sysfs_rda_tp(struct device *dev,
-struct device_attribute *attr, char *buf)
-{
- ssize_t ret = 0;
-
- if (!hdcp_drv_mgr) {
- pr_err("invalid input\n");
- return -EINVAL;
- }
-
- switch (hdcp_drv_mgr->tp_msgid) {
- case DOWN_CHECK_TOPOLOGY:
- case DOWN_REQUEST_TOPOLOGY:
- buf[MSG_ID_IDX] = hdcp_drv_mgr->tp_msgid;
- buf[RET_CODE_IDX] = HDCP_AUTHED;
- ret = HEADER_LEN;
-
- memcpy(buf + HEADER_LEN, &hdcp_drv_mgr->cached_tp,
- sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
-
- ret += sizeof(struct HDCP_V2V1_MSG_TOPOLOGY);
-
- /* clear the flag once data is read back to user space*/
- hdcp_drv_mgr->tp_msgid = -1;
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static ssize_t msm_hdcp_1x_sysfs_wta_tp(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int msgid = 0;
- ssize_t ret = count;
-
- if (!hdcp_drv_mgr || !buf) {
- pr_err("invalid input\n");
- return -EINVAL;
- }
-
- msgid = buf[0];
-
- switch (msgid) {
- case DOWN_CHECK_TOPOLOGY:
- case DOWN_REQUEST_TOPOLOGY:
- hdcp_drv_mgr->tp_msgid = msgid;
- break;
- /* more cases added here */
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static ssize_t hdcp2p2_sysfs_wta_min_level_change(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int rc;
- int min_enc_lvl;
- struct hdcp_lib_handle *handle;
- ssize_t ret = count;
-
- if (!hdcp_drv_mgr) {
- pr_err("invalid input\n");
- return -EINVAL;
- }
-
- handle = hdcp_drv_mgr->handle;
-
- rc = kstrtoint(buf, 10, &min_enc_lvl);
- if (rc) {
- pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc);
- return -EINVAL;
- }
-
- if (handle && handle->client_ops->notify_lvl_change) {
- handle->client_ops->notify_lvl_change(handle->client_ctx,
- min_enc_lvl);
- }
-
- return ret;
-}
-
-static DEVICE_ATTR(tp, 0644, msm_hdcp_1x_sysfs_rda_tp,
- msm_hdcp_1x_sysfs_wta_tp);
-
-static DEVICE_ATTR(min_level_change, 0200, NULL,
- hdcp2p2_sysfs_wta_min_level_change);
-
-void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp)
-{
- if (!hdcp_drv_mgr) {
- pr_err("invalid input\n");
- return;
- }
-
- memcpy((void *)&hdcp_drv_mgr->cached_tp,
- hdcp1_cached_tp,
- sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
-}
-
-static struct attribute *msm_hdcp_fs_attrs[] = {
- &dev_attr_tp.attr,
- &dev_attr_min_level_change.attr,
- NULL
-};
-
-static struct attribute_group msm_hdcp_fs_attr_group = {
- .attrs = msm_hdcp_fs_attrs
-};
-
-static int msm_hdcp_open(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static int msm_hdcp_close(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static const struct file_operations msm_hdcp_fops = {
- .owner = THIS_MODULE,
- .open = msm_hdcp_open,
- .release = msm_hdcp_close,
-};
-
-static const struct of_device_id msm_hdcp_dt_match[] = {
- { .compatible = "qcom,msm-hdcp",},
- {}
-};
-
-MODULE_DEVICE_TABLE(of, msm_hdcp_dt_match);
-
-static int msm_hdcp_probe(struct platform_device *pdev)
-{
- int ret;
-
- hdcp_drv_mgr = devm_kzalloc(&pdev->dev, sizeof(struct msm_hdcp_mgr),
- GFP_KERNEL);
- if (!hdcp_drv_mgr)
- return -ENOMEM;
-
- hdcp_drv_mgr->pdev = pdev;
-
- platform_set_drvdata(pdev, hdcp_drv_mgr);
-
- ret = alloc_chrdev_region(&hdcp_drv_mgr->dev_num, 0, 1, DRIVER_NAME);
- if (ret < 0) {
- pr_err("alloc_chrdev_region failed ret = %d\n", ret);
- goto error_get_dev_num;
- }
-
- hdcp_drv_mgr->class = class_create(THIS_MODULE, CLASS_NAME);
- if (IS_ERR(hdcp_drv_mgr->class)) {
- ret = PTR_ERR(hdcp_drv_mgr->class);
- pr_err("couldn't create class rc = %d\n", ret);
- goto error_class_create;
- }
-
- hdcp_drv_mgr->device = device_create(hdcp_drv_mgr->class, NULL,
- hdcp_drv_mgr->dev_num, NULL, DRIVER_NAME);
- if (IS_ERR(hdcp_drv_mgr->device)) {
- ret = PTR_ERR(hdcp_drv_mgr->device);
- pr_err("device_create failed %d\n", ret);
- goto error_class_device_create;
- }
-
- cdev_init(&hdcp_drv_mgr->cdev, &msm_hdcp_fops);
- ret = cdev_add(&hdcp_drv_mgr->cdev,
- MKDEV(MAJOR(hdcp_drv_mgr->dev_num), 0), 1);
- if (ret < 0) {
- pr_err("cdev_add failed %d\n", ret);
- goto error_cdev_add;
- }
-
- ret = sysfs_create_group(&hdcp_drv_mgr->device->kobj,
- &msm_hdcp_fs_attr_group);
- if (ret)
- pr_err("unable to register rotator sysfs nodes\n");
-
- /* Store the handle in the hdcp drv mgr
- * to be used for the sysfs notifications
- */
- hdcp_drv_mgr->handle = drv_client_handle;
-
- return 0;
-error_cdev_add:
- device_destroy(hdcp_drv_mgr->class, hdcp_drv_mgr->dev_num);
-error_class_device_create:
- class_destroy(hdcp_drv_mgr->class);
-error_class_create:
- unregister_chrdev_region(hdcp_drv_mgr->dev_num, 1);
-error_get_dev_num:
- devm_kfree(&pdev->dev, hdcp_drv_mgr);
- hdcp_drv_mgr = NULL;
- return ret;
-}
-
-static int msm_hdcp_remove(struct platform_device *pdev)
-{
- struct msm_hdcp_mgr *mgr;
-
- mgr = (struct msm_hdcp_mgr *)platform_get_drvdata(pdev);
- if (!mgr)
- return -ENODEV;
-
- sysfs_remove_group(&hdcp_drv_mgr->device->kobj,
- &msm_hdcp_fs_attr_group);
- cdev_del(&hdcp_drv_mgr->cdev);
- device_destroy(hdcp_drv_mgr->class, hdcp_drv_mgr->dev_num);
- class_destroy(hdcp_drv_mgr->class);
- unregister_chrdev_region(hdcp_drv_mgr->dev_num, 1);
-
- devm_kfree(&pdev->dev, hdcp_drv_mgr);
- hdcp_drv_mgr = NULL;
- return 0;
-}
-
-static struct platform_driver msm_hdcp_driver = {
- .probe = msm_hdcp_probe,
- .remove = msm_hdcp_remove,
- .driver = {
- .name = "msm_hdcp",
- .of_match_table = msm_hdcp_dt_match,
- .pm = NULL,
- }
-};
-
-static int __init msm_hdcp_init(void)
-{
- return platform_driver_register(&msm_hdcp_driver);
-}
-
-static void __exit msm_hdcp_exit(void)
-{
- return platform_driver_unregister(&msm_hdcp_driver);
-}
-
-module_init(msm_hdcp_init);
-module_exit(msm_hdcp_exit);
-
-MODULE_DESCRIPTION("MSM HDCP driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/msm_hdcp.c b/drivers/misc/msm_hdcp.c
new file mode 100644
index 0000000..ea8e84d
--- /dev/null
+++ b/drivers/misc/msm_hdcp.c
@@ -0,0 +1,356 @@
+/* Copyright (c) 2018, 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.
+ */
+
+#define pr_fmt(fmt) "[msm-hdcp] %s: " fmt, __func__
+
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/msm_hdcp.h>
+#include <linux/of.h>
+
+#define CLASS_NAME "hdcp"
+#define DRIVER_NAME "msm_hdcp"
+
+struct msm_hdcp {
+ struct platform_device *pdev;
+ dev_t dev_num;
+ struct cdev cdev;
+ struct class *class;
+ struct device *device;
+ struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
+ u32 tp_msgid;
+ void *client_ctx;
+ void (*cb)(void *ctx, int data);
+};
+
+void msm_hdcp_register_cb(struct device *dev, void *ctx,
+ void (*cb)(void *ctx, int data))
+{
+ struct msm_hdcp *hdcp = NULL;
+
+ if (!dev) {
+ pr_err("invalid device pointer\n");
+ return;
+ }
+
+ hdcp = dev_get_drvdata(dev);
+ if (!hdcp) {
+ pr_err("invalid driver pointer\n");
+ return;
+ }
+
+ hdcp->cb = cb;
+ hdcp->client_ctx = ctx;
+}
+
+void msm_hdcp_notify_topology(struct device *dev)
+{
+ char *envp[4];
+ char tp[SZ_16];
+ char ver[SZ_16];
+ struct msm_hdcp *hdcp = NULL;
+
+ if (!dev) {
+ pr_err("invalid device pointer\n");
+ return;
+ }
+
+ hdcp = dev_get_drvdata(dev);
+ if (!hdcp) {
+ pr_err("invalid driver pointer\n");
+ return;
+ }
+
+ snprintf(tp, SZ_16, "%d", DOWN_CHECK_TOPOLOGY);
+ snprintf(ver, SZ_16, "%d", HDCP_V1_TX);
+
+ envp[0] = "HDCP_MGR_EVENT=MSG_READY";
+ envp[1] = tp;
+ envp[2] = ver;
+ envp[3] = NULL;
+
+ kobject_uevent_env(&hdcp->device->kobj, KOBJ_CHANGE, envp);
+}
+
+void msm_hdcp_cache_repeater_topology(struct device *dev,
+ struct HDCP_V2V1_MSG_TOPOLOGY *tp)
+{
+ struct msm_hdcp *hdcp = NULL;
+
+ if (!dev || !tp) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ hdcp = dev_get_drvdata(dev);
+ if (!hdcp) {
+ pr_err("invalid driver pointer\n");
+ return;
+ }
+
+ memcpy(&hdcp->cached_tp, tp,
+ sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
+}
+
+static ssize_t msm_hdcp_1x_sysfs_rda_tp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+ struct msm_hdcp *hdcp = NULL;
+
+ if (!dev) {
+ pr_err("invalid device pointer\n");
+ return -ENODEV;
+ }
+
+ hdcp = dev_get_drvdata(dev);
+ if (!hdcp) {
+ pr_err("invalid driver pointer\n");
+ return -ENODEV;
+ }
+
+ switch (hdcp->tp_msgid) {
+ case DOWN_CHECK_TOPOLOGY:
+ case DOWN_REQUEST_TOPOLOGY:
+ buf[MSG_ID_IDX] = hdcp->tp_msgid;
+ buf[RET_CODE_IDX] = HDCP_AUTHED;
+ ret = HEADER_LEN;
+
+ memcpy(buf + HEADER_LEN, &hdcp->cached_tp,
+ sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
+
+ ret += sizeof(struct HDCP_V2V1_MSG_TOPOLOGY);
+
+ /* clear the flag once data is read back to user space*/
+ hdcp->tp_msgid = -1;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static ssize_t msm_hdcp_1x_sysfs_wta_tp(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int msgid = 0;
+ ssize_t ret = count;
+ struct msm_hdcp *hdcp = NULL;
+
+ if (!dev) {
+ pr_err("invalid device pointer\n");
+ return -ENODEV;
+ }
+
+ hdcp = dev_get_drvdata(dev);
+ if (!hdcp) {
+ pr_err("invalid driver pointer\n");
+ return -ENODEV;
+ }
+
+ msgid = buf[0];
+
+ switch (msgid) {
+ case DOWN_CHECK_TOPOLOGY:
+ case DOWN_REQUEST_TOPOLOGY:
+ hdcp->tp_msgid = msgid;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static ssize_t msm_hdcp_2x_sysfs_wta_min_level_change(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int rc;
+ int min_enc_lvl;
+ ssize_t ret = count;
+ struct msm_hdcp *hdcp = NULL;
+
+ if (!dev) {
+ pr_err("invalid device pointer\n");
+ return -ENODEV;
+ }
+
+ hdcp = dev_get_drvdata(dev);
+ if (!hdcp) {
+ pr_err("invalid driver pointer\n");
+ return -ENODEV;
+ }
+
+ rc = kstrtoint(buf, 10, &min_enc_lvl);
+ if (rc) {
+ pr_err("kstrtoint failed. rc=%d\n", rc);
+ return -EINVAL;
+ }
+
+ if (hdcp->cb && hdcp->client_ctx)
+ hdcp->cb(hdcp->client_ctx, min_enc_lvl);
+
+ return ret;
+}
+
+static DEVICE_ATTR(tp, 0644, msm_hdcp_1x_sysfs_rda_tp,
+ msm_hdcp_1x_sysfs_wta_tp);
+
+static DEVICE_ATTR(min_level_change, 0200, NULL,
+ msm_hdcp_2x_sysfs_wta_min_level_change);
+
+static struct attribute *msm_hdcp_fs_attrs[] = {
+ &dev_attr_tp.attr,
+ &dev_attr_min_level_change.attr,
+ NULL
+};
+
+static struct attribute_group msm_hdcp_fs_attr_group = {
+ .attrs = msm_hdcp_fs_attrs
+};
+
+static int msm_hdcp_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int msm_hdcp_close(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static const struct file_operations msm_hdcp_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_hdcp_open,
+ .release = msm_hdcp_close,
+};
+
+static const struct of_device_id msm_hdcp_dt_match[] = {
+ { .compatible = "qcom,msm-hdcp",},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_hdcp_dt_match);
+
+static int msm_hdcp_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct msm_hdcp *hdcp;
+
+ hdcp = devm_kzalloc(&pdev->dev, sizeof(struct msm_hdcp), GFP_KERNEL);
+ if (!hdcp)
+ return -ENOMEM;
+
+ hdcp->pdev = pdev;
+
+ platform_set_drvdata(pdev, hdcp);
+
+ ret = alloc_chrdev_region(&hdcp->dev_num, 0, 1, DRIVER_NAME);
+ if (ret < 0) {
+ pr_err("alloc_chrdev_region failed ret = %d\n", ret);
+ goto error_get_dev_num;
+ }
+
+ hdcp->class = class_create(THIS_MODULE, CLASS_NAME);
+ if (IS_ERR(hdcp->class)) {
+ ret = PTR_ERR(hdcp->class);
+ pr_err("couldn't create class rc = %d\n", ret);
+ goto error_class_create;
+ }
+
+ hdcp->device = device_create(hdcp->class, NULL,
+ hdcp->dev_num, NULL, DRIVER_NAME);
+ if (IS_ERR(hdcp->device)) {
+ ret = PTR_ERR(hdcp->device);
+ pr_err("device_create failed %d\n", ret);
+ goto error_class_device_create;
+ }
+
+ cdev_init(&hdcp->cdev, &msm_hdcp_fops);
+ ret = cdev_add(&hdcp->cdev, MKDEV(MAJOR(hdcp->dev_num), 0), 1);
+ if (ret < 0) {
+ pr_err("cdev_add failed %d\n", ret);
+ goto error_cdev_add;
+ }
+
+ ret = sysfs_create_group(&hdcp->device->kobj, &msm_hdcp_fs_attr_group);
+ if (ret)
+ pr_err("unable to register msm_hdcp sysfs nodes\n");
+
+ return 0;
+error_cdev_add:
+ device_destroy(hdcp->class, hdcp->dev_num);
+error_class_device_create:
+ class_destroy(hdcp->class);
+error_class_create:
+ unregister_chrdev_region(hdcp->dev_num, 1);
+error_get_dev_num:
+ devm_kfree(&pdev->dev, hdcp);
+ hdcp = NULL;
+ return ret;
+}
+
+static int msm_hdcp_remove(struct platform_device *pdev)
+{
+ struct msm_hdcp *hdcp;
+
+ hdcp = platform_get_drvdata(pdev);
+ if (!hdcp)
+ return -ENODEV;
+
+ sysfs_remove_group(&hdcp->device->kobj,
+ &msm_hdcp_fs_attr_group);
+ cdev_del(&hdcp->cdev);
+ device_destroy(hdcp->class, hdcp->dev_num);
+ class_destroy(hdcp->class);
+ unregister_chrdev_region(hdcp->dev_num, 1);
+
+ devm_kfree(&pdev->dev, hdcp);
+ hdcp = NULL;
+ return 0;
+}
+
+static struct platform_driver msm_hdcp_driver = {
+ .probe = msm_hdcp_probe,
+ .remove = msm_hdcp_remove,
+ .driver = {
+ .name = "msm_hdcp",
+ .of_match_table = msm_hdcp_dt_match,
+ .pm = NULL,
+ }
+};
+
+static int __init msm_hdcp_init(void)
+{
+ return platform_driver_register(&msm_hdcp_driver);
+}
+
+static void __exit msm_hdcp_exit(void)
+{
+ return platform_driver_unregister(&msm_hdcp_driver);
+}
+
+module_init(msm_hdcp_init);
+module_exit(msm_hdcp_exit);
+
+MODULE_DESCRIPTION("MSM HDCP driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c
index 7d69dd5..42a513c 100644
--- a/drivers/misc/uid_sys_stats.c
+++ b/drivers/misc/uid_sys_stats.c
@@ -1,4 +1,4 @@
-/* drivers/misc/uid_cputime.c
+/* drivers/misc/uid_sys_stats.c
*
* Copyright (C) 2014 - 2015 Google, Inc.
*
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 89edc6d..da9cddb 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -470,6 +470,9 @@
mmc_host_clear_sdr104(host);
err = mmc_hw_reset(host);
host->card->sdr104_blocked = true;
+ } else {
+ /* If sdr104_wa is not present, just return status */
+ err = host->bus_ops->alive(host);
}
if (err)
pr_err("%s: %s: Fallback to lower speed mode failed with err=%d\n",
@@ -1059,9 +1062,10 @@
completion = ktime_get();
delta_us = ktime_us_delta(completion,
mrq->io_start);
- blk_update_latency_hist(&host->io_lat_s,
- (mrq->data->flags & MMC_DATA_READ),
- delta_us);
+ blk_update_latency_hist(
+ (mrq->data->flags & MMC_DATA_READ) ?
+ &host->io_lat_read :
+ &host->io_lat_write, delta_us);
}
#endif
}
@@ -4826,8 +4830,14 @@
latency_hist_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ size_t written_bytes;
- return blk_latency_hist_show(&host->io_lat_s, buf);
+ written_bytes = blk_latency_hist_show("Read", &host->io_lat_read,
+ buf, PAGE_SIZE);
+ written_bytes += blk_latency_hist_show("Write", &host->io_lat_write,
+ buf + written_bytes, PAGE_SIZE - written_bytes);
+
+ return written_bytes;
}
/*
@@ -4845,9 +4855,10 @@
if (kstrtol(buf, 0, &value))
return -EINVAL;
- if (value == BLK_IO_LAT_HIST_ZERO)
- blk_zero_latency_hist(&host->io_lat_s);
- else if (value == BLK_IO_LAT_HIST_ENABLE ||
+ if (value == BLK_IO_LAT_HIST_ZERO) {
+ memset(&host->io_lat_read, 0, sizeof(host->io_lat_read));
+ memset(&host->io_lat_write, 0, sizeof(host->io_lat_write));
+ } else if (value == BLK_IO_LAT_HIST_ENABLE ||
value == BLK_IO_LAT_HIST_DISABLE)
host->latency_hist_enabled = value;
return count;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 0abc7a3..0bea2cb 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2692,6 +2692,52 @@
msm_host_offset->CORE_PWRCTL_CTL), irq_flags);
}
+static int sdhci_msm_clear_pwrctl_status(struct sdhci_host *host, u8 value)
+{
+ 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;
+ int ret = 0, retry = 10;
+
+ /*
+ * There is a rare HW scenario where the first clear pulse could be
+ * lost when actual reset and clear/read of status register is
+ * happening at a time. Hence, retry for at least 10 times to make
+ * sure status register is cleared. Otherwise, this will result in
+ * a spurious power IRQ resulting in system instability.
+ */
+ do {
+ if (retry == 0) {
+ pr_err("%s: Timedout clearing (0x%x) pwrctl status register\n",
+ mmc_hostname(host->mmc), value);
+ sdhci_msm_dump_pwr_ctrl_regs(host);
+ WARN_ON(1);
+ ret = -EBUSY;
+ break;
+ }
+
+ /*
+ * Clear the PWRCTL_STATUS interrupt bits by writing to the
+ * corresponding bits in the PWRCTL_CLEAR register.
+ */
+ sdhci_msm_writeb_relaxed(value, host,
+ msm_host_offset->CORE_PWRCTL_CLEAR);
+ /*
+ * SDHC has core_mem and hc_mem device memory and these memory
+ * addresses do not fall within 1KB region. Hence, any update
+ * to core_mem address space would require an mb() to ensure
+ * this gets completed before its next update to registers
+ * within hc_mem.
+ */
+ mb();
+ retry--;
+ udelay(10);
+ } while (value & sdhci_msm_readb_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_STATUS));
+
+ return ret;
+}
+
static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
{
struct sdhci_host *host = (struct sdhci_host *)data;
@@ -2704,7 +2750,6 @@
int ret = 0;
int pwr_state = 0, io_level = 0;
unsigned long flags;
- int retry = 10;
irq_status = sdhci_msm_readb_relaxed(host,
msm_host_offset->CORE_PWRCTL_STATUS);
@@ -2712,40 +2757,7 @@
pr_debug("%s: Received IRQ(%d), status=0x%x\n",
mmc_hostname(msm_host->mmc), irq, irq_status);
- /* Clear the interrupt */
- sdhci_msm_writeb_relaxed(irq_status, host,
- msm_host_offset->CORE_PWRCTL_CLEAR);
-
- /*
- * SDHC has core_mem and hc_mem device memory and these memory
- * addresses do not fall within 1KB region. Hence, any update to
- * core_mem address space would require an mb() to ensure this gets
- * completed before its next update to registers within hc_mem.
- */
- mb();
- /*
- * There is a rare HW scenario where the first clear pulse could be
- * lost when actual reset and clear/read of status register is
- * happening at a time. Hence, retry for at least 10 times to make
- * sure status register is cleared. Otherwise, this will result in
- * a spurious power IRQ resulting in system instability.
- */
- while (irq_status & sdhci_msm_readb_relaxed(host,
- msm_host_offset->CORE_PWRCTL_STATUS)) {
- if (retry == 0) {
- pr_err("%s: Timedout clearing (0x%x) pwrctl status register\n",
- mmc_hostname(host->mmc), irq_status);
- sdhci_msm_dump_pwr_ctrl_regs(host);
- BUG_ON(1);
- }
- sdhci_msm_writeb_relaxed(irq_status, host,
- msm_host_offset->CORE_PWRCTL_CLEAR);
- retry--;
- udelay(10);
- }
- if (likely(retry < 10))
- pr_debug("%s: success clearing (0x%x) pwrctl status register, retries left %d\n",
- mmc_hostname(host->mmc), irq_status, retry);
+ sdhci_msm_clear_pwrctl_status(host, irq_status);
/* Handle BUS ON/OFF*/
if (irq_status & CORE_PWRCTL_BUS_ON) {
@@ -3124,6 +3136,7 @@
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ u8 irq_status;
const struct sdhci_msm_offset *msm_host_offset =
msm_host->offset;
@@ -3131,10 +3144,9 @@
!msm_host->regs_restore.is_valid)
return;
+ writel_relaxed(0, host->ioaddr + msm_host_offset->CORE_PWRCTL_MASK);
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);
@@ -3145,8 +3157,6 @@
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,
@@ -3162,6 +3172,24 @@
msm_host_offset->CORE_TESTBUS_CONFIG);
msm_host->regs_restore.is_valid = false;
+ /*
+ * Clear the PWRCTL_STATUS register.
+ * There is a rare HW scenario where the first clear pulse could be
+ * lost when actual reset and clear/read of status register is
+ * happening at a time. Hence, retry for at least 10 times to make
+ * sure status register is cleared. Otherwise, this will result in
+ * a spurious power IRQ resulting in system instability.
+ */
+ irq_status = sdhci_msm_readb_relaxed(host,
+ msm_host_offset->CORE_PWRCTL_STATUS);
+
+ sdhci_msm_clear_pwrctl_status(host, irq_status);
+
+ writel_relaxed(msm_host->regs_restore.vendor_pwrctl_ctl,
+ host->ioaddr + msm_host_offset->CORE_PWRCTL_CTL);
+ writel_relaxed(msm_host->regs_restore.vendor_pwrctl_mask,
+ host->ioaddr + msm_host_offset->CORE_PWRCTL_MASK);
+
pr_debug("%s: %s: registers restored. PWRCTL_MASK = 0x%x\n",
mmc_hostname(host->mmc), __func__,
readl_relaxed(host->ioaddr +
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index d9fab22..1a4a790 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -2193,16 +2193,9 @@
if (ctrl->nand_version >= 0x0702)
tmp |= ACC_CONTROL_RD_ERASED;
tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
- if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
- /*
- * FIXME: Flash DMA + prefetch may see spurious erased-page ECC
- * errors
- */
- if (has_flash_dma(ctrl))
- tmp &= ~ACC_CONTROL_PREFETCH;
- else
- tmp |= ACC_CONTROL_PREFETCH;
- }
+ if (ctrl->features & BRCMNAND_HAS_PREFETCH)
+ tmp &= ~ACC_CONTROL_PREFETCH;
+
nand_writereg(ctrl, offs, tmp);
return 0;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index a77cfd7..21c0308 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2320,6 +2320,7 @@
static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
+ unsigned int max_bitflips = 0;
int page, realpage, chipnr;
struct nand_chip *chip = mtd_to_nand(mtd);
struct mtd_ecc_stats stats;
@@ -2377,6 +2378,8 @@
nand_wait_ready(mtd);
}
+ max_bitflips = max_t(unsigned int, max_bitflips, ret);
+
readlen -= len;
if (!readlen)
break;
@@ -2402,7 +2405,7 @@
if (mtd->ecc_stats.failed - stats.failed)
return -EBADMSG;
- return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+ return max_bitflips;
}
/**
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index f9b2a77..e26c4f8 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1835,8 +1835,14 @@
/* Add ECC info retrieval from DT */
for (i = 0; i < ARRAY_SIZE(strengths); i++) {
- if (ecc->strength <= strengths[i])
+ if (ecc->strength <= strengths[i]) {
+ /*
+ * Update ecc->strength value with the actual strength
+ * that will be used by the ECC engine.
+ */
+ ecc->strength = strengths[i];
break;
+ }
}
if (i >= ARRAY_SIZE(strengths)) {
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
index 3ad514c..ddc629e 100644
--- a/drivers/mtd/nand/vf610_nfc.c
+++ b/drivers/mtd/nand/vf610_nfc.c
@@ -752,10 +752,8 @@
if (mtd->oobsize > 64)
mtd->oobsize = 64;
- /*
- * mtd->ecclayout is not specified here because we're using the
- * default large page ECC layout defined in NAND core.
- */
+ /* Use default large page ECC layout defined in NAND core */
+ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
if (chip->ecc.strength == 32) {
nfc->ecc_mode = ECC_60_BYTE;
chip->ecc.bytes = 60;
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index d1e6931..46913ef2 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -99,6 +99,8 @@
/* Linked list of all ubiblock instances */
static LIST_HEAD(ubiblock_devices);
+static DEFINE_IDR(ubiblock_minor_idr);
+/* Protects ubiblock_devices and ubiblock_minor_idr */
static DEFINE_MUTEX(devices_mutex);
static int ubiblock_major;
@@ -353,8 +355,6 @@
.init_request = ubiblock_init_request,
};
-static DEFINE_IDR(ubiblock_minor_idr);
-
int ubiblock_create(struct ubi_volume_info *vi)
{
struct ubiblock *dev;
@@ -367,14 +367,15 @@
/* Check that the volume isn't already handled */
mutex_lock(&devices_mutex);
if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
- mutex_unlock(&devices_mutex);
- return -EEXIST;
+ ret = -EEXIST;
+ goto out_unlock;
}
- mutex_unlock(&devices_mutex);
dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
+ if (!dev) {
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
mutex_init(&dev->dev_mutex);
@@ -439,14 +440,13 @@
goto out_free_queue;
}
- mutex_lock(&devices_mutex);
list_add_tail(&dev->list, &ubiblock_devices);
- mutex_unlock(&devices_mutex);
/* Must be the last step: anyone can call file ops from now on */
add_disk(dev->gd);
dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
dev->ubi_num, dev->vol_id, vi->name);
+ mutex_unlock(&devices_mutex);
return 0;
out_free_queue:
@@ -459,6 +459,8 @@
put_disk(dev->gd);
out_free_dev:
kfree(dev);
+out_unlock:
+ mutex_unlock(&devices_mutex);
return ret;
}
@@ -480,30 +482,36 @@
int ubiblock_remove(struct ubi_volume_info *vi)
{
struct ubiblock *dev;
+ int ret;
mutex_lock(&devices_mutex);
dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
if (!dev) {
- mutex_unlock(&devices_mutex);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_unlock;
}
/* Found a device, let's lock it so we can check if it's busy */
mutex_lock(&dev->dev_mutex);
if (dev->refcnt > 0) {
- mutex_unlock(&dev->dev_mutex);
- mutex_unlock(&devices_mutex);
- return -EBUSY;
+ ret = -EBUSY;
+ goto out_unlock_dev;
}
/* Remove from device list */
list_del(&dev->list);
- mutex_unlock(&devices_mutex);
-
ubiblock_cleanup(dev);
mutex_unlock(&dev->dev_mutex);
+ mutex_unlock(&devices_mutex);
+
kfree(dev);
return 0;
+
+out_unlock_dev:
+ mutex_unlock(&dev->dev_mutex);
+out_unlock:
+ mutex_unlock(&devices_mutex);
+ return ret;
}
static int ubiblock_resize(struct ubi_volume_info *vi)
@@ -632,6 +640,7 @@
struct ubiblock *next;
struct ubiblock *dev;
+ mutex_lock(&devices_mutex);
list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
/* The module is being forcefully removed */
WARN_ON(dev->desc);
@@ -640,6 +649,7 @@
ubiblock_cleanup(dev);
kfree(dev);
}
+ mutex_unlock(&devices_mutex);
}
int __init ubiblock_init(void)
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index b5b8cd6..668b462 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1529,6 +1529,46 @@
}
/**
+ * erase_aeb - erase a PEB given in UBI attach info PEB
+ * @ubi: UBI device description object
+ * @aeb: UBI attach info PEB
+ * @sync: If true, erase synchronously. Otherwise schedule for erasure
+ */
+static int erase_aeb(struct ubi_device *ubi, struct ubi_ainf_peb *aeb, bool sync)
+{
+ struct ubi_wl_entry *e;
+ int err;
+
+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
+ if (!e)
+ return -ENOMEM;
+
+ e->pnum = aeb->pnum;
+ e->ec = aeb->ec;
+ ubi->lookuptbl[e->pnum] = e;
+
+ if (sync) {
+ err = sync_erase(ubi, e, false);
+ if (err)
+ goto out_free;
+
+ wl_tree_add(e, &ubi->free);
+ ubi->free_count++;
+ } else {
+ err = schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false);
+ if (err)
+ goto out_free;
+ }
+
+ return 0;
+
+out_free:
+ wl_entry_destroy(ubi, e);
+
+ return err;
+}
+
+/**
* ubi_wl_init - initialize the WL sub-system using attaching information.
* @ubi: UBI device description object
* @ai: attaching information
@@ -1566,18 +1606,10 @@
list_for_each_entry_safe(aeb, tmp, &ai->erase, u.list) {
cond_resched();
- e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
- if (!e)
+ err = erase_aeb(ubi, aeb, false);
+ if (err)
goto out_free;
- e->pnum = aeb->pnum;
- e->ec = aeb->ec;
- ubi->lookuptbl[e->pnum] = e;
- if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false)) {
- wl_entry_destroy(ubi, e);
- goto out_free;
- }
-
found_pebs++;
}
@@ -1635,6 +1667,8 @@
ubi_assert(!ubi->lookuptbl[e->pnum]);
ubi->lookuptbl[e->pnum] = e;
} else {
+ bool sync = false;
+
/*
* Usually old Fastmap PEBs are scheduled for erasure
* and we don't have to care about them but if we face
@@ -1644,18 +1678,21 @@
if (ubi->lookuptbl[aeb->pnum])
continue;
- e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
- if (!e)
- goto out_free;
+ /*
+ * The fastmap update code might not find a free PEB for
+ * writing the fastmap anchor to and then reuses the
+ * current fastmap anchor PEB. When this PEB gets erased
+ * and a power cut happens before it is written again we
+ * must make sure that the fastmap attach code doesn't
+ * find any outdated fastmap anchors, hence we erase the
+ * outdated fastmap anchor PEBs synchronously here.
+ */
+ if (aeb->vol_id == UBI_FM_SB_VOLUME_ID)
+ sync = true;
- e->pnum = aeb->pnum;
- e->ec = aeb->ec;
- ubi_assert(!ubi->lookuptbl[e->pnum]);
- ubi->lookuptbl[e->pnum] = e;
- if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false)) {
- wl_entry_destroy(ubi, e);
+ err = erase_aeb(ubi, aeb, sync);
+ if (err)
goto out_free;
- }
}
found_pebs++;
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index a09d3d4..c3ca98f 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -447,6 +447,9 @@
config VMXNET3
tristate "VMware VMXNET3 ethernet driver"
depends on PCI && INET
+ depends on !(PAGE_SIZE_64KB || ARM64_64K_PAGES || \
+ IA64_PAGE_SIZE_64KB || MICROBLAZE_64K_PAGES || \
+ PARISC_PAGE_SIZE_64KB || PPC_64K_PAGES)
help
This driver supports VMware's vmxnet3 virtual ethernet NIC.
To compile this driver as a module, choose M here: the
diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c
index e278e3d..c616387 100644
--- a/drivers/net/ethernet/arc/emac_rockchip.c
+++ b/drivers/net/ethernet/arc/emac_rockchip.c
@@ -220,9 +220,11 @@
/* RMII TX/RX needs always a rate of 25MHz */
err = clk_set_rate(priv->macclk, 25000000);
- if (err)
+ if (err) {
dev_err(dev,
"failed to change mac clock rate (%d)\n", err);
+ goto out_clk_disable_macclk;
+ }
}
err = arc_emac_probe(ndev, interface);
@@ -232,7 +234,8 @@
}
return 0;
-
+out_clk_disable_macclk:
+ clk_disable_unprepare(priv->macclk);
out_regulator_disable:
if (priv->regulator)
regulator_disable(priv->regulator);
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index fd20688..e3b41ba 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -1375,9 +1375,11 @@
gfar_init_addr_hash_table(priv);
- /* Insert receive time stamps into padding alignment bytes */
+ /* Insert receive time stamps into padding alignment bytes, and
+ * plus 2 bytes padding to ensure the cpu alignment.
+ */
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
- priv->padding = 8;
+ priv->padding = 8 + DEFAULT_PADDING;
if (dev->features & NETIF_F_IP_CSUM ||
priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
@@ -1787,6 +1789,7 @@
GFAR_SUPPORTED_GBIT : 0;
phy_interface_t interface;
struct phy_device *phydev;
+ struct ethtool_eee edata;
priv->oldlink = 0;
priv->oldspeed = 0;
@@ -1811,6 +1814,10 @@
/* Add support for flow control, but don't advertise it by default */
phydev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+ /* disable EEE autoneg, EEE not supported by eTSEC */
+ memset(&edata, 0, sizeof(struct ethtool_eee));
+ phy_ethtool_set_eee(phydev, &edata);
+
return 0;
}
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index ed6fae9..7e2ebfc 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -5657,6 +5657,7 @@
int id = port->id;
bool allmulti = dev->flags & IFF_ALLMULTI;
+retry:
mvpp2_prs_mac_promisc_set(priv, id, dev->flags & IFF_PROMISC);
mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_ALL, allmulti);
mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_IP6, allmulti);
@@ -5664,9 +5665,13 @@
/* Remove all port->id's mcast enries */
mvpp2_prs_mcast_del_all(priv, id);
- if (allmulti && !netdev_mc_empty(dev)) {
- netdev_for_each_mc_addr(ha, dev)
- mvpp2_prs_mac_da_accept(priv, id, ha->addr, true);
+ if (!allmulti) {
+ netdev_for_each_mc_addr(ha, dev) {
+ if (mvpp2_prs_mac_da_accept(priv, id, ha->addr, true)) {
+ allmulti = true;
+ goto retry;
+ }
+ }
}
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c
index d1cd9c3..6143113 100644
--- a/drivers/net/ethernet/mellanox/mlx4/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx4/qp.c
@@ -286,6 +286,9 @@
u64 in_param = 0;
int err;
+ if (!cnt)
+ return;
+
if (mlx4_is_mfunc(dev)) {
set_param_l(&in_param, base_qpn);
set_param_h(&in_param, cnt);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index bdbcd2b..c3c28f0 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -3849,7 +3849,7 @@
struct list_head *head = &mbx->cmd_q;
struct qlcnic_cmd_args *cmd = NULL;
- spin_lock(&mbx->queue_lock);
+ spin_lock_bh(&mbx->queue_lock);
while (!list_empty(head)) {
cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
@@ -3860,7 +3860,7 @@
qlcnic_83xx_notify_cmd_completion(adapter, cmd);
}
- spin_unlock(&mbx->queue_lock);
+ spin_unlock_bh(&mbx->queue_lock);
}
static int qlcnic_83xx_check_mbx_status(struct qlcnic_adapter *adapter)
@@ -3896,12 +3896,12 @@
{
struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
- spin_lock(&mbx->queue_lock);
+ spin_lock_bh(&mbx->queue_lock);
list_del(&cmd->list);
mbx->num_cmds--;
- spin_unlock(&mbx->queue_lock);
+ spin_unlock_bh(&mbx->queue_lock);
qlcnic_83xx_notify_cmd_completion(adapter, cmd);
}
@@ -3966,7 +3966,7 @@
init_completion(&cmd->completion);
cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_UNKNOWN;
- spin_lock(&mbx->queue_lock);
+ spin_lock_bh(&mbx->queue_lock);
list_add_tail(&cmd->list, &mbx->cmd_q);
mbx->num_cmds++;
@@ -3974,7 +3974,7 @@
*timeout = cmd->total_cmds * QLC_83XX_MBX_TIMEOUT;
queue_work(mbx->work_q, &mbx->work);
- spin_unlock(&mbx->queue_lock);
+ spin_unlock_bh(&mbx->queue_lock);
return 0;
}
@@ -4070,15 +4070,15 @@
mbx->rsp_status = QLC_83XX_MBX_RESPONSE_WAIT;
spin_unlock_irqrestore(&mbx->aen_lock, flags);
- spin_lock(&mbx->queue_lock);
+ spin_lock_bh(&mbx->queue_lock);
if (list_empty(head)) {
- spin_unlock(&mbx->queue_lock);
+ spin_unlock_bh(&mbx->queue_lock);
return;
}
cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
- spin_unlock(&mbx->queue_lock);
+ spin_unlock_bh(&mbx->queue_lock);
mbx_ops->encode_cmd(adapter, cmd);
mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_REQUEST);
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 298b74e..18e68c9 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -1387,7 +1387,7 @@
{
void __iomem *ioaddr = tp->mmio_addr;
- return RTL_R8(IBISR0) & 0x02;
+ return RTL_R8(IBISR0) & 0x20;
}
static void rtl8168ep_stop_cmac(struct rtl8169_private *tp)
@@ -1395,7 +1395,7 @@
void __iomem *ioaddr = tp->mmio_addr;
RTL_W8(IBCR2, RTL_R8(IBCR2) & ~0x01);
- rtl_msleep_loop_wait_low(tp, &rtl_ocp_tx_cond, 50, 2000);
+ rtl_msleep_loop_wait_high(tp, &rtl_ocp_tx_cond, 50, 2000);
RTL_W8(IBISR0, RTL_R8(IBISR0) | 0x20);
RTL_W8(IBCR0, RTL_R8(IBCR0) & ~0x01);
}
diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c
index 95c0b45..313e006 100644
--- a/drivers/net/hippi/rrunner.c
+++ b/drivers/net/hippi/rrunner.c
@@ -1381,8 +1381,8 @@
rrpriv->info_dma);
rrpriv->info = NULL;
- free_irq(pdev->irq, dev);
spin_unlock_irqrestore(&rrpriv->lock, flags);
+ free_irq(pdev->irq, dev);
return 0;
}
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c
index 980e385..627eb82 100644
--- a/drivers/net/ipvlan/ipvlan_core.c
+++ b/drivers/net/ipvlan/ipvlan_core.c
@@ -370,6 +370,7 @@
.flowi4_oif = dev->ifindex,
.flowi4_tos = RT_TOS(ip4h->tos),
.flowi4_flags = FLOWI_FLAG_ANYSRC,
+ .flowi4_mark = skb->mark,
.daddr = ip4h->daddr,
.saddr = ip4h->saddr,
};
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index db65d9a..e1e5e84 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -944,6 +944,7 @@
{QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */
{QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)}, /* Quectel EC21 Mini PCIe */
{QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */
+ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0306, 4)}, /* Quectel EP06 Mini PCIe */
/* 4. Gobi 1000 devices */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 91d29f5..f7c63cf 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -39,6 +39,9 @@
.max_power = 40, \
}
+#define WIL_BRP_ANT_LIMIT_MIN (1)
+#define WIL_BRP_ANT_LIMIT_MAX (27)
+
static struct ieee80211_channel wil_60ghz_channels[] = {
CHAN60G(1, 0),
CHAN60G(2, 0),
@@ -52,6 +55,49 @@
};
#endif
+enum wil_nl_60g_cmd_type {
+ NL_60G_CMD_FW_WMI,
+ NL_60G_CMD_DEBUG,
+ NL_60G_CMD_STATISTICS,
+ NL_60G_CMD_REGISTER,
+};
+
+enum wil_nl_60g_evt_type {
+ NL_60G_EVT_DRIVER_ERROR,
+ NL_60G_EVT_FW_ERROR,
+ NL_60G_EVT_FW_WMI,
+ NL_60G_EVT_DRIVER_SHUTOWN,
+ NL_60G_EVT_DRIVER_DEBUG_EVENT,
+};
+
+enum wil_nl_60g_debug_cmd {
+ NL_60G_DBG_FORCE_WMI_SEND,
+};
+
+struct wil_nl_60g_send_receive_wmi {
+ u32 cmd_id; /* enum wmi_command_id or enum wmi_event_id */
+ u8 reserved[2];
+ u8 dev_id; /* mid */
+ u16 buf_len;
+ u8 buf[0];
+} __packed;
+
+struct wil_nl_60g_event {
+ u32 evt_type; /* wil_nl_60g_evt_type */
+ u32 buf_len;
+ u8 reserved[9];
+ u8 buf[0];
+} __packed;
+
+struct wil_nl_60g_debug { /* NL_60G_CMD_DEBUG */
+ u32 cmd_id; /* wil_nl_60g_debug_cmd */
+} __packed;
+
+struct wil_nl_60g_debug_force_wmi {
+ struct wil_nl_60g_debug hdr;
+ u32 enable;
+} __packed;
+
/* 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,
@@ -65,17 +111,24 @@
#define WIL_MAX_RF_SECTORS (128)
#define WIL_CID_ALL (0xff)
-enum qca_wlan_vendor_attr_rf_sector {
+enum qca_wlan_vendor_attr_wil {
QCA_ATTR_MAC_ADDR = 6,
+ QCA_ATTR_FEATURE_FLAGS = 7,
+ QCA_ATTR_TEST = 8,
QCA_ATTR_PAD = 13,
QCA_ATTR_TSF = 29,
QCA_ATTR_DMG_RF_SECTOR_INDEX = 30,
QCA_ATTR_DMG_RF_SECTOR_TYPE = 31,
QCA_ATTR_DMG_RF_MODULE_MASK = 32,
QCA_ATTR_DMG_RF_SECTOR_CFG = 33,
- QCA_ATTR_DMG_RF_SECTOR_MAX,
+ QCA_ATTR_BRP_ANT_LIMIT_MODE = 38,
+ QCA_ATTR_BRP_ANT_NUM_LIMIT = 39,
+ QCA_ATTR_WIL_MAX,
};
+#define WIL_ATTR_60G_CMD_TYPE QCA_ATTR_FEATURE_FLAGS
+#define WIL_ATTR_60G_BUF QCA_ATTR_TEST
+
enum qca_wlan_vendor_attr_dmg_rf_sector_type {
QCA_ATTR_DMG_RF_SECTOR_TYPE_RX,
QCA_ATTR_DMG_RF_SECTOR_TYPE_TX,
@@ -98,8 +151,22 @@
QCA_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST - 1
};
+enum qca_wlan_vendor_attr_brp_ant_limit_mode {
+ QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_DISABLE,
+ QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_EFFECTIVE,
+ QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_FORCE,
+ QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODES_NUM
+};
+
static const struct
-nla_policy wil_rf_sector_policy[QCA_ATTR_DMG_RF_SECTOR_MAX + 1] = {
+nla_policy wil_brp_ant_limit_policy[QCA_ATTR_WIL_MAX + 1] = {
+ [QCA_ATTR_MAC_ADDR] = { .len = ETH_ALEN },
+ [QCA_ATTR_BRP_ANT_NUM_LIMIT] = { .type = NLA_U8 },
+ [QCA_ATTR_BRP_ANT_LIMIT_MODE] = { .type = NLA_U8 },
+};
+
+static const struct
+nla_policy wil_rf_sector_policy[QCA_ATTR_WIL_MAX + 1] = {
[QCA_ATTR_MAC_ADDR] = { .len = ETH_ALEN },
[QCA_ATTR_DMG_RF_SECTOR_INDEX] = { .type = NLA_U16 },
[QCA_ATTR_DMG_RF_SECTOR_TYPE] = { .type = NLA_U8 },
@@ -118,7 +185,14 @@
[QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16] = { .type = NLA_U32 },
};
+static const struct
+nla_policy wil_nl_60g_policy[QCA_ATTR_WIL_MAX + 1] = {
+ [WIL_ATTR_60G_CMD_TYPE] = { .type = NLA_U32 },
+ [WIL_ATTR_60G_BUF] = { .type = NLA_BINARY },
+};
+
enum qca_nl80211_vendor_subcmds {
+ QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA = 128,
QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION = 129,
QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION = 130,
@@ -132,6 +206,7 @@
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG = 140,
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR = 141,
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR = 142,
+ QCA_NL80211_VENDOR_SUBCMD_BRP_SET_ANT_LIMIT = 153,
};
static int wil_rf_sector_get_cfg(struct wiphy *wiphy,
@@ -146,7 +221,11 @@
static int wil_rf_sector_set_selected(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data, int data_len);
+static int wil_brp_set_ant_limit(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+static int wil_nl_60g_handle_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
/* vendor specific commands */
static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
{
@@ -221,6 +300,20 @@
WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = wil_rf_sector_set_selected
},
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_BRP_SET_ANT_LIMIT,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wil_brp_set_ant_limit
+ },
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_UNSPEC,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wil_nl_60g_handle_cmd
+ },
};
/* vendor specific events */
@@ -237,6 +330,10 @@
.vendor_id = QCA_NL80211_VENDOR_ID,
.subcmd = QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT
},
+ [QCA_NL80211_VENDOR_EVENT_UNSPEC_INDEX] = {
+ .vendor_id = QCA_NL80211_VENDOR_ID,
+ .subcmd = QCA_NL80211_VENDOR_SUBCMD_UNSPEC
+ },
};
static struct ieee80211_supported_band wil_band_60ghz = {
@@ -2052,7 +2149,7 @@
{
struct wil6210_priv *wil = wdev_to_wil(wdev);
int rc;
- struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
+ struct nlattr *tb[QCA_ATTR_WIL_MAX + 1];
u16 sector_index;
u8 sector_type;
u32 rf_modules_vec;
@@ -2069,7 +2166,7 @@
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
return -EOPNOTSUPP;
- rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
+ rc = nla_parse(tb, QCA_ATTR_WIL_MAX, data, data_len,
wil_rf_sector_policy);
if (rc) {
wil_err(wil, "Invalid rf sector ATTR\n");
@@ -2171,7 +2268,7 @@
{
struct wil6210_priv *wil = wdev_to_wil(wdev);
int rc, tmp;
- struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
+ struct nlattr *tb[QCA_ATTR_WIL_MAX + 1];
struct nlattr *tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1];
u16 sector_index, rf_module_index;
u8 sector_type;
@@ -2187,7 +2284,7 @@
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
return -EOPNOTSUPP;
- rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
+ rc = nla_parse(tb, QCA_ATTR_WIL_MAX, data, data_len,
wil_rf_sector_policy);
if (rc) {
wil_err(wil, "Invalid rf sector ATTR\n");
@@ -2278,7 +2375,7 @@
{
struct wil6210_priv *wil = wdev_to_wil(wdev);
int rc;
- struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
+ struct nlattr *tb[QCA_ATTR_WIL_MAX + 1];
u8 sector_type, mac_addr[ETH_ALEN];
int cid = 0;
struct wmi_get_selected_rf_sector_index_cmd cmd;
@@ -2291,7 +2388,7 @@
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
return -EOPNOTSUPP;
- rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
+ rc = nla_parse(tb, QCA_ATTR_WIL_MAX, data, data_len,
wil_rf_sector_policy);
if (rc) {
wil_err(wil, "Invalid rf sector ATTR\n");
@@ -2390,7 +2487,7 @@
{
struct wil6210_priv *wil = wdev_to_wil(wdev);
int rc;
- struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
+ struct nlattr *tb[QCA_ATTR_WIL_MAX + 1];
u16 sector_index;
u8 sector_type, mac_addr[ETH_ALEN], i;
int cid = 0;
@@ -2398,7 +2495,7 @@
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
return -EOPNOTSUPP;
- rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
+ rc = nla_parse(tb, QCA_ATTR_WIL_MAX, data, data_len,
wil_rf_sector_policy);
if (rc) {
wil_err(wil, "Invalid rf sector ATTR\n");
@@ -2477,3 +2574,259 @@
return rc;
}
+
+static int
+wil_brp_wmi_set_ant_limit(struct wil6210_priv *wil, u8 cid, u8 limit_mode,
+ u8 antenna_num_limit)
+{
+ int rc;
+ struct wmi_brp_set_ant_limit_cmd cmd = {
+ .cid = cid,
+ .limit_mode = limit_mode,
+ .ant_limit = antenna_num_limit,
+ };
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_brp_set_ant_limit_event evt;
+ } __packed reply;
+
+ reply.evt.status = WMI_FW_STATUS_FAILURE;
+
+ rc = wmi_call(wil, WMI_BRP_SET_ANT_LIMIT_CMDID, &cmd, sizeof(cmd),
+ WMI_BRP_SET_ANT_LIMIT_EVENTID, &reply,
+ sizeof(reply), 250);
+ if (rc)
+ return rc;
+
+ if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
+ wil_err(wil, "brp set antenna limit failed with status %d\n",
+ reply.evt.status);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static int wil_brp_set_ant_limit(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct wil6210_priv *wil = wdev_to_wil(wdev);
+ struct nlattr *tb[QCA_ATTR_WIL_MAX + 1];
+ u8 mac_addr[ETH_ALEN];
+ u8 antenna_num_limit = 0;
+ u8 limit_mode;
+ int cid = 0;
+ int rc;
+
+ if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
+ return -ENOTSUPP;
+
+ rc = nla_parse(tb, QCA_ATTR_WIL_MAX, data, data_len,
+ wil_brp_ant_limit_policy);
+ if (rc) {
+ wil_err(wil, "Invalid ant limit ATTR\n");
+ return rc;
+ }
+
+ if (!tb[QCA_ATTR_BRP_ANT_LIMIT_MODE] || !tb[QCA_ATTR_MAC_ADDR]) {
+ wil_err(wil, "Invalid antenna limit spec\n");
+ return -EINVAL;
+ }
+
+ limit_mode = nla_get_u8(tb[QCA_ATTR_BRP_ANT_LIMIT_MODE]);
+ if (limit_mode >= QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODES_NUM) {
+ wil_err(wil, "Invalid limit mode %d\n", limit_mode);
+ return -EINVAL;
+ }
+
+ if (limit_mode != QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_DISABLE) {
+ if (!tb[QCA_ATTR_BRP_ANT_NUM_LIMIT]) {
+ wil_err(wil, "Invalid limit number\n");
+ return -EINVAL;
+ }
+
+ antenna_num_limit = nla_get_u8(tb[QCA_ATTR_BRP_ANT_NUM_LIMIT]);
+ if (antenna_num_limit > WIL_BRP_ANT_LIMIT_MAX ||
+ antenna_num_limit < WIL_BRP_ANT_LIMIT_MIN) {
+ wil_err(wil, "Invalid number of antenna limit: %d\n",
+ antenna_num_limit);
+ return -EINVAL;
+ }
+ }
+
+ ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR]));
+ cid = wil_find_cid(wil, mac_addr);
+ if (cid < 0) {
+ wil_err(wil, "invalid MAC address %pM\n", mac_addr);
+ return -ENOENT;
+ }
+
+ return wil_brp_wmi_set_ant_limit(wil, cid, limit_mode,
+ antenna_num_limit);
+}
+
+static int wil_nl_60g_handle_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct wil6210_priv *wil = wdev_to_wil(wdev);
+ struct nlattr *tb[QCA_ATTR_WIL_MAX + 1];
+ struct wil_nl_60g_send_receive_wmi *cmd;
+ struct wil_nl_60g_debug_force_wmi debug_force_wmi;
+ int rc, len;
+ u32 wil_nl_60g_cmd_type, publish;
+
+ rc = nla_parse(tb, QCA_ATTR_WIL_MAX, data, data_len,
+ wil_nl_60g_policy);
+ if (rc) {
+ wil_err(wil, "Invalid nl_60g_cmd ATTR\n");
+ return rc;
+ }
+
+ if (!tb[WIL_ATTR_60G_CMD_TYPE]) {
+ wil_err(wil, "Invalid nl_60g_cmd type\n");
+ return -EINVAL;
+ }
+
+ wil_nl_60g_cmd_type = nla_get_u32(tb[WIL_ATTR_60G_CMD_TYPE]);
+
+ switch (wil_nl_60g_cmd_type) {
+ case NL_60G_CMD_REGISTER:
+ if (!tb[WIL_ATTR_60G_BUF]) {
+ wil_err(wil, "Invalid nl_60g_cmd spec\n");
+ return -EINVAL;
+ }
+
+ len = nla_len(tb[WIL_ATTR_60G_BUF]);
+ if (len != sizeof(publish)) {
+ wil_err(wil, "cmd buffer wrong len %d\n", len);
+ return -EINVAL;
+ }
+ memcpy(&publish, nla_data(tb[WIL_ATTR_60G_BUF]), len);
+ wil->publish_nl_evt = publish;
+
+ wil_dbg_wmi(wil, "Publish wmi event %s\n",
+ publish ? "enabled" : "disabled");
+ break;
+ case NL_60G_CMD_DEBUG:
+ if (!tb[WIL_ATTR_60G_BUF]) {
+ wil_err(wil, "Invalid nl_60g_cmd spec\n");
+ return -EINVAL;
+ }
+
+ len = nla_len(tb[WIL_ATTR_60G_BUF]);
+ if (len < sizeof(struct wil_nl_60g_debug)) {
+ wil_err(wil, "cmd buffer too short %d\n", len);
+ return -EINVAL;
+ }
+
+ memcpy(&debug_force_wmi, nla_data(tb[WIL_ATTR_60G_BUF]),
+ sizeof(struct wil_nl_60g_debug));
+
+ switch (debug_force_wmi.hdr.cmd_id) {
+ case NL_60G_DBG_FORCE_WMI_SEND:
+ if (len != sizeof(debug_force_wmi)) {
+ wil_err(wil, "cmd buffer wrong len %d\n", len);
+ return -EINVAL;
+ }
+
+ memcpy(&debug_force_wmi, nla_data(tb[WIL_ATTR_60G_BUF]),
+ sizeof(debug_force_wmi));
+ wil->force_wmi_send = debug_force_wmi.enable;
+
+ wil_dbg_wmi(wil, "force sending wmi commands %d\n",
+ wil->force_wmi_send);
+ break;
+ default:
+ rc = -EINVAL;
+ wil_err(wil, "invalid debug_cmd id %d",
+ debug_force_wmi.hdr.cmd_id);
+ }
+ break;
+ case NL_60G_CMD_FW_WMI:
+ if (!tb[WIL_ATTR_60G_BUF]) {
+ wil_err(wil, "Invalid nl_60g_cmd spec\n");
+ return -EINVAL;
+ }
+
+ len = nla_len(tb[WIL_ATTR_60G_BUF]);
+ if (len < offsetof(struct wil_nl_60g_send_receive_wmi, buf)) {
+ wil_err(wil, "wmi cmd buffer too small\n");
+ return -EINVAL;
+ }
+
+ cmd = kmalloc(len, GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ memcpy(cmd, nla_data(tb[WIL_ATTR_60G_BUF]), (unsigned int)len);
+
+ wil_dbg_wmi(wil, "sending user-space command (0x%04x) [%d]\n",
+ cmd->cmd_id, cmd->buf_len);
+
+ if (wil->force_wmi_send)
+ rc = wmi_force_send(wil, cmd->cmd_id, cmd->buf,
+ cmd->buf_len);
+ else
+ rc = wmi_send(wil, cmd->cmd_id, cmd->buf, cmd->buf_len);
+
+ kfree(cmd);
+ break;
+ default:
+ rc = -EINVAL;
+ wil_err(wil, "invalid nl_60g_cmd type %d", wil_nl_60g_cmd_type);
+ }
+
+ return rc;
+}
+
+void wil_nl_60g_receive_wmi_evt(struct wil6210_priv *wil, u8 *cmd, int len)
+{
+ struct sk_buff *vendor_event = NULL;
+ struct wil_nl_60g_event *evt;
+ struct wil_nl_60g_send_receive_wmi *wmi_buf;
+ struct wmi_cmd_hdr *wmi_hdr = (struct wmi_cmd_hdr *)cmd;
+ int data_len;
+
+ if (!wil->publish_nl_evt)
+ return;
+
+ wil_dbg_wmi(wil, "report wmi event to user-space (0x%04x) [%d]\n",
+ le16_to_cpu(wmi_hdr->command_id), len);
+
+ data_len = len - sizeof(struct wmi_cmd_hdr);
+
+ evt = kzalloc(sizeof(*evt) + sizeof(*wmi_buf) + data_len, GFP_KERNEL);
+ if (!evt)
+ return;
+
+ evt->evt_type = NL_60G_EVT_FW_WMI;
+ evt->buf_len = sizeof(*wmi_buf) + data_len;
+
+ wmi_buf = (struct wil_nl_60g_send_receive_wmi *)evt->buf;
+
+ wmi_buf->cmd_id = le16_to_cpu(wmi_hdr->command_id);
+ wmi_buf->dev_id = wmi_hdr->mid;
+ wmi_buf->buf_len = data_len;
+ memcpy(wmi_buf->buf, cmd + sizeof(struct wmi_cmd_hdr), data_len);
+
+ vendor_event = cfg80211_vendor_event_alloc(
+ wil_to_wiphy(wil),
+ NULL,
+ data_len + 4 + NLMSG_HDRLEN +
+ sizeof(*evt) + sizeof(*wmi_buf),
+ QCA_NL80211_VENDOR_EVENT_UNSPEC_INDEX,
+ GFP_KERNEL);
+ if (!vendor_event)
+ goto out;
+
+ if (nla_put(vendor_event, WIL_ATTR_60G_BUF,
+ sizeof(*evt) + sizeof(*wmi_buf) + data_len, evt)) {
+ wil_err(wil, "failed to fill WIL_ATTR_60G_BUF\n");
+ goto out;
+ }
+
+ cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+
+out:
+ kfree(evt);
+}
diff --git a/drivers/net/wireless/ath/wil6210/ftm.h b/drivers/net/wireless/ath/wil6210/ftm.h
index 21923c2..e9efad7 100644
--- a/drivers/net/wireless/ath/wil6210/ftm.h
+++ b/drivers/net/wireless/ath/wil6210/ftm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -417,6 +417,7 @@
QCA_NL80211_VENDOR_EVENT_FTM_MEAS_RESULT_INDEX,
QCA_NL80211_VENDOR_EVENT_FTM_SESSION_DONE_INDEX,
QCA_NL80211_VENDOR_EVENT_AOA_MEAS_RESULT_INDEX,
+ QCA_NL80211_VENDOR_EVENT_UNSPEC_INDEX,
};
/* measurement parameters. Specified for each peer as part
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 9cef0f0..2baa6cf 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1228,6 +1228,8 @@
wmi_event_flush(wil);
+ wil->force_wmi_send = false;
+
flush_workqueue(wil->wq_service);
flush_workqueue(wil->wmi_wq);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 62d1d07..dcec343 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -636,8 +636,8 @@
v->swtail = next_tail) {
rc = wil_vring_alloc_skb(wil, v, v->swtail, headroom);
if (unlikely(rc)) {
- wil_err(wil, "Error %d in wil_rx_refill[%d]\n",
- rc, v->swtail);
+ wil_err_ratelimited(wil, "Error %d in rx refill[%d]\n",
+ rc, v->swtail);
break;
}
}
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 2f6d6c9..9b68663 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -811,6 +811,9 @@
u32 rgf_fw_assert_code_addr;
u32 rgf_ucode_assert_code_addr;
u32 iccm_base;
+
+ bool publish_nl_evt; /* deliver WMI events to user space */
+ bool force_wmi_send; /* allow WMI command while FW in sysassert */
};
#define wil_to_wiphy(i) (i->wdev->wiphy)
@@ -943,6 +946,7 @@
int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
struct wil6210_mbox_hdr *hdr);
int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len);
+int wmi_force_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len);
void wmi_recv_cmd(struct wil6210_priv *wil);
int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
u16 reply_id, void *reply, u8 reply_size, int to_msec);
@@ -1114,6 +1118,7 @@
void wil_aoa_evt_meas(struct wil6210_priv *wil,
struct wmi_aoa_meas_event *evt,
int len);
+void wil_nl_60g_receive_wmi_evt(struct wil6210_priv *wil, u8 *cmd, int len);
/* link loss */
int wmi_link_maintain_cfg_write(struct wil6210_priv *wil,
const u8 *addr,
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index f2dba31..5510132 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -517,7 +517,8 @@
}
}
-static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
+static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
+ bool force_send)
{
struct {
struct wil6210_mbox_hdr hdr;
@@ -549,7 +550,7 @@
might_sleep();
- if (!test_bit(wil_status_fwready, wil->status)) {
+ if (!test_bit(wil_status_fwready, wil->status) && !force_send) {
wil_err(wil, "WMI: cannot send command while FW not ready\n");
return -EAGAIN;
}
@@ -588,7 +589,7 @@
wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
/* wait till FW finish with previous command */
for (retry = 5; retry > 0; retry--) {
- if (!test_bit(wil_status_fwready, wil->status)) {
+ if (!test_bit(wil_status_fwready, wil->status) && !force_send) {
wil_err(wil, "WMI: cannot send command while FW not ready\n");
rc = -EAGAIN;
goto out;
@@ -643,7 +644,18 @@
int rc;
mutex_lock(&wil->wmi_mutex);
- rc = __wmi_send(wil, cmdid, buf, len);
+ rc = __wmi_send(wil, cmdid, buf, len, false);
+ mutex_unlock(&wil->wmi_mutex);
+
+ return rc;
+}
+
+int wmi_force_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
+{
+ int rc;
+
+ mutex_lock(&wil->wmi_mutex);
+ rc = __wmi_send(wil, cmdid, buf, len, true);
mutex_unlock(&wil->wmi_mutex);
return rc;
@@ -1363,6 +1375,7 @@
struct wmi_cmd_hdr *wmi = &evt->event.wmi;
u16 id = le16_to_cpu(wmi->command_id);
u32 tstamp = le32_to_cpu(wmi->fw_timestamp);
+ wil_nl_60g_receive_wmi_evt(wil, cmd, len);
if (test_bit(wil_status_resuming, wil->status)) {
if (id == WMI_TRAFFIC_RESUME_EVENTID)
clear_bit(wil_status_resuming,
@@ -1436,7 +1449,7 @@
reinit_completion(&wil->wmi_call);
spin_unlock(&wil->wmi_ev_lock);
- rc = __wmi_send(wil, cmdid, buf, len);
+ rc = __wmi_send(wil, cmdid, buf, len, false);
if (rc)
goto out;
diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c
index 6e5d909..a635fc6 100644
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -71,8 +71,18 @@
MODULE_FIRMWARE("b43/ucode13.fw");
MODULE_FIRMWARE("b43/ucode14.fw");
MODULE_FIRMWARE("b43/ucode15.fw");
+MODULE_FIRMWARE("b43/ucode16_lp.fw");
MODULE_FIRMWARE("b43/ucode16_mimo.fw");
+MODULE_FIRMWARE("b43/ucode24_lcn.fw");
+MODULE_FIRMWARE("b43/ucode25_lcn.fw");
+MODULE_FIRMWARE("b43/ucode25_mimo.fw");
+MODULE_FIRMWARE("b43/ucode26_mimo.fw");
+MODULE_FIRMWARE("b43/ucode29_mimo.fw");
+MODULE_FIRMWARE("b43/ucode33_lcn40.fw");
+MODULE_FIRMWARE("b43/ucode30_mimo.fw");
MODULE_FIRMWARE("b43/ucode5.fw");
+MODULE_FIRMWARE("b43/ucode40.fw");
+MODULE_FIRMWARE("b43/ucode42.fw");
MODULE_FIRMWARE("b43/ucode9.fw");
static int modparam_bad_frames_preempt;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index edffe5a..d46f086 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -2049,7 +2049,7 @@
return head_pad;
}
-/**
+/*
* struct brcmf_skbuff_cb reserves first two bytes in sk_buff::cb for
* bus layer usage.
*/
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
index 82d5389..0c3fe17 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
@@ -1128,7 +1128,7 @@
}
if (0 == tmp) {
read_addr = REG_DBI_RDATA + addr % 4;
- ret = rtl_read_word(rtlpriv, read_addr);
+ ret = rtl_read_byte(rtlpriv, read_addr);
}
return ret;
}
@@ -1170,7 +1170,8 @@
}
tmp = _rtl8821ae_dbi_read(rtlpriv, 0x70f);
- _rtl8821ae_dbi_write(rtlpriv, 0x70f, tmp | BIT(7));
+ _rtl8821ae_dbi_write(rtlpriv, 0x70f, tmp | BIT(7) |
+ ASPM_L1_LATENCY << 3);
tmp = _rtl8821ae_dbi_read(rtlpriv, 0x719);
_rtl8821ae_dbi_write(rtlpriv, 0x719, tmp | BIT(3) | BIT(4));
diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h
index dafe486..340e7b3 100644
--- a/drivers/net/wireless/realtek/rtlwifi/wifi.h
+++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h
@@ -99,6 +99,7 @@
#define RTL_USB_MAX_RX_COUNT 100
#define QBSS_LOAD_SIZE 5
#define MAX_WMMELE_LENGTH 64
+#define ASPM_L1_LATENCY 7
#define TOTAL_CAM_ENTRY 32
diff --git a/drivers/net/wireless/st/cw1200/wsm.c b/drivers/net/wireless/st/cw1200/wsm.c
index 680d60e..ed93bf3 100644
--- a/drivers/net/wireless/st/cw1200/wsm.c
+++ b/drivers/net/wireless/st/cw1200/wsm.c
@@ -379,7 +379,6 @@
{
int ret;
int count;
- int i;
count = WSM_GET32(buf);
if (WARN_ON(count <= 0))
@@ -395,11 +394,10 @@
}
cw1200_debug_txed_multi(priv, count);
- for (i = 0; i < count; ++i) {
+ do {
ret = wsm_tx_confirm(priv, buf, link_id);
- if (ret)
- return ret;
- }
+ } while (!ret && --count);
+
return ret;
underflow:
diff --git a/drivers/of/base.c b/drivers/of/base.c
index a0bccb5..23a6d36 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -20,9 +20,11 @@
#define pr_fmt(fmt) "OF: " fmt
+#include <linux/bootmem.h>
#include <linux/console.h>
#include <linux/ctype.h>
#include <linux/cpu.h>
+#include <linux/memblock.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
@@ -198,9 +200,100 @@
return 0;
}
+static struct device_node **phandle_cache;
+static u32 phandle_cache_mask;
+
+/*
+ * Assumptions behind phandle_cache implementation:
+ * - phandle property values are in a contiguous range of 1..n
+ *
+ * If the assumptions do not hold, then
+ * - the phandle lookup overhead reduction provided by the cache
+ * will likely be less
+ */
+static void of_populate_phandle_cache(void)
+{
+ unsigned long flags;
+ u32 cache_entries;
+ struct device_node *np;
+ u32 phandles = 0;
+
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+
+ kfree(phandle_cache);
+ phandle_cache = NULL;
+
+ for_each_of_allnodes(np)
+ if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL)
+ phandles++;
+
+ cache_entries = roundup_pow_of_two(phandles);
+ phandle_cache_mask = cache_entries - 1;
+
+ phandle_cache = kcalloc(cache_entries, sizeof(*phandle_cache),
+ GFP_ATOMIC);
+
+ if (phandle_cache)
+ for_each_of_allnodes(np)
+ if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL)
+ phandle_cache[np->phandle & phandle_cache_mask] = np;
+
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+}
+
+void __init of_populate_phandle_cache_early(void)
+{
+ u32 cache_entries;
+ struct device_node *np;
+ u32 phandles = 0;
+ size_t size;
+
+ for_each_of_allnodes(np)
+ if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL)
+ phandles++;
+
+ cache_entries = roundup_pow_of_two(phandles);
+ phandle_cache_mask = cache_entries - 1;
+
+ size = cache_entries * sizeof(*phandle_cache);
+ phandle_cache = memblock_virt_alloc(size, 4);
+ memset(phandle_cache, 0, size);
+
+ for_each_of_allnodes(np)
+ if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL)
+ phandle_cache[np->phandle & phandle_cache_mask] = np;
+}
+
+#ifndef CONFIG_MODULES
+static int __init of_free_phandle_cache(void)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+
+ kfree(phandle_cache);
+ phandle_cache = NULL;
+
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+
+ return 0;
+}
+late_initcall_sync(of_free_phandle_cache);
+#endif
+
void __init of_core_init(void)
{
+ unsigned long flags;
struct device_node *np;
+ phys_addr_t size;
+
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+ size = (phandle_cache_mask + 1) * sizeof(*phandle_cache);
+ memblock_free(__pa(phandle_cache), size);
+ phandle_cache = NULL;
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+
+ of_populate_phandle_cache();
/* Create the kset, and register existing nodes */
mutex_lock(&of_mutex);
@@ -1093,16 +1186,32 @@
*/
struct device_node *of_find_node_by_phandle(phandle handle)
{
- struct device_node *np;
+ struct device_node *np = NULL;
unsigned long flags;
+ phandle masked_handle;
if (!handle)
return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
- for_each_of_allnodes(np)
- if (np->phandle == handle)
- break;
+
+ masked_handle = handle & phandle_cache_mask;
+
+ if (phandle_cache) {
+ if (phandle_cache[masked_handle] &&
+ handle == phandle_cache[masked_handle]->phandle)
+ np = phandle_cache[masked_handle];
+ }
+
+ if (!np) {
+ for_each_of_allnodes(np)
+ if (np->phandle == handle) {
+ if (phandle_cache)
+ phandle_cache[masked_handle] = np;
+ break;
+ }
+ }
+
of_node_get(np);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index c0914fb..755b386 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -31,6 +31,8 @@
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
#include <asm/page.h>
+#include "of_private.h"
+
/*
* of_fdt_limit_memory - limit the number of regions in the /memory node
* @limit: maximum entries
@@ -1269,6 +1271,8 @@
/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
of_alias_scan(early_init_dt_alloc_memory_arch);
+
+ of_populate_phandle_cache_early();
}
/**
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 18bbb451..c4d7fdc 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -86,6 +86,11 @@
extern void __of_sysfs_remove_bin_file(struct device_node *np,
struct property *prop);
+/* illegal phandle value (set when unresolved) */
+#define OF_PHANDLE_ILLEGAL 0xdeadbeef
+
+extern void __init of_populate_phandle_cache_early(void);
+
/* iterators for transactions, used for overlays */
/* forward iterator */
#define for_each_transaction_entry(_oft, _te) \
diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c
index 46325d6..67b1d72 100644
--- a/drivers/of/resolver.c
+++ b/drivers/of/resolver.c
@@ -21,9 +21,6 @@
#include <linux/string.h>
#include <linux/slab.h>
-/* illegal phandle value (set when unresolved) */
-#define OF_PHANDLE_ILLEGAL 0xdeadbeef
-
/**
* Find a node with the give full name by recursively following any of
* the child node links.
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
index 043c19a..eac0a12 100644
--- a/drivers/pci/host/pci-keystone.c
+++ b/drivers/pci/host/pci-keystone.c
@@ -181,7 +181,7 @@
}
/* interrupt controller is in a child node */
- *np_temp = of_find_node_by_name(np_pcie, controller);
+ *np_temp = of_get_child_by_name(np_pcie, controller);
if (!(*np_temp)) {
dev_err(dev, "Node for %s is absent\n", controller);
return -EINVAL;
@@ -190,6 +190,7 @@
temp = of_irq_count(*np_temp);
if (!temp) {
dev_err(dev, "No IRQ entries in %s\n", controller);
+ of_node_put(*np_temp);
return -EINVAL;
}
@@ -207,6 +208,8 @@
break;
}
+ of_node_put(*np_temp);
+
if (temp) {
*num_irqs = temp;
return 0;
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index b897813..20d48a0 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -5094,20 +5094,6 @@
return arch_setup_msi_irq_default(pdev, desc, 1);
}
-static int msm_pcie_get_msi_multiple(int nvec)
-{
- int msi_multiple = 0;
-
- while (nvec) {
- nvec = nvec >> 1;
- msi_multiple++;
- }
- PCIE_GEN_DBG("log2 number of MSI multiple:%d\n",
- msi_multiple - 1);
-
- return msi_multiple - 1;
-}
-
int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
struct msi_desc *entry;
@@ -5123,7 +5109,7 @@
list_for_each_entry(entry, &dev->dev.msi_list, list) {
entry->msi_attrib.multiple =
- msm_pcie_get_msi_multiple(nvec);
+ __ilog2_u32(__roundup_pow_of_two(nvec));
if (pcie_dev->msi_gicm_addr)
ret = arch_setup_msi_irq_qgic(dev, entry, nvec);
diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c
index 37e29b5..0e7f8f3 100644
--- a/drivers/pci/host/vmd.c
+++ b/drivers/pci/host/vmd.c
@@ -727,7 +727,7 @@
irq_domain_remove(vmd->irq_domain);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int vmd_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
diff --git a/drivers/perf/xgene_pmu.c b/drivers/perf/xgene_pmu.c
index a8ac4bc..35b5289 100644
--- a/drivers/perf/xgene_pmu.c
+++ b/drivers/perf/xgene_pmu.c
@@ -25,6 +25,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
+#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/of_irq.h>
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index b40a074..df63b7d 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -368,6 +368,18 @@
writel(value, padcfg0);
}
+static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
+{
+ u32 value;
+
+ /* Put the pad into GPIO mode */
+ value = readl(padcfg0) & ~PADCFG0_PMODE_MASK;
+ /* Disable SCI/SMI/NMI generation */
+ value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI);
+ value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI);
+ writel(value, padcfg0);
+}
+
static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned pin)
@@ -375,7 +387,6 @@
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
void __iomem *padcfg0;
unsigned long flags;
- u32 value;
raw_spin_lock_irqsave(&pctrl->lock, flags);
@@ -385,13 +396,7 @@
}
padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
- /* Put the pad into GPIO mode */
- value = readl(padcfg0) & ~PADCFG0_PMODE_MASK;
- /* Disable SCI/SMI/NMI generation */
- value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI);
- value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI);
- writel(value, padcfg0);
-
+ intel_gpio_set_gpio_mode(padcfg0);
/* Disable TX buffer and enable RX (this will be input) */
__intel_gpio_set_direction(padcfg0, true);
@@ -770,6 +775,8 @@
raw_spin_lock_irqsave(&pctrl->lock, flags);
+ intel_gpio_set_gpio_mode(reg);
+
value = readl(reg);
value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV);
diff --git a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c
index 866aa3c..6cf0006 100644
--- a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c
+++ b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c
@@ -436,3 +436,7 @@
return 0;
}
EXPORT_SYMBOL_GPL(pxa2xx_pinctrl_exit);
+
+MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
+MODULE_DESCRIPTION("Marvell PXA2xx pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 6515ce4..dab5db5 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -63,6 +63,16 @@
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm TLMM block found in the Qualcomm 9615 platform.
+config PINCTRL_MDM9650
+ tristate "QTI MDM9650 pin controller driver"
+ depends on GPIOLIB && OF
+ select PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver settings
+ for the QTI TLMM block which is found in the QTI MDM9650
+ platform.
+ Say Y here to enable pinctrl settings for MDM9650.
+
config PINCTRL_MSM8X74
tristate "Qualcomm 8x74 pin controller driver"
depends on GPIOLIB && OF
@@ -89,6 +99,16 @@
Technologies Inc MSM8953 platform.
If unsure say N.
+config PINCTRL_MSM8909
+ tristate "Qualcomm Technologies Inc MSM8909 pin controller driver"
+ depends on GPIOLIB && OF && (ARCH_MSM8909 || COMPILE_TEST)
+ select PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc TLMM block found on the Qualcomm
+ Technologies Inc MSM8909 platform.
+ If unsure say N.
+
config PINCTRL_MSM8937
tristate "Qualcomm Technologies Inc MSM8937 pin controller driver"
depends on GPIOLIB && OF
@@ -99,6 +119,16 @@
Technologies Inc MSM8937 platform.
If unsure say N.
+config PINCTRL_MSM8917
+ tristate "Qualcomm Technologies Inc MSM8917 pin controller driver"
+ depends on GPIOLIB && OF
+ select PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc TLMM block found on the Qualcomm
+ Technologies Inc MSM8917 platform.
+ If unsure say N.
+
config PINCTRL_SDM845
tristate "Qualcomm Technologies Inc SDM845 pin controller driver"
depends on GPIOLIB && OF
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index db71677..5389139 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -12,7 +12,9 @@
obj-$(CONFIG_PINCTRL_QDF2XXX) += pinctrl-qdf2xxx.o
obj-$(CONFIG_PINCTRL_MDM9615) += pinctrl-mdm9615.o
obj-$(CONFIG_PINCTRL_MSM8953) += pinctrl-msm8953.o
+obj-$(CONFIG_PINCTRL_MSM8909) += pinctrl-msm8909.o
obj-$(CONFIG_PINCTRL_MSM8937) += pinctrl-msm8937.o
+obj-$(CONFIG_PINCTRL_MSM8917) += pinctrl-msm8917.o
obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o
@@ -20,3 +22,4 @@
obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o pinctrl-sdm845-v2.o
obj-$(CONFIG_PINCTRL_SDM670) += pinctrl-sdm670.o
obj-$(CONFIG_PINCTRL_SDXPOORWILLS) += pinctrl-sdxpoorwills.o
+obj-$(CONFIG_PINCTRL_MDM9650) += pinctrl-mdm9650.o
diff --git a/drivers/pinctrl/qcom/pinctrl-mdm9650.c b/drivers/pinctrl/qcom/pinctrl-mdm9650.c
new file mode 100644
index 0000000..c80e932
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-mdm9650.c
@@ -0,0 +1,1224 @@
+/*
+ * Copyright (c) 2015, 2017-2018, 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/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define REG_BASE 0x0
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = REG_BASE + REG_SIZE * id, \
+ .io_reg = REG_BASE + 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .intr_status_reg = REG_BASE + 0xc + REG_SIZE * id, \
+ .intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 4, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+static const struct pinctrl_pin_desc mdm9650_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "SDC1_CLK"),
+ PINCTRL_PIN(101, "SDC1_CMD"),
+ PINCTRL_PIN(102, "SDC1_DATA"),
+ PINCTRL_PIN(103, "SDC2_CLK"),
+ PINCTRL_PIN(104, "SDC2_CMD"),
+ PINCTRL_PIN(105, "SDC2_DATA"),
+ PINCTRL_PIN(106, "QDSD_CLK"),
+ PINCTRL_PIN(107, "QDSD_CMD"),
+ PINCTRL_PIN(108, "QDSD_DATA0"),
+ PINCTRL_PIN(109, "QDSD_DATA1"),
+ PINCTRL_PIN(110, "QDSD_DATA2"),
+ PINCTRL_PIN(111, "QDSD_DATA3"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+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);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+
+static const unsigned int sdc1_clk_pins[] = { 100 };
+static const unsigned int sdc1_cmd_pins[] = { 101 };
+static const unsigned int sdc1_data_pins[] = { 102 };
+static const unsigned int sdc2_clk_pins[] = { 103 };
+static const unsigned int sdc2_cmd_pins[] = { 104 };
+static const unsigned int sdc2_data_pins[] = { 105 };
+static const unsigned int qdsd_clk_pins[] = { 106 };
+static const unsigned int qdsd_cmd_pins[] = { 107 };
+static const unsigned int qdsd_data0_pins[] = { 108 };
+static const unsigned int qdsd_data1_pins[] = { 109 };
+static const unsigned int qdsd_data2_pins[] = { 110 };
+static const unsigned int qdsd_data3_pins[] = { 111 };
+
+enum mdm9650_functions {
+ msm_mux_uim2_data,
+ msm_mux_qdss_stm31,
+ msm_mux_ebi0_wrcdc,
+ msm_mux_uim2_present,
+ msm_mux_qdss_stm30,
+ msm_mux_blsp_spi1,
+ msm_mux_uim2_reset,
+ msm_mux_qdss_stm29,
+ msm_mux_uim2_clk,
+ msm_mux_blsp_i2c1,
+ msm_mux_qdss_stm28,
+ msm_mux_blsp_spi2,
+ msm_mux_blsp_uart1,
+ msm_mux_blsp_uart2,
+ msm_mux_blsp_uart4,
+ msm_mux_qdss_stm23,
+ msm_mux_qdss_tracedata_a,
+ msm_mux_qdss_stm22,
+ msm_mux_qdss_stm21,
+ msm_mux_blsp_i2c2,
+ msm_mux_qdss_stm20,
+ msm_mux_pri_mi2s_ws_b,
+ msm_mux_blsp_spi3,
+ msm_mux_blsp_uart3,
+ msm_mux_ldo_en,
+ msm_mux_qdss_cti_trig1_out_b,
+ msm_mux_pwr_modem,
+ msm_mux_pri_mi2s_data0_b,
+ msm_mux_qdss_cti_trig1_in_b,
+ msm_mux_pwr_nav,
+ msm_mux_pri_mi2s_data1_b,
+ msm_mux_blsp_i2c3,
+ msm_mux_pwr_crypto,
+ msm_mux_pri_mi2s_sck_b,
+ msm_mux_pri_mi2s_ws_a,
+ msm_mux_qdss_stm19,
+ msm_mux_pri_mi2s_data0_a,
+ msm_mux_qdss_stm18,
+ msm_mux_pri_mi2s_data1_a,
+ msm_mux_slimbus_data,
+ msm_mux_qdss_stm17,
+ msm_mux_bimc_dte0,
+ msm_mux_native_tsens,
+ msm_mux_pri_mi2s_sck_a,
+ msm_mux_blsp_i2c4,
+ msm_mux_slimbus_clk,
+ msm_mux_qdss_stm16,
+ msm_mux_bimc_dte1,
+ msm_mux_sec_mi2s_ws_a,
+ msm_mux_blsp_spi4,
+ msm_mux_qdss_stm27,
+ msm_mux_sec_mi2s_data0_a,
+ msm_mux_qdss_cti,
+ msm_mux_qdss_stm26,
+ msm_mux_sec_mi2s_data1_a,
+ msm_mux_qdss_stm25,
+ msm_mux_sec_mi2s_sck_a,
+ msm_mux_qdss_stm24,
+ msm_mux_sec_mi2s_ws_b,
+ msm_mux_ebi2_a,
+ msm_mux_sec_mi2s_data0_b,
+ msm_mux_ebi2_lcd,
+ msm_mux_sec_mi2s_data1_b,
+ msm_mux_ebi1_smt4,
+ msm_mux_sec_mi2s_sck_b,
+ msm_mux_m_voc_ext_vfr_ref_irq_a,
+ msm_mux_adsp_ext_vfr_irq_a,
+ msm_mux_qdss_stm11,
+ msm_mux_epm1,
+ msm_mux_m_voc_ext_vfr_ref_irq_2_a,
+ msm_mux_adsp_ext_vfr_irq_b,
+ msm_mux_qdss_stm10,
+ msm_mux_native_char,
+ msm_mux_native_char3,
+ msm_mux_native_char2,
+ msm_mux_native_char1,
+ msm_mux_native_char0,
+ msm_mux_pa_indicator,
+ msm_mux_qdss_traceclk_a,
+ msm_mux_prng_rosc,
+ msm_mux_nav_pps_in_a,
+ msm_mux_qdss_tracectl_a,
+ msm_mux_epm2,
+ msm_mux_nav_pps_in_b,
+ msm_mux_coex_uart,
+ msm_mux_nav_dr,
+ msm_mux_cri_trng0,
+ msm_mux_qlink_req,
+ msm_mux_qlink_en,
+ msm_mux_cri_trng1,
+ msm_mux_cri_trng,
+ msm_mux_ap2mdm_status,
+ msm_mux_mdm2ap_status,
+ msm_mux_ap2mdm_err,
+ msm_mux_mdm2ap_err,
+ msm_mux_qdss_stm15,
+ msm_mux_ap2mdm_vdd,
+ msm_mux_qdss_stm14,
+ msm_mux_mdm2ap_vdd,
+ msm_mux_qdss_stm13,
+ msm_mux_ap2mdm_wake,
+ msm_mux_m_voc_ext_vfr_ref_irq_2_b,
+ msm_mux_qdss_stm12,
+ msm_mux_pciehost_rst,
+ msm_mux_pci_e,
+ msm_mux_qdss_stm9,
+ msm_mux_qdss_cti_trig1_out_a,
+ msm_mux_qdss_cti_trig2_in_b,
+ msm_mux_qdss_stm8,
+ msm_mux_qdss_cti_trig1_in_a,
+ msm_mux_qdss_cti_trig2_out_b,
+ msm_mux_qdss_stm7,
+ msm_mux_pcie_clkreq,
+ msm_mux_qdss_stm6,
+ msm_mux_qdss_stm5,
+ msm_mux_ap2mdm_chnl,
+ msm_mux_qdss_stm4,
+ msm_mux_qdss_cti_trig2_out_a,
+ msm_mux_qdss_stm3,
+ msm_mux_mdm2ap_chnl,
+ msm_mux_m_voc_ext_vfr_ref_irq_b,
+ msm_mux_qdss_stm2,
+ msm_mux_uim_batt,
+ msm_mux_qdss_stm1,
+ msm_mux_qdss_cti_trig2_in_a,
+ msm_mux_qdss_stm0,
+ msm_mux_i2s_mclk,
+ msm_mux_audio_ref,
+ msm_mux_ldo_update,
+ msm_mux_dbg_out,
+ msm_mux_gcc_plltest,
+ msm_mux_uim1_data,
+ msm_mux_uim1_present,
+ msm_mux_uim1_reset,
+ msm_mux_uim1_clk,
+ msm_mux_gpio,
+ msm_mux_NA,
+};
+
+static const char * const uim2_data_groups[] = {
+ "gpio0",
+};
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "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",
+};
+static const char * const qdss_stm31_groups[] = {
+ "gpio0",
+};
+static const char * const ebi0_wrcdc_groups[] = {
+ "gpio0", "gpio2",
+};
+static const char * const uim2_present_groups[] = {
+ "gpio1",
+};
+static const char * const qdss_stm30_groups[] = {
+ "gpio1",
+};
+static const char * const blsp_spi1_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio68", "gpio69", "gpio71",
+};
+static const char * const uim2_reset_groups[] = {
+ "gpio2",
+};
+static const char * const blsp_i2c1_groups[] = {
+ "gpio2", "gpio3", "gpio84", "gpio85",
+};
+static const char * const qdss_stm29_groups[] = {
+ "gpio2",
+};
+static const char * const uim2_clk_groups[] = {
+ "gpio3",
+};
+static const char * const qdss_stm28_groups[] = {
+ "gpio3",
+};
+static const char * const blsp_spi2_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7", "gpio60", "gpio68", "gpio71",
+};
+static const char * const blsp_uart1_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio20", "gpio21", "gpio22",
+ "gpio23",
+};
+static const char * const blsp_uart2_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const qdss_stm23_groups[] = {
+ "gpio4",
+};
+static const char * const qdss_tracedata_a_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7", "gpio8", "gpio9", "gpio16",
+ "gpio17", "gpio18", "gpio19", "gpio20", "gpio22", "gpio40", "gpio43",
+ "gpio68", "gpio69",
+};
+static const char * const qdss_stm22_groups[] = {
+ "gpio5",
+};
+static const char * const blsp_i2c2_groups[] = {
+ "gpio6", "gpio7", "gpio48", "gpio49",
+};
+static const char * const qdss_stm21_groups[] = {
+ "gpio6",
+};
+static const char * const qdss_stm20_groups[] = {
+ "gpio7",
+};
+static const char * const pri_mi2s_ws_b_groups[] = {
+ "gpio8",
+};
+static const char * const blsp_spi3_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio68", "gpio69", "gpio71",
+};
+static const char * const blsp_uart3_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const blsp_uart4_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", "gpio18",
+ "gpio19",
+};
+static const char * const ldo_en_groups[] = {
+ "gpio8",
+};
+static const char * const qdss_cti_trig1_out_b_groups[] = {
+ "gpio8",
+};
+static const char * const pwr_modem_groups[] = {
+ "gpio8",
+};
+static const char * const pri_mi2s_data0_b_groups[] = {
+ "gpio9",
+};
+static const char * const qdss_cti_trig1_in_b_groups[] = {
+ "gpio9",
+};
+static const char * const pwr_nav_groups[] = {
+ "gpio9",
+};
+static const char * const pri_mi2s_data1_b_groups[] = {
+ "gpio10",
+};
+static const char * const blsp_i2c3_groups[] = {
+ "gpio10", "gpio11",
+};
+static const char * const pwr_crypto_groups[] = {
+ "gpio10",
+};
+static const char * const pri_mi2s_sck_b_groups[] = {
+ "gpio11",
+};
+static const char * const pri_mi2s_ws_a_groups[] = {
+ "gpio12",
+};
+static const char * const qdss_stm19_groups[] = {
+ "gpio12",
+};
+static const char * const pri_mi2s_data0_a_groups[] = {
+ "gpio13",
+};
+static const char * const qdss_stm18_groups[] = {
+ "gpio13",
+};
+static const char * const pri_mi2s_data1_a_groups[] = {
+ "gpio14",
+};
+static const char * const blsp_i2c4_groups[] = {
+ "gpio14", "gpio15", "gpio18", "gpio19",
+};
+static const char * const slimbus_data_groups[] = {
+ "gpio14",
+};
+static const char * const qdss_stm17_groups[] = {
+ "gpio14",
+};
+static const char * const bimc_dte0_groups[] = {
+ "gpio14", "gpio59",
+};
+static const char * const native_tsens_groups[] = {
+ "gpio14",
+};
+static const char * const pri_mi2s_sck_a_groups[] = {
+ "gpio15",
+};
+static const char * const slimbus_clk_groups[] = {
+ "gpio15",
+};
+static const char * const qdss_stm16_groups[] = {
+ "gpio15",
+};
+static const char * const bimc_dte1_groups[] = {
+ "gpio15", "gpio60",
+};
+static const char * const sec_mi2s_ws_a_groups[] = {
+ "gpio16",
+};
+static const char * const blsp_spi4_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19", "gpio68", "gpio69", "gpio71",
+};
+static const char * const qdss_stm27_groups[] = {
+ "gpio16",
+};
+static const char * const sec_mi2s_data0_a_groups[] = {
+ "gpio17",
+};
+static const char * const qdss_cti_groups[] = {
+ "gpio17", "gpio18", "gpio52", "gpio53", "gpio92", "gpio93",
+};
+static const char * const qdss_stm26_groups[] = {
+ "gpio17",
+};
+static const char * const sec_mi2s_data1_a_groups[] = {
+ "gpio18",
+};
+static const char * const qdss_stm25_groups[] = {
+ "gpio18",
+};
+static const char * const sec_mi2s_sck_a_groups[] = {
+ "gpio19",
+};
+static const char * const qdss_stm24_groups[] = {
+ "gpio19",
+};
+static const char * const sec_mi2s_ws_b_groups[] = {
+ "gpio20",
+};
+static const char * const ebi2_a_groups[] = {
+ "gpio20",
+};
+static const char * const sec_mi2s_data0_b_groups[] = {
+ "gpio21",
+};
+static const char * const ebi2_lcd_groups[] = {
+ "gpio21", "gpio22", "gpio23",
+};
+static const char * const sec_mi2s_data1_b_groups[] = {
+ "gpio22",
+};
+static const char * const ebi1_smt4_groups[] = {
+ "gpio22",
+};
+static const char * const sec_mi2s_sck_b_groups[] = {
+ "gpio23",
+};
+static const char * const m_voc_ext_vfr_ref_irq_a_groups[] = {
+ "gpio24",
+};
+static const char * const adsp_ext_vfr_irq_a_groups[] = {
+ "gpio24",
+};
+static const char * const qdss_stm11_groups[] = {
+ "gpio24",
+};
+static const char * const epm1_groups[] = {
+ "gpio25",
+};
+static const char * const m_voc_ext_vfr_ref_irq_2_a_groups[] = {
+ "gpio25",
+};
+static const char * const adsp_ext_vfr_irq_b_groups[] = {
+ "gpio25",
+};
+static const char * const qdss_stm10_groups[] = {
+ "gpio25",
+};
+static const char * const native_char_groups[] = {
+ "gpio27",
+};
+static const char * const native_char3_groups[] = {
+ "gpio28",
+};
+static const char * const native_char2_groups[] = {
+ "gpio29",
+};
+static const char * const native_char1_groups[] = {
+ "gpio32",
+};
+static const char * const native_char0_groups[] = {
+ "gpio33",
+};
+static const char * const pa_indicator_groups[] = {
+ "gpio36",
+};
+static const char * const qdss_traceclk_a_groups[] = {
+ "gpio36",
+};
+static const char * const prng_rosc_groups[] = {
+ "gpio47",
+};
+static const char * const nav_pps_in_a_groups[] = {
+ "gpio50",
+};
+static const char * const qdss_tracectl_a_groups[] = {
+ "gpio50",
+};
+static const char * const epm2_groups[] = {
+ "gpio51",
+};
+static const char * const nav_pps_in_b_groups[] = {
+ "gpio51",
+};
+static const char * const coex_uart_groups[] = {
+ "gpio52", "gpio53",
+};
+static const char * const nav_dr_groups[] = {
+ "gpio39",
+};
+static const char * const cri_trng0_groups[] = {
+ "gpio40",
+};
+static const char * const qlink_req_groups[] = {
+ "gpio41",
+};
+static const char * const qlink_en_groups[] = {
+ "gpio42",
+};
+static const char * const cri_trng1_groups[] = {
+ "gpio43",
+};
+static const char * const cri_trng_groups[] = {
+ "gpio44",
+};
+static const char * const ap2mdm_status_groups[] = {
+ "gpio54",
+};
+static const char * const mdm2ap_status_groups[] = {
+ "gpio55",
+};
+static const char * const ap2mdm_err_groups[] = {
+ "gpio56",
+};
+static const char * const mdm2ap_err_groups[] = {
+ "gpio57",
+};
+static const char * const qdss_stm15_groups[] = {
+ "gpio57",
+};
+static const char * const ap2mdm_vdd_groups[] = {
+ "gpio58",
+};
+static const char * const qdss_stm14_groups[] = {
+ "gpio58",
+};
+static const char * const mdm2ap_vdd_groups[] = {
+ "gpio59",
+};
+static const char * const qdss_stm13_groups[] = {
+ "gpio59",
+};
+static const char * const ap2mdm_wake_groups[] = {
+ "gpio60",
+};
+static const char * const m_voc_ext_vfr_ref_irq_2_b_groups[] = {
+ "gpio60",
+};
+static const char * const qdss_stm12_groups[] = {
+ "gpio60",
+};
+static const char * const pciehost_rst_groups[] = {
+ "gpio61",
+};
+static const char * const pci_e_groups[] = {
+ "gpio61", "gpio61", "gpio65",
+};
+static const char * const qdss_stm9_groups[] = {
+ "gpio61",
+};
+static const char * const qdss_cti_trig1_out_a_groups[] = {
+ "gpio62",
+};
+static const char * const qdss_cti_trig2_in_b_groups[] = {
+ "gpio62",
+};
+static const char * const qdss_stm8_groups[] = {
+ "gpio62",
+};
+static const char * const qdss_cti_trig1_in_a_groups[] = {
+ "gpio63",
+};
+static const char * const qdss_cti_trig2_out_b_groups[] = {
+ "gpio63",
+};
+static const char * const qdss_stm7_groups[] = {
+ "gpio63",
+};
+static const char * const pcie_clkreq_groups[] = {
+ "gpio64",
+};
+static const char * const qdss_stm6_groups[] = {
+ "gpio64",
+};
+static const char * const qdss_stm5_groups[] = {
+ "gpio65",
+};
+static const char * const ap2mdm_chnl_groups[] = {
+ "gpio66",
+};
+static const char * const qdss_stm4_groups[] = {
+ "gpio66",
+};
+static const char * const qdss_cti_trig2_out_a_groups[] = {
+ "gpio67",
+};
+static const char * const qdss_stm3_groups[] = {
+ "gpio67",
+};
+static const char * const mdm2ap_chnl_groups[] = {
+ "gpio68",
+};
+static const char * const m_voc_ext_vfr_ref_irq_b_groups[] = {
+ "gpio68",
+};
+static const char * const qdss_stm2_groups[] = {
+ "gpio68",
+};
+static const char * const uim_batt_groups[] = {
+ "gpio69",
+};
+static const char * const qdss_stm1_groups[] = {
+ "gpio69",
+};
+static const char * const qdss_cti_trig2_in_a_groups[] = {
+ "gpio70",
+};
+static const char * const qdss_stm0_groups[] = {
+ "gpio70",
+};
+static const char * const i2s_mclk_groups[] = {
+ "gpio71",
+};
+static const char * const audio_ref_groups[] = {
+ "gpio71",
+};
+static const char * const ldo_update_groups[] = {
+ "gpio71",
+};
+static const char * const dbg_out_groups[] = {
+ "gpio71",
+};
+static const char * const gcc_plltest_groups[] = {
+ "gpio73", "gpio74",
+};
+static const char * const uim1_data_groups[] = {
+ "gpio76",
+};
+static const char * const uim1_present_groups[] = {
+ "gpio77",
+};
+static const char * const uim1_reset_groups[] = {
+ "gpio78",
+};
+static const char * const uim1_clk_groups[] = {
+ "gpio79",
+};
+
+static const struct msm_function mdm9650_functions[] = {
+ FUNCTION(gpio),
+ FUNCTION(uim2_data),
+ FUNCTION(qdss_stm31),
+ FUNCTION(ebi0_wrcdc),
+ FUNCTION(uim2_present),
+ FUNCTION(blsp_uart1),
+ FUNCTION(qdss_stm30),
+ FUNCTION(blsp_spi1),
+ FUNCTION(uim2_reset),
+ FUNCTION(blsp_i2c1),
+ FUNCTION(qdss_stm29),
+ FUNCTION(uim2_clk),
+ FUNCTION(qdss_stm28),
+ FUNCTION(blsp_spi2),
+ FUNCTION(blsp_uart2),
+ FUNCTION(qdss_stm23),
+ FUNCTION(qdss_tracedata_a),
+ FUNCTION(qdss_stm22),
+ FUNCTION(blsp_i2c2),
+ FUNCTION(qdss_stm21),
+ FUNCTION(qdss_stm20),
+ FUNCTION(pri_mi2s_ws_b),
+ FUNCTION(blsp_spi3),
+ FUNCTION(blsp_uart3),
+ FUNCTION(ldo_en),
+ FUNCTION(qdss_cti_trig1_out_b),
+ FUNCTION(pwr_modem),
+ FUNCTION(pri_mi2s_data0_b),
+ FUNCTION(qdss_cti_trig1_in_b),
+ FUNCTION(pwr_nav),
+ FUNCTION(pri_mi2s_data1_b),
+ FUNCTION(blsp_i2c3),
+ FUNCTION(pwr_crypto),
+ FUNCTION(pri_mi2s_sck_b),
+ FUNCTION(pri_mi2s_ws_a),
+ FUNCTION(blsp_uart4),
+ FUNCTION(qdss_stm19),
+ FUNCTION(pri_mi2s_data0_a),
+ FUNCTION(qdss_stm18),
+ FUNCTION(pri_mi2s_data1_a),
+ FUNCTION(blsp_i2c4),
+ FUNCTION(slimbus_data),
+ FUNCTION(qdss_stm17),
+ FUNCTION(bimc_dte0),
+ FUNCTION(native_tsens),
+ FUNCTION(pri_mi2s_sck_a),
+ FUNCTION(slimbus_clk),
+ FUNCTION(qdss_stm16),
+ FUNCTION(bimc_dte1),
+ FUNCTION(sec_mi2s_ws_a),
+ FUNCTION(blsp_spi4),
+ FUNCTION(qdss_stm27),
+ FUNCTION(sec_mi2s_data0_a),
+ FUNCTION(qdss_cti),
+ FUNCTION(qdss_stm26),
+ FUNCTION(sec_mi2s_data1_a),
+ FUNCTION(qdss_stm25),
+ FUNCTION(sec_mi2s_sck_a),
+ FUNCTION(qdss_stm24),
+ FUNCTION(sec_mi2s_ws_b),
+ FUNCTION(ebi2_a),
+ FUNCTION(sec_mi2s_data0_b),
+ FUNCTION(ebi2_lcd),
+ FUNCTION(sec_mi2s_data1_b),
+ FUNCTION(ebi1_smt4),
+ FUNCTION(sec_mi2s_sck_b),
+ FUNCTION(m_voc_ext_vfr_ref_irq_a),
+ FUNCTION(adsp_ext_vfr_irq_a),
+ FUNCTION(qdss_stm11),
+ FUNCTION(epm1),
+ FUNCTION(m_voc_ext_vfr_ref_irq_2_a),
+ FUNCTION(adsp_ext_vfr_irq_b),
+ FUNCTION(qdss_stm10),
+ FUNCTION(native_char),
+ FUNCTION(native_char3),
+ FUNCTION(native_char2),
+ FUNCTION(native_char1),
+ FUNCTION(native_char0),
+ FUNCTION(pa_indicator),
+ FUNCTION(qdss_traceclk_a),
+ FUNCTION(prng_rosc),
+ FUNCTION(nav_pps_in_a),
+ FUNCTION(qdss_tracectl_a),
+ FUNCTION(epm2),
+ FUNCTION(nav_pps_in_b),
+ FUNCTION(coex_uart),
+ FUNCTION(nav_dr),
+ FUNCTION(cri_trng0),
+ FUNCTION(qlink_req),
+ FUNCTION(qlink_en),
+ FUNCTION(cri_trng1),
+ FUNCTION(cri_trng),
+ FUNCTION(ap2mdm_status),
+ FUNCTION(mdm2ap_status),
+ FUNCTION(ap2mdm_err),
+ FUNCTION(mdm2ap_err),
+ FUNCTION(qdss_stm15),
+ FUNCTION(ap2mdm_vdd),
+ FUNCTION(qdss_stm14),
+ FUNCTION(mdm2ap_vdd),
+ FUNCTION(qdss_stm13),
+ FUNCTION(ap2mdm_wake),
+ FUNCTION(m_voc_ext_vfr_ref_irq_2_b),
+ FUNCTION(qdss_stm12),
+ FUNCTION(pciehost_rst),
+ FUNCTION(pci_e),
+ FUNCTION(qdss_stm9),
+ FUNCTION(qdss_cti_trig1_out_a),
+ FUNCTION(qdss_cti_trig2_in_b),
+ FUNCTION(qdss_stm8),
+ FUNCTION(qdss_cti_trig1_in_a),
+ FUNCTION(qdss_cti_trig2_out_b),
+ FUNCTION(qdss_stm7),
+ FUNCTION(pcie_clkreq),
+ FUNCTION(qdss_stm6),
+ FUNCTION(qdss_stm5),
+ FUNCTION(ap2mdm_chnl),
+ FUNCTION(qdss_stm4),
+ FUNCTION(qdss_cti_trig2_out_a),
+ FUNCTION(qdss_stm3),
+ FUNCTION(mdm2ap_chnl),
+ FUNCTION(m_voc_ext_vfr_ref_irq_b),
+ FUNCTION(qdss_stm2),
+ FUNCTION(uim_batt),
+ FUNCTION(qdss_stm1),
+ FUNCTION(qdss_cti_trig2_in_a),
+ FUNCTION(qdss_stm0),
+ FUNCTION(i2s_mclk),
+ FUNCTION(audio_ref),
+ FUNCTION(ldo_update),
+ FUNCTION(dbg_out),
+ FUNCTION(gcc_plltest),
+ FUNCTION(uim1_data),
+ FUNCTION(uim1_present),
+ FUNCTION(uim1_reset),
+ FUNCTION(uim1_clk),
+};
+
+static const struct msm_pingroup mdm9650_groups[] = {
+ PINGROUP(0, uim2_data, blsp_spi1, blsp_uart1, qdss_stm31,
+ ebi0_wrcdc, NA, NA, NA, NA),
+ PINGROUP(1, uim2_present, blsp_spi1, blsp_uart1, qdss_stm30, NA,
+ NA, NA, NA, NA),
+ PINGROUP(2, uim2_reset, blsp_spi1, blsp_uart1, blsp_i2c1,
+ qdss_stm29, ebi0_wrcdc, NA, NA, NA),
+ PINGROUP(3, uim2_clk, blsp_spi1, blsp_uart1, blsp_i2c1,
+ qdss_stm28, NA, NA, NA, NA),
+ PINGROUP(4, blsp_spi2, blsp_uart2, NA, qdss_stm23, qdss_tracedata_a,
+ NA, NA, NA, NA),
+ PINGROUP(5, blsp_spi2, blsp_uart2, NA, qdss_stm22, qdss_tracedata_a,
+ NA, NA, NA, NA),
+ PINGROUP(6, blsp_spi2, blsp_uart2, blsp_i2c2, NA, qdss_stm21,
+ qdss_tracedata_a, NA, NA, NA),
+ PINGROUP(7, blsp_spi2, blsp_uart2, blsp_i2c2, NA, qdss_stm20,
+ qdss_tracedata_a, NA, NA, NA),
+ PINGROUP(8, pri_mi2s_ws_b, blsp_spi3, blsp_uart3, ldo_en, NA,
+ qdss_tracedata_a, qdss_cti_trig1_out_b, pwr_modem, NA),
+ PINGROUP(9, pri_mi2s_data0_b, blsp_spi3, blsp_uart3, NA,
+ qdss_tracedata_a, qdss_cti_trig1_in_b, pwr_nav, NA, NA),
+ PINGROUP(10, pri_mi2s_data1_b, blsp_spi3, blsp_uart3, blsp_i2c3,
+ pwr_crypto, NA, NA, NA, NA),
+ PINGROUP(11, pri_mi2s_sck_b, blsp_spi3, blsp_uart3, blsp_i2c3, NA, NA,
+ NA, NA, NA),
+ PINGROUP(12, pri_mi2s_ws_a, blsp_uart4, NA, qdss_stm19, NA, NA,
+ NA, NA, NA),
+ PINGROUP(13, pri_mi2s_data0_a, blsp_uart4, NA, qdss_stm18, NA, NA,
+ NA, NA, NA),
+ PINGROUP(14, pri_mi2s_data1_a, blsp_uart4, blsp_i2c4,
+ slimbus_data, NA, NA, qdss_stm17, bimc_dte0, native_tsens),
+ PINGROUP(15, pri_mi2s_sck_a, blsp_uart4, blsp_i2c4,
+ slimbus_clk, NA, qdss_stm16, bimc_dte1, NA, NA),
+ PINGROUP(16, sec_mi2s_ws_a, blsp_spi4, blsp_uart4, NA, NA,
+ qdss_stm27, qdss_tracedata_a, NA, NA),
+ PINGROUP(17, sec_mi2s_data0_a, blsp_spi4, blsp_uart4, qdss_cti,
+ qdss_stm26, qdss_tracedata_a, NA, NA, NA),
+ PINGROUP(18, sec_mi2s_data1_a, blsp_spi4, blsp_uart4,
+ blsp_i2c4, qdss_cti, NA, qdss_stm25, qdss_tracedata_a,
+ NA),
+ PINGROUP(19, sec_mi2s_sck_a, blsp_spi4, blsp_uart4,
+ blsp_i2c4, NA, qdss_stm24, qdss_tracedata_a, NA, NA),
+ PINGROUP(20, sec_mi2s_ws_b, ebi2_a, blsp_uart1, qdss_tracedata_a,
+ NA, NA, NA, NA, NA),
+ PINGROUP(21, sec_mi2s_data0_b, ebi2_lcd, blsp_uart1, NA, NA, NA,
+ NA, NA, NA),
+ PINGROUP(22, sec_mi2s_data1_b, ebi2_lcd, blsp_uart1,
+ qdss_tracedata_a, NA, ebi1_smt4, NA, NA, NA),
+ PINGROUP(23, sec_mi2s_sck_b, ebi2_lcd, blsp_uart1, NA, NA, NA,
+ NA, NA, NA),
+ PINGROUP(24, m_voc_ext_vfr_ref_irq_a, adsp_ext_vfr_irq_a, NA,
+ qdss_stm11, NA, NA, NA, NA, NA),
+ PINGROUP(25, m_voc_ext_vfr_ref_irq_2_a, adsp_ext_vfr_irq_b, NA,
+ qdss_stm10, NA, NA, NA, NA, NA),
+ PINGROUP(26, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(27, NA, NA, native_char, NA, NA, NA, NA, NA, NA),
+ PINGROUP(28, NA, NA, NA, native_char3, NA, NA, NA, NA, NA),
+ PINGROUP(29, NA, NA, NA, native_char2, NA, NA, NA, NA, NA),
+ PINGROUP(30, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(31, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(32, NA, native_char1, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(33, NA, native_char0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(34, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(35, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(36, NA, pa_indicator, qdss_traceclk_a, NA, NA, NA, NA, NA, NA),
+ PINGROUP(37, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(38, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(39, NA, nav_dr, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(40, cri_trng0, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(41, qlink_req, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(42, qlink_en, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(43, cri_trng1, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(44, NA, cri_trng, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(45, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(46, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(47, NA, prng_rosc, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(48, NA, blsp_i2c2, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(49, NA, blsp_i2c2, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(50, nav_pps_in_a, qdss_tracectl_a, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(51, nav_pps_in_b, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(52, coex_uart, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(53, coex_uart, NA, qdss_cti, NA, NA, NA, NA, NA, NA),
+ PINGROUP(54, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(55, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(56, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(57, NA, qdss_stm15, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(58, NA, qdss_stm14, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(59, NA, qdss_stm13, bimc_dte0, NA, NA, NA, NA, NA, NA),
+ PINGROUP(60, m_voc_ext_vfr_ref_irq_2_b, blsp_spi2, NA, NA, qdss_stm12,
+ bimc_dte1, NA, NA, NA),
+ PINGROUP(61, pci_e, pci_e, NA, NA, qdss_stm9, NA, NA, NA, NA),
+ PINGROUP(62, qdss_cti_trig1_out_a, qdss_cti_trig2_in_b, NA, qdss_stm8,
+ NA, NA, NA, NA, NA),
+ PINGROUP(63, qdss_cti_trig1_in_a, qdss_cti_trig2_out_b, NA, qdss_stm7,
+ NA, NA, NA, NA, NA),
+ PINGROUP(64, pcie_clkreq, qdss_stm6, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(65, NA, qdss_stm5, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(66, NA, qdss_stm4, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(67, qdss_cti_trig2_out_a, NA, qdss_stm3, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(68, m_voc_ext_vfr_ref_irq_b, blsp_spi1, blsp_spi2, blsp_spi3,
+ blsp_spi4, NA, qdss_stm2, qdss_tracedata_a, NA),
+ PINGROUP(69, uim_batt, blsp_spi1, blsp_spi3, blsp_spi4, qdss_stm1,
+ qdss_tracedata_a, NA, NA, NA),
+ PINGROUP(70, qdss_cti_trig2_in_a, NA, qdss_stm0, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(71, i2s_mclk, audio_ref, blsp_spi1, blsp_spi2, blsp_spi3,
+ blsp_spi4, ldo_update, dbg_out, NA),
+ PINGROUP(72, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(73, NA, NA, gcc_plltest, NA, NA, NA, NA, NA, NA),
+ PINGROUP(74, NA, gcc_plltest, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(75, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(76, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(77, uim1_present, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(78, uim1_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(79, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(80, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(81, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(82, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(83, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(84, NA, NA, blsp_i2c1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(85, NA, NA, blsp_i2c1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(86, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(87, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(88, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(89, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(90, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(91, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(92, NA, NA, qdss_cti, NA, NA, NA, NA, NA, NA),
+ PINGROUP(93, NA, NA, qdss_cti, NA, NA, NA, NA, NA, NA),
+ PINGROUP(94, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(95, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(96, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(97, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(98, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(99, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ SDC_QDSD_PINGROUP(sdc1_clk, 0x10a000, 13, 6),
+ SDC_QDSD_PINGROUP(sdc1_cmd, 0x10a000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc1_data, 0x10a000, 9, 0),
+ SDC_QDSD_PINGROUP(sdc2_clk, 0x109000, 14, 6),
+ SDC_QDSD_PINGROUP(sdc2_cmd, 0x109000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc2_data, 0x109000, 9, 0),
+ SDC_QDSD_PINGROUP(qdsd_clk, 0x19c000, 3, 0),
+ SDC_QDSD_PINGROUP(qdsd_cmd, 0x19c000, 8, 5),
+ SDC_QDSD_PINGROUP(qdsd_data0, 0x19c000, 13, 10),
+ SDC_QDSD_PINGROUP(qdsd_data1, 0x19c000, 18, 15),
+ SDC_QDSD_PINGROUP(qdsd_data2, 0x19c000, 23, 20),
+ SDC_QDSD_PINGROUP(qdsd_data3, 0x19c000, 28, 25),
+};
+
+static const struct msm_pinctrl_soc_data mdm9650_pinctrl = {
+ .pins = mdm9650_pins,
+ .npins = ARRAY_SIZE(mdm9650_pins),
+ .functions = mdm9650_functions,
+ .nfunctions = ARRAY_SIZE(mdm9650_functions),
+ .groups = mdm9650_groups,
+ .ngroups = ARRAY_SIZE(mdm9650_groups),
+ .ngpios = 100,
+};
+
+static int mdm9650_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &mdm9650_pinctrl);
+}
+
+static const struct of_device_id mdm9650_pinctrl_of_match[] = {
+ { .compatible = "qcom,mdm9650-pinctrl", },
+ { },
+};
+
+static struct platform_driver mdm9650_pinctrl_driver = {
+ .driver = {
+ .name = "mdm9650-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = mdm9650_pinctrl_of_match,
+ },
+ .probe = mdm9650_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init mdm9650_pinctrl_init(void)
+{
+ return platform_driver_register(&mdm9650_pinctrl_driver);
+}
+arch_initcall(mdm9650_pinctrl_init);
+
+static void __exit mdm9650_pinctrl_exit(void)
+{
+ platform_driver_unregister(&mdm9650_pinctrl_driver);
+}
+module_exit(mdm9650_pinctrl_exit);
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. MDM9650 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, mdm9650_pinctrl_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 1441678..9e1c8d2 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -25,6 +25,7 @@
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
@@ -583,6 +584,9 @@
clear_bit(d->hwirq, pctrl->enabled_irqs);
spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ if (d->parent_data)
+ irq_chip_mask_parent(d);
}
static void msm_gpio_irq_enable(struct irq_data *d)
@@ -611,6 +615,9 @@
set_bit(d->hwirq, pctrl->enabled_irqs);
spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ if (d->parent_data)
+ irq_chip_enable_parent(d);
}
static void msm_gpio_irq_unmask(struct irq_data *d)
@@ -632,6 +639,9 @@
set_bit(d->hwirq, pctrl->enabled_irqs);
spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ if (d->parent_data)
+ irq_chip_unmask_parent(d);
}
static void msm_gpio_irq_ack(struct irq_data *d)
@@ -745,6 +755,9 @@
spin_unlock_irqrestore(&pctrl->lock, flags);
+ if (d->parent_data)
+ irq_chip_set_type_parent(d, type);
+
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
irq_set_handler_locked(d, handle_level_irq);
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
@@ -765,9 +778,35 @@
spin_unlock_irqrestore(&pctrl->lock, flags);
+ if (d->parent_data)
+ irq_chip_set_wake_parent(d, on);
+
return 0;
}
+static int msm_gpiochip_irq_reqres(struct irq_data *d)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+ if (!try_module_get(chip->owner))
+ return -ENODEV;
+
+ if (gpiochip_lock_as_irq(chip, d->hwirq)) {
+ pr_err("unable to lock HW IRQ %lu for IRQ\n", d->hwirq);
+ module_put(chip->owner);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void msm_gpiochip_irq_relres(struct irq_data *d)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+ gpiochip_unlock_as_irq(chip, d->hwirq);
+ module_put(chip->owner);
+}
+
static struct irq_chip msm_gpio_irq_chip = {
.name = "msmgpio",
.irq_enable = msm_gpio_irq_enable,
@@ -776,6 +815,65 @@
.irq_ack = msm_gpio_irq_ack,
.irq_set_type = msm_gpio_irq_set_type,
.irq_set_wake = msm_gpio_irq_set_wake,
+ .irq_request_resources = msm_gpiochip_irq_reqres,
+ .irq_release_resources = msm_gpiochip_irq_relres,
+ .flags = IRQCHIP_MASK_ON_SUSPEND |
+ IRQCHIP_SKIP_SET_WAKE,
+};
+
+static void msm_gpio_domain_set_info(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct gpio_chip *gc = d->host_data;
+
+ irq_domain_set_info(d, irq, hwirq, gc->irqchip, d->host_data,
+ gc->irq_handler, NULL, NULL);
+
+ if (gc->can_sleep && !gc->irq_not_threaded)
+ irq_set_nested_thread(irq, 1);
+
+ irq_set_noprobe(irq);
+}
+
+static int msm_gpio_domain_translate(struct irq_domain *d,
+ struct irq_fwspec *fwspec, unsigned long *hwirq, unsigned int *type)
+{
+ if (is_of_node(fwspec->fwnode)) {
+ if (fwspec->param_count < 2)
+ return -EINVAL;
+ if (hwirq)
+ *hwirq = fwspec->param[0];
+ if (type)
+ *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int msm_gpio_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ int ret = 0;
+ irq_hw_number_t hwirq;
+ struct irq_fwspec *fwspec = arg, parent_fwspec;
+
+ ret = msm_gpio_domain_translate(domain, fwspec, &hwirq, NULL);
+ if (ret)
+ return ret;
+
+ msm_gpio_domain_set_info(domain, virq, hwirq);
+
+ parent_fwspec = *fwspec;
+ parent_fwspec.fwnode = domain->parent->fwnode;
+ return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
+ &parent_fwspec);
+}
+
+static const struct irq_domain_ops msm_gpio_domain_ops = {
+ .translate = msm_gpio_domain_translate,
+ .alloc = msm_gpio_domain_alloc,
+ .free = irq_domain_free_irqs_top,
};
static struct irq_chip msm_dirconn_irq_chip;
@@ -1299,11 +1397,25 @@
}
}
+static int msm_gpiochip_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ struct irq_fwspec fwspec;
+
+ fwspec.fwnode = of_node_to_fwnode(chip->of_node);
+ fwspec.param[0] = offset;
+ fwspec.param[1] = IRQ_TYPE_NONE;
+ fwspec.param_count = 2;
+
+ return irq_create_fwspec_mapping(&fwspec);
+}
+
static int msm_gpio_init(struct msm_pinctrl *pctrl)
{
struct gpio_chip *chip;
int ret;
unsigned ngpio = pctrl->soc->ngpios;
+ struct device_node *irq_parent = NULL;
+ struct irq_domain *domain_parent;
if (WARN_ON(ngpio > MAX_NR_GPIO))
return -EINVAL;
@@ -1329,19 +1441,45 @@
return ret;
}
- ret = gpiochip_irqchip_add(chip,
- &msm_gpio_irq_chip,
- 0,
- handle_fasteoi_irq,
- IRQ_TYPE_NONE);
- if (ret) {
- dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n");
- gpiochip_remove(&pctrl->chip);
- return -ENOSYS;
- }
+ irq_parent = of_irq_find_parent(chip->of_node);
+ if (of_device_is_compatible(irq_parent, "qcom,mpm-gpio")) {
+ chip->irqchip = &msm_gpio_irq_chip;
+ chip->irq_handler = handle_fasteoi_irq;
+ chip->irq_default_type = IRQ_TYPE_NONE;
+ chip->to_irq = msm_gpiochip_to_irq;
+ chip->lock_key = NULL;
+ domain_parent = irq_find_host(irq_parent);
+ if (!domain_parent) {
+ pr_err("unable to find parent domain\n");
+ gpiochip_remove(&pctrl->chip);
+ return -ENXIO;
+ }
- gpiochip_set_chained_irqchip(chip, &msm_gpio_irq_chip, pctrl->irq,
- msm_gpio_irq_handler);
+ chip->irqdomain = irq_domain_add_hierarchy(domain_parent, 0,
+ chip->ngpio,
+ chip->of_node,
+ &msm_gpio_domain_ops,
+ chip);
+ if (!chip->irqdomain) {
+ dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n");
+ chip->irqchip = NULL;
+ gpiochip_remove(&pctrl->chip);
+ return -ENXIO;
+ }
+ } else {
+ ret = gpiochip_irqchip_add(chip,
+ &msm_gpio_irq_chip,
+ 0,
+ handle_fasteoi_irq,
+ IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n");
+ gpiochip_remove(&pctrl->chip);
+ return ret;
+ }
+ }
+ gpiochip_set_chained_irqchip(chip, &msm_gpio_irq_chip,
+ pctrl->irq, msm_gpio_irq_handler);
msm_gpio_setup_dir_connects(pctrl);
return 0;
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8909.c b/drivers/pinctrl/qcom/pinctrl-msm8909.c
new file mode 100644
index 0000000..c8c3de7
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-msm8909.c
@@ -0,0 +1,1299 @@
+/*
+ * Copyright (c) 2016-2018, 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/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define REG_BASE 0x0
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = REG_BASE + REG_SIZE * id, \
+ .io_reg = REG_BASE + 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .intr_status_reg = REG_BASE + 0xc + REG_SIZE * id, \
+ .intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 4, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+static const struct pinctrl_pin_desc msm8909_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "SDC1_CLK"),
+ PINCTRL_PIN(114, "SDC1_CMD"),
+ PINCTRL_PIN(115, "SDC1_DATA"),
+ PINCTRL_PIN(116, "SDC2_CLK"),
+ PINCTRL_PIN(117, "SDC2_CMD"),
+ PINCTRL_PIN(118, "SDC2_DATA"),
+ PINCTRL_PIN(119, "QDSD_CLK"),
+ PINCTRL_PIN(120, "QDSD_CMD"),
+ PINCTRL_PIN(121, "QDSD_DATA0"),
+ PINCTRL_PIN(122, "QDSD_DATA1"),
+ PINCTRL_PIN(123, "QDSD_DATA2"),
+ PINCTRL_PIN(124, "QDSD_DATA3"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+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);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+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);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+
+static const unsigned int sdc1_clk_pins[] = { 113 };
+static const unsigned int sdc1_cmd_pins[] = { 114 };
+static const unsigned int sdc1_data_pins[] = { 115 };
+static const unsigned int sdc2_clk_pins[] = { 116 };
+static const unsigned int sdc2_cmd_pins[] = { 117 };
+static const unsigned int sdc2_data_pins[] = { 118 };
+static const unsigned int qdsd_clk_pins[] = { 119 };
+static const unsigned int qdsd_cmd_pins[] = { 120 };
+static const unsigned int qdsd_data0_pins[] = { 121 };
+static const unsigned int qdsd_data1_pins[] = { 122 };
+static const unsigned int qdsd_data2_pins[] = { 123 };
+static const unsigned int qdsd_data3_pins[] = { 124 };
+
+enum msm8909_functions {
+ msm_mux_blsp_spi3,
+ msm_mux_gpio,
+ msm_mux_sec_mi2s,
+ msm_mux_blsp_spi1,
+ msm_mux_blsp_uart1,
+ msm_mux_blsp_uim1,
+ msm_mux_blsp3_spi,
+ msm_mux_dmic0_clk,
+ msm_mux_qdss_tracectl_b,
+ msm_mux_blsp2_spi,
+ msm_mux_dmic0_data,
+ msm_mux_qdss_traceclk_b,
+ msm_mux_blsp_i2c1,
+ msm_mux_qdss_tracedata_a,
+ msm_mux_bimc_dte0,
+ msm_mux_bimc_dte1,
+ msm_mux_blsp_spi6,
+ msm_mux_m_voc,
+ msm_mux_blsp_i2c6,
+ msm_mux_dbg_out,
+ msm_mux_blsp_spi4,
+ msm_mux_gcc_gp2_clk_b,
+ msm_mux_gcc_gp3_clk_b,
+ msm_mux_blsp_i2c4,
+ msm_mux_gcc_gp1_clk_b,
+ msm_mux_qdss_tracedata_b,
+ msm_mux_blsp_spi5,
+ msm_mux_blsp_i2c5,
+ msm_mux_uim3_clk,
+ msm_mux_qdss_cti_trig_out_a0,
+ msm_mux_mdp_vsync,
+ msm_mux_ebi2_lcd,
+ msm_mux_dsi_rst,
+ msm_mux_cam_mclk,
+ msm_mux_uim3_data,
+ msm_mux_blsp_spi2,
+ msm_mux_blsp_uart2,
+ msm_mux_blsp_uim2,
+ msm_mux_qdss_cti_trig_in_a0,
+ msm_mux_uim3_present,
+ msm_mux_qdss_cti_trig_in_b0,
+ msm_mux_uim3_reset,
+ msm_mux_qdss_cti_trig_out_b0,
+ msm_mux_webcam1_rst,
+ msm_mux_pwr_modem_enabled_a,
+ msm_mux_blsp_i2c3,
+ msm_mux_flash_strobe,
+ msm_mux_cci_timer0,
+ msm_mux_cci_timer1,
+ msm_mux_atest_combodac_to_gpio_native,
+ msm_mux_cci_async,
+ msm_mux_cam1_standby,
+ msm_mux_pwr_nav_enabled_a,
+ msm_mux_cam1_rst,
+ msm_mux_pwr_crypto_enabled_a,
+ msm_mux_atest_bbrx1,
+ msm_mux_backlight_en,
+ msm_mux_blsp1_spi,
+ msm_mux_atest_bbrx0,
+ msm_mux_sd_card,
+ msm_mux_cci_timer2,
+ msm_mux_adsp_ext,
+ msm_mux_wcss_bt,
+ msm_mux_wcss_wlan2,
+ msm_mux_wcss_wlan1,
+ msm_mux_wcss_wlan0,
+ msm_mux_wcss_wlan,
+ msm_mux_prng_rosc,
+ msm_mux_wcss_fm,
+ msm_mux_ext_lpass,
+ msm_mux_qdss_tracectl_a,
+ msm_mux_qdss_traceclk_a,
+ msm_mux_uim2_data,
+ msm_mux_gcc_gp1_clk_a,
+ msm_mux_qdss_cti_trig_in_a1,
+ msm_mux_uim2_clk,
+ msm_mux_gcc_gp2_clk_a,
+ msm_mux_qdss_cti_trig_in_b1,
+ msm_mux_uim2_reset,
+ msm_mux_gcc_gp3_clk_a,
+ msm_mux_qdss_cti_trig_out_b1,
+ msm_mux_uim2_present,
+ msm_mux_qdss_cti_trig_out_a1,
+ msm_mux_uim1_data,
+ msm_mux_uim1_clk,
+ msm_mux_uim1_reset,
+ msm_mux_uim1_present,
+ msm_mux_uim_batt,
+ msm_mux_smb_int,
+ msm_mux_cdc_pdm0,
+ msm_mux_pri_mi2s_mclk_a,
+ msm_mux_atest_char3,
+ msm_mux_pri_mi2s_sck_a,
+ msm_mux_atest_char2,
+ msm_mux_pri_mi2s_ws_a,
+ msm_mux_atest_char1,
+ msm_mux_pri_mi2s_data0_a,
+ msm_mux_atest_char0,
+ msm_mux_atest_gpsadc_dtest0_native,
+ msm_mux_gcc_plltest,
+ msm_mux_pri_mi2s_data1_a,
+ msm_mux_atest_char,
+ msm_mux_atest_tsens,
+ msm_mux_ebi0_wrcdc,
+ msm_mux_mag_int,
+ msm_mux_atest_gpsadc_dtest1_native,
+ msm_mux_pa_indicator,
+ msm_mux_modem_tsync,
+ msm_mux_nav_tsync,
+ msm_mux_nav_pps,
+ msm_mux_gsm0_tx,
+ msm_mux_ssbi0,
+ msm_mux_ssbi1,
+ msm_mux_kpsns0,
+ msm_mux_pbs0,
+ msm_mux_kpsns1,
+ msm_mux_pbs1,
+ msm_mux_kpsns2,
+ msm_mux_pbs2,
+ msm_mux_ext_buck,
+ msm_mux_alsp_int,
+ msm_mux_pri_mi2s_sck_b,
+ msm_mux_pwr_modem_enabled_b,
+ msm_mux_pri_mi2s_data0_b,
+ msm_mux_pwr_nav_enabled_b,
+ msm_mux_gyro_accl,
+ msm_mux_pri_mi2s_data1_b,
+ msm_mux_pwr_crypto_enabled_b,
+ msm_mux_atest_wlan0,
+ msm_mux_euro_us,
+ msm_mux_atest_wlan1,
+ msm_mux_pri_mi2s_mclk_b,
+ msm_mux_ldo_update,
+ msm_mux_gcc_tlmm,
+ msm_mux_ebi2_a,
+ msm_mux_sd_write,
+ msm_mux_ldo_en,
+ msm_mux_msim_int,
+ msm_mux_pri_mi2s_ws_b,
+ msm_mux_blsp_i2c2,
+ msm_mux_NA,
+};
+
+static const char * const blsp_spi3_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "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", "gpio104",
+ "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+ "gpio111", "gpio112",
+};
+static const char * const sec_mi2s_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio98",
+};
+static const char * const blsp_spi1_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart1_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uim1_groups[] = {
+ "gpio4", "gpio5",
+};
+static const char * const blsp3_spi_groups[] = {
+ "gpio4", "gpio65", "gpio95",
+};
+static const char * const dmic0_clk_groups[] = {
+ "gpio4",
+};
+static const char * const qdss_tracectl_b_groups[] = {
+ "gpio4",
+};
+static const char * const blsp2_spi_groups[] = {
+ "gpio5", "gpio17", "gpio98",
+};
+static const char * const dmic0_data_groups[] = {
+ "gpio5",
+};
+static const char * const qdss_traceclk_b_groups[] = {
+ "gpio5",
+};
+static const char * const blsp_i2c1_groups[] = {
+ "gpio6", "gpio7",
+};
+static const char * const qdss_tracedata_a_groups[] = {
+ "gpio6", "gpio8", "gpio9", "gpio10", "gpio39", "gpio40", "gpio41",
+ "gpio42", "gpio43", "gpio47", "gpio48", "gpio58", "gpio65", "gpio94",
+ "gpio96", "gpio97",
+};
+static const char * const bimc_dte0_groups[] = {
+ "gpio6", "gpio59",
+};
+static const char * const bimc_dte1_groups[] = {
+ "gpio7", "gpio60",
+};
+static const char * const blsp_spi6_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const m_voc_groups[] = {
+ "gpio8", "gpio95",
+};
+static const char * const blsp_i2c6_groups[] = {
+ "gpio10", "gpio11",
+};
+static const char * const dbg_out_groups[] = {
+ "gpio10",
+};
+static const char * const blsp_spi4_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15",
+};
+static const char * const gcc_gp2_clk_b_groups[] = {
+ "gpio12",
+};
+static const char * const gcc_gp3_clk_b_groups[] = {
+ "gpio13",
+};
+static const char * const blsp_i2c4_groups[] = {
+ "gpio14", "gpio15",
+};
+static const char * const gcc_gp1_clk_b_groups[] = {
+ "gpio14",
+};
+static const char * const qdss_tracedata_b_groups[] = {
+ "gpio14", "gpio16", "gpio17", "gpio26", "gpio27", "gpio28", "gpio29",
+ "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36",
+ "gpio37", "gpio93",
+};
+static const char * const blsp_spi5_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const blsp_i2c5_groups[] = {
+ "gpio18", "gpio19",
+};
+static const char * const uim3_clk_groups[] = {
+ "gpio23",
+};
+static const char * const qdss_cti_trig_out_a0_groups[] = {
+ "gpio23",
+};
+static const char * const mdp_vsync_groups[] = {
+ "gpio24", "gpio25",
+};
+static const char * const ebi2_lcd_groups[] = {
+ "gpio24", "gpio24", "gpio25", "gpio95",
+};
+static const char * const dsi_rst_groups[] = {
+ "gpio25",
+};
+static const char * const cam_mclk_groups[] = {
+ "gpio26", "gpio27",
+};
+static const char * const uim3_data_groups[] = {
+ "gpio20",
+};
+static const char * const blsp_spi2_groups[] = {
+ "gpio20", "gpio21", "gpio111", "gpio112",
+};
+static const char * const blsp_uart2_groups[] = {
+ "gpio20", "gpio21", "gpio111", "gpio112",
+};
+static const char * const blsp_uim2_groups[] = {
+ "gpio20", "gpio21",
+};
+static const char * const qdss_cti_trig_in_a0_groups[] = {
+ "gpio20",
+};
+static const char * const uim3_present_groups[] = {
+ "gpio21",
+};
+static const char * const qdss_cti_trig_in_b0_groups[] = {
+ "gpio21",
+};
+static const char * const uim3_reset_groups[] = {
+ "gpio22",
+};
+static const char * const qdss_cti_trig_out_b0_groups[] = {
+ "gpio22",
+};
+static const char * const webcam1_rst_groups[] = {
+ "gpio28",
+};
+static const char * const pwr_modem_enabled_a_groups[] = {
+ "gpio28",
+};
+static const char * const blsp_i2c3_groups[] = {
+ "gpio29", "gpio30",
+};
+static const char * const flash_strobe_groups[] = {
+ "gpio31", "gpio32",
+};
+static const char * const cci_timer0_groups[] = {
+ "gpio31",
+};
+static const char * const cci_timer1_groups[] = {
+ "gpio32",
+};
+static const char * const atest_combodac_to_gpio_native_groups[] = {
+ "gpio32", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43",
+ "gpio44", "gpio45", "gpio47", "gpio48", "gpio66", "gpio81", "gpio83",
+ "gpio84", "gpio85", "gpio86", "gpio94", "gpio95", "gpio110",
+};
+static const char * const cci_async_groups[] = {
+ "gpio33",
+};
+static const char * const cam1_standby_groups[] = {
+ "gpio34",
+};
+static const char * const pwr_nav_enabled_a_groups[] = {
+ "gpio34",
+};
+static const char * const cam1_rst_groups[] = {
+ "gpio35",
+};
+static const char * const pwr_crypto_enabled_a_groups[] = {
+ "gpio35",
+};
+static const char * const atest_bbrx1_groups[] = {
+ "gpio36",
+};
+static const char * const backlight_en_groups[] = {
+ "gpio37",
+};
+static const char * const blsp1_spi_groups[] = {
+ "gpio37", "gpio65", "gpio97",
+};
+static const char * const atest_bbrx0_groups[] = {
+ "gpio37",
+};
+static const char * const sd_card_groups[] = {
+ "gpio38",
+};
+static const char * const cci_timer2_groups[] = {
+ "gpio38",
+};
+static const char * const adsp_ext_groups[] = {
+ "gpio38",
+};
+static const char * const wcss_bt_groups[] = {
+ "gpio39", "gpio47", "gpio48",
+};
+static const char * const wcss_wlan2_groups[] = {
+ "gpio40",
+};
+static const char * const wcss_wlan1_groups[] = {
+ "gpio41",
+};
+static const char * const wcss_wlan0_groups[] = {
+ "gpio42",
+};
+static const char * const wcss_wlan_groups[] = {
+ "gpio43", "gpio44",
+};
+static const char * const prng_rosc_groups[] = {
+ "gpio43",
+};
+static const char * const wcss_fm_groups[] = {
+ "gpio45", "gpio46",
+};
+static const char * const ext_lpass_groups[] = {
+ "gpio45",
+};
+static const char * const qdss_tracectl_a_groups[] = {
+ "gpio45",
+};
+static const char * const qdss_traceclk_a_groups[] = {
+ "gpio46",
+};
+static const char * const uim2_data_groups[] = {
+ "gpio49",
+};
+static const char * const gcc_gp1_clk_a_groups[] = {
+ "gpio49",
+};
+static const char * const qdss_cti_trig_in_a1_groups[] = {
+ "gpio49",
+};
+static const char * const uim2_clk_groups[] = {
+ "gpio50",
+};
+static const char * const gcc_gp2_clk_a_groups[] = {
+ "gpio50",
+};
+static const char * const qdss_cti_trig_in_b1_groups[] = {
+ "gpio50",
+};
+static const char * const uim2_reset_groups[] = {
+ "gpio51",
+};
+static const char * const gcc_gp3_clk_a_groups[] = {
+ "gpio51",
+};
+static const char * const qdss_cti_trig_out_b1_groups[] = {
+ "gpio51",
+};
+static const char * const uim2_present_groups[] = {
+ "gpio52",
+};
+static const char * const qdss_cti_trig_out_a1_groups[] = {
+ "gpio52",
+};
+static const char * const uim1_data_groups[] = {
+ "gpio53",
+};
+static const char * const uim1_clk_groups[] = {
+ "gpio54",
+};
+static const char * const uim1_reset_groups[] = {
+ "gpio55",
+};
+static const char * const uim1_present_groups[] = {
+ "gpio56",
+};
+static const char * const uim_batt_groups[] = {
+ "gpio57",
+};
+static const char * const smb_int_groups[] = {
+ "gpio58",
+};
+static const char * const cdc_pdm0_groups[] = {
+ "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", "gpio64",
+};
+static const char * const pri_mi2s_mclk_a_groups[] = {
+ "gpio59",
+};
+static const char * const atest_char3_groups[] = {
+ "gpio59",
+};
+static const char * const pri_mi2s_sck_a_groups[] = {
+ "gpio60",
+};
+static const char * const atest_char2_groups[] = {
+ "gpio60",
+};
+static const char * const pri_mi2s_ws_a_groups[] = {
+ "gpio61",
+};
+static const char * const atest_char1_groups[] = {
+ "gpio61",
+};
+static const char * const pri_mi2s_data0_a_groups[] = {
+ "gpio62",
+};
+static const char * const atest_char0_groups[] = {
+ "gpio62",
+};
+static const char * const atest_gpsadc_dtest0_native_groups[] = {
+ "gpio65",
+};
+static const char * const gcc_plltest_groups[] = {
+ "gpio66", "gpio67",
+};
+static const char * const pri_mi2s_data1_a_groups[] = {
+ "gpio63",
+};
+static const char * const atest_char_groups[] = {
+ "gpio63",
+};
+static const char * const atest_tsens_groups[] = {
+ "gpio63",
+};
+static const char * const ebi0_wrcdc_groups[] = {
+ "gpio64",
+};
+static const char * const mag_int_groups[] = {
+ "gpio65",
+};
+static const char * const atest_gpsadc_dtest1_native_groups[] = {
+ "gpio79",
+};
+static const char * const pa_indicator_groups[] = {
+ "gpio82",
+};
+static const char * const modem_tsync_groups[] = {
+ "gpio83",
+};
+static const char * const nav_tsync_groups[] = {
+ "gpio83",
+};
+static const char * const nav_pps_groups[] = {
+ "gpio83",
+};
+static const char * const gsm0_tx_groups[] = {
+ "gpio85",
+};
+static const char * const ssbi0_groups[] = {
+ "gpio88",
+};
+static const char * const ssbi1_groups[] = {
+ "gpio89",
+};
+static const char * const kpsns0_groups[] = {
+ "gpio90",
+};
+static const char * const pbs0_groups[] = {
+ "gpio90",
+};
+static const char * const kpsns1_groups[] = {
+ "gpio91",
+};
+static const char * const pbs1_groups[] = {
+ "gpio91",
+};
+static const char * const kpsns2_groups[] = {
+ "gpio92",
+};
+static const char * const pbs2_groups[] = {
+ "gpio92",
+};
+static const char * const ext_buck_groups[] = {
+ "gpio93",
+};
+static const char * const alsp_int_groups[] = {
+ "gpio94",
+};
+static const char * const pri_mi2s_sck_b_groups[] = {
+ "gpio94",
+};
+static const char * const pwr_modem_enabled_b_groups[] = {
+ "gpio94",
+};
+static const char * const pri_mi2s_data0_b_groups[] = {
+ "gpio95",
+};
+static const char * const pwr_nav_enabled_b_groups[] = {
+ "gpio95",
+};
+static const char * const gyro_accl_groups[] = {
+ "gpio96",
+};
+static const char * const pri_mi2s_data1_b_groups[] = {
+ "gpio96",
+};
+static const char * const pwr_crypto_enabled_b_groups[] = {
+ "gpio96",
+};
+static const char * const atest_wlan0_groups[] = {
+ "gpio96",
+};
+static const char * const euro_us_groups[] = {
+ "gpio97",
+};
+static const char * const atest_wlan1_groups[] = {
+ "gpio97",
+};
+static const char * const pri_mi2s_mclk_b_groups[] = {
+ "gpio98",
+};
+static const char * const ldo_update_groups[] = {
+ "gpio98",
+};
+static const char * const gcc_tlmm_groups[] = {
+ "gpio98",
+};
+static const char * const ebi2_a_groups[] = {
+ "gpio99",
+};
+static const char * const sd_write_groups[] = {
+ "gpio99",
+};
+static const char * const ldo_en_groups[] = {
+ "gpio99",
+};
+static const char * const msim_int_groups[] = {
+ "gpio110",
+};
+static const char * const pri_mi2s_ws_b_groups[] = {
+ "gpio110",
+};
+static const char * const blsp_i2c2_groups[] = {
+ "gpio111", "gpio112",
+};
+
+static const struct msm_function msm8909_functions[] = {
+ FUNCTION(blsp_spi3),
+ FUNCTION(gpio),
+ FUNCTION(sec_mi2s),
+ FUNCTION(blsp_spi1),
+ FUNCTION(blsp_uart1),
+ FUNCTION(blsp_uim1),
+ FUNCTION(blsp3_spi),
+ FUNCTION(dmic0_clk),
+ FUNCTION(qdss_tracectl_b),
+ FUNCTION(blsp2_spi),
+ FUNCTION(dmic0_data),
+ FUNCTION(qdss_traceclk_b),
+ FUNCTION(blsp_i2c1),
+ FUNCTION(qdss_tracedata_a),
+ FUNCTION(bimc_dte0),
+ FUNCTION(bimc_dte1),
+ FUNCTION(blsp_spi6),
+ FUNCTION(m_voc),
+ FUNCTION(blsp_i2c6),
+ FUNCTION(dbg_out),
+ FUNCTION(blsp_spi4),
+ FUNCTION(gcc_gp2_clk_b),
+ FUNCTION(gcc_gp3_clk_b),
+ FUNCTION(blsp_i2c4),
+ FUNCTION(gcc_gp1_clk_b),
+ FUNCTION(qdss_tracedata_b),
+ FUNCTION(blsp_spi5),
+ FUNCTION(blsp_i2c5),
+ FUNCTION(uim3_clk),
+ FUNCTION(qdss_cti_trig_out_a0),
+ FUNCTION(mdp_vsync),
+ FUNCTION(ebi2_lcd),
+ FUNCTION(dsi_rst),
+ FUNCTION(cam_mclk),
+ FUNCTION(uim3_data),
+ FUNCTION(blsp_spi2),
+ FUNCTION(blsp_uart2),
+ FUNCTION(blsp_uim2),
+ FUNCTION(qdss_cti_trig_in_a0),
+ FUNCTION(uim3_present),
+ FUNCTION(qdss_cti_trig_in_b0),
+ FUNCTION(uim3_reset),
+ FUNCTION(qdss_cti_trig_out_b0),
+ FUNCTION(webcam1_rst),
+ FUNCTION(pwr_modem_enabled_a),
+ FUNCTION(blsp_i2c3),
+ FUNCTION(flash_strobe),
+ FUNCTION(cci_timer0),
+ FUNCTION(cci_timer1),
+ FUNCTION(atest_combodac_to_gpio_native),
+ FUNCTION(cci_async),
+ FUNCTION(cam1_standby),
+ FUNCTION(pwr_nav_enabled_a),
+ FUNCTION(cam1_rst),
+ FUNCTION(pwr_crypto_enabled_a),
+ FUNCTION(atest_bbrx1),
+ FUNCTION(backlight_en),
+ FUNCTION(blsp1_spi),
+ FUNCTION(atest_bbrx0),
+ FUNCTION(sd_card),
+ FUNCTION(cci_timer2),
+ FUNCTION(adsp_ext),
+ FUNCTION(wcss_bt),
+ FUNCTION(wcss_wlan2),
+ FUNCTION(wcss_wlan1),
+ FUNCTION(wcss_wlan0),
+ FUNCTION(wcss_wlan),
+ FUNCTION(prng_rosc),
+ FUNCTION(wcss_fm),
+ FUNCTION(ext_lpass),
+ FUNCTION(qdss_tracectl_a),
+ FUNCTION(qdss_traceclk_a),
+ FUNCTION(uim2_data),
+ FUNCTION(gcc_gp1_clk_a),
+ FUNCTION(qdss_cti_trig_in_a1),
+ FUNCTION(uim2_clk),
+ FUNCTION(gcc_gp2_clk_a),
+ FUNCTION(qdss_cti_trig_in_b1),
+ FUNCTION(uim2_reset),
+ FUNCTION(gcc_gp3_clk_a),
+ FUNCTION(qdss_cti_trig_out_b1),
+ FUNCTION(uim2_present),
+ FUNCTION(qdss_cti_trig_out_a1),
+ FUNCTION(uim1_data),
+ FUNCTION(uim1_clk),
+ FUNCTION(uim1_reset),
+ FUNCTION(uim1_present),
+ FUNCTION(uim_batt),
+ FUNCTION(smb_int),
+ FUNCTION(cdc_pdm0),
+ FUNCTION(pri_mi2s_mclk_a),
+ FUNCTION(atest_char3),
+ FUNCTION(pri_mi2s_sck_a),
+ FUNCTION(atest_char2),
+ FUNCTION(pri_mi2s_ws_a),
+ FUNCTION(atest_char1),
+ FUNCTION(pri_mi2s_data0_a),
+ FUNCTION(atest_char0),
+ FUNCTION(atest_gpsadc_dtest0_native),
+ FUNCTION(gcc_plltest),
+ FUNCTION(pri_mi2s_data1_a),
+ FUNCTION(atest_char),
+ FUNCTION(atest_tsens),
+ FUNCTION(ebi0_wrcdc),
+ FUNCTION(mag_int),
+ FUNCTION(atest_gpsadc_dtest1_native),
+ FUNCTION(pa_indicator),
+ FUNCTION(modem_tsync),
+ FUNCTION(nav_tsync),
+ FUNCTION(nav_pps),
+ FUNCTION(gsm0_tx),
+ FUNCTION(ssbi0),
+ FUNCTION(ssbi1),
+ FUNCTION(kpsns0),
+ FUNCTION(pbs0),
+ FUNCTION(kpsns1),
+ FUNCTION(pbs1),
+ FUNCTION(kpsns2),
+ FUNCTION(pbs2),
+ FUNCTION(ext_buck),
+ FUNCTION(alsp_int),
+ FUNCTION(pri_mi2s_sck_b),
+ FUNCTION(pwr_modem_enabled_b),
+ FUNCTION(pri_mi2s_data0_b),
+ FUNCTION(pwr_nav_enabled_b),
+ FUNCTION(gyro_accl),
+ FUNCTION(pri_mi2s_data1_b),
+ FUNCTION(pwr_crypto_enabled_b),
+ FUNCTION(atest_wlan0),
+ FUNCTION(euro_us),
+ FUNCTION(atest_wlan1),
+ FUNCTION(pri_mi2s_mclk_b),
+ FUNCTION(ldo_update),
+ FUNCTION(gcc_tlmm),
+ FUNCTION(ebi2_a),
+ FUNCTION(sd_write),
+ FUNCTION(ldo_en),
+ FUNCTION(msim_int),
+ FUNCTION(pri_mi2s_ws_b),
+ FUNCTION(blsp_i2c2),
+};
+
+static const struct msm_pingroup msm8909_groups[] = {
+ PINGROUP(0, blsp_spi3, sec_mi2s, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(1, blsp_spi3, sec_mi2s, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(2, blsp_spi3, sec_mi2s, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(3, blsp_spi3, sec_mi2s, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(4, blsp_spi1, blsp_uart1, blsp_uim1, blsp3_spi, dmic0_clk, NA,
+ NA, NA, NA),
+ PINGROUP(5, blsp_spi1, blsp_uart1, blsp_uim1, blsp2_spi, dmic0_data,
+ NA, NA, NA, NA),
+ PINGROUP(6, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(7, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA,
+ bimc_dte1),
+ PINGROUP(8, blsp_spi6, m_voc, NA, NA, NA, NA, NA, qdss_tracedata_a, NA),
+ PINGROUP(9, blsp_spi6, NA, NA, NA, NA, NA, qdss_tracedata_a, NA, NA),
+ PINGROUP(10, blsp_spi6, blsp_i2c6, dbg_out, qdss_tracedata_a, NA, NA,
+ NA, NA, NA),
+ PINGROUP(11, blsp_spi6, blsp_i2c6, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(12, blsp_spi4, gcc_gp2_clk_b, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(13, blsp_spi4, gcc_gp3_clk_b, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(14, blsp_spi4, blsp_i2c4, gcc_gp1_clk_b, NA, NA, NA, NA, NA,
+ qdss_tracedata_b),
+ PINGROUP(15, blsp_spi4, blsp_i2c4, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(16, blsp_spi5, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA),
+ PINGROUP(17, blsp_spi5, blsp2_spi, NA, NA, NA, NA, NA,
+ qdss_tracedata_b, NA),
+ PINGROUP(18, blsp_spi5, blsp_i2c5, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(19, blsp_spi5, blsp_i2c5, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(20, uim3_data, blsp_spi2, blsp_uart2, blsp_uim2, NA,
+ qdss_cti_trig_in_a0, NA, NA, NA),
+ PINGROUP(21, uim3_present, blsp_spi2, blsp_uart2, blsp_uim2, NA,
+ qdss_cti_trig_in_b0, NA, NA, NA),
+ PINGROUP(22, uim3_reset, NA, qdss_cti_trig_out_b0, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(23, uim3_clk, qdss_cti_trig_out_a0, NA, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(24, mdp_vsync, ebi2_lcd, ebi2_lcd, NA, NA, NA, NA, NA, NA),
+ PINGROUP(25, mdp_vsync, ebi2_lcd, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(26, cam_mclk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(27, cam_mclk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(28, NA, pwr_modem_enabled_a, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(29, blsp_i2c3, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA),
+ PINGROUP(30, blsp_i2c3, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA),
+ PINGROUP(31, cci_timer0, NA, NA, NA, NA, NA, NA, qdss_tracedata_b, NA),
+ PINGROUP(32, cci_timer1, NA, qdss_tracedata_b, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA),
+ PINGROUP(33, cci_async, qdss_tracedata_b, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(34, pwr_nav_enabled_a, qdss_tracedata_b, NA, NA, NA, NA, NA,
+ NA, NA),
+ PINGROUP(35, pwr_crypto_enabled_a, qdss_tracedata_b, NA, NA, NA, NA,
+ NA, NA, NA),
+ PINGROUP(36, qdss_tracedata_b, NA, atest_bbrx1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(37, blsp1_spi, qdss_tracedata_b, NA, atest_bbrx0, NA, NA, NA,
+ NA, NA),
+ PINGROUP(38, cci_timer2, adsp_ext, NA, atest_combodac_to_gpio_native,
+ NA, NA, NA, NA, NA),
+ PINGROUP(39, wcss_bt, qdss_tracedata_a, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+ PINGROUP(40, wcss_wlan2, qdss_tracedata_a, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+ PINGROUP(41, wcss_wlan1, qdss_tracedata_a, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+ PINGROUP(42, wcss_wlan0, qdss_tracedata_a, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+ PINGROUP(43, wcss_wlan, prng_rosc, qdss_tracedata_a, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA),
+ PINGROUP(44, wcss_wlan, NA, atest_combodac_to_gpio_native, NA, NA, NA,
+ NA, NA, NA),
+ PINGROUP(45, wcss_fm, ext_lpass, qdss_tracectl_a, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA),
+ PINGROUP(46, wcss_fm, qdss_traceclk_a, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(47, wcss_bt, qdss_tracedata_a, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+ PINGROUP(48, wcss_bt, qdss_tracedata_a, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+ PINGROUP(49, uim2_data, gcc_gp1_clk_a, qdss_cti_trig_in_a1, NA, NA, NA,
+ NA, NA, NA),
+ PINGROUP(50, uim2_clk, gcc_gp2_clk_a, qdss_cti_trig_in_b1, NA, NA, NA,
+ NA, NA, NA),
+ PINGROUP(51, uim2_reset, gcc_gp3_clk_a, qdss_cti_trig_out_b1, NA, NA,
+ NA, NA, NA, NA),
+ PINGROUP(52, uim2_present, qdss_cti_trig_out_a1, NA, NA, NA, NA, NA,
+ NA, NA),
+ PINGROUP(53, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(54, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(55, uim1_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(56, uim1_present, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(57, uim_batt, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(58, qdss_tracedata_a, smb_int, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(59, cdc_pdm0, pri_mi2s_mclk_a, atest_char3, NA, NA, NA, NA,
+ NA, bimc_dte0),
+ PINGROUP(60, cdc_pdm0, pri_mi2s_sck_a, atest_char2, NA, NA, NA, NA, NA,
+ bimc_dte1),
+ PINGROUP(61, cdc_pdm0, pri_mi2s_ws_a, atest_char1, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(62, cdc_pdm0, pri_mi2s_data0_a, atest_char0, NA, NA, NA, NA,
+ NA, NA),
+ PINGROUP(63, cdc_pdm0, pri_mi2s_data1_a, atest_char, NA, NA, NA, NA,
+ NA, NA),
+ PINGROUP(64, cdc_pdm0, NA, NA, NA, NA, NA, ebi0_wrcdc, NA, NA),
+ PINGROUP(65, blsp3_spi, blsp1_spi, qdss_tracedata_a, NA,
+ atest_gpsadc_dtest0_native, NA, NA, NA, NA),
+ PINGROUP(66, NA, gcc_plltest, NA, atest_combodac_to_gpio_native, NA,
+ NA, NA, NA, NA),
+ PINGROUP(67, NA, gcc_plltest, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(68, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(69, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(70, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(71, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(72, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(73, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(74, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(75, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(76, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(77, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(78, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(79, NA, NA, atest_gpsadc_dtest1_native, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(80, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(81, NA, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA,
+ NA),
+ PINGROUP(82, NA, pa_indicator, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(83, NA, modem_tsync, nav_tsync, nav_pps, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA),
+ PINGROUP(84, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(85, gsm0_tx, NA, NA, atest_combodac_to_gpio_native, NA, NA,
+ NA, NA, NA),
+ PINGROUP(86, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(87, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(88, NA, ssbi0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(89, NA, ssbi1, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(90, pbs0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(91, pbs1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(92, pbs2, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(93, qdss_tracedata_b, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(94, pri_mi2s_sck_b, pwr_modem_enabled_b, qdss_tracedata_a, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA),
+ PINGROUP(95, blsp3_spi, pri_mi2s_data0_b, ebi2_lcd, m_voc,
+ pwr_nav_enabled_b, NA, atest_combodac_to_gpio_native, NA, NA),
+ PINGROUP(96, pri_mi2s_data1_b, NA, pwr_crypto_enabled_b,
+ qdss_tracedata_a, NA, atest_wlan0, NA, NA, NA),
+ PINGROUP(97, blsp1_spi, qdss_tracedata_a, NA, atest_wlan1, NA, NA, NA,
+ NA, NA),
+ PINGROUP(98, sec_mi2s, pri_mi2s_mclk_b, blsp2_spi, ldo_update, NA, NA,
+ NA, NA, NA),
+ PINGROUP(99, ebi2_a, sd_write, ldo_en, NA, NA, NA, NA, NA, NA),
+ PINGROUP(100, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(101, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(102, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(103, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(104, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(105, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(106, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(107, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(108, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(109, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(110, pri_mi2s_ws_b, NA, atest_combodac_to_gpio_native, NA, NA,
+ NA, NA, NA, NA),
+ PINGROUP(111, blsp_spi2, blsp_uart2, blsp_i2c2, NA, NA, NA, NA, NA, NA),
+ PINGROUP(112, blsp_spi2, blsp_uart2, blsp_i2c2, NA, NA, NA, NA, NA, NA),
+ SDC_QDSD_PINGROUP(sdc1_clk, 0x10a000, 13, 6),
+ SDC_QDSD_PINGROUP(sdc1_cmd, 0x10a000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc1_data, 0x10a000, 9, 0),
+ SDC_QDSD_PINGROUP(sdc2_clk, 0x109000, 14, 6),
+ SDC_QDSD_PINGROUP(sdc2_cmd, 0x109000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc2_data, 0x109000, 9, 0),
+ SDC_QDSD_PINGROUP(qdsd_clk, 0x19c000, 3, 0),
+ SDC_QDSD_PINGROUP(qdsd_cmd, 0x19c000, 8, 5),
+ SDC_QDSD_PINGROUP(qdsd_data0, 0x19c000, 13, 10),
+ SDC_QDSD_PINGROUP(qdsd_data1, 0x19c000, 18, 15),
+ SDC_QDSD_PINGROUP(qdsd_data2, 0x19c000, 23, 20),
+ SDC_QDSD_PINGROUP(qdsd_data3, 0x19c000, 28, 25),
+};
+
+static const struct msm_pinctrl_soc_data msm8909_pinctrl = {
+ .pins = msm8909_pins,
+ .npins = ARRAY_SIZE(msm8909_pins),
+ .functions = msm8909_functions,
+ .nfunctions = ARRAY_SIZE(msm8909_functions),
+ .groups = msm8909_groups,
+ .ngroups = ARRAY_SIZE(msm8909_groups),
+ .ngpios = 113,
+};
+
+static int msm8909_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &msm8909_pinctrl);
+}
+
+static const struct of_device_id msm8909_pinctrl_of_match[] = {
+ { .compatible = "qcom,msm8909-pinctrl", },
+ { },
+};
+
+static struct platform_driver msm8909_pinctrl_driver = {
+ .driver = {
+ .name = "msm8909-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = msm8909_pinctrl_of_match,
+ },
+ .probe = msm8909_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init msm8909_pinctrl_init(void)
+{
+ return platform_driver_register(&msm8909_pinctrl_driver);
+}
+arch_initcall(msm8909_pinctrl_init);
+
+static void __exit msm8909_pinctrl_exit(void)
+{
+ platform_driver_unregister(&msm8909_pinctrl_driver);
+}
+module_exit(msm8909_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI msm8909 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, msm8909_pinctrl_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8917.c b/drivers/pinctrl/qcom/pinctrl-msm8917.c
new file mode 100644
index 0000000..1c0c64c
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-msm8917.c
@@ -0,0 +1,1474 @@
+/* Copyright (c) 2015-2016, 2018, 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/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define REG_BASE 0x0
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = REG_BASE + REG_SIZE * id, \
+ .io_reg = REG_BASE + 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .intr_status_reg = REG_BASE + 0xc + REG_SIZE * id, \
+ .intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 4, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+static const struct pinctrl_pin_desc msm8917_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "SDC1_CLK"),
+ PINCTRL_PIN(135, "SDC1_CMD"),
+ PINCTRL_PIN(136, "SDC1_DATA"),
+ PINCTRL_PIN(137, "SDC1_RCLK"),
+ PINCTRL_PIN(138, "SDC2_CLK"),
+ PINCTRL_PIN(139, "SDC2_CMD"),
+ PINCTRL_PIN(140, "SDC2_DATA"),
+ PINCTRL_PIN(141, "QDSD_CLK"),
+ PINCTRL_PIN(142, "QDSD_CMD"),
+ PINCTRL_PIN(143, "QDSD_DATA0"),
+ PINCTRL_PIN(144, "QDSD_DATA1"),
+ PINCTRL_PIN(145, "QDSD_DATA2"),
+ PINCTRL_PIN(146, "QDSD_DATA3"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+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);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+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);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+
+static const unsigned int sdc1_clk_pins[] = { 134 };
+static const unsigned int sdc1_cmd_pins[] = { 135 };
+static const unsigned int sdc1_data_pins[] = { 136 };
+static const unsigned int sdc1_rclk_pins[] = { 137 };
+static const unsigned int sdc2_clk_pins[] = { 138 };
+static const unsigned int sdc2_cmd_pins[] = { 139 };
+static const unsigned int sdc2_data_pins[] = { 140 };
+static const unsigned int qdsd_clk_pins[] = { 141 };
+static const unsigned int qdsd_cmd_pins[] = { 142 };
+static const unsigned int qdsd_data0_pins[] = { 143 };
+static const unsigned int qdsd_data1_pins[] = { 144 };
+static const unsigned int qdsd_data2_pins[] = { 145 };
+static const unsigned int qdsd_data3_pins[] = { 146 };
+
+enum msm8917_functions {
+ msm_mux_qdss_tracedata_b,
+ msm_mux_blsp_uart1,
+ msm_mux_gpio,
+ msm_mux_blsp_spi1,
+ msm_mux_adsp_ext,
+ msm_mux_blsp_i2c1,
+ msm_mux_prng_rosc,
+ msm_mux_qdss_cti_trig_out_b0,
+ msm_mux_blsp_spi2,
+ msm_mux_blsp_uart2,
+ msm_mux_blsp_uart3,
+ msm_mux_pbs0,
+ msm_mux_pbs1,
+ msm_mux_pwr_modem_enabled_b,
+ msm_mux_blsp_i2c3,
+ msm_mux_gcc_gp2_clk_b,
+ msm_mux_ldo_update,
+ msm_mux_atest_combodac_to_gpio_native,
+ msm_mux_ldo_en,
+ msm_mux_blsp_i2c2,
+ msm_mux_gcc_gp1_clk_b,
+ msm_mux_pbs2,
+ msm_mux_atest_gpsadc_dtest0_native,
+ msm_mux_blsp_spi3,
+ msm_mux_gcc_gp3_clk_b,
+ msm_mux_blsp_spi4,
+ msm_mux_blsp_uart4,
+ msm_mux_sec_mi2s,
+ msm_mux_pwr_nav_enabled_b,
+ msm_mux_codec_mad,
+ msm_mux_pwr_crypto_enabled_b,
+ msm_mux_blsp_i2c4,
+ msm_mux_blsp_spi5,
+ msm_mux_blsp_uart5,
+ msm_mux_qdss_traceclk_a,
+ msm_mux_atest_bbrx1,
+ msm_mux_m_voc,
+ msm_mux_qdss_cti_trig_in_a0,
+ msm_mux_qdss_cti_trig_in_b0,
+ msm_mux_blsp_i2c6,
+ msm_mux_qdss_traceclk_b,
+ msm_mux_atest_wlan0,
+ msm_mux_atest_bbrx0,
+ msm_mux_blsp_i2c5,
+ msm_mux_qdss_tracectl_a,
+ msm_mux_atest_gpsadc_dtest1_native,
+ msm_mux_qdss_tracedata_a,
+ msm_mux_blsp_spi6,
+ msm_mux_blsp_uart6,
+ msm_mux_qdss_tracectl_b,
+ msm_mux_atest_wlan1,
+ msm_mux_mdp_vsync,
+ msm_mux_pri_mi2s_mclk_a,
+ msm_mux_sec_mi2s_mclk_a,
+ msm_mux_cam_mclk,
+ msm_mux_cci_i2c,
+ msm_mux_pwr_modem_enabled_a,
+ msm_mux_cci_timer0,
+ msm_mux_cci_timer1,
+ msm_mux_cam1_standby,
+ msm_mux_pwr_nav_enabled_a,
+ msm_mux_cam1_rst,
+ msm_mux_pwr_crypto_enabled_a,
+ msm_mux_forced_usb,
+ msm_mux_qdss_cti_trig_out_b1,
+ msm_mux_cam2_rst,
+ msm_mux_webcam_standby,
+ msm_mux_cci_async,
+ msm_mux_webcam_rst,
+ msm_mux_ov_ldo,
+ msm_mux_sd_write,
+ msm_mux_accel_int,
+ msm_mux_gcc_gp1_clk_a,
+ msm_mux_alsp_int,
+ msm_mux_gcc_gp2_clk_a,
+ msm_mux_mag_int,
+ msm_mux_gcc_gp3_clk_a,
+ msm_mux_blsp6_spi,
+ msm_mux_fp_int,
+ msm_mux_qdss_cti_trig_in_b1,
+ msm_mux_uim_batt,
+ msm_mux_cam2_standby,
+ msm_mux_uim1_data,
+ msm_mux_uim1_clk,
+ msm_mux_uim1_reset,
+ msm_mux_uim1_present,
+ msm_mux_uim2_data,
+ msm_mux_uim2_clk,
+ msm_mux_uim2_reset,
+ msm_mux_uim2_present,
+ msm_mux_sensor_rst,
+ msm_mux_mipi_dsi0,
+ msm_mux_smb_int,
+ msm_mux_cam0_ldo,
+ msm_mux_us_euro,
+ msm_mux_atest_char3,
+ msm_mux_dbg_out,
+ msm_mux_bimc_dte0,
+ msm_mux_ts_resout,
+ msm_mux_ts_sample,
+ msm_mux_sec_mi2s_mclk_b,
+ msm_mux_pri_mi2s,
+ msm_mux_sdcard_det,
+ msm_mux_atest_char1,
+ msm_mux_ebi_cdc,
+ msm_mux_audio_reset,
+ msm_mux_atest_char0,
+ msm_mux_audio_ref,
+ msm_mux_cdc_pdm0,
+ msm_mux_pri_mi2s_mclk_b,
+ msm_mux_lpass_slimbus,
+ msm_mux_lpass_slimbus0,
+ msm_mux_lpass_slimbus1,
+ msm_mux_codec_int1,
+ msm_mux_codec_int2,
+ msm_mux_wcss_bt,
+ msm_mux_atest_char2,
+ msm_mux_ebi_ch0,
+ msm_mux_wcss_wlan2,
+ msm_mux_wcss_wlan1,
+ msm_mux_wcss_wlan0,
+ msm_mux_wcss_wlan,
+ msm_mux_wcss_fm,
+ msm_mux_ext_lpass,
+ msm_mux_cri_trng,
+ msm_mux_cri_trng1,
+ msm_mux_cri_trng0,
+ msm_mux_blsp_spi7,
+ msm_mux_blsp_uart7,
+ msm_mux_pri_mi2s_ws,
+ msm_mux_blsp_i2c7,
+ msm_mux_gcc_tlmm,
+ msm_mux_dmic0_clk,
+ msm_mux_dmic0_data,
+ msm_mux_key_volp,
+ msm_mux_qdss_cti_trig_in_a1,
+ msm_mux_us_emitter,
+ msm_mux_wsa_irq,
+ msm_mux_wsa_io,
+ msm_mux_blsp_spi8,
+ msm_mux_blsp_uart8,
+ msm_mux_blsp_i2c8,
+ msm_mux_gcc_plltest,
+ msm_mux_nav_pps_in_a,
+ msm_mux_pa_indicator,
+ msm_mux_modem_tsync,
+ msm_mux_nav_tsync,
+ msm_mux_nav_pps_in_b,
+ msm_mux_nav_pps,
+ msm_mux_gsm0_tx,
+ msm_mux_atest_char,
+ msm_mux_atest_tsens,
+ msm_mux_bimc_dte1,
+ msm_mux_ssbi_wtr1,
+ msm_mux_fp_gpio,
+ msm_mux_coex_uart,
+ msm_mux_key_snapshot,
+ msm_mux_key_focus,
+ msm_mux_nfc_pwr,
+ msm_mux_blsp8_spi,
+ msm_mux_qdss_cti_trig_out_a0,
+ msm_mux_qdss_cti_trig_out_a1,
+ msm_mux_NA,
+};
+
+static const char * const qdss_tracedata_b_groups[] = {
+ "gpio0", "gpio1", "gpio6", "gpio7", "gpio12", "gpio13", "gpio23",
+ "gpio42", "gpio43", "gpio44", "gpio47", "gpio66", "gpio86", "gpio87",
+ "gpio88", "gpio92",
+};
+static const char * const blsp_uart1_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "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", "gpio104",
+ "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",
+};
+static const char * const blsp_spi1_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const adsp_ext_groups[] = {
+ "gpio1",
+};
+static const char * const blsp_i2c1_groups[] = {
+ "gpio2", "gpio3",
+};
+static const char * const prng_rosc_groups[] = {
+ "gpio2",
+};
+static const char * const qdss_cti_trig_out_b0_groups[] = {
+ "gpio2",
+};
+static const char * const blsp_spi2_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart2_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart3_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const pbs0_groups[] = {
+ "gpio8",
+};
+static const char * const pbs1_groups[] = {
+ "gpio9",
+};
+static const char * const pwr_modem_enabled_b_groups[] = {
+ "gpio9",
+};
+static const char * const blsp_i2c3_groups[] = {
+ "gpio10", "gpio11",
+};
+static const char * const gcc_gp2_clk_b_groups[] = {
+ "gpio10",
+};
+static const char * const ldo_update_groups[] = {
+ "gpio4",
+};
+static const char * const atest_combodac_to_gpio_native_groups[] = {
+ "gpio4", "gpio12", "gpio13", "gpio20", "gpio21", "gpio28", "gpio29",
+ "gpio30", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43", "gpio44",
+ "gpio45", "gpio46", "gpio47", "gpio48", "gpio67", "gpio115",
+};
+static const char * const ldo_en_groups[] = {
+ "gpio5",
+};
+static const char * const blsp_i2c2_groups[] = {
+ "gpio6", "gpio7",
+};
+static const char * const gcc_gp1_clk_b_groups[] = {
+ "gpio6",
+};
+static const char * const pbs2_groups[] = {
+ "gpio7",
+};
+static const char * const atest_gpsadc_dtest0_native_groups[] = {
+ "gpio7",
+};
+static const char * const blsp_spi3_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const gcc_gp3_clk_b_groups[] = {
+ "gpio11",
+};
+static const char * const blsp_spi4_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15",
+};
+static const char * const blsp_uart4_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15",
+};
+static const char * const sec_mi2s_groups[] = {
+ "gpio12", "gpio13", "gpio94", "gpio95",
+};
+static const char * const pwr_nav_enabled_b_groups[] = {
+ "gpio12",
+};
+static const char * const codec_mad_groups[] = {
+ "gpio13",
+};
+static const char * const pwr_crypto_enabled_b_groups[] = {
+ "gpio13",
+};
+static const char * const blsp_i2c4_groups[] = {
+ "gpio14", "gpio15",
+};
+static const char * const blsp_spi5_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const blsp_uart5_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const qdss_traceclk_a_groups[] = {
+ "gpio16",
+};
+static const char * const atest_bbrx1_groups[] = {
+ "gpio16",
+};
+static const char * const m_voc_groups[] = {
+ "gpio17", "gpio21",
+};
+static const char * const qdss_cti_trig_in_a0_groups[] = {
+ "gpio17",
+};
+static const char * const qdss_cti_trig_in_b0_groups[] = {
+ "gpio21",
+};
+static const char * const blsp_i2c6_groups[] = {
+ "gpio22", "gpio23",
+};
+static const char * const qdss_traceclk_b_groups[] = {
+ "gpio22",
+};
+static const char * const atest_wlan0_groups[] = {
+ "gpio22",
+};
+static const char * const atest_bbrx0_groups[] = {
+ "gpio17",
+};
+static const char * const blsp_i2c5_groups[] = {
+ "gpio18", "gpio19",
+};
+static const char * const qdss_tracectl_a_groups[] = {
+ "gpio18",
+};
+static const char * const atest_gpsadc_dtest1_native_groups[] = {
+ "gpio18",
+};
+static const char * const qdss_tracedata_a_groups[] = {
+ "gpio19", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31",
+ "gpio32", "gpio33", "gpio34", "gpio35", "gpio36", "gpio38", "gpio39",
+ "gpio40", "gpio50",
+};
+static const char * const blsp_spi6_groups[] = {
+ "gpio20", "gpio21", "gpio22", "gpio23",
+};
+static const char * const blsp_uart6_groups[] = {
+ "gpio20", "gpio21", "gpio22", "gpio23",
+};
+static const char * const qdss_tracectl_b_groups[] = {
+ "gpio20",
+};
+static const char * const atest_wlan1_groups[] = {
+ "gpio23",
+};
+static const char * const mdp_vsync_groups[] = {
+ "gpio24", "gpio25",
+};
+static const char * const pri_mi2s_mclk_a_groups[] = {
+ "gpio25",
+};
+static const char * const sec_mi2s_mclk_a_groups[] = {
+ "gpio25",
+};
+static const char * const cam_mclk_groups[] = {
+ "gpio26", "gpio27", "gpio28",
+};
+static const char * const cci_i2c_groups[] = {
+ "gpio29", "gpio30", "gpio31", "gpio32",
+};
+static const char * const pwr_modem_enabled_a_groups[] = {
+ "gpio29",
+};
+static const char * const cci_timer0_groups[] = {
+ "gpio33",
+};
+static const char * const cci_timer1_groups[] = {
+ "gpio34",
+};
+static const char * const cam1_standby_groups[] = {
+ "gpio35",
+};
+static const char * const pwr_nav_enabled_a_groups[] = {
+ "gpio35",
+};
+static const char * const cam1_rst_groups[] = {
+ "gpio36",
+};
+static const char * const pwr_crypto_enabled_a_groups[] = {
+ "gpio36",
+};
+static const char * const forced_usb_groups[] = {
+ "gpio37",
+};
+static const char * const qdss_cti_trig_out_b1_groups[] = {
+ "gpio37",
+};
+static const char * const cam2_rst_groups[] = {
+ "gpio38",
+};
+static const char * const webcam_standby_groups[] = {
+ "gpio39",
+};
+static const char * const cci_async_groups[] = {
+ "gpio39",
+};
+static const char * const webcam_rst_groups[] = {
+ "gpio40",
+};
+static const char * const ov_ldo_groups[] = {
+ "gpio41",
+};
+static const char * const sd_write_groups[] = {
+ "gpio41",
+};
+static const char * const accel_int_groups[] = {
+ "gpio42",
+};
+static const char * const gcc_gp1_clk_a_groups[] = {
+ "gpio42",
+};
+static const char * const alsp_int_groups[] = {
+ "gpio43",
+};
+static const char * const gcc_gp2_clk_a_groups[] = {
+ "gpio43",
+};
+static const char * const mag_int_groups[] = {
+ "gpio44",
+};
+static const char * const gcc_gp3_clk_a_groups[] = {
+ "gpio44",
+};
+static const char * const blsp6_spi_groups[] = {
+ "gpio47",
+};
+static const char * const fp_int_groups[] = {
+ "gpio48",
+};
+static const char * const qdss_cti_trig_in_b1_groups[] = {
+ "gpio48",
+};
+static const char * const uim_batt_groups[] = {
+ "gpio49",
+};
+static const char * const cam2_standby_groups[] = {
+ "gpio50",
+};
+static const char * const uim1_data_groups[] = {
+ "gpio51",
+};
+static const char * const uim1_clk_groups[] = {
+ "gpio52",
+};
+static const char * const uim1_reset_groups[] = {
+ "gpio53",
+};
+static const char * const uim1_present_groups[] = {
+ "gpio54",
+};
+static const char * const uim2_data_groups[] = {
+ "gpio55",
+};
+static const char * const uim2_clk_groups[] = {
+ "gpio56",
+};
+static const char * const uim2_reset_groups[] = {
+ "gpio57",
+};
+static const char * const uim2_present_groups[] = {
+ "gpio58",
+};
+static const char * const sensor_rst_groups[] = {
+ "gpio59",
+};
+static const char * const mipi_dsi0_groups[] = {
+ "gpio60",
+};
+static const char * const smb_int_groups[] = {
+ "gpio61",
+};
+static const char * const cam0_ldo_groups[] = {
+ "gpio62",
+};
+static const char * const us_euro_groups[] = {
+ "gpio63",
+};
+static const char * const atest_char3_groups[] = {
+ "gpio63",
+};
+static const char * const dbg_out_groups[] = {
+ "gpio63",
+};
+static const char * const bimc_dte0_groups[] = {
+ "gpio63", "gpio65",
+};
+static const char * const ts_resout_groups[] = {
+ "gpio64",
+};
+static const char * const ts_sample_groups[] = {
+ "gpio65",
+};
+static const char * const sec_mi2s_mclk_b_groups[] = {
+ "gpio66",
+};
+static const char * const pri_mi2s_groups[] = {
+ "gpio66", "gpio85", "gpio86", "gpio88", "gpio94", "gpio95",
+};
+static const char * const sdcard_det_groups[] = {
+ "gpio67",
+};
+static const char * const atest_char1_groups[] = {
+ "gpio67",
+};
+static const char * const ebi_cdc_groups[] = {
+ "gpio67", "gpio69", "gpio118", "gpio119", "gpio120", "gpio123",
+};
+static const char * const audio_reset_groups[] = {
+ "gpio68",
+};
+static const char * const atest_char0_groups[] = {
+ "gpio68",
+};
+static const char * const audio_ref_groups[] = {
+ "gpio69",
+};
+static const char * const cdc_pdm0_groups[] = {
+ "gpio69", "gpio70", "gpio71", "gpio72", "gpio73", "gpio74",
+};
+static const char * const pri_mi2s_mclk_b_groups[] = {
+ "gpio69",
+};
+static const char * const lpass_slimbus_groups[] = {
+ "gpio70",
+};
+static const char * const lpass_slimbus0_groups[] = {
+ "gpio71",
+};
+static const char * const lpass_slimbus1_groups[] = {
+ "gpio72",
+};
+static const char * const codec_int1_groups[] = {
+ "gpio73",
+};
+static const char * const codec_int2_groups[] = {
+ "gpio74",
+};
+static const char * const wcss_bt_groups[] = {
+ "gpio75", "gpio83", "gpio84",
+};
+static const char * const atest_char2_groups[] = {
+ "gpio75",
+};
+static const char * const ebi_ch0_groups[] = {
+ "gpio75",
+};
+static const char * const wcss_wlan2_groups[] = {
+ "gpio76",
+};
+static const char * const wcss_wlan1_groups[] = {
+ "gpio77",
+};
+static const char * const wcss_wlan0_groups[] = {
+ "gpio78",
+};
+static const char * const wcss_wlan_groups[] = {
+ "gpio79", "gpio80",
+};
+static const char * const wcss_fm_groups[] = {
+ "gpio81", "gpio82",
+};
+static const char * const ext_lpass_groups[] = {
+ "gpio81",
+};
+static const char * const cri_trng_groups[] = {
+ "gpio82",
+};
+static const char * const cri_trng1_groups[] = {
+ "gpio83",
+};
+static const char * const cri_trng0_groups[] = {
+ "gpio84",
+};
+static const char * const blsp_spi7_groups[] = {
+ "gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const blsp_uart7_groups[] = {
+ "gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const pri_mi2s_ws_groups[] = {
+ "gpio87",
+};
+static const char * const blsp_i2c7_groups[] = {
+ "gpio87", "gpio88",
+};
+static const char * const gcc_tlmm_groups[] = {
+ "gpio87",
+};
+static const char * const dmic0_clk_groups[] = {
+ "gpio89",
+};
+static const char * const dmic0_data_groups[] = {
+ "gpio90",
+};
+static const char * const key_volp_groups[] = {
+ "gpio91",
+};
+static const char * const qdss_cti_trig_in_a1_groups[] = {
+ "gpio91",
+};
+static const char * const us_emitter_groups[] = {
+ "gpio92",
+};
+static const char * const wsa_irq_groups[] = {
+ "gpio93",
+};
+static const char * const wsa_io_groups[] = {
+ "gpio94", "gpio95",
+};
+static const char * const blsp_spi8_groups[] = {
+ "gpio96", "gpio97", "gpio98", "gpio99",
+};
+static const char * const blsp_uart8_groups[] = {
+ "gpio96", "gpio97", "gpio98", "gpio99",
+};
+static const char * const blsp_i2c8_groups[] = {
+ "gpio98", "gpio99",
+};
+static const char * const gcc_plltest_groups[] = {
+ "gpio98", "gpio99",
+};
+static const char * const nav_pps_in_a_groups[] = {
+ "gpio115",
+};
+static const char * const pa_indicator_groups[] = {
+ "gpio116",
+};
+static const char * const modem_tsync_groups[] = {
+ "gpio117",
+};
+static const char * const nav_tsync_groups[] = {
+ "gpio117",
+};
+static const char * const nav_pps_in_b_groups[] = {
+ "gpio117",
+};
+static const char * const nav_pps_groups[] = {
+ "gpio117",
+};
+static const char * const gsm0_tx_groups[] = {
+ "gpio119",
+};
+static const char * const atest_char_groups[] = {
+ "gpio120",
+};
+static const char * const atest_tsens_groups[] = {
+ "gpio120",
+};
+static const char * const bimc_dte1_groups[] = {
+ "gpio121", "gpio122",
+};
+static const char * const ssbi_wtr1_groups[] = {
+ "gpio122", "gpio123",
+};
+static const char * const fp_gpio_groups[] = {
+ "gpio124",
+};
+static const char * const coex_uart_groups[] = {
+ "gpio124", "gpio127",
+};
+static const char * const key_snapshot_groups[] = {
+ "gpio127",
+};
+static const char * const key_focus_groups[] = {
+ "gpio128",
+};
+static const char * const nfc_pwr_groups[] = {
+ "gpio129",
+};
+static const char * const blsp8_spi_groups[] = {
+ "gpio130",
+};
+static const char * const qdss_cti_trig_out_a0_groups[] = {
+ "gpio132",
+};
+static const char * const qdss_cti_trig_out_a1_groups[] = {
+ "gpio133",
+};
+
+static const struct msm_function msm8917_functions[] = {
+ FUNCTION(qdss_tracedata_b),
+ FUNCTION(blsp_uart1),
+ FUNCTION(gpio),
+ FUNCTION(blsp_spi1),
+ FUNCTION(adsp_ext),
+ FUNCTION(blsp_i2c1),
+ FUNCTION(prng_rosc),
+ FUNCTION(qdss_cti_trig_out_b0),
+ FUNCTION(blsp_spi2),
+ FUNCTION(blsp_uart2),
+ FUNCTION(blsp_uart3),
+ FUNCTION(pbs0),
+ FUNCTION(pbs1),
+ FUNCTION(pwr_modem_enabled_b),
+ FUNCTION(blsp_i2c3),
+ FUNCTION(gcc_gp2_clk_b),
+ FUNCTION(ldo_update),
+ FUNCTION(atest_combodac_to_gpio_native),
+ FUNCTION(ldo_en),
+ FUNCTION(blsp_i2c2),
+ FUNCTION(gcc_gp1_clk_b),
+ FUNCTION(pbs2),
+ FUNCTION(atest_gpsadc_dtest0_native),
+ FUNCTION(blsp_spi3),
+ FUNCTION(gcc_gp3_clk_b),
+ FUNCTION(blsp_spi4),
+ FUNCTION(blsp_uart4),
+ FUNCTION(sec_mi2s),
+ FUNCTION(pwr_nav_enabled_b),
+ FUNCTION(codec_mad),
+ FUNCTION(pwr_crypto_enabled_b),
+ FUNCTION(blsp_i2c4),
+ FUNCTION(blsp_spi5),
+ FUNCTION(blsp_uart5),
+ FUNCTION(qdss_traceclk_a),
+ FUNCTION(atest_bbrx1),
+ FUNCTION(m_voc),
+ FUNCTION(qdss_cti_trig_in_a0),
+ FUNCTION(qdss_cti_trig_in_b0),
+ FUNCTION(blsp_i2c6),
+ FUNCTION(qdss_traceclk_b),
+ FUNCTION(atest_wlan0),
+ FUNCTION(atest_bbrx0),
+ FUNCTION(blsp_i2c5),
+ FUNCTION(qdss_tracectl_a),
+ FUNCTION(atest_gpsadc_dtest1_native),
+ FUNCTION(qdss_tracedata_a),
+ FUNCTION(blsp_spi6),
+ FUNCTION(blsp_uart6),
+ FUNCTION(qdss_tracectl_b),
+ FUNCTION(atest_wlan1),
+ FUNCTION(mdp_vsync),
+ FUNCTION(pri_mi2s_mclk_a),
+ FUNCTION(sec_mi2s_mclk_a),
+ FUNCTION(cam_mclk),
+ FUNCTION(cci_i2c),
+ FUNCTION(pwr_modem_enabled_a),
+ FUNCTION(cci_timer0),
+ FUNCTION(cci_timer1),
+ FUNCTION(cam1_standby),
+ FUNCTION(pwr_nav_enabled_a),
+ FUNCTION(cam1_rst),
+ FUNCTION(pwr_crypto_enabled_a),
+ FUNCTION(forced_usb),
+ FUNCTION(qdss_cti_trig_out_b1),
+ FUNCTION(cam2_rst),
+ FUNCTION(webcam_standby),
+ FUNCTION(cci_async),
+ FUNCTION(webcam_rst),
+ FUNCTION(ov_ldo),
+ FUNCTION(sd_write),
+ FUNCTION(accel_int),
+ FUNCTION(gcc_gp1_clk_a),
+ FUNCTION(alsp_int),
+ FUNCTION(gcc_gp2_clk_a),
+ FUNCTION(mag_int),
+ FUNCTION(gcc_gp3_clk_a),
+ FUNCTION(blsp6_spi),
+ FUNCTION(fp_int),
+ FUNCTION(qdss_cti_trig_in_b1),
+ FUNCTION(uim_batt),
+ FUNCTION(cam2_standby),
+ FUNCTION(uim1_data),
+ FUNCTION(uim1_clk),
+ FUNCTION(uim1_reset),
+ FUNCTION(uim1_present),
+ FUNCTION(uim2_data),
+ FUNCTION(uim2_clk),
+ FUNCTION(uim2_reset),
+ FUNCTION(uim2_present),
+ FUNCTION(sensor_rst),
+ FUNCTION(mipi_dsi0),
+ FUNCTION(smb_int),
+ FUNCTION(cam0_ldo),
+ FUNCTION(us_euro),
+ FUNCTION(atest_char3),
+ FUNCTION(dbg_out),
+ FUNCTION(bimc_dte0),
+ FUNCTION(ts_resout),
+ FUNCTION(ts_sample),
+ FUNCTION(sec_mi2s_mclk_b),
+ FUNCTION(pri_mi2s),
+ FUNCTION(sdcard_det),
+ FUNCTION(atest_char1),
+ FUNCTION(ebi_cdc),
+ FUNCTION(audio_reset),
+ FUNCTION(atest_char0),
+ FUNCTION(audio_ref),
+ FUNCTION(cdc_pdm0),
+ FUNCTION(pri_mi2s_mclk_b),
+ FUNCTION(lpass_slimbus),
+ FUNCTION(lpass_slimbus0),
+ FUNCTION(lpass_slimbus1),
+ FUNCTION(codec_int1),
+ FUNCTION(codec_int2),
+ FUNCTION(wcss_bt),
+ FUNCTION(atest_char2),
+ FUNCTION(ebi_ch0),
+ FUNCTION(wcss_wlan2),
+ FUNCTION(wcss_wlan1),
+ FUNCTION(wcss_wlan0),
+ FUNCTION(wcss_wlan),
+ FUNCTION(wcss_fm),
+ FUNCTION(ext_lpass),
+ FUNCTION(cri_trng),
+ FUNCTION(cri_trng1),
+ FUNCTION(cri_trng0),
+ FUNCTION(blsp_spi7),
+ FUNCTION(blsp_uart7),
+ FUNCTION(pri_mi2s_ws),
+ FUNCTION(blsp_i2c7),
+ FUNCTION(gcc_tlmm),
+ FUNCTION(dmic0_clk),
+ FUNCTION(dmic0_data),
+ FUNCTION(key_volp),
+ FUNCTION(qdss_cti_trig_in_a1),
+ FUNCTION(us_emitter),
+ FUNCTION(wsa_irq),
+ FUNCTION(wsa_io),
+ FUNCTION(blsp_spi8),
+ FUNCTION(blsp_uart8),
+ FUNCTION(blsp_i2c8),
+ FUNCTION(gcc_plltest),
+ FUNCTION(nav_pps_in_a),
+ FUNCTION(pa_indicator),
+ FUNCTION(modem_tsync),
+ FUNCTION(nav_tsync),
+ FUNCTION(nav_pps_in_b),
+ FUNCTION(nav_pps),
+ FUNCTION(gsm0_tx),
+ FUNCTION(atest_char),
+ FUNCTION(atest_tsens),
+ FUNCTION(bimc_dte1),
+ FUNCTION(ssbi_wtr1),
+ FUNCTION(fp_gpio),
+ FUNCTION(coex_uart),
+ FUNCTION(key_snapshot),
+ FUNCTION(key_focus),
+ FUNCTION(nfc_pwr),
+ FUNCTION(blsp8_spi),
+ FUNCTION(qdss_cti_trig_out_a0),
+ FUNCTION(qdss_cti_trig_out_a1),
+};
+
+static const struct msm_pingroup msm8917_groups[] = {
+ PINGROUP(0, blsp_spi1, blsp_uart1, qdss_tracedata_b, NA, NA, NA, NA,
+ NA, NA),
+ PINGROUP(1, blsp_spi1, blsp_uart1, adsp_ext, NA, NA, NA, NA, NA,
+ qdss_tracedata_b),
+ PINGROUP(2, blsp_spi1, blsp_uart1, blsp_i2c1, prng_rosc, NA, NA, NA,
+ NA, NA),
+ PINGROUP(3, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(4, blsp_spi2, blsp_uart2, ldo_update, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA),
+ PINGROUP(5, blsp_spi2, blsp_uart2, ldo_en, NA, NA, NA, NA, NA, NA),
+ PINGROUP(6, blsp_spi2, blsp_uart2, blsp_i2c2, gcc_gp1_clk_b,
+ qdss_tracedata_b, NA, NA, NA, NA),
+ PINGROUP(7, blsp_spi2, blsp_uart2, blsp_i2c2, pbs2, NA,
+ qdss_tracedata_b, NA, atest_gpsadc_dtest0_native, NA),
+ PINGROUP(8, blsp_spi3, blsp_uart3, pbs0, NA, NA, NA, NA, NA, NA),
+ PINGROUP(9, blsp_spi3, blsp_uart3, pbs1, pwr_modem_enabled_b, NA, NA,
+ NA, NA, NA),
+ PINGROUP(10, blsp_spi3, blsp_uart3, blsp_i2c3, gcc_gp2_clk_b, NA, NA,
+ NA, NA, NA),
+ PINGROUP(11, blsp_spi3, blsp_uart3, blsp_i2c3, gcc_gp3_clk_b, NA, NA,
+ NA, NA, NA),
+ PINGROUP(12, blsp_spi4, blsp_uart4, sec_mi2s, pwr_nav_enabled_b, NA,
+ NA, NA, NA, NA),
+ PINGROUP(13, blsp_spi4, blsp_uart4, sec_mi2s, pwr_crypto_enabled_b, NA,
+ NA, NA, NA, NA),
+ PINGROUP(14, blsp_spi4, blsp_uart4, blsp_i2c4, NA, NA, NA, NA, NA, NA),
+ PINGROUP(15, blsp_spi4, blsp_uart4, blsp_i2c4, NA, NA, NA, NA, NA, NA),
+ PINGROUP(16, blsp_spi5, blsp_uart5, NA, NA, NA, NA, qdss_traceclk_a,
+ NA, atest_bbrx1),
+ PINGROUP(17, blsp_spi5, blsp_uart5, m_voc, qdss_cti_trig_in_a0, NA,
+ atest_bbrx0, NA, NA, NA),
+ PINGROUP(18, blsp_spi5, blsp_uart5, blsp_i2c5, qdss_tracectl_a, NA,
+ atest_gpsadc_dtest1_native, NA, NA, NA),
+ PINGROUP(19, blsp_spi5, blsp_uart5, blsp_i2c5, qdss_tracedata_a, NA,
+ NA, NA, NA, NA),
+ PINGROUP(20, blsp_spi6, blsp_uart6, NA, NA, NA, NA, NA, NA,
+ qdss_tracectl_b),
+ PINGROUP(21, blsp_spi6, blsp_uart6, m_voc, NA, NA, NA, NA, NA,
+ qdss_cti_trig_in_b0),
+ PINGROUP(22, blsp_spi6, blsp_uart6, blsp_i2c6, qdss_traceclk_b, NA,
+ atest_wlan0, NA, NA, NA),
+ PINGROUP(23, blsp_spi6, blsp_uart6, blsp_i2c6, qdss_tracedata_b, NA,
+ atest_wlan1, NA, NA, NA),
+ PINGROUP(24, mdp_vsync, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(25, mdp_vsync, pri_mi2s_mclk_a, sec_mi2s_mclk_a, NA, NA, NA,
+ NA, NA, NA),
+ PINGROUP(26, cam_mclk, NA, NA, NA, NA, NA, qdss_tracedata_a, NA, NA),
+ PINGROUP(27, cam_mclk, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+ PINGROUP(28, cam_mclk, NA, NA, NA, NA, NA, qdss_tracedata_a, NA,
+ atest_combodac_to_gpio_native),
+ PINGROUP(29, cci_i2c, pwr_modem_enabled_a, NA, NA, NA, NA, NA,
+ qdss_tracedata_a, NA),
+ PINGROUP(30, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+ PINGROUP(31, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+ PINGROUP(32, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+ PINGROUP(33, cci_timer0, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+ PINGROUP(34, cci_timer1, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+ PINGROUP(35, pwr_nav_enabled_a, NA, NA, NA, NA, NA, NA, NA,
+ qdss_tracedata_a),
+ PINGROUP(36, pwr_crypto_enabled_a, NA, NA, NA, NA, NA, NA, NA,
+ qdss_tracedata_a),
+ PINGROUP(37, NA, NA, NA, NA, NA, qdss_cti_trig_out_b1, NA, NA, NA),
+ PINGROUP(38, NA, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(39, cci_async, NA, NA, NA, NA, NA, qdss_tracedata_a, NA,
+ atest_combodac_to_gpio_native),
+ PINGROUP(40, NA, NA, NA, NA, qdss_tracedata_a, NA,
+ atest_combodac_to_gpio_native, NA, NA),
+ PINGROUP(41, sd_write, NA, NA, NA, NA, NA, NA, NA,
+ atest_combodac_to_gpio_native),
+ PINGROUP(42, gcc_gp1_clk_a, qdss_tracedata_b, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+ PINGROUP(43, gcc_gp2_clk_a, qdss_tracedata_b, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+ PINGROUP(44, gcc_gp3_clk_a, qdss_tracedata_b, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+ PINGROUP(45, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(46, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(47, blsp6_spi, NA, qdss_tracedata_b, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA),
+ PINGROUP(48, NA, qdss_cti_trig_in_b1, NA,
+ atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+ PINGROUP(49, uim_batt, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(50, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(51, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(52, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(53, uim1_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(54, uim1_present, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(55, uim2_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(56, uim2_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(57, uim2_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(58, uim2_present, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(59, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(60, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(61, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(62, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(63, atest_char3, dbg_out, bimc_dte0, NA, NA, NA, NA, NA, NA),
+ PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(65, bimc_dte0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(66, sec_mi2s_mclk_b, pri_mi2s, NA, qdss_tracedata_b, NA, NA,
+ NA, NA, NA),
+ PINGROUP(67, atest_char1, ebi_cdc, NA, atest_combodac_to_gpio_native,
+ NA, NA, NA, NA, NA),
+ PINGROUP(68, atest_char0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(69, audio_ref, cdc_pdm0, pri_mi2s_mclk_b, ebi_cdc, NA, NA, NA,
+ NA, NA),
+ PINGROUP(70, lpass_slimbus, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(71, lpass_slimbus0, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(72, lpass_slimbus1, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(73, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(74, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(75, wcss_bt, atest_char2, NA, ebi_ch0, NA, NA, NA, NA, NA),
+ PINGROUP(76, wcss_wlan2, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(77, wcss_wlan1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(78, wcss_wlan0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(79, wcss_wlan, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(80, wcss_wlan, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(81, wcss_fm, ext_lpass, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(82, wcss_fm, cri_trng, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(83, wcss_bt, cri_trng1, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(84, wcss_bt, cri_trng0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(85, pri_mi2s, blsp_spi7, blsp_uart7, NA, NA, NA, NA, NA, NA),
+ PINGROUP(86, pri_mi2s, blsp_spi7, blsp_uart7, qdss_tracedata_b, NA, NA,
+ NA, NA, NA),
+ PINGROUP(87, pri_mi2s_ws, blsp_spi7, blsp_uart7, blsp_i2c7,
+ qdss_tracedata_b, gcc_tlmm, NA, NA, NA),
+ PINGROUP(88, pri_mi2s, blsp_spi7, blsp_uart7, blsp_i2c7, NA, NA, NA,
+ NA, NA),
+ PINGROUP(89, dmic0_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(90, dmic0_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(91, NA, NA, NA, NA, NA, qdss_cti_trig_in_a1, NA, NA, NA),
+ PINGROUP(92, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA, NA),
+ PINGROUP(93, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(94, wsa_io, sec_mi2s, pri_mi2s, NA, NA, NA, NA, NA, NA),
+ PINGROUP(95, wsa_io, sec_mi2s, pri_mi2s, NA, NA, NA, NA, NA, NA),
+ PINGROUP(96, blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(97, blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(98, blsp_spi8, blsp_uart8, blsp_i2c8, gcc_plltest, NA, NA, NA,
+ NA, NA),
+ PINGROUP(99, blsp_spi8, blsp_uart8, blsp_i2c8, gcc_plltest, NA, NA, NA,
+ NA, NA),
+ PINGROUP(100, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(101, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(102, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(103, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(104, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(105, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(106, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(107, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(108, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(109, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(110, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(111, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(112, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(113, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(114, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(115, NA, NA, nav_pps_in_a, NA, atest_combodac_to_gpio_native,
+ NA, NA, NA, NA),
+ PINGROUP(116, NA, pa_indicator, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(117, NA, modem_tsync, nav_tsync, nav_pps_in_b, nav_pps, NA,
+ NA, NA, NA),
+ PINGROUP(118, NA, ebi_cdc, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(119, gsm0_tx, NA, ebi_cdc, NA, NA, NA, NA, NA, NA),
+ PINGROUP(120, NA, atest_char, ebi_cdc, NA, atest_tsens, NA, NA, NA, NA),
+ PINGROUP(121, NA, NA, NA, bimc_dte1, NA, NA, NA, NA, NA),
+ PINGROUP(122, NA, ssbi_wtr1, NA, NA, bimc_dte1, NA, NA, NA, NA),
+ PINGROUP(123, NA, ssbi_wtr1, ebi_cdc, NA, NA, NA, NA, NA, NA),
+ PINGROUP(124, coex_uart, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(125, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(126, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(127, coex_uart, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(128, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(129, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(130, blsp8_spi, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(131, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(132, qdss_cti_trig_out_a0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(133, qdss_cti_trig_out_a1, NA, NA, NA, NA, NA, NA, NA, NA),
+ SDC_QDSD_PINGROUP(sdc1_clk, 0x10a000, 13, 6),
+ SDC_QDSD_PINGROUP(sdc1_cmd, 0x10a000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc1_data, 0x10a000, 9, 0),
+ SDC_QDSD_PINGROUP(sdc1_rclk, 0x10a000, 15, 0),
+ SDC_QDSD_PINGROUP(sdc2_clk, 0x109000, 14, 6),
+ SDC_QDSD_PINGROUP(sdc2_cmd, 0x109000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc2_data, 0x109000, 9, 0),
+ SDC_QDSD_PINGROUP(qdsd_clk, 0x19c000, 3, 0),
+ SDC_QDSD_PINGROUP(qdsd_cmd, 0x19c000, 8, 5),
+ SDC_QDSD_PINGROUP(qdsd_data0, 0x19c000, 13, 10),
+ SDC_QDSD_PINGROUP(qdsd_data1, 0x19c000, 18, 15),
+ SDC_QDSD_PINGROUP(qdsd_data2, 0x19c000, 23, 20),
+ SDC_QDSD_PINGROUP(qdsd_data3, 0x19c000, 28, 25),
+};
+
+static const struct msm_pinctrl_soc_data msm8917_pinctrl = {
+ .pins = msm8917_pins,
+ .npins = ARRAY_SIZE(msm8917_pins),
+ .functions = msm8917_functions,
+ .nfunctions = ARRAY_SIZE(msm8917_functions),
+ .groups = msm8917_groups,
+ .ngroups = ARRAY_SIZE(msm8917_groups),
+ .ngpios = 134,
+};
+
+static int msm8917_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &msm8917_pinctrl);
+}
+
+static const struct of_device_id msm8917_pinctrl_of_match[] = {
+ { .compatible = "qcom,msm8917-pinctrl", },
+ { },
+};
+
+static struct platform_driver msm8917_pinctrl_driver = {
+ .driver = {
+ .name = "msm8917-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = msm8917_pinctrl_of_match,
+ },
+ .probe = msm8917_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init msm8917_pinctrl_init(void)
+{
+ return platform_driver_register(&msm8917_pinctrl_driver);
+}
+arch_initcall(msm8917_pinctrl_init);
+
+static void __exit msm8917_pinctrl_exit(void)
+{
+ platform_driver_unregister(&msm8917_pinctrl_driver);
+}
+module_exit(msm8917_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI msm8917 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, msm8917_pinctrl_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c
index f7af6da..37a6199 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm670.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -1588,7 +1588,7 @@
[156] = SDC_QDSD_PINGROUP(sdc2_data, 0x9a000, 9, 0),
[157] = UFS_RESET(ufs_reset, 0x9f000),
};
-static const struct msm_dir_conn sdm670_dir_conn[] = {
+static struct msm_dir_conn sdm670_dir_conn[] = {
{1, 510},
{3, 511},
{5, 512},
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c b/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c
index e77dcd9..72b730d 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -1681,7 +1681,7 @@
[153] = UFS_RESET(ufs_reset, 0x99f000),
};
-static const struct msm_dir_conn sdm845_dir_conn[] = {
+static struct msm_dir_conn sdm845_dir_conn[] = {
{1, 510},
{3, 511},
{5, 512},
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
index 4f2a726..f5f7743 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
@@ -428,7 +428,7 @@
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */
- SUNXI_FUNCTION(0x4, "uart0")), /* RX */
+ SUNXI_FUNCTION(0x3, "uart0")), /* RX */
SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c b/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c
index 1b580ba..907d7db 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c
@@ -145,19 +145,19 @@
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x3, "mcsi"), /* MCLK */
- SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)), /* PB_EINT14 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 14)), /* PB_EINT14 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 15),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x3, "mcsi"), /* SCK */
SUNXI_FUNCTION(0x4, "i2c4"), /* SCK */
- SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)), /* PB_EINT15 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 15)), /* PB_EINT15 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 16),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x3, "mcsi"), /* SDA */
SUNXI_FUNCTION(0x4, "i2c4"), /* SDA */
- SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)), /* PB_EINT16 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 16)), /* PB_EINT16 */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 4abd8f1..782ce62 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -163,7 +163,7 @@
config MSM_MHI_DEV
tristate "Modem Device Interface Driver"
- depends on EP_PCIE && IPA
+ depends on EP_PCIE && IPA3
help
This kernel module is used to interact with PCIe Root complex
supporting MHI protocol. MHI is a data transmission protocol
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index bf498f9..b99435d 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -3167,52 +3167,53 @@
EXPORT_SYMBOL(ipa_get_smmu_params);
/**
- * ipa_conn_wdi3_pipes() - connect wdi3 pipes
+ * ipa_conn_wdi_pipes() - connect wdi pipes
*/
-int ipa_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
- struct ipa_wdi3_conn_out_params *out)
+int ipa_conn_wdi_pipes(struct ipa_wdi_conn_in_params *in,
+ struct ipa_wdi_conn_out_params *out,
+ ipa_wdi_meter_notifier_cb wdi_notify)
{
int ret;
- IPA_API_DISPATCH_RETURN(ipa_conn_wdi3_pipes, in, out);
+ IPA_API_DISPATCH_RETURN(ipa_conn_wdi_pipes, in, out, wdi_notify);
return ret;
}
/**
- * ipa_disconn_wdi3_pipes() - disconnect wdi3 pipes
+ * ipa_disconn_wdi_pipes() - disconnect wdi pipes
*/
-int ipa_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
+int ipa_disconn_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
{
int ret;
- IPA_API_DISPATCH_RETURN(ipa_disconn_wdi3_pipes, ipa_ep_idx_tx,
+ IPA_API_DISPATCH_RETURN(ipa_disconn_wdi_pipes, ipa_ep_idx_tx,
ipa_ep_idx_rx);
return ret;
}
/**
- * ipa_enable_wdi3_pipes() - enable wdi3 pipes
+ * ipa_enable_wdi_pipes() - enable wdi pipes
*/
-int ipa_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
+int ipa_enable_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
{
int ret;
- IPA_API_DISPATCH_RETURN(ipa_enable_wdi3_pipes, ipa_ep_idx_tx,
+ IPA_API_DISPATCH_RETURN(ipa_enable_wdi_pipes, ipa_ep_idx_tx,
ipa_ep_idx_rx);
return ret;
}
/**
- * ipa_disable_wdi3_pipes() - disable wdi3 pipes
+ * ipa_disable_wdi_pipes() - disable wdi pipes
*/
-int ipa_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
+int ipa_disable_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
{
int ret;
- IPA_API_DISPATCH_RETURN(ipa_disable_wdi3_pipes, ipa_ep_idx_tx,
+ IPA_API_DISPATCH_RETURN(ipa_disable_wdi_pipes, ipa_ep_idx_tx,
ipa_ep_idx_rx);
return ret;
diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h
index 79d0c70..fc4362f 100644
--- a/drivers/platform/msm/ipa/ipa_api.h
+++ b/drivers/platform/msm/ipa/ipa_api.h
@@ -403,16 +403,17 @@
void (*ipa_ntn_uc_dereg_rdyCB)(void);
- int (*ipa_conn_wdi3_pipes)(struct ipa_wdi3_conn_in_params *in,
- struct ipa_wdi3_conn_out_params *out);
+ int (*ipa_conn_wdi_pipes)(struct ipa_wdi_conn_in_params *in,
+ struct ipa_wdi_conn_out_params *out,
+ ipa_wdi_meter_notifier_cb wdi_notify);
- int (*ipa_disconn_wdi3_pipes)(int ipa_ep_idx_tx,
+ int (*ipa_disconn_wdi_pipes)(int ipa_ep_idx_tx,
int ipa_ep_idx_rx);
- int (*ipa_enable_wdi3_pipes)(int ipa_ep_idx_tx,
+ int (*ipa_enable_wdi_pipes)(int ipa_ep_idx_tx,
int ipa_ep_idx_rx);
- int (*ipa_disable_wdi3_pipes)(int ipa_ep_idx_tx,
+ int (*ipa_disable_wdi_pipes)(int ipa_ep_idx_tx,
int ipa_ep_idx_rx);
int (*ipa_tz_unlock_reg)(struct ipa_tz_unlock_reg_info *reg_info,
diff --git a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
index eadd58b..9f8bfbe 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -619,8 +619,10 @@
}
if (ecm_ipa_ctx->is_vlan_mode)
- if (unlikely(skb->protocol != ETH_P_8021Q))
- ECM_IPA_DEBUG("ether_type != ETH_P_8021Q && vlan\n");
+ if (unlikely(skb->protocol != htons(ETH_P_8021Q)))
+ ECM_IPA_DEBUG(
+ "ether_type != ETH_P_8021Q && vlan, prot = 0x%X\n"
+ , skb->protocol);
ret = ipa_tx_dp(ecm_ipa_ctx->ipa_to_usb_client, skb, NULL);
if (ret) {
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c b/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c
index f4c8763..b2e454a 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018 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,9 +14,10 @@
#include <linux/msm_ipa.h>
#include <linux/string.h>
#include "../ipa_common_i.h"
+#include "../ipa_v3/ipa_pm.h"
-#define OFFLOAD_DRV_NAME "ipa_wdi3"
-#define IPA_WDI3_DBG(fmt, args...) \
+#define OFFLOAD_DRV_NAME "ipa_wdi"
+#define IPA_WDI_DBG(fmt, args...) \
do { \
pr_debug(OFFLOAD_DRV_NAME " %s:%d " fmt, \
__func__, __LINE__, ## args); \
@@ -26,7 +27,7 @@
OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
-#define IPA_WDI3_DBG_LOW(fmt, args...) \
+#define IPA_WDI_DBG_LOW(fmt, args...) \
do { \
pr_debug(OFFLOAD_DRV_NAME " %s:%d " fmt, \
__func__, __LINE__, ## args); \
@@ -34,7 +35,7 @@
OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
-#define IPA_WDI3_ERR(fmt, args...) \
+#define IPA_WDI_ERR(fmt, args...) \
do { \
pr_err(OFFLOAD_DRV_NAME " %s:%d " fmt, \
__func__, __LINE__, ## args); \
@@ -44,32 +45,107 @@
OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
-struct ipa_wdi3_intf_info {
+struct ipa_wdi_intf_info {
char netdev_name[IPA_RESOURCE_NAME_MAX];
u8 hdr_len;
u32 partial_hdr_hdl[IPA_IP_MAX];
struct list_head link;
};
-struct ipa_wdi3_context {
+struct ipa_wdi_context {
struct list_head head_intf_list;
- ipa_notify_cb notify;
- void *priv;
- struct completion wdi3_completion;
+ struct completion wdi_completion;
struct mutex lock;
+ enum ipa_wdi_version wdi_version;
+ u8 is_smmu_enabled;
+ u32 tx_pipe_hdl;
+ u32 rx_pipe_hdl;
+ u8 num_sys_pipe_needed;
+ u32 sys_pipe_hdl[IPA_WDI_MAX_SUPPORTED_SYS_PIPE];
+ u32 ipa_pm_hdl;
+ ipa_wdi_meter_notifier_cb wdi_notify;
};
-static struct ipa_wdi3_context *ipa_wdi3_ctx;
+static struct ipa_wdi_context *ipa_wdi_ctx;
-static int ipa_wdi3_commit_partial_hdr(
+int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
+ struct ipa_wdi_init_out_params *out)
+{
+ struct ipa_wdi_uc_ready_params uc_ready_params;
+ struct ipa_smmu_in_params smmu_in;
+ struct ipa_smmu_out_params smmu_out;
+
+ if (ipa_wdi_ctx) {
+ IPA_WDI_ERR("ipa_wdi_ctx was initialized before\n");
+ return -EFAULT;
+ }
+
+ if (in->wdi_version > IPA_WDI_3 || in->wdi_version < IPA_WDI_1) {
+ IPA_WDI_ERR("wrong wdi version: %d\n", in->wdi_version);
+ return -EFAULT;
+ }
+
+ ipa_wdi_ctx = kzalloc(sizeof(*ipa_wdi_ctx), GFP_KERNEL);
+ if (ipa_wdi_ctx == NULL)
+ return -ENOMEM;
+
+ mutex_init(&ipa_wdi_ctx->lock);
+ init_completion(&ipa_wdi_ctx->wdi_completion);
+ INIT_LIST_HEAD(&ipa_wdi_ctx->head_intf_list);
+
+ ipa_wdi_ctx->wdi_version = in->wdi_version;
+ uc_ready_params.notify = in->notify;
+ uc_ready_params.priv = in->priv;
+ ipa_wdi_ctx->wdi_notify = in->wdi_notify;
+
+ if (ipa_uc_reg_rdyCB(&uc_ready_params) != 0) {
+ mutex_destroy(&ipa_wdi_ctx->lock);
+ kfree(ipa_wdi_ctx);
+ ipa_wdi_ctx = NULL;
+ return -EFAULT;
+ }
+
+ out->is_uC_ready = uc_ready_params.is_uC_ready;
+
+ smmu_in.smmu_client = IPA_SMMU_WLAN_CLIENT;
+ if (ipa_get_smmu_params(&smmu_in, &smmu_out))
+ out->is_smmu_enabled = false;
+ else
+ out->is_smmu_enabled = smmu_out.smmu_enable;
+
+ ipa_wdi_ctx->is_smmu_enabled = out->is_smmu_enabled;
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_wdi_init);
+
+int ipa_wdi_cleanup(void)
+{
+ struct ipa_wdi_intf_info *entry;
+ struct ipa_wdi_intf_info *next;
+
+ /* clear interface list */
+ list_for_each_entry_safe(entry, next,
+ &ipa_wdi_ctx->head_intf_list, link) {
+ list_del(&entry->link);
+ kfree(entry);
+ }
+ mutex_destroy(&ipa_wdi_ctx->lock);
+ kfree(ipa_wdi_ctx);
+ ipa_wdi_ctx = NULL;
+ return 0;
+}
+EXPORT_SYMBOL(ipa_wdi_cleanup);
+
+static int ipa_wdi_commit_partial_hdr(
struct ipa_ioc_add_hdr *hdr,
const char *netdev_name,
- struct ipa_wdi3_hdr_info *hdr_info)
+ struct ipa_wdi_hdr_info *hdr_info)
{
int i;
if (!hdr || !hdr_info || !netdev_name) {
- IPA_WDI3_ERR("Invalid input\n");
+ IPA_WDI_ERR("Invalid input\n");
return -EINVAL;
}
@@ -90,18 +166,18 @@
}
if (ipa_add_hdr(hdr)) {
- IPA_WDI3_ERR("fail to add partial headers\n");
+ IPA_WDI_ERR("fail to add partial headers\n");
return -EFAULT;
}
return 0;
}
-int ipa_wdi3_reg_intf(struct ipa_wdi3_reg_intf_in_params *in)
+int ipa_wdi_reg_intf(struct ipa_wdi_reg_intf_in_params *in)
{
struct ipa_ioc_add_hdr *hdr;
- struct ipa_wdi3_intf_info *new_intf;
- struct ipa_wdi3_intf_info *entry;
+ struct ipa_wdi_intf_info *new_intf;
+ struct ipa_wdi_intf_info *entry;
struct ipa_tx_intf tx;
struct ipa_rx_intf rx;
struct ipa_ioc_tx_intf_prop tx_prop[2];
@@ -110,36 +186,30 @@
int ret = 0;
if (in == NULL) {
- IPA_WDI3_ERR("invalid params in=%pK\n", in);
+ IPA_WDI_ERR("invalid params in=NULL\n");
return -EINVAL;
}
- if (!ipa_wdi3_ctx) {
- ipa_wdi3_ctx = kzalloc(sizeof(*ipa_wdi3_ctx), GFP_KERNEL);
- if (ipa_wdi3_ctx == NULL) {
- IPA_WDI3_ERR("fail to alloc wdi3 ctx\n");
- return -ENOMEM;
- }
- mutex_init(&ipa_wdi3_ctx->lock);
- INIT_LIST_HEAD(&ipa_wdi3_ctx->head_intf_list);
+ if (!ipa_wdi_ctx) {
+ IPA_WDI_ERR("wdi ctx is not initialized\n");
+ return -EPERM;
}
- IPA_WDI3_DBG("register interface for netdev %s\n",
+ IPA_WDI_DBG("register interface for netdev %s\n",
in->netdev_name);
- mutex_lock(&ipa_wdi3_ctx->lock);
- list_for_each_entry(entry, &ipa_wdi3_ctx->head_intf_list, link)
+ mutex_lock(&ipa_wdi_ctx->lock);
+ list_for_each_entry(entry, &ipa_wdi_ctx->head_intf_list, link)
if (strcmp(entry->netdev_name, in->netdev_name) == 0) {
- IPA_WDI3_DBG("intf was added before.\n");
- mutex_unlock(&ipa_wdi3_ctx->lock);
+ IPA_WDI_DBG("intf was added before\n");
+ mutex_unlock(&ipa_wdi_ctx->lock);
return 0;
}
- IPA_WDI3_DBG("intf was not added before, proceed.\n");
+ IPA_WDI_DBG("intf was not added before, proceed\n");
new_intf = kzalloc(sizeof(*new_intf), GFP_KERNEL);
if (new_intf == NULL) {
- IPA_WDI3_ERR("fail to alloc new intf\n");
- mutex_unlock(&ipa_wdi3_ctx->lock);
+ mutex_unlock(&ipa_wdi_ctx->lock);
return -ENOMEM;
}
@@ -152,20 +222,19 @@
len = sizeof(struct ipa_ioc_add_hdr) + 2 * sizeof(struct ipa_hdr_add);
hdr = kzalloc(len, GFP_KERNEL);
if (hdr == NULL) {
- IPA_WDI3_ERR("fail to alloc %d bytes\n", len);
ret = -EFAULT;
goto fail_alloc_hdr;
}
- if (ipa_wdi3_commit_partial_hdr(hdr, in->netdev_name, in->hdr_info)) {
- IPA_WDI3_ERR("fail to commit partial headers\n");
+ if (ipa_wdi_commit_partial_hdr(hdr, in->netdev_name, in->hdr_info)) {
+ IPA_WDI_ERR("fail to commit partial headers\n");
ret = -EFAULT;
goto fail_commit_hdr;
}
new_intf->partial_hdr_hdl[IPA_IP_v4] = hdr->hdr[IPA_IP_v4].hdr_hdl;
new_intf->partial_hdr_hdl[IPA_IP_v6] = hdr->hdr[IPA_IP_v6].hdr_hdl;
- IPA_WDI3_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
+ IPA_WDI_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
hdr->hdr[IPA_IP_v4].hdr_hdl, hdr->hdr[IPA_IP_v6].hdr_hdl);
/* populate tx prop */
@@ -175,12 +244,14 @@
memset(tx_prop, 0, sizeof(tx_prop));
tx_prop[0].ip = IPA_IP_v4;
tx_prop[0].dst_pipe = IPA_CLIENT_WLAN1_CONS;
+ tx_prop[0].alt_dst_pipe = in->alt_dst_pipe;
tx_prop[0].hdr_l2_type = in->hdr_info[0].hdr_type;
strlcpy(tx_prop[0].hdr_name, hdr->hdr[IPA_IP_v4].name,
sizeof(tx_prop[0].hdr_name));
tx_prop[1].ip = IPA_IP_v6;
tx_prop[1].dst_pipe = IPA_CLIENT_WLAN1_CONS;
+ tx_prop[1].alt_dst_pipe = in->alt_dst_pipe;
tx_prop[1].hdr_l2_type = in->hdr_info[1].hdr_type;
strlcpy(tx_prop[1].hdr_name, hdr->hdr[IPA_IP_v6].name,
sizeof(tx_prop[1].hdr_name));
@@ -209,54 +280,53 @@
}
if (ipa_register_intf(in->netdev_name, &tx, &rx)) {
- IPA_WDI3_ERR("fail to add interface prop\n");
+ IPA_WDI_ERR("fail to add interface prop\n");
ret = -EFAULT;
goto fail_commit_hdr;
}
- list_add(&new_intf->link, &ipa_wdi3_ctx->head_intf_list);
- init_completion(&ipa_wdi3_ctx->wdi3_completion);
+ list_add(&new_intf->link, &ipa_wdi_ctx->head_intf_list);
+ init_completion(&ipa_wdi_ctx->wdi_completion);
kfree(hdr);
- mutex_unlock(&ipa_wdi3_ctx->lock);
+ mutex_unlock(&ipa_wdi_ctx->lock);
return 0;
fail_commit_hdr:
kfree(hdr);
fail_alloc_hdr:
kfree(new_intf);
- mutex_unlock(&ipa_wdi3_ctx->lock);
+ mutex_unlock(&ipa_wdi_ctx->lock);
return ret;
}
-EXPORT_SYMBOL(ipa_wdi3_reg_intf);
+EXPORT_SYMBOL(ipa_wdi_reg_intf);
-int ipa_wdi3_dereg_intf(const char *netdev_name)
+int ipa_wdi_dereg_intf(const char *netdev_name)
{
int len, ret = 0;
struct ipa_ioc_del_hdr *hdr = NULL;
- struct ipa_wdi3_intf_info *entry;
- struct ipa_wdi3_intf_info *next;
+ struct ipa_wdi_intf_info *entry;
+ struct ipa_wdi_intf_info *next;
if (!netdev_name) {
- IPA_WDI3_ERR("no netdev name.\n");
+ IPA_WDI_ERR("no netdev name\n");
return -EINVAL;
}
- if (!ipa_wdi3_ctx) {
- IPA_WDI3_ERR("wdi3 ctx is not initialized.\n");
+ if (!ipa_wdi_ctx) {
+ IPA_WDI_ERR("wdi ctx is not initialized\n");
return -EPERM;
}
- mutex_lock(&ipa_wdi3_ctx->lock);
- list_for_each_entry_safe(entry, next, &ipa_wdi3_ctx->head_intf_list,
+ mutex_lock(&ipa_wdi_ctx->lock);
+ list_for_each_entry_safe(entry, next, &ipa_wdi_ctx->head_intf_list,
link)
if (strcmp(entry->netdev_name, netdev_name) == 0) {
len = sizeof(struct ipa_ioc_del_hdr) +
2 * sizeof(struct ipa_hdr_del);
hdr = kzalloc(len, GFP_KERNEL);
if (hdr == NULL) {
- IPA_WDI3_ERR("fail to alloc %d bytes\n", len);
- mutex_unlock(&ipa_wdi3_ctx->lock);
+ mutex_unlock(&ipa_wdi_ctx->lock);
return -ENOMEM;
}
@@ -264,20 +334,21 @@
hdr->num_hdls = 2;
hdr->hdl[0].hdl = entry->partial_hdr_hdl[0];
hdr->hdl[1].hdl = entry->partial_hdr_hdl[1];
- IPA_WDI3_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
+ IPA_WDI_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
hdr->hdl[0].hdl, hdr->hdl[1].hdl);
if (ipa_del_hdr(hdr)) {
- IPA_WDI3_ERR("fail to delete partial header\n");
+ IPA_WDI_ERR("fail to delete partial header\n");
ret = -EFAULT;
goto fail;
}
if (ipa_deregister_intf(entry->netdev_name)) {
- IPA_WDI3_ERR("fail to del interface props\n");
+ IPA_WDI_ERR("fail to del interface props\n");
ret = -EFAULT;
goto fail;
}
+
list_del(&entry->link);
kfree(entry);
@@ -286,241 +357,512 @@
fail:
kfree(hdr);
- mutex_unlock(&ipa_wdi3_ctx->lock);
+ mutex_unlock(&ipa_wdi_ctx->lock);
return ret;
}
-EXPORT_SYMBOL(ipa_wdi3_dereg_intf);
+EXPORT_SYMBOL(ipa_wdi_dereg_intf);
-static void ipa_wdi3_rm_notify(void *user_data, enum ipa_rm_event event,
+static void ipa_wdi_rm_notify(void *user_data, enum ipa_rm_event event,
unsigned long data)
{
- if (!ipa_wdi3_ctx) {
- IPA_WDI3_ERR("Invalid context\n");
+ if (!ipa_wdi_ctx) {
+ IPA_WDI_ERR("Invalid context\n");
return;
}
switch (event) {
case IPA_RM_RESOURCE_GRANTED:
- complete_all(&ipa_wdi3_ctx->wdi3_completion);
+ complete_all(&ipa_wdi_ctx->wdi_completion);
break;
case IPA_RM_RESOURCE_RELEASED:
break;
default:
- IPA_WDI3_ERR("Invalid RM Evt: %d", event);
+ IPA_WDI_ERR("Invalid RM Evt: %d", event);
break;
}
}
-static int ipa_wdi3_cons_release(void)
+static int ipa_wdi_cons_release(void)
{
return 0;
}
-static int ipa_wdi3_cons_request(void)
+static int ipa_wdi_cons_request(void)
{
int ret = 0;
- if (!ipa_wdi3_ctx) {
- IPA_WDI3_ERR("wdi3 ctx is not initialized\n");
+ if (!ipa_wdi_ctx) {
+ IPA_WDI_ERR("wdi ctx is not initialized\n");
ret = -EFAULT;
}
return ret;
}
-int ipa_wdi3_conn_pipes(struct ipa_wdi3_conn_in_params *in,
- struct ipa_wdi3_conn_out_params *out)
+static void ipa_wdi_pm_cb(void *p, enum ipa_pm_cb_event event)
{
- int ret = 0;
+ IPA_WDI_DBG("received pm event %d\n", event);
+}
+
+int ipa_wdi_conn_pipes(struct ipa_wdi_conn_in_params *in,
+ struct ipa_wdi_conn_out_params *out)
+{
+ int i, j, ret = 0;
struct ipa_rm_create_params param;
+ struct ipa_pm_register_params pm_params;
+ struct ipa_wdi_in_params in_tx;
+ struct ipa_wdi_in_params in_rx;
+ struct ipa_wdi_out_params out_tx;
+ struct ipa_wdi_out_params out_rx;
if (!(in && out)) {
- IPA_WDI3_ERR("empty parameters. in=%pK out=%pK\n", in, out);
+ IPA_WDI_ERR("empty parameters. in=%pK out=%pK\n", in, out);
return -EINVAL;
}
- if (!ipa_wdi3_ctx) {
- ipa_wdi3_ctx = kzalloc(sizeof(*ipa_wdi3_ctx), GFP_KERNEL);
- if (ipa_wdi3_ctx == NULL) {
- IPA_WDI3_ERR("fail to alloc wdi3 ctx\n");
- return -EFAULT;
+ if (!ipa_wdi_ctx) {
+ IPA_WDI_ERR("wdi ctx is not initialized\n");
+ return -EPERM;
+ }
+
+ if (in->num_sys_pipe_needed > IPA_WDI_MAX_SUPPORTED_SYS_PIPE) {
+ IPA_WDI_ERR("ipa can only support up to %d sys pipe\n",
+ IPA_WDI_MAX_SUPPORTED_SYS_PIPE);
+ return -EINVAL;
+ }
+ ipa_wdi_ctx->num_sys_pipe_needed = in->num_sys_pipe_needed;
+ IPA_WDI_DBG("number of sys pipe %d\n", in->num_sys_pipe_needed);
+
+ /* setup sys pipe when needed */
+ for (i = 0; i < ipa_wdi_ctx->num_sys_pipe_needed; i++) {
+ ret = ipa_setup_sys_pipe(&in->sys_in[i],
+ &ipa_wdi_ctx->sys_pipe_hdl[i]);
+ if (ret) {
+ IPA_WDI_ERR("fail to setup sys pipe %d\n", i);
+ ret = -EFAULT;
+ goto fail_setup_sys_pipe;
}
- mutex_init(&ipa_wdi3_ctx->lock);
- INIT_LIST_HEAD(&ipa_wdi3_ctx->head_intf_list);
- }
- ipa_wdi3_ctx->notify = in->notify;
- ipa_wdi3_ctx->priv = in->priv;
-
- memset(¶m, 0, sizeof(param));
- param.name = IPA_RM_RESOURCE_WLAN_PROD;
- param.reg_params.user_data = ipa_wdi3_ctx;
- param.reg_params.notify_cb = ipa_wdi3_rm_notify;
- param.floor_voltage = IPA_VOLTAGE_SVS;
- ret = ipa_rm_create_resource(¶m);
- if (ret) {
- IPA_WDI3_ERR("fail to create WLAN_PROD resource\n");
- return -EFAULT;
}
- memset(¶m, 0, sizeof(param));
- param.name = IPA_RM_RESOURCE_WLAN_CONS;
- param.request_resource = ipa_wdi3_cons_request;
- param.release_resource = ipa_wdi3_cons_release;
- ret = ipa_rm_create_resource(¶m);
- if (ret) {
- IPA_WDI3_ERR("fail to create WLAN_CONS resource\n");
- goto fail_create_rm_cons;
+ if (!ipa_pm_is_used()) {
+ memset(¶m, 0, sizeof(param));
+ param.name = IPA_RM_RESOURCE_WLAN_PROD;
+ param.reg_params.user_data = ipa_wdi_ctx;
+ param.reg_params.notify_cb = ipa_wdi_rm_notify;
+ param.floor_voltage = IPA_VOLTAGE_SVS;
+ ret = ipa_rm_create_resource(¶m);
+ if (ret) {
+ IPA_WDI_ERR("fail to create WLAN_PROD resource\n");
+ ret = -EFAULT;
+ goto fail_setup_sys_pipe;
+ }
+
+ memset(¶m, 0, sizeof(param));
+ param.name = IPA_RM_RESOURCE_WLAN_CONS;
+ param.request_resource = ipa_wdi_cons_request;
+ param.release_resource = ipa_wdi_cons_release;
+ ret = ipa_rm_create_resource(¶m);
+ if (ret) {
+ IPA_WDI_ERR("fail to create WLAN_CONS resource\n");
+ goto fail_create_rm_cons;
+ }
+
+ if (ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
+ IPA_RM_RESOURCE_APPS_CONS)) {
+ IPA_WDI_ERR("fail to add rm dependency\n");
+ ret = -EFAULT;
+ goto fail_add_dependency;
+ }
+ } else {
+ pm_params.name = "wdi";
+ pm_params.callback = ipa_wdi_pm_cb;
+ pm_params.user_data = NULL;
+ pm_params.group = IPA_PM_GROUP_DEFAULT;
+ if (ipa_pm_register(&pm_params, &ipa_wdi_ctx->ipa_pm_hdl)) {
+ IPA_WDI_ERR("fail to register ipa pm\n");
+ ret = -EFAULT;
+ goto fail_setup_sys_pipe;
+ }
}
- if (ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
- IPA_RM_RESOURCE_APPS_CONS)) {
- IPA_WDI3_ERR("fail to add rm dependency\n");
- ret = -EFAULT;
- goto fail;
- }
+ if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
+ if (ipa_conn_wdi_pipes(in, out, ipa_wdi_ctx->wdi_notify)) {
+ IPA_WDI_ERR("fail to setup wdi pipes\n");
+ ret = -EFAULT;
+ goto fail_connect_pipe;
+ }
+ } else {
+ memset(&in_tx, 0, sizeof(in_tx));
+ memset(&in_rx, 0, sizeof(in_rx));
+ memset(&out_tx, 0, sizeof(out_tx));
+ memset(&out_rx, 0, sizeof(out_rx));
+ in_rx.wdi_notify = ipa_wdi_ctx->wdi_notify;
+ if (in->is_smmu_enabled == false) {
+ /* firsr setup rx pipe */
+ in_rx.sys.ipa_ep_cfg = in->u_rx.rx.ipa_ep_cfg;
+ in_rx.sys.client = in->u_rx.rx.client;
+ in_rx.sys.notify = in->notify;
+ in_rx.sys.priv = in->priv;
+ in_rx.smmu_enabled = in->is_smmu_enabled;
+ in_rx.u.ul.rdy_ring_base_pa =
+ in->u_rx.rx.transfer_ring_base_pa;
+ in_rx.u.ul.rdy_ring_size =
+ in->u_rx.rx.transfer_ring_size;
+ in_rx.u.ul.rdy_ring_rp_pa =
+ in->u_rx.rx.transfer_ring_doorbell_pa;
+ in_rx.u.ul.rdy_comp_ring_base_pa =
+ in->u_rx.rx.event_ring_base_pa;
+ in_rx.u.ul.rdy_comp_ring_wp_pa =
+ in->u_rx.rx.event_ring_doorbell_pa;
+ in_rx.u.ul.rdy_comp_ring_size =
+ in->u_rx.rx.event_ring_size;
+ if (ipa_connect_wdi_pipe(&in_rx, &out_rx)) {
+ IPA_WDI_ERR("fail to setup rx pipe\n");
+ ret = -EFAULT;
+ goto fail_connect_pipe;
+ }
+ ipa_wdi_ctx->rx_pipe_hdl = out_rx.clnt_hdl;
+ out->rx_uc_db_pa = out_rx.uc_door_bell_pa;
+ IPA_WDI_DBG("rx uc db pa: 0x%pad\n", &out->rx_uc_db_pa);
- if (ipa_conn_wdi3_pipes(in, out)) {
- IPA_WDI3_ERR("fail to setup wdi3 pipes\n");
- ret = -EFAULT;
- goto fail;
+ /* then setup tx pipe */
+ in_tx.sys.ipa_ep_cfg = in->u_tx.tx.ipa_ep_cfg;
+ in_tx.sys.client = in->u_tx.tx.client;
+ in_tx.smmu_enabled = in->is_smmu_enabled;
+ in_tx.u.dl.comp_ring_base_pa =
+ in->u_tx.tx.transfer_ring_base_pa;
+ in_tx.u.dl.comp_ring_size =
+ in->u_tx.tx.transfer_ring_size;
+ in_tx.u.dl.ce_ring_base_pa =
+ in->u_tx.tx.event_ring_base_pa;
+ in_tx.u.dl.ce_door_bell_pa =
+ in->u_tx.tx.event_ring_doorbell_pa;
+ in_tx.u.dl.ce_ring_size =
+ in->u_tx.tx.event_ring_size;
+ in_tx.u.dl.num_tx_buffers =
+ in->u_tx.tx.num_pkt_buffers;
+ if (ipa_connect_wdi_pipe(&in_tx, &out_tx)) {
+ IPA_WDI_ERR("fail to setup tx pipe\n");
+ ret = -EFAULT;
+ goto fail;
+ }
+ ipa_wdi_ctx->tx_pipe_hdl = out_tx.clnt_hdl;
+ out->tx_uc_db_pa = out_tx.uc_door_bell_pa;
+ IPA_WDI_DBG("tx uc db pa: 0x%pad\n", &out->tx_uc_db_pa);
+ } else { /* smmu is enabled */
+ /* firsr setup rx pipe */
+ in_rx.sys.ipa_ep_cfg = in->u_rx.rx_smmu.ipa_ep_cfg;
+ in_rx.sys.client = in->u_rx.rx_smmu.client;
+ in_rx.sys.notify = in->notify;
+ in_rx.sys.priv = in->priv;
+ in_rx.smmu_enabled = in->is_smmu_enabled;
+ in_rx.u.ul_smmu.rdy_ring =
+ in->u_rx.rx_smmu.transfer_ring_base;
+ in_rx.u.ul_smmu.rdy_ring_size =
+ in->u_rx.rx_smmu.transfer_ring_size;
+ in_rx.u.ul_smmu.rdy_ring_rp_pa =
+ in->u_rx.rx_smmu.transfer_ring_doorbell_pa;
+ in_rx.u.ul_smmu.rdy_comp_ring =
+ in->u_rx.rx_smmu.event_ring_base;
+ in_rx.u.ul_smmu.rdy_comp_ring_wp_pa =
+ in->u_rx.rx_smmu.event_ring_doorbell_pa;
+ in_rx.u.ul_smmu.rdy_comp_ring_size =
+ in->u_rx.rx_smmu.event_ring_size;
+ if (ipa_connect_wdi_pipe(&in_rx, &out_rx)) {
+ IPA_WDI_ERR("fail to setup rx pipe\n");
+ ret = -EFAULT;
+ goto fail_connect_pipe;
+ }
+ ipa_wdi_ctx->rx_pipe_hdl = out_rx.clnt_hdl;
+ out->rx_uc_db_pa = out_rx.uc_door_bell_pa;
+ IPA_WDI_DBG("rx uc db pa: 0x%pad\n", &out->rx_uc_db_pa);
+
+ /* then setup tx pipe */
+ in_tx.sys.ipa_ep_cfg = in->u_tx.tx_smmu.ipa_ep_cfg;
+ in_tx.sys.client = in->u_tx.tx_smmu.client;
+ in_tx.smmu_enabled = in->is_smmu_enabled;
+ in_tx.u.dl_smmu.comp_ring =
+ in->u_tx.tx_smmu.transfer_ring_base;
+ in_tx.u.dl_smmu.comp_ring_size =
+ in->u_tx.tx_smmu.transfer_ring_size;
+ in_tx.u.dl_smmu.ce_ring =
+ in->u_tx.tx_smmu.event_ring_base;
+ in_tx.u.dl_smmu.ce_door_bell_pa =
+ in->u_tx.tx_smmu.event_ring_doorbell_pa;
+ in_tx.u.dl_smmu.ce_ring_size =
+ in->u_tx.tx_smmu.event_ring_size;
+ in_tx.u.dl_smmu.num_tx_buffers =
+ in->u_tx.tx_smmu.num_pkt_buffers;
+ if (ipa_connect_wdi_pipe(&in_tx, &out_tx)) {
+ IPA_WDI_ERR("fail to setup tx pipe\n");
+ ret = -EFAULT;
+ goto fail;
+ }
+ ipa_wdi_ctx->tx_pipe_hdl = out_tx.clnt_hdl;
+ out->tx_uc_db_pa = out_tx.uc_door_bell_pa;
+ IPA_WDI_DBG("tx uc db pa: 0x%pad\n", &out->tx_uc_db_pa);
+ }
}
return 0;
fail:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
+ ipa_disconnect_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl);
+fail_connect_pipe:
+ if (!ipa_pm_is_used())
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_WLAN_PROD,
+ IPA_RM_RESOURCE_APPS_CONS);
+ else
+ ipa_pm_deregister(ipa_wdi_ctx->ipa_pm_hdl);
+fail_add_dependency:
+ if (!ipa_pm_is_used())
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
fail_create_rm_cons:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
-
+ if (!ipa_pm_is_used())
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
+fail_setup_sys_pipe:
+ for (j = 0; j < i; j++)
+ ipa_teardown_sys_pipe(ipa_wdi_ctx->sys_pipe_hdl[j]);
return ret;
}
-EXPORT_SYMBOL(ipa_wdi3_conn_pipes);
+EXPORT_SYMBOL(ipa_wdi_conn_pipes);
-int ipa_wdi3_disconn_pipes(void)
+int ipa_wdi_disconn_pipes(void)
{
- int ipa_ep_idx_rx, ipa_ep_idx_tx;
+ int i, ipa_ep_idx_rx, ipa_ep_idx_tx;
- if (!ipa_wdi3_ctx) {
- IPA_WDI3_ERR("wdi3 ctx is not initialized\n");
+ if (!ipa_wdi_ctx) {
+ IPA_WDI_ERR("wdi ctx is not initialized\n");
return -EPERM;
}
- ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
- ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
- if (ipa_disconn_wdi3_pipes(ipa_ep_idx_rx, ipa_ep_idx_tx)) {
- IPA_WDI3_ERR("fail to tear down wdi3 pipes\n");
- return -EFAULT;
- }
-
- if (ipa_rm_delete_dependency(IPA_RM_RESOURCE_WLAN_PROD,
- IPA_RM_RESOURCE_APPS_CONS)) {
- IPA_WDI3_ERR("fail to delete rm dependency\n");
- return -EFAULT;
- }
-
- if (ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
- IPA_WDI3_ERR("fail to delete WLAN_PROD resource\n");
- return -EFAULT;
- }
-
- if (ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS)) {
- IPA_WDI3_ERR("fail to delete WLAN_CONS resource\n");
- return -EFAULT;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(ipa_wdi3_disconn_pipes);
-
-int ipa_wdi3_enable_pipes(void)
-{
- int ret;
- int ipa_ep_idx_tx, ipa_ep_idx_rx;
-
- if (!ipa_wdi3_ctx) {
- IPA_WDI3_ERR("wdi3 ctx is not initialized.\n");
- return -EPERM;
- }
-
- ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
- ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
- if (ipa_enable_wdi3_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
- IPA_WDI3_ERR("fail to enable wdi3 pipes\n");
- return -EFAULT;
- }
-
- ret = ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD);
- if (ret == -EINPROGRESS) {
- if (wait_for_completion_timeout(&ipa_wdi3_ctx->wdi3_completion,
- 10*HZ) == 0) {
- IPA_WDI3_ERR("WLAN_PROD resource req time out\n");
+ /* tear down sys pipe if needed */
+ for (i = 0; i < ipa_wdi_ctx->num_sys_pipe_needed; i++) {
+ if (ipa_teardown_sys_pipe(ipa_wdi_ctx->sys_pipe_hdl[i])) {
+ IPA_WDI_ERR("fail to tear down sys pipe %d\n", i);
return -EFAULT;
}
- } else if (ret != 0) {
- IPA_WDI3_ERR("fail to request resource\n");
- return -EFAULT;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(ipa_wdi3_enable_pipes);
-
-int ipa_wdi3_disable_pipes(void)
-{
- int ret;
- int ipa_ep_idx_tx, ipa_ep_idx_rx;
-
- if (!ipa_wdi3_ctx) {
- IPA_WDI3_ERR("wdi3 ctx is not initialized.\n");
- return -EPERM;
- }
-
- ret = ipa_rm_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
- if (ret != 0) {
- IPA_WDI3_ERR("fail to release resource\n");
- return -EFAULT;
}
ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
- if (ipa_disable_wdi3_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
- IPA_WDI3_ERR("fail to disable wdi3 pipes\n");
- return -EFAULT;
+
+ if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
+ if (ipa_disconn_wdi_pipes(ipa_ep_idx_rx, ipa_ep_idx_tx)) {
+ IPA_WDI_ERR("fail to tear down wdi pipes\n");
+ return -EFAULT;
+ }
+ } else {
+ if (ipa_disconnect_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+ IPA_WDI_ERR("fail to tear down wdi tx pipes\n");
+ return -EFAULT;
+ }
+ if (ipa_disconnect_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+ IPA_WDI_ERR("fail to tear down wdi rx pipes\n");
+ return -EFAULT;
+ }
+ }
+
+ if (!ipa_pm_is_used()) {
+ if (ipa_rm_delete_dependency(IPA_RM_RESOURCE_WLAN_PROD,
+ IPA_RM_RESOURCE_APPS_CONS)) {
+ IPA_WDI_ERR("fail to delete rm dependency\n");
+ return -EFAULT;
+ }
+
+ if (ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
+ IPA_WDI_ERR("fail to delete WLAN_PROD resource\n");
+ return -EFAULT;
+ }
+
+ if (ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS)) {
+ IPA_WDI_ERR("fail to delete WLAN_CONS resource\n");
+ return -EFAULT;
+ }
+ } else {
+ if (ipa_pm_deregister(ipa_wdi_ctx->ipa_pm_hdl)) {
+ IPA_WDI_ERR("fail to deregister ipa pm\n");
+ return -EFAULT;
+ }
}
return 0;
}
-EXPORT_SYMBOL(ipa_wdi3_disable_pipes);
+EXPORT_SYMBOL(ipa_wdi_disconn_pipes);
-int ipa_wdi3_set_perf_profile(struct ipa_wdi3_perf_profile *profile)
+int ipa_wdi_enable_pipes(void)
+{
+ int ret;
+ int ipa_ep_idx_tx, ipa_ep_idx_rx;
+
+ if (!ipa_wdi_ctx) {
+ IPA_WDI_ERR("wdi ctx is not initialized\n");
+ return -EPERM;
+ }
+
+ ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
+ ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
+
+ if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
+ if (ipa_enable_wdi_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
+ IPA_WDI_ERR("fail to enable wdi pipes\n");
+ return -EFAULT;
+ }
+ } else {
+ if (ipa_enable_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+ IPA_WDI_ERR("fail to enable wdi tx pipe\n");
+ return -EFAULT;
+ }
+ if (ipa_resume_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+ IPA_WDI_ERR("fail to resume wdi tx pipe\n");
+ return -EFAULT;
+ }
+ if (ipa_enable_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+ IPA_WDI_ERR("fail to enable wdi rx pipe\n");
+ return -EFAULT;
+ }
+ if (ipa_resume_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+ IPA_WDI_ERR("fail to resume wdi rx pipe\n");
+ return -EFAULT;
+ }
+ }
+
+ if (!ipa_pm_is_used()) {
+ ret = ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD);
+ if (ret == -EINPROGRESS) {
+ if (wait_for_completion_timeout(
+ &ipa_wdi_ctx->wdi_completion, 10*HZ) == 0) {
+ IPA_WDI_ERR("WLAN_PROD res req time out\n");
+ return -EFAULT;
+ }
+ } else if (ret != 0) {
+ IPA_WDI_ERR("fail to request resource\n");
+ return -EFAULT;
+ }
+ } else {
+ ret = ipa_pm_activate_sync(ipa_wdi_ctx->ipa_pm_hdl);
+ if (ret) {
+ IPA_WDI_ERR("fail to activate ipa pm\n");
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_wdi_enable_pipes);
+
+int ipa_wdi_disable_pipes(void)
+{
+ int ret;
+ int ipa_ep_idx_tx, ipa_ep_idx_rx;
+
+ if (!ipa_wdi_ctx) {
+ IPA_WDI_ERR("wdi ctx is not initialized.\n");
+ return -EPERM;
+ }
+
+ ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
+ ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
+
+ if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
+ if (ipa_disable_wdi_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
+ IPA_WDI_ERR("fail to disable wdi pipes\n");
+ return -EFAULT;
+ }
+ } else {
+ if (ipa_suspend_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+ IPA_WDI_ERR("fail to suspend wdi tx pipe\n");
+ return -EFAULT;
+ }
+ if (ipa_disable_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+ IPA_WDI_ERR("fail to disable wdi tx pipe\n");
+ return -EFAULT;
+ }
+ if (ipa_suspend_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+ IPA_WDI_ERR("fail to suspend wdi rx pipe\n");
+ return -EFAULT;
+ }
+ if (ipa_disable_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+ IPA_WDI_ERR("fail to disable wdi rx pipe\n");
+ return -EFAULT;
+ }
+ }
+
+ if (!ipa_pm_is_used()) {
+ ret = ipa_rm_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
+ if (ret != 0) {
+ IPA_WDI_ERR("fail to release resource\n");
+ return -EFAULT;
+ }
+ } else {
+ ret = ipa_pm_deactivate_sync(ipa_wdi_ctx->ipa_pm_hdl);
+ if (ret) {
+ IPA_WDI_ERR("fail to deactivate ipa pm\n");
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_wdi_disable_pipes);
+
+int ipa_wdi_set_perf_profile(struct ipa_wdi_perf_profile *profile)
{
struct ipa_rm_perf_profile rm_profile;
enum ipa_rm_resource_name resource_name;
if (profile == NULL) {
- IPA_WDI3_ERR("Invalid input\n");
+ IPA_WDI_ERR("Invalid input\n");
return -EINVAL;
}
- rm_profile.max_supported_bandwidth_mbps =
- profile->max_supported_bw_mbps;
+ if (!ipa_pm_is_used()) {
+ rm_profile.max_supported_bandwidth_mbps =
+ profile->max_supported_bw_mbps;
- if (profile->client == IPA_CLIENT_WLAN1_PROD) {
- resource_name = IPA_RM_RESOURCE_WLAN_PROD;
- } else if (profile->client == IPA_CLIENT_WLAN1_CONS) {
- resource_name = IPA_RM_RESOURCE_WLAN_CONS;
+ if (profile->client == IPA_CLIENT_WLAN1_PROD) {
+ resource_name = IPA_RM_RESOURCE_WLAN_PROD;
+ } else if (profile->client == IPA_CLIENT_WLAN1_CONS) {
+ resource_name = IPA_RM_RESOURCE_WLAN_CONS;
+ } else {
+ IPA_WDI_ERR("not supported\n");
+ return -EINVAL;
+ }
+
+ if (ipa_rm_set_perf_profile(resource_name, &rm_profile)) {
+ IPA_WDI_ERR("fail to setup rm perf profile\n");
+ return -EFAULT;
+ }
} else {
- IPA_WDI3_ERR("not supported\n");
- return -EINVAL;
- }
-
- if (ipa_rm_set_perf_profile(resource_name, &rm_profile)) {
- IPA_WDI3_ERR("fail to setup rm perf profile\n");
- return -EFAULT;
+ if (ipa_pm_set_perf_profile(ipa_wdi_ctx->ipa_pm_hdl,
+ profile->max_supported_bw_mbps)) {
+ IPA_WDI_ERR("fail to setup pm perf profile\n");
+ return -EFAULT;
+ }
}
return 0;
}
-EXPORT_SYMBOL(ipa_wdi3_set_perf_profile);
+EXPORT_SYMBOL(ipa_wdi_set_perf_profile);
+
+int ipa_wdi_create_smmu_mapping(u32 num_buffers,
+ struct ipa_wdi_buffer_info *info)
+{
+ return ipa_create_wdi_mapping(num_buffers, info);
+}
+EXPORT_SYMBOL(ipa_wdi_create_smmu_mapping);
+
+int ipa_wdi_release_smmu_mapping(u32 num_buffers,
+ struct ipa_wdi_buffer_info *info)
+{
+ return ipa_release_wdi_mapping(num_buffers, info);
+}
+EXPORT_SYMBOL(ipa_wdi_release_smmu_mapping);
+
+int ipa_wdi_get_stats(struct IpaHwStatsWDIInfoData_t *stats)
+{
+ return ipa_get_wdi_stats(stats);
+}
+EXPORT_SYMBOL(ipa_wdi_get_stats);
diff --git a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
index ad23d82..4980167 100644
--- a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
@@ -2026,8 +2026,10 @@
}
if (rndis_ipa_ctx->is_vlan_mode)
- if (unlikely(skb->protocol != ETH_P_8021Q))
- RNDIS_IPA_DEBUG("ether_type != ETH_P_8021Q && vlan\n");
+ if (unlikely(skb->protocol != htons(ETH_P_8021Q)))
+ RNDIS_IPA_DEBUG(
+ "ether_type != ETH_P_8021Q && vlan, prot = 0x%X\n"
+ , skb->protocol);
/* make room at the head of the SKB to put the RNDIS header */
rndis_hdr = (struct rndis_pkt_hdr *)skb_push(skb,
diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h
index 98a1cf9..b37a127 100644
--- a/drivers/platform/msm/ipa/ipa_common_i.h
+++ b/drivers/platform/msm/ipa/ipa_common_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -419,14 +419,15 @@
void *user_data);
void ipa_ntn_uc_dereg_rdyCB(void);
-int ipa_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
- struct ipa_wdi3_conn_out_params *out);
+int ipa_conn_wdi_pipes(struct ipa_wdi_conn_in_params *in,
+ struct ipa_wdi_conn_out_params *out,
+ ipa_wdi_meter_notifier_cb wdi_notify);
-int ipa_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
+int ipa_disconn_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
-int ipa_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
+int ipa_enable_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
-int ipa_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
+int ipa_disable_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
const char *ipa_get_version_string(enum ipa_hw_type ver);
int ipa_start_gsi_channel(u32 clnt_hdl);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index 78d1c96..e43a201 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -4358,7 +4358,7 @@
else
IPADBG(":ipa Uc interface init ok\n");
- result = ipa_wdi_init();
+ result = ipa2_wdi_init();
if (result)
IPAERR(":wdi init failed (%d)\n", -result);
else
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index 91017a5..bd7f600 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -67,6 +67,16 @@
#define IPA_MAX_NUM_REQ_CACHE 10
#define IPA_IPC_LOG_PAGES 50
+#define IPA_WDI_RX_RING_RES 0
+#define IPA_WDI_RX_RING_RP_RES 1
+#define IPA_WDI_RX_COMP_RING_RES 2
+#define IPA_WDI_RX_COMP_RING_WP_RES 3
+#define IPA_WDI_TX_RING_RES 4
+#define IPA_WDI_CE_RING_RES 5
+#define IPA_WDI_CE_DB_RES 6
+#define IPA_WDI_TX_DB_RES 7
+#define IPA_WDI_MAX_RES 8
+
#define IPADBG(fmt, args...) \
do { \
pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args);\
@@ -1578,8 +1588,9 @@
int ipa2_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv);
void ipa2_ntn_uc_dereg_rdyCB(void);
-int ipa2_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
- struct ipa_wdi3_conn_out_params *out);
+int ipa2_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
+ struct ipa_wdi_conn_out_params *out,
+ ipa_wdi_meter_notifier_cb wdi_notify);
int ipa2_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
int ipa2_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
int ipa2_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
@@ -1601,6 +1612,9 @@
*/
int ipa2_uc_dereg_rdyCB(void);
+int ipa2_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
+ phys_addr_t pa, struct sg_table *sgt, size_t len, bool device,
+ unsigned long *iova);
/*
* Tethering bridge (Rmnet / MBIM)
*/
@@ -1864,7 +1878,7 @@
int ipa_active_clients_trylock(unsigned long *flags);
void ipa_active_clients_unlock(void);
void ipa_active_clients_trylock_unlock(unsigned long *flags);
-int ipa_wdi_init(void);
+int ipa2_wdi_init(void);
int ipa_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id);
int ipa_tag_process(struct ipa_desc *desc, int num_descs,
unsigned long timeout);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index a3db092..66a8d0b 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -51,6 +51,7 @@
u32 tmp[IPA_RT_FLT_HW_RULE_BUF_SIZE/4];
u8 *start;
int pipe_idx;
+ struct ipa_hdr_entry *hdr_entry;
if (buf == NULL) {
memset(tmp, 0, (IPA_RT_FLT_HW_RULE_BUF_SIZE/4));
@@ -74,6 +75,18 @@
}
rule_hdr->u.hdr.pipe_dest_idx = pipe_idx;
rule_hdr->u.hdr.system = !ipa_ctx->hdr_tbl_lcl;
+
+ /* Adding check to confirm still
+ * header entry present in header table or not
+ */
+
+ if (entry->hdr) {
+ hdr_entry = ipa_id_find(entry->rule.hdr_hdl);
+ if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+ IPAERR_RL("Header entry already deleted\n");
+ return -EPERM;
+ }
+ }
if (entry->hdr) {
if (entry->hdr->cookie == IPA_HDR_COOKIE) {
rule_hdr->u.hdr.hdr_offset =
@@ -140,6 +153,8 @@
u32 tmp[IPA_RT_FLT_HW_RULE_BUF_SIZE/4];
u8 *start;
int pipe_idx;
+ struct ipa_hdr_entry *hdr_entry;
+ struct ipa_hdr_proc_ctx_entry *hdr_proc_entry;
if (buf == NULL) {
memset(tmp, 0, IPA_RT_FLT_HW_RULE_BUF_SIZE);
@@ -162,6 +177,24 @@
return -EPERM;
}
rule_hdr->u.hdr_v2_5.pipe_dest_idx = pipe_idx;
+ /* Adding check to confirm still
+ * header entry present in header table or not
+ */
+
+ if (entry->hdr) {
+ hdr_entry = ipa_id_find(entry->rule.hdr_hdl);
+ if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+ IPAERR_RL("Header entry already deleted\n");
+ return -EPERM;
+ }
+ } else if (entry->proc_ctx) {
+ hdr_proc_entry = ipa_id_find(entry->rule.hdr_proc_ctx_hdl);
+ if (!hdr_proc_entry ||
+ hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+ IPAERR_RL("Proc header entry already deleted\n");
+ return -EPERM;
+ }
+ }
if (entry->proc_ctx || (entry->hdr && entry->hdr->is_hdr_proc_ctx)) {
struct ipa_hdr_proc_ctx_entry *proc_ctx;
@@ -1132,6 +1165,8 @@
{
struct ipa_rt_entry *entry;
int id;
+ struct ipa_hdr_entry *hdr_entry;
+ struct ipa_hdr_proc_ctx_entry *hdr_proc_entry;
entry = ipa_id_find(rule_hdl);
@@ -1153,6 +1188,24 @@
return -EINVAL;
}
}
+ /* Adding check to confirm still
+ * header entry present in header table or not
+ */
+
+ if (entry->hdr) {
+ hdr_entry = ipa_id_find(entry->rule.hdr_hdl);
+ if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+ IPAERR_RL("Header entry already deleted\n");
+ return -EINVAL;
+ }
+ } else if (entry->proc_ctx) {
+ hdr_proc_entry = ipa_id_find(entry->rule.hdr_proc_ctx_hdl);
+ if (!hdr_proc_entry ||
+ hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+ IPAERR_RL("Proc header entry already deleted\n");
+ return -EINVAL;
+ }
+ }
if (entry->hdr)
__ipa_release_hdr(entry->hdr->id);
@@ -1466,6 +1519,7 @@
{
struct ipa_rt_entry *entry;
struct ipa_hdr_entry *hdr = NULL;
+ struct ipa_hdr_entry *hdr_entry;
if (rtrule->rule.hdr_hdl) {
hdr = ipa_id_find(rtrule->rule.hdr_hdl);
@@ -1486,6 +1540,17 @@
goto error;
}
+ /* Adding check to confirm still
+ * header entry present in header table or not
+ */
+
+ if (entry->hdr) {
+ hdr_entry = ipa_id_find(entry->rule.hdr_hdl);
+ if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+ IPAERR_RL("Header entry already deleted\n");
+ return -EPERM;
+ }
+ }
if (entry->hdr)
entry->hdr->ref_cnt--;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
index cf8f0b8..459c207 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
@@ -26,15 +26,6 @@
#define IPA_WDI_RESUMED BIT(2)
#define IPA_UC_POLL_SLEEP_USEC 100
-#define IPA_WDI_RX_RING_RES 0
-#define IPA_WDI_RX_RING_RP_RES 1
-#define IPA_WDI_RX_COMP_RING_RES 2
-#define IPA_WDI_RX_COMP_RING_WP_RES 3
-#define IPA_WDI_TX_RING_RES 4
-#define IPA_WDI_CE_RING_RES 5
-#define IPA_WDI_CE_DB_RES 6
-#define IPA_WDI_MAX_RES 7
-
struct ipa_wdi_res {
struct ipa_wdi_buffer_info *res;
unsigned int nents;
@@ -448,7 +439,7 @@
return 0;
}
-int ipa_wdi_init(void)
+int ipa2_wdi_init(void)
{
struct ipa_uc_hdlrs uc_wdi_cbs = { 0 };
@@ -629,7 +620,7 @@
}
}
-static int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
+int ipa2_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
phys_addr_t pa, struct sg_table *sgt, size_t len, bool device,
unsigned long *iova)
{
@@ -845,7 +836,7 @@
in->smmu_enabled,
in->u.dl_smmu.comp_ring_size,
in->u.dl.comp_ring_size);
- if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
in->smmu_enabled,
in->u.dl.comp_ring_base_pa,
&in->u.dl_smmu.comp_ring,
@@ -870,7 +861,7 @@
in->smmu_enabled,
in->u.dl_smmu.ce_ring_size,
in->u.dl.ce_ring_size);
- if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
in->smmu_enabled,
in->u.dl.ce_ring_base_pa,
&in->u.dl_smmu.ce_ring,
@@ -891,7 +882,7 @@
pa = in->smmu_enabled ? in->u.dl_smmu.ce_door_bell_pa :
in->u.dl.ce_door_bell_pa;
- if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
in->smmu_enabled,
pa,
NULL,
@@ -919,7 +910,7 @@
in->smmu_enabled,
in->u.dl_smmu.comp_ring_size,
in->u.dl.comp_ring_size);
- if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
in->smmu_enabled,
in->u.dl.comp_ring_base_pa,
&in->u.dl_smmu.comp_ring,
@@ -939,7 +930,7 @@
in->smmu_enabled,
in->u.dl_smmu.ce_ring_size,
in->u.dl.ce_ring_size);
- if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
in->smmu_enabled,
in->u.dl.ce_ring_base_pa,
&in->u.dl_smmu.ce_ring,
@@ -954,7 +945,7 @@
tx->ce_ring_size = len;
pa = in->smmu_enabled ? in->u.dl_smmu.ce_door_bell_pa :
in->u.dl.ce_door_bell_pa;
- if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
in->smmu_enabled,
pa,
NULL,
@@ -995,7 +986,7 @@
in->smmu_enabled,
in->u.ul_smmu.rdy_ring_size,
in->u.ul.rdy_ring_size);
- if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
in->smmu_enabled,
in->u.ul.rdy_ring_base_pa,
&in->u.ul_smmu.rdy_ring,
@@ -1016,7 +1007,7 @@
pa = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_rp_pa :
in->u.ul.rdy_ring_rp_pa;
- if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
in->smmu_enabled,
pa,
NULL,
@@ -1040,7 +1031,8 @@
in->smmu_enabled,
in->u.ul_smmu.rdy_comp_ring_size,
in->u.ul.rdy_comp_ring_size);
- if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_COMP_RING_RES,
+ if (ipa2_create_uc_smmu_mapping(
+ IPA_WDI_RX_COMP_RING_RES,
in->smmu_enabled,
in->u.ul.rdy_comp_ring_base_pa,
&in->u.ul_smmu.rdy_comp_ring,
@@ -1062,7 +1054,7 @@
pa = in->smmu_enabled ?
in->u.ul_smmu.rdy_comp_ring_wp_pa :
in->u.ul.rdy_comp_ring_wp_pa;
- if (ipa_create_uc_smmu_mapping(
+ if (ipa2_create_uc_smmu_mapping(
IPA_WDI_RX_COMP_RING_WP_RES,
in->smmu_enabled,
pa,
@@ -1090,7 +1082,7 @@
in->smmu_enabled,
in->u.ul_smmu.rdy_ring_size,
in->u.ul.rdy_ring_size);
- if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
in->smmu_enabled,
in->u.ul.rdy_ring_base_pa,
&in->u.ul_smmu.rdy_ring,
@@ -1106,7 +1098,7 @@
pa = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_rp_pa :
in->u.ul.rdy_ring_rp_pa;
- if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
in->smmu_enabled,
pa,
NULL,
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index 27120c8..c9273ec 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -5160,10 +5160,10 @@
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;
- api_ctrl->ipa_conn_wdi3_pipes = ipa2_conn_wdi3_pipes;
- api_ctrl->ipa_disconn_wdi3_pipes = ipa2_disconn_wdi3_pipes;
- api_ctrl->ipa_enable_wdi3_pipes = ipa2_enable_wdi3_pipes;
- api_ctrl->ipa_disable_wdi3_pipes = ipa2_disable_wdi3_pipes;
+ api_ctrl->ipa_conn_wdi_pipes = ipa2_conn_wdi3_pipes;
+ api_ctrl->ipa_disconn_wdi_pipes = ipa2_disconn_wdi3_pipes;
+ api_ctrl->ipa_enable_wdi_pipes = ipa2_enable_wdi3_pipes;
+ api_ctrl->ipa_disable_wdi_pipes = ipa2_disable_wdi3_pipes;
api_ctrl->ipa_pm_is_used = ipa2_pm_is_used;
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c b/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c
index a2c33a1..62748b2 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -10,43 +10,27 @@
* GNU General Public License for more details.
*/
#include "ipa_i.h"
-#include "ipa_uc_offload_i.h"
#include <linux/ipa_wdi3.h>
#define IPA_HW_WDI3_RX_MBOX_START_INDEX 48
#define IPA_HW_WDI3_TX_MBOX_START_INDEX 50
static int ipa_send_wdi3_setup_pipe_cmd(
- struct ipa_wdi3_setup_info *info, u8 dir)
+ u8 is_smmu_enabled, struct ipa_wdi_pipe_setup_info *info,
+ struct ipa_wdi_pipe_setup_info_smmu *info_smmu, u8 dir)
{
int ipa_ep_idx;
- int result = 0;
+ int result = 0, len;
+ unsigned long va;
struct ipa_mem_buffer cmd;
struct IpaHwWdi3SetUpCmdData_t *wdi3_params;
struct IpaHwOffloadSetUpCmdData_t *cmd_data;
- if (info == NULL) {
+ if (info == NULL || info_smmu == NULL) {
IPAERR("invalid input\n");
return -EINVAL;
}
- ipa_ep_idx = ipa_get_ep_mapping(info->client);
- IPAERR("ep number: %d\n", ipa_ep_idx);
- if (ipa_ep_idx == -1) {
- IPAERR("fail to get ep idx.\n");
- return -EFAULT;
- }
-
- IPAERR("client=%d ep=%d\n", info->client, ipa_ep_idx);
- IPAERR("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
- IPAERR("ring_size = %hu\n", info->transfer_ring_size);
- IPAERR("ring_db_pa = 0x%pad\n", &info->transfer_ring_doorbell_pa);
- IPAERR("evt_ring_base_pa = 0x%pad\n", &info->event_ring_base_pa);
- IPAERR("evt_ring_size = %hu\n", info->event_ring_size);
- IPAERR("evt_ring_db_pa = 0x%pad\n", &info->event_ring_doorbell_pa);
- IPAERR("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
- IPAERR("pkt_offset = %d.\n", info->pkt_offset);
-
cmd.size = sizeof(*cmd_data);
cmd.base = dma_alloc_coherent(ipa_ctx->uc_pdev, cmd.size,
&cmd.phys_base, GFP_KERNEL);
@@ -54,35 +38,181 @@
IPAERR("fail to get DMA memory.\n");
return -ENOMEM;
}
- IPAERR("suceeded in allocating memory.\n");
cmd_data = (struct IpaHwOffloadSetUpCmdData_t *)cmd.base;
cmd_data->protocol = IPA_HW_FEATURE_WDI3;
- wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
- wdi3_params->transfer_ring_base_pa = (u32)info->transfer_ring_base_pa;
- wdi3_params->transfer_ring_base_pa_hi =
- (u32)((u64)info->transfer_ring_base_pa >> 32);
- wdi3_params->transfer_ring_size = info->transfer_ring_size;
- wdi3_params->transfer_ring_doorbell_pa =
- (u32)info->transfer_ring_doorbell_pa;
- wdi3_params->transfer_ring_doorbell_pa_hi =
- (u32)((u64)info->transfer_ring_doorbell_pa >> 32);
- wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
- wdi3_params->event_ring_base_pa_hi =
- (u32)((u64)info->event_ring_base_pa >> 32);
- wdi3_params->event_ring_size = info->event_ring_size;
- wdi3_params->event_ring_doorbell_pa =
- (u32)info->event_ring_doorbell_pa;
- wdi3_params->event_ring_doorbell_pa_hi =
- (u32)((u64)info->event_ring_doorbell_pa >> 32);
- wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
- wdi3_params->ipa_pipe_number = ipa_ep_idx;
- wdi3_params->dir = dir;
- wdi3_params->pkt_offset = info->pkt_offset;
- memcpy(wdi3_params->desc_format_template, info->desc_format_template,
- sizeof(wdi3_params->desc_format_template));
- IPAERR("suceeded in populating the command memory.\n");
+ if (!is_smmu_enabled) {
+ ipa_ep_idx = ipa_get_ep_mapping(info->client);
+ if (ipa_ep_idx == -1) {
+ IPAERR("fail to get ep idx.\n");
+ return -EFAULT;
+ }
+
+ IPADBG("client=%d ep=%d\n", info->client, ipa_ep_idx);
+ IPADBG("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
+ IPADBG("ring_size = %hu\n", info->transfer_ring_size);
+ IPADBG("ring_db_pa = 0x%pad\n",
+ &info->transfer_ring_doorbell_pa);
+ IPADBG("evt_ring_base_pa = 0x%pad\n",
+ &info->event_ring_base_pa);
+ IPADBG("evt_ring_size = %hu\n", info->event_ring_size);
+ IPADBG("evt_ring_db_pa = 0x%pad\n",
+ &info->event_ring_doorbell_pa);
+ IPADBG("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
+ IPADBG("pkt_offset = %d\n", info->pkt_offset);
+
+ wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
+ wdi3_params->transfer_ring_base_pa =
+ (u32)info->transfer_ring_base_pa;
+ wdi3_params->transfer_ring_base_pa_hi =
+ (u32)((u64)info->transfer_ring_base_pa >> 32);
+ wdi3_params->transfer_ring_size = info->transfer_ring_size;
+ wdi3_params->transfer_ring_doorbell_pa =
+ (u32)info->transfer_ring_doorbell_pa;
+ wdi3_params->transfer_ring_doorbell_pa_hi =
+ (u32)((u64)info->transfer_ring_doorbell_pa >> 32);
+ wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
+ wdi3_params->event_ring_base_pa_hi =
+ (u32)((u64)info->event_ring_base_pa >> 32);
+ wdi3_params->event_ring_size = info->event_ring_size;
+ wdi3_params->event_ring_doorbell_pa =
+ (u32)info->event_ring_doorbell_pa;
+ wdi3_params->event_ring_doorbell_pa_hi =
+ (u32)((u64)info->event_ring_doorbell_pa >> 32);
+ wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
+ wdi3_params->ipa_pipe_number = ipa_ep_idx;
+ wdi3_params->dir = dir;
+ wdi3_params->pkt_offset = info->pkt_offset;
+ memcpy(wdi3_params->desc_format_template,
+ info->desc_format_template,
+ sizeof(wdi3_params->desc_format_template));
+ } else {
+ ipa_ep_idx = ipa_get_ep_mapping(info_smmu->client);
+ if (ipa_ep_idx == -1) {
+ IPAERR("fail to get ep idx\n");
+ return -EFAULT;
+ }
+
+ IPADBG("client=%d ep=%d\n", info_smmu->client, ipa_ep_idx);
+ IPADBG("ring_size = %hu\n", info_smmu->transfer_ring_size);
+ IPADBG("ring_db_pa = 0x%pad\n",
+ &info_smmu->transfer_ring_doorbell_pa);
+ IPADBG("evt_ring_size = %hu\n", info_smmu->event_ring_size);
+ IPADBG("evt_ring_db_pa = 0x%pad\n",
+ &info_smmu->event_ring_doorbell_pa);
+ IPADBG("num_pkt_buffers = %hu\n", info_smmu->num_pkt_buffers);
+ IPADBG("pkt_offset = %d\n", info_smmu->pkt_offset);
+
+ wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
+
+ if (dir == IPA_WDI3_TX_DIR) {
+ len = info_smmu->transfer_ring_size;
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
+ true, info->transfer_ring_base_pa,
+ &info_smmu->transfer_ring_base, len,
+ false, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->transfer_ring_base_pa = (u32)va;
+ wdi3_params->transfer_ring_base_pa_hi =
+ (u32)((u64)va >> 32);
+ wdi3_params->transfer_ring_size = len;
+
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_TX_DB_RES,
+ true, info_smmu->transfer_ring_doorbell_pa,
+ NULL, 4, true, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->transfer_ring_doorbell_pa =
+ (u32)va;
+ wdi3_params->transfer_ring_doorbell_pa_hi =
+ (u32)((u64)va >> 32);
+
+ len = info_smmu->event_ring_size;
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
+ true, info->event_ring_base_pa,
+ &info_smmu->event_ring_base, len,
+ false, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->event_ring_base_pa = (u32)va;
+ wdi3_params->event_ring_base_pa_hi =
+ (u32)((u64)va >> 32);
+ wdi3_params->event_ring_size = len;
+
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
+ true, info_smmu->event_ring_doorbell_pa,
+ NULL, 4, true, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->event_ring_doorbell_pa =
+ (u32)va;
+ wdi3_params->event_ring_doorbell_pa_hi =
+ (u32)((u64)va >> 32);
+ } else {
+ len = info_smmu->transfer_ring_size;
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
+ true, info->transfer_ring_base_pa,
+ &info_smmu->transfer_ring_base, len,
+ false, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->transfer_ring_base_pa = (u32)va;
+ wdi3_params->transfer_ring_base_pa_hi =
+ (u32)((u64)va >> 32);
+ wdi3_params->transfer_ring_size = len;
+
+ if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
+ true, info_smmu->transfer_ring_doorbell_pa,
+ NULL, 4, true, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->transfer_ring_doorbell_pa =
+ (u32)va;
+ wdi3_params->transfer_ring_doorbell_pa_hi =
+ (u32)((u64)va >> 32);
+
+ len = info_smmu->event_ring_size;
+ if (ipa2_create_uc_smmu_mapping(
+ IPA_WDI_RX_COMP_RING_RES, true,
+ info->event_ring_base_pa,
+ &info_smmu->event_ring_base, len,
+ false, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->event_ring_base_pa = (u32)va;
+ wdi3_params->event_ring_base_pa_hi =
+ (u32)((u64)va >> 32);
+ wdi3_params->event_ring_size = len;
+
+ if (ipa2_create_uc_smmu_mapping(
+ IPA_WDI_RX_COMP_RING_WP_RES, true,
+ info_smmu->event_ring_doorbell_pa,
+ NULL, 4, true, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->event_ring_doorbell_pa =
+ (u32)va;
+ wdi3_params->event_ring_doorbell_pa_hi =
+ (u32)((u64)va >> 32);
+ }
+ wdi3_params->num_pkt_buffers = info_smmu->num_pkt_buffers;
+ wdi3_params->ipa_pipe_number = ipa_ep_idx;
+ wdi3_params->dir = dir;
+ wdi3_params->pkt_offset = info_smmu->pkt_offset;
+ memcpy(wdi3_params->desc_format_template,
+ info_smmu->desc_format_template,
+ sizeof(wdi3_params->desc_format_template));
+ }
result = ipa_uc_send_cmd((u32)(cmd.phys_base),
IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP,
@@ -94,13 +224,15 @@
}
dma_free_coherent(ipa_ctx->uc_pdev, cmd.size, cmd.base, cmd.phys_base);
- IPAERR("suceeded in freeing memory.\n");
return result;
}
-int ipa2_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
- struct ipa_wdi3_conn_out_params *out)
+int ipa2_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
+ struct ipa_wdi_conn_out_params *out,
+ ipa_wdi_meter_notifier_cb wdi_notify)
{
+ enum ipa_client_type rx_client;
+ enum ipa_client_type tx_client;
struct ipa_ep_context *ep_rx;
struct ipa_ep_context *ep_tx;
int ipa_ep_idx_rx;
@@ -112,12 +244,26 @@
return -EINVAL;
}
- ipa_ep_idx_rx = ipa_get_ep_mapping(in->rx.client);
- ipa_ep_idx_tx = ipa_get_ep_mapping(in->tx.client);
+ if (in->is_smmu_enabled == false) {
+ rx_client = in->u_rx.rx.client;
+ tx_client = in->u_tx.tx.client;
+ } else {
+ rx_client = in->u_rx.rx_smmu.client;
+ tx_client = in->u_tx.tx_smmu.client;
+ }
+
+ ipa_ep_idx_rx = ipa_get_ep_mapping(rx_client);
+ ipa_ep_idx_tx = ipa_get_ep_mapping(tx_client);
+
if (ipa_ep_idx_rx == -1 || ipa_ep_idx_tx == -1) {
IPAERR("fail to alloc EP.\n");
return -EFAULT;
}
+ if (ipa_ep_idx_rx >= IPA_MAX_NUM_PIPES ||
+ ipa_ep_idx_tx >= IPA_MAX_NUM_PIPES) {
+ IPAERR("ep out of range.\n");
+ return -EFAULT;
+ }
ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx];
ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx];
@@ -132,9 +278,14 @@
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+ if (wdi_notify)
+ ipa_ctx->uc_wdi_ctx.stats_notify = wdi_notify;
+ else
+ IPADBG("wdi_notify is null\n");
+
/* setup rx ep cfg */
ep_rx->valid = 1;
- ep_rx->client = in->rx.client;
+ ep_rx->client = rx_client;
result = ipa_disable_data_path(ipa_ep_idx_rx);
if (result) {
IPAERR("disable data path failed res=%d clnt=%d.\n", result,
@@ -145,65 +296,71 @@
ep_rx->client_notify = in->notify;
ep_rx->priv = in->priv;
- memcpy(&ep_rx->cfg, &in->rx.ipa_ep_cfg, sizeof(ep_rx->cfg));
+ if (in->is_smmu_enabled == false)
+ memcpy(&ep_rx->cfg, &in->u_rx.rx.ipa_ep_cfg,
+ sizeof(ep_rx->cfg));
+ else
+ memcpy(&ep_rx->cfg, &in->u_rx.rx_smmu.ipa_ep_cfg,
+ sizeof(ep_rx->cfg));
if (ipa_cfg_ep(ipa_ep_idx_rx, &ep_rx->cfg)) {
IPAERR("fail to setup rx pipe cfg\n");
result = -EFAULT;
goto fail;
}
- IPAERR("configured RX EP.\n");
- if (ipa_send_wdi3_setup_pipe_cmd(&in->rx, IPA_WDI3_RX_DIR)) {
+ if (ipa_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
+ &in->u_rx.rx, &in->u_rx.rx_smmu, IPA_WDI3_RX_DIR)) {
IPAERR("fail to send cmd to uc for rx pipe\n");
result = -EFAULT;
goto fail;
}
- IPAERR("rx pipe was setup.\n");
-
ipa_install_dflt_flt_rules(ipa_ep_idx_rx);
out->rx_uc_db_pa = ipa_ctx->ipa_wrapper_base +
IPA_REG_BASE_OFST_v2_5 +
IPA_UC_MAILBOX_m_n_OFFS_v2_5(
IPA_HW_WDI3_RX_MBOX_START_INDEX/32,
IPA_HW_WDI3_RX_MBOX_START_INDEX % 32);
- IPADBG("client %d (ep: %d) connected\n", in->rx.client,
+
+ IPADBG("client %d (ep: %d) connected\n", rx_client,
ipa_ep_idx_rx);
- /* setup dl ep cfg */
+ /* setup tx ep cfg */
ep_tx->valid = 1;
- ep_tx->client = in->tx.client;
+ ep_tx->client = tx_client;
result = ipa_disable_data_path(ipa_ep_idx_tx);
if (result) {
- IPAERR("disable data path failed res=%d clnt=%d.\n", result,
+ IPAERR("disable data path failed res=%d ep=%d.\n", result,
ipa_ep_idx_tx);
result = -EFAULT;
goto fail;
}
- memcpy(&ep_tx->cfg, &in->tx.ipa_ep_cfg, sizeof(ep_tx->cfg));
+ if (in->is_smmu_enabled == false)
+ memcpy(&ep_tx->cfg, &in->u_tx.tx.ipa_ep_cfg,
+ sizeof(ep_tx->cfg));
+ else
+ memcpy(&ep_tx->cfg, &in->u_tx.tx_smmu.ipa_ep_cfg,
+ sizeof(ep_tx->cfg));
if (ipa_cfg_ep(ipa_ep_idx_tx, &ep_tx->cfg)) {
IPAERR("fail to setup tx pipe cfg\n");
result = -EFAULT;
goto fail;
}
- IPAERR("configured TX EP in DMA mode.\n");
- if (ipa_send_wdi3_setup_pipe_cmd(&in->tx, IPA_WDI3_TX_DIR)) {
+ if (ipa_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
+ &in->u_tx.tx, &in->u_tx.tx_smmu, IPA_WDI3_TX_DIR)) {
IPAERR("fail to send cmd to uc for tx pipe\n");
result = -EFAULT;
goto fail;
}
- IPAERR("tx pipe was setup.\n");
-
out->tx_uc_db_pa = ipa_ctx->ipa_wrapper_base +
IPA_REG_BASE_OFST_v2_5 +
IPA_UC_MAILBOX_m_n_OFFS_v2_5(
IPA_HW_WDI3_TX_MBOX_START_INDEX/32,
IPA_HW_WDI3_TX_MBOX_START_INDEX % 32);
- out->tx_uc_db_va = ioremap(out->tx_uc_db_pa, 4);
- IPADBG("client %d (ep: %d) connected\n", in->tx.client,
+ IPADBG("client %d (ep: %d) connected\n", tx_client,
ipa_ep_idx_tx);
fail:
@@ -233,7 +390,6 @@
wdi3 = &cmd_data->CommonCh_params.Wdi3CommonCh_params;
wdi3->params.ipa_pipe_number = ipa_ep_idx;
- IPAERR("cmd: %d ep_idx: %d\n", command, ipa_ep_idx);
result = ipa_uc_send_cmd((u32)(cmd.phys_base), command,
IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS,
false, 10*HZ);
@@ -256,6 +412,12 @@
IPADBG("ep_tx = %d\n", ipa_ep_idx_tx);
IPADBG("ep_rx = %d\n", ipa_ep_idx_rx);
+ if (ipa_ep_idx_tx < 0 || ipa_ep_idx_tx >= IPA_MAX_NUM_PIPES ||
+ ipa_ep_idx_rx < 0 || ipa_ep_idx_rx >= IPA_MAX_NUM_PIPES) {
+ IPAERR("invalid ipa ep index\n");
+ return -EINVAL;
+ }
+
ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx];
ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx];
@@ -291,8 +453,8 @@
struct ipa_ep_context *ep_tx, *ep_rx;
int result = 0;
- IPAERR("ep_tx = %d\n", ipa_ep_idx_tx);
- IPAERR("ep_rx = %d\n", ipa_ep_idx_rx);
+ IPADBG("ep_tx = %d\n", ipa_ep_idx_tx);
+ IPADBG("ep_rx = %d\n", ipa_ep_idx_rx);
ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx];
ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx];
@@ -301,7 +463,6 @@
if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE)) {
IPAERR("fail to enable tx pipe\n");
- WARN_ON(1);
result = -EFAULT;
goto fail;
}
@@ -310,7 +471,6 @@
if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
IPA_CPU_2_HW_CMD_OFFLOAD_RESUME)) {
IPAERR("fail to resume tx pipe\n");
- WARN_ON(1);
result = -EFAULT;
goto fail;
}
@@ -319,7 +479,6 @@
if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE)) {
IPAERR("fail to enable rx pipe\n");
- WARN_ON(1);
result = -EFAULT;
goto fail;
}
@@ -328,7 +487,6 @@
if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
IPA_CPU_2_HW_CMD_OFFLOAD_RESUME)) {
IPAERR("fail to resume rx pipe\n");
- WARN_ON(1);
result = -EFAULT;
goto fail;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 4488df3..754c1f4 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -371,11 +371,9 @@
static int ipa3_active_clients_panic_notifier(struct notifier_block *this,
unsigned long event, void *ptr)
{
- 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);
- mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
return NOTIFY_DONE;
}
@@ -2140,7 +2138,7 @@
}
}
-static void ipa3_halt_q6_cons_gsi_channels(void)
+static void ipa3_halt_q6_gsi_channels(bool prod)
{
int ep_idx;
int client_idx;
@@ -2149,8 +2147,10 @@
int ret;
int code = 0;
+ /* if prod flag is true, then we halt the producer channels also */
for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
- if (IPA_CLIENT_IS_Q6_CONS(client_idx)) {
+ if (IPA_CLIENT_IS_Q6_CONS(client_idx)
+ || (IPA_CLIENT_IS_Q6_PROD(client_idx) && prod)) {
ep_idx = ipa3_get_ep_mapping(client_idx);
if (ep_idx == -1)
continue;
@@ -2192,7 +2192,6 @@
}
}
-
static int ipa3_q6_clean_q6_flt_tbls(enum ipa_ip_type ip,
enum ipa_rule_type rlt)
{
@@ -2607,6 +2606,7 @@
{
int client_idx;
int ep_idx;
+ bool prod = false;
IPADBG_LOW("ENTER\n");
@@ -2619,7 +2619,17 @@
/* Handle the issue where SUSPEND was removed for some reason */
ipa3_q6_avoid_holb();
- ipa3_halt_q6_cons_gsi_channels();
+
+ /* halt both prod and cons channels starting at IPAv4 */
+ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+ prod = true;
+ ipa3_halt_q6_gsi_channels(prod);
+ IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+ IPADBG("Exit without consumer check\n");
+ return;
+ }
+
+ ipa3_halt_q6_gsi_channels(prod);
for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++)
if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
@@ -4505,8 +4515,6 @@
IPADBG("teth_bridge initialized");
}
- ipa3_debugfs_init();
-
result = ipa3_uc_interface_init();
if (result)
IPAERR(":ipa Uc interface init failed (%d)\n", -result);
@@ -4544,6 +4552,8 @@
complete_all(&ipa3_ctx->init_completion_obj);
pr_info("IPA driver initialization was successful.\n");
+ ipa3_debugfs_init();
+
return 0;
fail_teth_bridge_driver_init:
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
index 17e4838..93f2597 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
@@ -192,7 +192,7 @@
chan_props.ring_len = 2 * GSI_CHAN_RE_SIZE_16B;
chan_props.ring_base_vaddr =
dma_alloc_coherent(ipa3_ctx->pdev, chan_props.ring_len,
- &chan_dma_addr, 0);
+ &chan_dma_addr, GFP_ATOMIC);
chan_props.ring_base_addr = chan_dma_addr;
chan_dma->base = chan_props.ring_base_vaddr;
chan_dma->phys_base = chan_props.ring_base_addr;
@@ -295,7 +295,7 @@
memset(&xfer_elem, 0, sizeof(struct gsi_xfer_elem));
buff = dma_alloc_coherent(ipa3_ctx->pdev, 1, &dma_addr,
- GFP_KERNEL);
+ GFP_ATOMIC);
xfer_elem.addr = dma_addr;
xfer_elem.len = 1;
xfer_elem.flags = GSI_XFER_FLAG_EOT;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 90edd2b..9a0f44a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -302,16 +302,17 @@
mem_flag);
if (!gsi_xfer_elem_array) {
IPAERR("Failed to alloc mem for gsi xfer array.\n");
- return -EFAULT;
+ return -ENOMEM;
}
spin_lock_bh(&sys->spinlock);
for (i = 0; i < num_desc; i++) {
tx_pkt = kmem_cache_zalloc(ipa3_ctx->tx_pkt_wrapper_cache,
- mem_flag);
+ GFP_ATOMIC);
if (!tx_pkt) {
IPAERR("failed to alloc tx wrapper\n");
+ result = -ENOMEM;
goto failure;
}
@@ -328,6 +329,7 @@
if (ipa_populate_tag_field(&desc[i], tx_pkt,
&tag_pyld_ret)) {
IPAERR("Failed to populate tag field\n");
+ result = -EFAULT;
goto failure_dma_map;
}
}
@@ -367,6 +369,7 @@
}
if (dma_mapping_error(ipa3_ctx->pdev, tx_pkt->mem.phys_base)) {
IPAERR("failed to do dma map.\n");
+ result = -EFAULT;
goto failure_dma_map;
}
@@ -413,6 +416,7 @@
gsi_xfer_elem_array, true);
if (result != GSI_STATUS_SUCCESS) {
IPAERR("GSI xfer failed.\n");
+ result = -EFAULT;
goto failure;
}
kfree(gsi_xfer_elem_array);
@@ -466,7 +470,7 @@
kfree(gsi_xfer_elem_array);
spin_unlock_bh(&sys->spinlock);
- return -EFAULT;
+ return result;
}
/**
@@ -952,11 +956,13 @@
goto fail_pm;
}
- result = ipa_pm_associate_ipa_cons_to_client(
- ep->sys->pm_hdl, sys_in->client);
- if (result) {
- IPAERR("failed to associate IPA PM client\n");
- goto fail_gen2;
+ if (IPA_CLIENT_IS_APPS_CONS(sys_in->client)) {
+ result = ipa_pm_associate_ipa_cons_to_client(
+ ep->sys->pm_hdl, sys_in->client);
+ if (result) {
+ IPAERR("failed to associate\n");
+ goto fail_gen2;
+ }
}
result = ipa_pm_set_perf_profile(ep->sys->pm_hdl,
@@ -3549,6 +3555,11 @@
dma_addr_t dma_addr;
dma_addr_t evt_dma_addr;
int result;
+ gfp_t mem_flag = GFP_KERNEL;
+
+ if (in->client == IPA_CLIENT_APPS_WAN_CONS ||
+ in->client == IPA_CLIENT_APPS_WAN_PROD)
+ mem_flag = GFP_ATOMIC;
if (!ep) {
IPAERR("EP context is empty\n");
@@ -3586,7 +3597,7 @@
gsi_evt_ring_props.ring_base_vaddr =
dma_alloc_coherent(ipa3_ctx->pdev,
gsi_evt_ring_props.ring_len,
- &evt_dma_addr, GFP_KERNEL);
+ &evt_dma_addr, mem_flag);
if (!gsi_evt_ring_props.ring_base_vaddr) {
IPAERR("fail to dma alloc %u bytes\n",
gsi_evt_ring_props.ring_len);
@@ -3656,7 +3667,7 @@
gsi_channel_props.ring_len = 2 * in->desc_fifo_sz;
gsi_channel_props.ring_base_vaddr =
dma_alloc_coherent(ipa3_ctx->pdev, gsi_channel_props.ring_len,
- &dma_addr, GFP_KERNEL);
+ &dma_addr, mem_flag);
if (!gsi_channel_props.ring_base_vaddr) {
IPAERR("fail to dma alloc %u bytes\n",
gsi_channel_props.ring_len);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c
index 8a4d945..547c9da 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -24,12 +24,63 @@
int ipa_hw_stats_init(void)
{
+ int ret = 0, ep_index;
+ struct ipa_teth_stats_endpoints *teth_stats_init;
+
if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
return 0;
/* initialize stats here */
ipa3_ctx->hw_stats.enabled = true;
- return 0;
+
+ teth_stats_init = kzalloc(sizeof(*teth_stats_init), GFP_KERNEL);
+ if (!teth_stats_init) {
+ IPAERR("mem allocated failed!\n");
+ return -ENOMEM;
+ }
+ /* enable prod mask */
+ teth_stats_init->prod_mask = (
+ IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_PROD) |
+ IPA_CLIENT_BIT_32(IPA_CLIENT_USB_PROD) |
+ IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN1_PROD));
+
+ if (IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_PROD)) {
+ ep_index = ipa3_get_ep_mapping(IPA_CLIENT_Q6_WAN_PROD);
+ if (ep_index == -1) {
+ IPAERR("Invalid client.\n");
+ kfree(teth_stats_init);
+ return -EINVAL;
+ }
+ teth_stats_init->dst_ep_mask[ep_index] =
+ (IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN1_CONS) |
+ IPA_CLIENT_BIT_32(IPA_CLIENT_USB_CONS));
+ }
+
+ if (IPA_CLIENT_BIT_32(IPA_CLIENT_USB_PROD)) {
+ ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD);
+ if (ep_index == -1) {
+ IPAERR("Invalid client.\n");
+ kfree(teth_stats_init);
+ return -EINVAL;
+ }
+ teth_stats_init->dst_ep_mask[ep_index] =
+ IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_CONS);
+ }
+
+ if (IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN1_PROD)) {
+ ep_index = ipa3_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
+ if (ep_index == -1) {
+ IPAERR("Invalid client.\n");
+ kfree(teth_stats_init);
+ return -EINVAL;
+ }
+ teth_stats_init->dst_ep_mask[ep_index] =
+ IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_CONS);
+ }
+
+ ret = ipa_init_teth_stats(teth_stats_init);
+ kfree(teth_stats_init);
+ return ret;
}
int ipa_init_quota_stats(u32 pipe_bitmask)
@@ -348,9 +399,12 @@
/* reset driver's cache */
memset(&ipa3_ctx->hw_stats.teth.init, 0,
sizeof(ipa3_ctx->hw_stats.teth.init));
- for (i = 0; i < IPA_CLIENT_MAX; i++)
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ memset(&ipa3_ctx->hw_stats.teth.prod_stats_sum[i], 0,
+ sizeof(ipa3_ctx->hw_stats.teth.prod_stats_sum[i]));
memset(&ipa3_ctx->hw_stats.teth.prod_stats[i], 0,
sizeof(ipa3_ctx->hw_stats.teth.prod_stats[i]));
+ }
ipa3_ctx->hw_stats.teth.init.prod_bitmask = in->prod_mask;
memcpy(ipa3_ctx->hw_stats.teth.init.cons_bitmask, in->dst_ep_mask,
sizeof(ipa3_ctx->hw_stats.teth.init.cons_bitmask));
@@ -458,8 +512,7 @@
return ret;
}
-int ipa_get_teth_stats(enum ipa_client_type prod,
- struct ipa_quota_stats_all *out)
+int ipa_get_teth_stats(void)
{
int i, j;
int ret;
@@ -470,15 +523,14 @@
struct ipa_mem_buffer mem;
struct ipa3_desc desc = { 0 };
struct ipahal_stats_tethering_all *stats;
+ struct ipa_hw_stats_teth *sw_stats = &ipa3_ctx->hw_stats.teth;
+ struct ipahal_stats_init_tethering *init =
+ (struct ipahal_stats_init_tethering *)
+ &ipa3_ctx->hw_stats.teth.init;
if (!ipa3_ctx->hw_stats.enabled)
return 0;
- if (!IPA_CLIENT_IS_PROD(prod) || ipa3_get_ep_mapping(prod) == -1) {
- IPAERR("invalid prod %d\n", prod);
- return -EINVAL;
- }
-
get_offset.init = ipa3_ctx->hw_stats.teth.init;
ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_TETHERING, &get_offset,
&offset);
@@ -539,6 +591,12 @@
goto free_stats;
}
+ /* reset prod_stats cache */
+ for (i = 0; i < IPA_CLIENT_MAX; i++) {
+ memset(&ipa3_ctx->hw_stats.teth.prod_stats[i], 0,
+ sizeof(ipa3_ctx->hw_stats.teth.prod_stats[i]));
+ }
+
/*
* update driver cache.
* the stats were read from hardware with clear_after_read meaning
@@ -546,8 +604,6 @@
*/
for (i = 0; i < IPA_CLIENT_MAX; i++) {
for (j = 0; j < IPA_CLIENT_MAX; j++) {
- struct ipa_hw_stats_teth *sw_stats =
- &ipa3_ctx->hw_stats.teth;
int prod_idx = ipa3_get_ep_mapping(i);
int cons_idx = ipa3_get_ep_mapping(j);
@@ -557,29 +613,64 @@
if (cons_idx == -1 || cons_idx >= IPA3_MAX_NUM_PIPES)
continue;
- if (ipa3_ctx->ep[prod_idx].client != i ||
- ipa3_ctx->ep[cons_idx].client != j)
- continue;
+ /* save hw-query result */
+ if ((init->prod_bitmask & (1 << prod_idx)) &&
+ (init->cons_bitmask[prod_idx]
+ & (1 << cons_idx))) {
+ IPADBG_LOW("prod %d cons %d\n",
+ prod_idx, cons_idx);
+ IPADBG_LOW("num_ipv4_bytes %lld\n",
+ stats->stats[prod_idx][cons_idx].
+ num_ipv4_bytes);
+ IPADBG_LOW("num_ipv4_pkts %lld\n",
+ stats->stats[prod_idx][cons_idx].
+ num_ipv4_pkts);
+ IPADBG_LOW("num_ipv6_pkts %lld\n",
+ stats->stats[prod_idx][cons_idx].
+ num_ipv6_pkts);
+ IPADBG_LOW("num_ipv6_bytes %lld\n",
+ stats->stats[prod_idx][cons_idx].
+ num_ipv6_bytes);
- sw_stats->prod_stats[i].client[j].num_ipv4_bytes +=
- stats->stats[prod_idx][cons_idx].num_ipv4_bytes;
- sw_stats->prod_stats[i].client[j].num_ipv4_pkts +=
- stats->stats[prod_idx][cons_idx].num_ipv4_pkts;
- sw_stats->prod_stats[i].client[j].num_ipv6_bytes +=
- stats->stats[prod_idx][cons_idx].num_ipv6_bytes;
- sw_stats->prod_stats[i].client[j].num_ipv6_pkts +=
- stats->stats[prod_idx][cons_idx].num_ipv6_pkts;
+ /* update stats*/
+ sw_stats->prod_stats[i].
+ client[j].num_ipv4_bytes =
+ stats->stats[prod_idx][cons_idx].
+ num_ipv4_bytes;
+ sw_stats->prod_stats[i].
+ client[j].num_ipv4_pkts =
+ stats->stats[prod_idx][cons_idx].
+ num_ipv4_pkts;
+ sw_stats->prod_stats[i].
+ client[j].num_ipv6_bytes =
+ stats->stats[prod_idx][cons_idx].
+ num_ipv6_bytes;
+ sw_stats->prod_stats[i].
+ client[j].num_ipv6_pkts =
+ stats->stats[prod_idx][cons_idx].
+ num_ipv6_pkts;
+
+ /* Accumulated stats */
+ sw_stats->prod_stats_sum[i].
+ client[j].num_ipv4_bytes +=
+ stats->stats[prod_idx][cons_idx].
+ num_ipv4_bytes;
+ sw_stats->prod_stats_sum[i].
+ client[j].num_ipv4_pkts +=
+ stats->stats[prod_idx][cons_idx].
+ num_ipv4_pkts;
+ sw_stats->prod_stats_sum[i].
+ client[j].num_ipv6_bytes +=
+ stats->stats[prod_idx][cons_idx].
+ num_ipv6_bytes;
+ sw_stats->prod_stats_sum[i].
+ client[j].num_ipv6_pkts +=
+ stats->stats[prod_idx][cons_idx].
+ num_ipv6_pkts;
+ }
}
}
- if (!out) {
- ret = 0;
- goto free_stats;
- }
-
- /* copy results to out parameter */
- *out = ipa3_ctx->hw_stats.teth.prod_stats[prod];
-
ret = 0;
free_stats:
kfree(stats);
@@ -591,6 +682,22 @@
}
+int ipa_query_teth_stats(enum ipa_client_type prod,
+ struct ipa_quota_stats_all *out, bool reset)
+{
+ if (!IPA_CLIENT_IS_PROD(prod) || ipa3_get_ep_mapping(prod) == -1) {
+ IPAERR("invalid prod %d\n", prod);
+ return -EINVAL;
+ }
+
+ /* copy results to out parameter */
+ if (reset)
+ *out = ipa3_ctx->hw_stats.teth.prod_stats[prod];
+ else
+ *out = ipa3_ctx->hw_stats.teth.prod_stats_sum[prod];
+ return 0;
+}
+
int ipa_reset_teth_stats(enum ipa_client_type prod, enum ipa_client_type cons)
{
int ret;
@@ -605,14 +712,14 @@
}
/* reading stats will reset them in hardware */
- ret = ipa_get_teth_stats(prod, NULL);
+ ret = ipa_get_teth_stats();
if (ret) {
IPAERR("ipa_get_teth_stats failed %d\n", ret);
return ret;
}
/* reset driver's cache */
- stats = &ipa3_ctx->hw_stats.teth.prod_stats[prod].client[cons];
+ stats = &ipa3_ctx->hw_stats.teth.prod_stats_sum[prod].client[cons];
memset(stats, 0, sizeof(*stats));
return 0;
}
@@ -632,7 +739,7 @@
}
/* reading stats will reset them in hardware */
- ret = ipa_get_teth_stats(prod, NULL);
+ ret = ipa_get_teth_stats();
if (ret) {
IPAERR("ipa_get_teth_stats failed %d\n", ret);
return ret;
@@ -640,7 +747,7 @@
/* reset driver's cache */
for (i = 0; i < IPA_CLIENT_MAX; i++) {
- stats = &ipa3_ctx->hw_stats.teth.prod_stats[prod].client[i];
+ stats = &ipa3_ctx->hw_stats.teth.prod_stats_sum[prod].client[i];
memset(stats, 0, sizeof(*stats));
}
@@ -659,7 +766,7 @@
/* reading stats will reset them in hardware */
for (i = 0; i < IPA_CLIENT_MAX; i++) {
if (IPA_CLIENT_IS_PROD(i) && ipa3_get_ep_mapping(i) != -1) {
- ret = ipa_get_teth_stats(i, NULL);
+ ret = ipa_get_teth_stats();
if (ret) {
IPAERR("ipa_get_teth_stats failed %d\n", ret);
return ret;
@@ -671,7 +778,7 @@
/* reset driver's cache */
for (i = 0; i < IPA_CLIENT_MAX; i++) {
- stats = &ipa3_ctx->hw_stats.teth.prod_stats[i];
+ stats = &ipa3_ctx->hw_stats.teth.prod_stats_sum[i];
memset(stats, 0, sizeof(*stats));
}
@@ -1566,7 +1673,7 @@
(1 << ep_idx)))
continue;
- res = ipa_get_teth_stats(i, out);
+ res = ipa_get_teth_stats();
if (res) {
mutex_unlock(&ipa3_ctx->lock);
kfree(out);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 7bd1731..d0db35a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -185,6 +185,16 @@
#define IPA3_ACTIVE_CLIENTS_LOG_HASHTABLE_SIZE 50
#define IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN 40
+#define IPA_WDI_RX_RING_RES 0
+#define IPA_WDI_RX_RING_RP_RES 1
+#define IPA_WDI_RX_COMP_RING_RES 2
+#define IPA_WDI_RX_COMP_RING_WP_RES 3
+#define IPA_WDI_TX_RING_RES 4
+#define IPA_WDI_CE_RING_RES 5
+#define IPA_WDI_CE_DB_RES 6
+#define IPA_WDI_TX_DB_RES 7
+#define IPA_WDI_MAX_RES 8
+
struct ipa3_active_client_htable_entry {
struct hlist_node list;
char id_string[IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN];
@@ -1114,6 +1124,7 @@
struct ipa_hw_stats_teth {
struct ipahal_stats_init_tethering init;
+ struct ipa_quota_stats_all prod_stats_sum[IPA_CLIENT_MAX];
struct ipa_quota_stats_all prod_stats[IPA_CLIENT_MAX];
};
@@ -1898,8 +1909,9 @@
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);
-int ipa3_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
- struct ipa_wdi3_conn_out_params *out);
+int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
+ struct ipa_wdi_conn_out_params *out,
+ ipa_wdi_meter_notifier_cb wdi_notify);
int ipa3_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
int ipa3_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
int ipa3_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
@@ -1921,6 +1933,10 @@
*/
int ipa3_uc_dereg_rdyCB(void);
+int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
+ phys_addr_t pa, struct sg_table *sgt, size_t len, bool device,
+ unsigned long *iova);
+
/*
* Tethering bridge (Rmnet / MBIM)
*/
@@ -2236,8 +2252,10 @@
int ipa_init_teth_stats(struct ipa_teth_stats_endpoints *in);
-int ipa_get_teth_stats(enum ipa_client_type prod,
- struct ipa_quota_stats_all *out);
+int ipa_get_teth_stats(void);
+
+int ipa_query_teth_stats(enum ipa_client_type prod,
+ struct ipa_quota_stats_all *out, bool reset);
int ipa_reset_teth_stats(enum ipa_client_type prod, enum ipa_client_type cons);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
index c2daa05..19d3d30 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -31,6 +31,13 @@
#define IPA_IPV6CT_MAX_NUM_OF_INIT_CMD_DESC 2
#define IPA_MAX_NUM_OF_TABLE_DMA_CMD_DESC 4
+/*
+ * The base table max entries is limited by index into table 13 bits number.
+ * Limit the memory size required by user to prevent kernel memory starvation
+ */
+#define IPA_TABLE_MAX_ENTRIES 8192
+#define MAX_ALLOC_NAT_SIZE(size) (IPA_TABLE_MAX_ENTRIES * size)
+
enum ipa_nat_ipv6ct_table_type {
IPA_NAT_BASE_TBL = 0,
IPA_NAT_EXPN_TBL = 1,
@@ -338,10 +345,12 @@
}
static int ipa3_nat_ipv6ct_allocate_mem(struct ipa3_nat_ipv6ct_common_mem *dev,
- struct ipa_ioc_nat_ipv6ct_table_alloc *table_alloc)
+ struct ipa_ioc_nat_ipv6ct_table_alloc *table_alloc,
+ enum ipahal_nat_type nat_type)
{
gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO;
int result = 0;
+ size_t nat_entry_size;
IPADBG("passed memory size %zu for %s\n",
table_alloc->size, dev->name);
@@ -358,6 +367,15 @@
goto bail;
}
+ ipahal_nat_entry_size(nat_type, &nat_entry_size);
+ if (table_alloc->size > MAX_ALLOC_NAT_SIZE(nat_entry_size)) {
+ IPAERR("Trying allocate more size = %zu, Max allowed = %zu\n",
+ table_alloc->size,
+ MAX_ALLOC_NAT_SIZE(nat_entry_size));
+ result = -EPERM;
+ goto bail;
+ }
+
if (!table_alloc->size) {
IPAERR_RL("Invalid Parameters\n");
result = -EPERM;
@@ -433,7 +451,8 @@
mutex_lock(&nat_ctx->dev.lock);
- result = ipa3_nat_ipv6ct_allocate_mem(&nat_ctx->dev, table_alloc);
+ result = ipa3_nat_ipv6ct_allocate_mem(&nat_ctx->dev, table_alloc,
+ IPAHAL_NAT_IPV4);
if (result)
goto bail;
@@ -507,7 +526,7 @@
mutex_lock(&ipa3_ctx->ipv6ct_mem.dev.lock);
result = ipa3_nat_ipv6ct_allocate_mem(
- &ipa3_ctx->ipv6ct_mem.dev, table_alloc);
+ &ipa3_ctx->ipv6ct_mem.dev, table_alloc, IPAHAL_NAT_IPV6CT);
if (result)
goto bail;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
index 205e7a5..0772dde 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
@@ -16,7 +16,7 @@
#include <linux/msm_ipa.h>
/* internal to ipa */
-#define IPA_PM_MAX_CLIENTS 11 /* actual max is value -1 since we start from 1*/
+#define IPA_PM_MAX_CLIENTS 12 /* actual max is value -1 since we start from 1*/
#define IPA_PM_MAX_EX_CL 64
#define IPA_PM_THRESHOLD_MAX 5
#define IPA_PM_EXCEPTION_MAX 2
@@ -90,6 +90,8 @@
bool skip_clk_vote;
};
+#ifdef CONFIG_IPA3
+
int ipa_pm_register(struct ipa_pm_register_params *params, u32 *hdl);
int ipa_pm_associate_ipa_cons_to_client(u32 hdl, enum ipa_client_type consumer);
int ipa_pm_activate(u32 hdl);
@@ -107,4 +109,80 @@
int ipa_pm_stat(char *buf, int size);
int ipa_pm_exceptions_stat(char *buf, int size);
+#else
+
+static inline int ipa_pm_register(
+ struct ipa_pm_register_params *params, u32 *hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_pm_associate_ipa_cons_to_client(
+ u32 hdl, enum ipa_client_type consumer)
+{
+ return -EPERM;
+}
+
+static inline int ipa_pm_activate(u32 hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_pm_activate_sync(u32 hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_pm_deferred_deactivate(u32 hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_pm_deactivate_sync(u32 hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_pm_set_perf_profile(u32 hdl, int throughput)
+{
+ return -EPERM;
+}
+
+static inline int ipa_pm_deregister(u32 hdl)
+{
+ return -EPERM;
+}
+
+/* IPA Internal Functions */
+static inline int ipa_pm_init(struct ipa_pm_init_params *params)
+{
+ return -EPERM;
+}
+
+static inline int ipa_pm_destroy(void)
+{
+ return -EPERM;
+}
+
+static inline int ipa_pm_handle_suspend(u32 pipe_bitmask)
+{
+ return -EPERM;
+}
+
+static inline int ipa_pm_deactivate_all_deferred(void)
+{
+ return -EPERM;
+}
+
+static inline int ipa_pm_stat(char *buf, int size)
+{
+ return -EPERM;
+}
+
+static inline int ipa_pm_exceptions_stat(char *buf, int size)
+{
+ return -EPERM;
+}
+#endif
+
#endif /* _IPA_PM_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
index c158c94..88de06e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -708,7 +708,7 @@
return -EINVAL;
}
- for (i = 0; i < req->filter_spec_ex_list_len-1; i++) {
+ for (i = 0; i < req->filter_spec_ex_list_len; i++) {
if ((req->filter_spec_ex_list[i].ip_type !=
QMI_IPA_IP_TYPE_V4_V01) &&
(req->filter_spec_ex_list[i].ip_type !=
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index 1bdc0fb..a0f1f54 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -52,6 +52,8 @@
struct ipa3_rt_entry *entry, u8 *buf)
{
struct ipahal_rt_rule_gen_params gen_params;
+ struct ipa3_hdr_entry *hdr_entry;
+ struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry;
int res = 0;
memset(&gen_params, 0, sizeof(gen_params));
@@ -71,6 +73,25 @@
return -EPERM;
}
+ /* Adding check to confirm still
+ * header entry present in header table or not
+ */
+
+ if (entry->hdr) {
+ hdr_entry = ipa3_id_find(entry->rule.hdr_hdl);
+ if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+ IPAERR_RL("Header entry already deleted\n");
+ return -EPERM;
+ }
+ } else if (entry->proc_ctx) {
+ hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl);
+ if (!hdr_proc_entry ||
+ hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+ IPAERR_RL("Proc header entry already deleted\n");
+ return -EPERM;
+ }
+ }
+
if (entry->proc_ctx || (entry->hdr && entry->hdr->is_hdr_proc_ctx)) {
struct ipa3_hdr_proc_ctx_entry *proc_ctx;
@@ -1269,6 +1290,8 @@
{
struct ipa3_rt_entry *entry;
int id;
+ struct ipa3_hdr_entry *hdr_entry;
+ struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry;
entry = ipa3_id_find(rule_hdl);
@@ -1291,6 +1314,25 @@
}
}
+ /* Adding check to confirm still
+ * header entry present in header table or not
+ */
+
+ if (entry->hdr) {
+ hdr_entry = ipa3_id_find(entry->rule.hdr_hdl);
+ if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+ IPAERR_RL("Header entry already deleted\n");
+ return -EINVAL;
+ }
+ } else if (entry->proc_ctx) {
+ hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl);
+ if (!hdr_proc_entry ||
+ hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+ IPAERR_RL("Proc header entry already deleted\n");
+ return -EINVAL;
+ }
+ }
+
if (entry->hdr)
__ipa3_release_hdr(entry->hdr->id);
else if (entry->proc_ctx)
@@ -1611,7 +1653,8 @@
struct ipa3_rt_entry *entry;
struct ipa3_hdr_entry *hdr = NULL;
struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL;
-
+ struct ipa3_hdr_entry *hdr_entry;
+ struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry;
if (rtrule->rule.hdr_hdl) {
hdr = ipa3_id_find(rtrule->rule.hdr_hdl);
if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) {
@@ -1638,6 +1681,25 @@
goto error;
}
+ /* Adding check to confirm still
+ * header entry present in header table or not
+ */
+
+ if (entry->hdr) {
+ hdr_entry = ipa3_id_find(entry->rule.hdr_hdl);
+ if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+ IPAERR_RL("Header entry already deleted\n");
+ return -EPERM;
+ }
+ } else if (entry->proc_ctx) {
+ hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl);
+ if (!hdr_proc_entry ||
+ hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+ IPAERR_RL("Proc header entry already deleted\n");
+ return -EPERM;
+ }
+ }
+
if (entry->hdr)
entry->hdr->ref_cnt--;
if (entry->proc_ctx)
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
index 648db5e..ec777bc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
@@ -16,6 +16,7 @@
#include "ipa_qmi_service.h"
#define IPA_HOLB_TMR_DIS 0x0
+#define IPA_HOLB_TMR_EN 0x1
#define IPA_HW_INTERFACE_WDI_VERSION 0x0001
#define IPA_HW_WDI_RX_MBOX_START_INDEX 48
@@ -27,15 +28,6 @@
#define IPA_WDI_RESUMED BIT(2)
#define IPA_UC_POLL_SLEEP_USEC 100
-#define IPA_WDI_RX_RING_RES 0
-#define IPA_WDI_RX_RING_RP_RES 1
-#define IPA_WDI_RX_COMP_RING_RES 2
-#define IPA_WDI_RX_COMP_RING_WP_RES 3
-#define IPA_WDI_TX_RING_RES 4
-#define IPA_WDI_CE_RING_RES 5
-#define IPA_WDI_CE_DB_RES 6
-#define IPA_WDI_MAX_RES 7
-
struct ipa_wdi_res {
struct ipa_wdi_buffer_info *res;
unsigned int nents;
@@ -669,7 +661,7 @@
}
}
-static int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
+int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
phys_addr_t pa, struct sg_table *sgt, size_t len, bool device,
unsigned long *iova)
{
@@ -702,6 +694,7 @@
case IPA_WDI_RX_RING_RP_RES:
case IPA_WDI_RX_COMP_RING_WP_RES:
case IPA_WDI_CE_DB_RES:
+ case IPA_WDI_TX_DB_RES:
if (ipa_create_uc_smmu_mapping_pa(pa, len,
(res_idx == IPA_WDI_CE_DB_RES) ? true : false,
iova)) {
@@ -839,35 +832,6 @@
in->u.ul.rdy_comp_ring_wp_pa;
ipa3_ctx->uc_ctx.rdy_comp_ring_size =
in->u.ul.rdy_comp_ring_size;
-
- /* check if the VA is empty */
- if (ipa3_ctx->ipa_wdi2) {
- if (in->smmu_enabled) {
- if (!in->u.ul_smmu.rdy_ring_rp_va ||
- !in->u.ul_smmu.rdy_comp_ring_wp_va)
- goto dma_alloc_fail;
- } else {
- if (!in->u.ul.rdy_ring_rp_va ||
- !in->u.ul.rdy_comp_ring_wp_va)
- goto dma_alloc_fail;
- }
- IPADBG("rdy_ring_rp value =%d\n",
- in->smmu_enabled ?
- *in->u.ul_smmu.rdy_ring_rp_va :
- *in->u.ul.rdy_ring_rp_va);
- IPADBG("rx_comp_ring_wp value=%d\n",
- in->smmu_enabled ?
- *in->u.ul_smmu.rdy_comp_ring_wp_va :
- *in->u.ul.rdy_comp_ring_wp_va);
- ipa3_ctx->uc_ctx.rdy_ring_rp_va =
- in->smmu_enabled ?
- in->u.ul_smmu.rdy_ring_rp_va :
- in->u.ul.rdy_ring_rp_va;
- ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va =
- in->smmu_enabled ?
- in->u.ul_smmu.rdy_comp_ring_wp_va :
- in->u.ul.rdy_comp_ring_wp_va;
- }
}
cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
@@ -1534,6 +1498,24 @@
return result;
}
+static void ipa3_cfg_holb_wdi_consumer(bool is_enable)
+{
+ u32 clnt_hdl;
+ struct ipa_ep_cfg_holb holb_cfg;
+
+ clnt_hdl = ipa3_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
+ if (clnt_hdl < ipa3_ctx->ipa_num_pipes &&
+ ipa3_ctx->ep[clnt_hdl].valid == 1) {
+ memset(&holb_cfg, 0, sizeof(holb_cfg));
+ if (is_enable)
+ holb_cfg.en = IPA_HOLB_TMR_EN;
+ else
+ holb_cfg.en = IPA_HOLB_TMR_DIS;
+ holb_cfg.tmr_val = 0;
+ ipa3_cfg_ep_holb(clnt_hdl, &holb_cfg);
+ }
+}
+
/**
* ipa3_suspend_wdi_pipe() - WDI client suspend
* @clnt_hdl: [in] opaque client handle assigned by IPA to client
@@ -1600,6 +1582,9 @@
}
}
+ /* Enabling HOLB on WDI consumer pipe */
+ ipa3_cfg_holb_wdi_consumer(true);
+
IPADBG("Post suspend event first for IPA Producer\n");
IPADBG("Client: %d clnt_hdl: %d\n", ep->client, clnt_hdl);
result = ipa3_uc_send_cmd(suspend.raw32b,
@@ -1609,8 +1594,12 @@
if (result) {
result = -EFAULT;
+ /* Disabling HOLB on WDI consumer pipe */
+ ipa3_cfg_holb_wdi_consumer(false);
goto uc_timeout;
}
+ /* Disabling HOLB on WDI consumer pipe */
+ ipa3_cfg_holb_wdi_consumer(false);
}
memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index b3726e1..897da58 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -88,6 +88,8 @@
#define IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_DEC_UCP 0x00000013
/* 2 Packet Processing pass + no decipher + uCP */
#define IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP 0x00000004
+/* 2 Packet Processing pass + no decipher + uCP + HPS REP DMA Parser. */
+#define IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP 0x00000804
/* 2 Packet Processing pass + decipher + uCP */
#define IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_DEC_UCP 0x00000015
/* Packet Processing + no decipher + no uCP */
@@ -1115,13 +1117,13 @@
[IPA_4_0][IPA_CLIENT_WLAN1_PROD] = {
true, IPA_v4_0_GROUP_UL_DL,
true,
- IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
+ IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP,
QMB_MASTER_SELECT_DDR,
{ 6, 2, 8, 16, IPA_EE_UC } },
[IPA_4_0][IPA_CLIENT_USB_PROD] = {
true, IPA_v4_0_GROUP_UL_DL,
true,
- IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
+ IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP,
QMB_MASTER_SELECT_DDR,
{ 0, 8, 8, 16, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_APPS_LAN_PROD] = {
@@ -1133,7 +1135,7 @@
[IPA_4_0][IPA_CLIENT_APPS_WAN_PROD] = {
true, IPA_v4_0_GROUP_UL_DL,
true,
- IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
+ IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP,
QMB_MASTER_SELECT_DDR,
{ 2, 3, 16, 32, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_APPS_CMD_PROD] = {
@@ -1145,13 +1147,13 @@
[IPA_4_0][IPA_CLIENT_ODU_PROD] = {
true, IPA_v4_0_GROUP_UL_DL,
true,
- IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
+ IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP,
QMB_MASTER_SELECT_DDR,
{ 1, 0, 8, 16, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_ETHERNET_PROD] = {
true, IPA_v4_0_GROUP_UL_DL,
true,
- IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
+ IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP,
QMB_MASTER_SELECT_DDR,
{ 9, 0, 8, 16, IPA_EE_UC } },
[IPA_4_0][IPA_CLIENT_Q6_WAN_PROD] = {
@@ -3822,6 +3824,9 @@
}
#define REQUIRED_TAG_PROCESS_DESCRIPTORS 4
+#define MAX_RETRY_ALLOC 10
+#define ALLOC_MIN_SLEEP_RX 100000
+#define ALLOC_MAX_SLEEP_RX 200000
/* ipa3_tag_process() - Initiates a tag process. Incorporates the input
* descriptors
@@ -3849,6 +3854,7 @@
int res;
struct ipa3_tag_completion *comp;
int ep_idx;
+ u32 retry_cnt = 0;
/* Not enough room for the required descriptors for the tag process */
if (IPA_TAG_MAX_DESC - descs_num < REQUIRED_TAG_PROCESS_DESCRIPTORS) {
@@ -3954,10 +3960,22 @@
tag_desc[desc_idx].callback = ipa3_tag_free_skb;
tag_desc[desc_idx].user1 = dummy_skb;
desc_idx++;
-
+retry_alloc:
/* send all descriptors to IPA with single EOT */
res = ipa3_send(sys, desc_idx, tag_desc, true);
if (res) {
+ if (res == -ENOMEM) {
+ if (retry_cnt < MAX_RETRY_ALLOC) {
+ IPADBG(
+ "failed to alloc memory retry cnt = %d\n",
+ retry_cnt);
+ retry_cnt++;
+ usleep_range(ALLOC_MIN_SLEEP_RX,
+ ALLOC_MAX_SLEEP_RX);
+ goto retry_alloc;
+ }
+
+ }
IPAERR("failed to send TAG packets %d\n", res);
res = -ENOMEM;
goto fail_free_skb;
@@ -4519,10 +4537,10 @@
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;
- api_ctrl->ipa_conn_wdi3_pipes = ipa3_conn_wdi3_pipes;
- api_ctrl->ipa_disconn_wdi3_pipes = ipa3_disconn_wdi3_pipes;
- api_ctrl->ipa_enable_wdi3_pipes = ipa3_enable_wdi3_pipes;
- api_ctrl->ipa_disable_wdi3_pipes = ipa3_disable_wdi3_pipes;
+ api_ctrl->ipa_conn_wdi_pipes = ipa3_conn_wdi3_pipes;
+ api_ctrl->ipa_disconn_wdi_pipes = ipa3_disconn_wdi3_pipes;
+ api_ctrl->ipa_enable_wdi_pipes = ipa3_enable_wdi3_pipes;
+ api_ctrl->ipa_disable_wdi_pipes = ipa3_disable_wdi3_pipes;
api_ctrl->ipa_tz_unlock_reg = ipa3_tz_unlock_reg;
api_ctrl->ipa_get_smmu_params = ipa3_get_smmu_params;
api_ctrl->ipa_is_vlan_mode = ipa3_is_vlan_mode;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c
index 7801745..6c019b9 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -16,35 +16,21 @@
#define IPA_HW_WDI3_TX_MBOX_START_INDEX 50
static int ipa3_send_wdi3_setup_pipe_cmd(
- struct ipa_wdi3_setup_info *info, u8 dir)
+ u8 is_smmu_enabled, struct ipa_wdi_pipe_setup_info *info,
+ struct ipa_wdi_pipe_setup_info_smmu *info_smmu, u8 dir)
{
int ipa_ep_idx;
- int result = 0;
+ int result = 0, len;
+ unsigned long va;
struct ipa_mem_buffer cmd;
struct IpaHwWdi3SetUpCmdData_t *wdi3_params;
struct IpaHwOffloadSetUpCmdData_t *cmd_data;
- if (info == NULL) {
+ if (info == NULL || info_smmu == NULL) {
IPAERR("invalid input\n");
return -EINVAL;
}
- ipa_ep_idx = ipa_get_ep_mapping(info->client);
- if (ipa_ep_idx == -1) {
- IPAERR("fail to get ep idx.\n");
- return -EFAULT;
- }
-
- IPADBG("client=%d ep=%d\n", info->client, ipa_ep_idx);
- IPADBG("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
- IPADBG("ring_size = %hu\n", info->transfer_ring_size);
- IPADBG("ring_db_pa = 0x%pad\n", &info->transfer_ring_doorbell_pa);
- IPADBG("evt_ring_base_pa = 0x%pad\n", &info->event_ring_base_pa);
- IPADBG("evt_ring_size = %hu\n", info->event_ring_size);
- IPADBG("evt_ring_db_pa = 0x%pad\n", &info->event_ring_doorbell_pa);
- IPADBG("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
- IPADBG("pkt_offset = %d\n", info->pkt_offset);
-
cmd.size = sizeof(*cmd_data);
cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
&cmd.phys_base, GFP_KERNEL);
@@ -56,29 +42,177 @@
cmd_data = (struct IpaHwOffloadSetUpCmdData_t *)cmd.base;
cmd_data->protocol = IPA_HW_FEATURE_WDI3;
- wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
- wdi3_params->transfer_ring_base_pa = (u32)info->transfer_ring_base_pa;
- wdi3_params->transfer_ring_base_pa_hi =
- (u32)((u64)info->transfer_ring_base_pa >> 32);
- wdi3_params->transfer_ring_size = info->transfer_ring_size;
- wdi3_params->transfer_ring_doorbell_pa =
- (u32)info->transfer_ring_doorbell_pa;
- wdi3_params->transfer_ring_doorbell_pa_hi =
- (u32)((u64)info->transfer_ring_doorbell_pa >> 32);
- wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
- wdi3_params->event_ring_base_pa_hi =
- (u32)((u64)info->event_ring_base_pa >> 32);
- wdi3_params->event_ring_size = info->event_ring_size;
- wdi3_params->event_ring_doorbell_pa =
- (u32)info->event_ring_doorbell_pa;
- wdi3_params->event_ring_doorbell_pa_hi =
- (u32)((u64)info->event_ring_doorbell_pa >> 32);
- wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
- wdi3_params->ipa_pipe_number = ipa_ep_idx;
- wdi3_params->dir = dir;
- wdi3_params->pkt_offset = info->pkt_offset;
- memcpy(wdi3_params->desc_format_template, info->desc_format_template,
- sizeof(wdi3_params->desc_format_template));
+ if (!is_smmu_enabled) {
+ ipa_ep_idx = ipa_get_ep_mapping(info->client);
+ if (ipa_ep_idx == -1) {
+ IPAERR("fail to get ep idx.\n");
+ return -EFAULT;
+ }
+
+ IPADBG("client=%d ep=%d\n", info->client, ipa_ep_idx);
+ IPADBG("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
+ IPADBG("ring_size = %hu\n", info->transfer_ring_size);
+ IPADBG("ring_db_pa = 0x%pad\n",
+ &info->transfer_ring_doorbell_pa);
+ IPADBG("evt_ring_base_pa = 0x%pad\n",
+ &info->event_ring_base_pa);
+ IPADBG("evt_ring_size = %hu\n", info->event_ring_size);
+ IPADBG("evt_ring_db_pa = 0x%pad\n",
+ &info->event_ring_doorbell_pa);
+ IPADBG("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
+ IPADBG("pkt_offset = %d\n", info->pkt_offset);
+
+ wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
+ wdi3_params->transfer_ring_base_pa =
+ (u32)info->transfer_ring_base_pa;
+ wdi3_params->transfer_ring_base_pa_hi =
+ (u32)((u64)info->transfer_ring_base_pa >> 32);
+ wdi3_params->transfer_ring_size = info->transfer_ring_size;
+ wdi3_params->transfer_ring_doorbell_pa =
+ (u32)info->transfer_ring_doorbell_pa;
+ wdi3_params->transfer_ring_doorbell_pa_hi =
+ (u32)((u64)info->transfer_ring_doorbell_pa >> 32);
+ wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
+ wdi3_params->event_ring_base_pa_hi =
+ (u32)((u64)info->event_ring_base_pa >> 32);
+ wdi3_params->event_ring_size = info->event_ring_size;
+ wdi3_params->event_ring_doorbell_pa =
+ (u32)info->event_ring_doorbell_pa;
+ wdi3_params->event_ring_doorbell_pa_hi =
+ (u32)((u64)info->event_ring_doorbell_pa >> 32);
+ wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
+ wdi3_params->ipa_pipe_number = ipa_ep_idx;
+ wdi3_params->dir = dir;
+ wdi3_params->pkt_offset = info->pkt_offset;
+ memcpy(wdi3_params->desc_format_template,
+ info->desc_format_template,
+ sizeof(wdi3_params->desc_format_template));
+ } else {
+ ipa_ep_idx = ipa_get_ep_mapping(info_smmu->client);
+ if (ipa_ep_idx == -1) {
+ IPAERR("fail to get ep idx\n");
+ return -EFAULT;
+ }
+
+ IPADBG("client=%d ep=%d\n", info_smmu->client, ipa_ep_idx);
+ IPADBG("ring_size = %hu\n", info_smmu->transfer_ring_size);
+ IPADBG("ring_db_pa = 0x%pad\n",
+ &info_smmu->transfer_ring_doorbell_pa);
+ IPADBG("evt_ring_size = %hu\n", info_smmu->event_ring_size);
+ IPADBG("evt_ring_db_pa = 0x%pad\n",
+ &info_smmu->event_ring_doorbell_pa);
+ IPADBG("num_pkt_buffers = %hu\n", info_smmu->num_pkt_buffers);
+ IPADBG("pkt_offset = %d\n", info_smmu->pkt_offset);
+
+ wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
+
+ if (dir == IPA_WDI3_TX_DIR) {
+ len = info_smmu->transfer_ring_size;
+ if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
+ true, info->transfer_ring_base_pa,
+ &info_smmu->transfer_ring_base, len,
+ false, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->transfer_ring_base_pa = (u32)va;
+ wdi3_params->transfer_ring_base_pa_hi =
+ (u32)((u64)va >> 32);
+ wdi3_params->transfer_ring_size = len;
+
+ if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_DB_RES,
+ true, info_smmu->transfer_ring_doorbell_pa,
+ NULL, 4, true, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->transfer_ring_doorbell_pa =
+ (u32)va;
+ wdi3_params->transfer_ring_doorbell_pa_hi =
+ (u32)((u64)va >> 32);
+
+ len = info_smmu->event_ring_size;
+ if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
+ true, info->event_ring_base_pa,
+ &info_smmu->event_ring_base, len,
+ false, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->event_ring_base_pa = (u32)va;
+ wdi3_params->event_ring_base_pa_hi =
+ (u32)((u64)va >> 32);
+ wdi3_params->event_ring_size = len;
+
+ if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
+ true, info_smmu->event_ring_doorbell_pa,
+ NULL, 4, true, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->event_ring_doorbell_pa =
+ (u32)va;
+ wdi3_params->event_ring_doorbell_pa_hi =
+ (u32)((u64)va >> 32);
+ } else {
+ len = info_smmu->transfer_ring_size;
+ if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
+ true, info->transfer_ring_base_pa,
+ &info_smmu->transfer_ring_base, len,
+ false, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->transfer_ring_base_pa = (u32)va;
+ wdi3_params->transfer_ring_base_pa_hi =
+ (u32)((u64)va >> 32);
+ wdi3_params->transfer_ring_size = len;
+
+ if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
+ true, info_smmu->transfer_ring_doorbell_pa,
+ NULL, 4, true, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->transfer_ring_doorbell_pa =
+ (u32)va;
+ wdi3_params->transfer_ring_doorbell_pa_hi =
+ (u32)((u64)va >> 32);
+
+ len = info_smmu->event_ring_size;
+ if (ipa_create_uc_smmu_mapping(
+ IPA_WDI_RX_COMP_RING_RES, true,
+ info->event_ring_base_pa,
+ &info_smmu->event_ring_base, len,
+ false, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->event_ring_base_pa = (u32)va;
+ wdi3_params->event_ring_base_pa_hi =
+ (u32)((u64)va >> 32);
+ wdi3_params->event_ring_size = len;
+
+ if (ipa_create_uc_smmu_mapping(
+ IPA_WDI_RX_COMP_RING_WP_RES, true,
+ info_smmu->event_ring_doorbell_pa,
+ NULL, 4, true, &va)) {
+ IPAERR("failed to get smmu mapping\n");
+ return -EFAULT;
+ }
+ wdi3_params->event_ring_doorbell_pa =
+ (u32)va;
+ wdi3_params->event_ring_doorbell_pa_hi =
+ (u32)((u64)va >> 32);
+ }
+ wdi3_params->num_pkt_buffers = info_smmu->num_pkt_buffers;
+ wdi3_params->ipa_pipe_number = ipa_ep_idx;
+ wdi3_params->dir = dir;
+ wdi3_params->pkt_offset = info_smmu->pkt_offset;
+ memcpy(wdi3_params->desc_format_template,
+ info_smmu->desc_format_template,
+ sizeof(wdi3_params->desc_format_template));
+ }
result = ipa3_uc_send_cmd((u32)(cmd.phys_base),
IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP,
@@ -93,9 +227,12 @@
return result;
}
-int ipa3_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
- struct ipa_wdi3_conn_out_params *out)
+int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
+ struct ipa_wdi_conn_out_params *out,
+ ipa_wdi_meter_notifier_cb wdi_notify)
{
+ enum ipa_client_type rx_client;
+ enum ipa_client_type tx_client;
struct ipa3_ep_context *ep_rx;
struct ipa3_ep_context *ep_tx;
int ipa_ep_idx_rx;
@@ -107,8 +244,17 @@
return -EINVAL;
}
- ipa_ep_idx_rx = ipa_get_ep_mapping(in->rx.client);
- ipa_ep_idx_tx = ipa_get_ep_mapping(in->tx.client);
+ if (in->is_smmu_enabled == false) {
+ rx_client = in->u_rx.rx.client;
+ tx_client = in->u_tx.tx.client;
+ } else {
+ rx_client = in->u_rx.rx_smmu.client;
+ tx_client = in->u_tx.tx_smmu.client;
+ }
+
+ ipa_ep_idx_rx = ipa_get_ep_mapping(rx_client);
+ ipa_ep_idx_tx = ipa_get_ep_mapping(tx_client);
+
if (ipa_ep_idx_rx == -1 || ipa_ep_idx_tx == -1) {
IPAERR("fail to alloc EP.\n");
return -EFAULT;
@@ -132,9 +278,14 @@
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+ if (wdi_notify)
+ ipa3_ctx->uc_wdi_ctx.stats_notify = wdi_notify;
+ else
+ IPADBG("wdi_notify is null\n");
+
/* setup rx ep cfg */
ep_rx->valid = 1;
- ep_rx->client = in->rx.client;
+ ep_rx->client = rx_client;
result = ipa3_disable_data_path(ipa_ep_idx_rx);
if (result) {
IPAERR("disable data path failed res=%d clnt=%d.\n", result,
@@ -145,7 +296,12 @@
ep_rx->client_notify = in->notify;
ep_rx->priv = in->priv;
- memcpy(&ep_rx->cfg, &in->rx.ipa_ep_cfg, sizeof(ep_rx->cfg));
+ if (in->is_smmu_enabled == false)
+ memcpy(&ep_rx->cfg, &in->u_rx.rx.ipa_ep_cfg,
+ sizeof(ep_rx->cfg));
+ else
+ memcpy(&ep_rx->cfg, &in->u_rx.rx_smmu.ipa_ep_cfg,
+ sizeof(ep_rx->cfg));
if (ipa3_cfg_ep(ipa_ep_idx_rx, &ep_rx->cfg)) {
IPAERR("fail to setup rx pipe cfg\n");
@@ -153,7 +309,8 @@
goto fail;
}
- if (ipa3_send_wdi3_setup_pipe_cmd(&in->rx, IPA_WDI3_RX_DIR)) {
+ if (ipa3_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
+ &in->u_rx.rx, &in->u_rx.rx_smmu, IPA_WDI3_RX_DIR)) {
IPAERR("fail to send cmd to uc for rx pipe\n");
result = -EFAULT;
goto fail;
@@ -165,12 +322,12 @@
IPA_HW_WDI3_RX_MBOX_START_INDEX/32,
IPA_HW_WDI3_RX_MBOX_START_INDEX % 32);
- IPADBG("client %d (ep: %d) connected\n", in->rx.client,
+ IPADBG("client %d (ep: %d) connected\n", rx_client,
ipa_ep_idx_rx);
- /* setup dl ep cfg */
+ /* setup tx ep cfg */
ep_tx->valid = 1;
- ep_tx->client = in->tx.client;
+ ep_tx->client = tx_client;
result = ipa3_disable_data_path(ipa_ep_idx_tx);
if (result) {
IPAERR("disable data path failed res=%d ep=%d.\n", result,
@@ -179,7 +336,12 @@
goto fail;
}
- memcpy(&ep_tx->cfg, &in->tx.ipa_ep_cfg, sizeof(ep_tx->cfg));
+ if (in->is_smmu_enabled == false)
+ memcpy(&ep_tx->cfg, &in->u_tx.tx.ipa_ep_cfg,
+ sizeof(ep_tx->cfg));
+ else
+ memcpy(&ep_tx->cfg, &in->u_tx.tx_smmu.ipa_ep_cfg,
+ sizeof(ep_tx->cfg));
if (ipa3_cfg_ep(ipa_ep_idx_tx, &ep_tx->cfg)) {
IPAERR("fail to setup tx pipe cfg\n");
@@ -187,7 +349,8 @@
goto fail;
}
- if (ipa3_send_wdi3_setup_pipe_cmd(&in->tx, IPA_WDI3_TX_DIR)) {
+ if (ipa3_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
+ &in->u_tx.tx, &in->u_tx.tx_smmu, IPA_WDI3_TX_DIR)) {
IPAERR("fail to send cmd to uc for tx pipe\n");
result = -EFAULT;
goto fail;
@@ -197,13 +360,7 @@
ipahal_get_reg_mn_ofst(IPA_UC_MAILBOX_m_n,
IPA_HW_WDI3_TX_MBOX_START_INDEX/32,
IPA_HW_WDI3_TX_MBOX_START_INDEX % 32);
- out->tx_uc_db_va = ioremap(out->tx_uc_db_pa, 4);
- if (!out->tx_uc_db_va) {
- IPAERR("fail to ioremap tx uc db\n");
- result = -EFAULT;
- goto fail;
- }
- IPADBG("client %d (ep: %d) connected\n", in->tx.client,
+ IPADBG("client %d (ep: %d) connected\n", tx_client,
ipa_ep_idx_tx);
fail:
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
index 48e7d7c..c3422d1 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
@@ -2129,11 +2129,11 @@
return;
}
- valmask->val = (1 << IPA_ENDP_INIT_AGGR_n_AGGR_FORCE_CLOSE_SHFT) &&
+ valmask->val = (1 << IPA_ENDP_INIT_AGGR_n_AGGR_FORCE_CLOSE_SHFT) &
IPA_ENDP_INIT_AGGR_n_AGGR_FORCE_CLOSE_BMSK;
valmask->mask = IPA_ENDP_INIT_AGGR_n_AGGR_FORCE_CLOSE_BMSK;
- valmask->val |= ((0 << IPA_ENDP_INIT_AGGR_n_AGGR_EN_SHFT) &&
+ valmask->val |= ((0 << IPA_ENDP_INIT_AGGR_n_AGGR_EN_SHFT) &
IPA_ENDP_INIT_AGGR_n_AGGR_EN_BMSK);
valmask->mask |= IPA_ENDP_INIT_AGGR_n_AGGR_EN_BMSK;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index 23dafe1..561c533 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -2699,11 +2699,16 @@
ipa_stop_polling_stats();
if (atomic_read(&rmnet_ipa3_ctx->is_initialized))
platform_driver_unregister(&rmnet_ipa_driver);
+
+ if (atomic_read(&rmnet_ipa3_ctx->is_ssr) &&
+ ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+ ipa3_q6_post_shutdown_cleanup();
IPAWANINFO("IPA BEFORE_SHUTDOWN handling is complete\n");
break;
case SUBSYS_AFTER_SHUTDOWN:
IPAWANINFO("IPA Received MPSS AFTER_SHUTDOWN\n");
- if (atomic_read(&rmnet_ipa3_ctx->is_ssr))
+ if (atomic_read(&rmnet_ipa3_ctx->is_ssr) &&
+ ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
ipa3_q6_post_shutdown_cleanup();
IPAWANINFO("IPA AFTER_SHUTDOWN handling is complete\n");
break;
@@ -3178,9 +3183,6 @@
req->reset_stats_valid = true;
req->reset_stats = true;
IPAWANDBG("reset the pipe stats\n");
- } else {
- /* print tethered-client enum */
- IPAWANDBG("Tethered-client enum(%d)\n", data->ipa_client);
}
rc = ipa3_qmi_get_data_stats(req, resp);
@@ -3272,7 +3274,7 @@
if (data->ipa_client == ipa_get_client(resp->
ul_src_pipe_stats_list[pipe_len].
pipe_index)) {
- /* update the DL stats */
+ /* update the UL stats */
data->ipv4_tx_packets += resp->
ul_src_pipe_stats_list[pipe_len].
num_ipv4_packets;
@@ -3299,6 +3301,133 @@
return 0;
}
+static int rmnet_ipa3_query_tethering_stats_hw(
+ struct wan_ioctl_query_tether_stats *data, bool reset)
+{
+ int rc = 0;
+ struct ipa_quota_stats_all *con_stats;
+
+ if (reset) {
+ IPAWANERR("only reset the pipe stats without returning stats");
+ rc = ipa_get_teth_stats();
+ if (rc) {
+ IPAWANERR("ipa_get_teth_stats failed %d,\n", rc);
+ return rc;
+ }
+ return 0;
+ }
+ /* qet HW-stats */
+ rc = ipa_get_teth_stats();
+ if (rc) {
+ IPAWANDBG("ipa_get_teth_stats failed %d,\n", rc);
+ return rc;
+ }
+
+ /* query DL stats */
+ IPAWANDBG("reset the pipe stats? (%d)\n", reset);
+ con_stats = kzalloc(sizeof(*con_stats), GFP_KERNEL);
+ if (!con_stats) {
+ IPAWANERR("no memory\n");
+ return -ENOMEM;
+ }
+ rc = ipa_query_teth_stats(IPA_CLIENT_Q6_WAN_PROD, con_stats, reset);
+ if (rc) {
+ IPAERR("IPA_CLIENT_Q6_WAN_PROD query failed %d,\n", rc);
+ kfree(con_stats);
+ return rc;
+ }
+ IPAWANDBG("wlan: v4_rx_p(%d) b(%lld) v6_rx_p(%d) b(%lld)\n",
+ con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv4_pkts,
+ con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv4_bytes,
+ con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv6_pkts,
+ con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv6_bytes);
+
+ IPAWANDBG("usb: v4_rx_p(%d) b(%lld) v6_rx_p(%d) b(%lld)\n",
+ con_stats->client[IPA_CLIENT_USB_CONS].num_ipv4_pkts,
+ con_stats->client[IPA_CLIENT_USB_CONS].num_ipv4_bytes,
+ con_stats->client[IPA_CLIENT_USB_CONS].num_ipv6_pkts,
+ con_stats->client[IPA_CLIENT_USB_CONS].num_ipv6_bytes);
+
+ /* update the DL stats */
+ data->ipv4_rx_packets =
+ con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv4_pkts +
+ con_stats->client[IPA_CLIENT_USB_CONS].num_ipv4_pkts;
+ data->ipv6_rx_packets =
+ con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv6_pkts +
+ con_stats->client[IPA_CLIENT_USB_CONS].num_ipv6_pkts;
+ data->ipv4_rx_bytes =
+ con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv4_bytes +
+ con_stats->client[IPA_CLIENT_USB_CONS].num_ipv4_bytes;
+ data->ipv6_rx_bytes =
+ con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv6_bytes +
+ con_stats->client[IPA_CLIENT_USB_CONS].num_ipv6_bytes;
+
+ IPAWANDBG("v4_rx_p(%lu) v6_rx_p(%lu) v4_rx_b(%lu) v6_rx_b(%lu)\n",
+ (unsigned long int) data->ipv4_rx_packets,
+ (unsigned long int) data->ipv6_rx_packets,
+ (unsigned long int) data->ipv4_rx_bytes,
+ (unsigned long int) data->ipv6_rx_bytes);
+
+ /* query USB UL stats */
+ memset(con_stats, 0, sizeof(struct ipa_quota_stats_all));
+ rc = ipa_query_teth_stats(IPA_CLIENT_USB_PROD, con_stats, reset);
+ if (rc) {
+ IPAERR("IPA_CLIENT_USB_PROD query failed %d\n", rc);
+ kfree(con_stats);
+ return rc;
+ }
+
+ IPAWANDBG("usb: v4_tx_p(%d) b(%lld) v6_tx_p(%d) b(%lld)\n",
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_pkts,
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_bytes,
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_pkts,
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_bytes);
+
+ /* update the USB UL stats */
+ data->ipv4_tx_packets =
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_pkts;
+ data->ipv6_tx_packets =
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_pkts;
+ data->ipv4_tx_bytes =
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_bytes;
+ data->ipv6_tx_bytes =
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_bytes;
+
+ /* query WLAN UL stats */
+ memset(con_stats, 0, sizeof(struct ipa_quota_stats_all));
+ rc = ipa_query_teth_stats(IPA_CLIENT_WLAN1_PROD, con_stats, reset);
+ if (rc) {
+ IPAERR("IPA_CLIENT_WLAN1_PROD query failed %d\n", rc);
+ kfree(con_stats);
+ return rc;
+ }
+
+ IPAWANDBG("wlan: v4_tx_p(%d) b(%lld) v6_tx_p(%d) b(%lld)\n",
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_pkts,
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_bytes,
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_pkts,
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_bytes);
+
+ /* update the wlan UL stats */
+ data->ipv4_tx_packets +=
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_pkts;
+ data->ipv6_tx_packets +=
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_pkts;
+ data->ipv4_tx_bytes +=
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_bytes;
+ data->ipv6_tx_bytes +=
+ con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_bytes;
+
+ IPAWANDBG("v4_tx_p(%lu) v6_tx_p(%lu) v4_tx_b(%lu) v6_tx_b(%lu)\n",
+ (unsigned long int) data->ipv4_tx_packets,
+ (unsigned long int) data->ipv6_tx_packets,
+ (unsigned long int) data->ipv4_tx_bytes,
+ (unsigned long int) data->ipv6_tx_bytes);
+ kfree(con_stats);
+ return rc;
+}
+
+
int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data,
bool reset)
{
@@ -3368,11 +3497,26 @@
} else {
IPAWANDBG_LOW(" query modem-backhaul stats\n");
tether_stats.ipa_client = data->ipa_client;
- rc = rmnet_ipa3_query_tethering_stats_modem(
- &tether_stats, data->reset_stats);
- if (rc) {
- IPAWANERR("modem WAN_IOC_QUERY_TETHER_STATS failed\n");
- return rc;
+ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0 ||
+ !ipa3_ctx->hw_stats.enabled) {
+ IPAWANDBG("hw version %d,hw_stats.enabled %d\n",
+ ipa3_ctx->ipa_hw_type,
+ ipa3_ctx->hw_stats.enabled);
+ /* get modem stats from QMI */
+ rc = rmnet_ipa3_query_tethering_stats_modem(
+ &tether_stats, data->reset_stats);
+ if (rc) {
+ IPAWANERR("modem QUERY_TETHER_STATS failed\n");
+ return rc;
+ }
+ } else {
+ /* get modem stats from IPA-HW counters */
+ rc = rmnet_ipa3_query_tethering_stats_hw(
+ &tether_stats, data->reset_stats);
+ if (rc) {
+ IPAWANERR("modem QUERY_TETHER_STATS failed\n");
+ return rc;
+ }
}
data->tx_bytes = tether_stats.ipv4_tx_bytes
+ tether_stats.ipv6_tx_bytes;
@@ -4026,11 +4170,6 @@
ipa3_qmi_init();
/* Register for Modem SSR */
- if (ipa3_ctx != NULL)
- /* SSR is not supported yet on IPA 4.0 */
- if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_0)
- return platform_driver_register(&rmnet_ipa_driver);
-
rmnet_ipa3_ctx->subsys_notify_handle = subsys_notif_register_notifier(
SUBSYS_MODEM,
&ipa3_ssr_notifier);
diff --git a/drivers/platform/msm/mhi_dev/Makefile b/drivers/platform/msm/mhi_dev/Makefile
index c1969e2..53ef716 100644
--- a/drivers/platform/msm/mhi_dev/Makefile
+++ b/drivers/platform/msm/mhi_dev/Makefile
@@ -4,3 +4,4 @@
obj-y += mhi_ring.o
obj-y += mhi_uci.o
obj-y += mhi_sm.o
+obj-y += mhi_dev_net.o
diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c
index 7179fcd..c2187c6 100644
--- a/drivers/platform/msm/mhi_dev/mhi.c
+++ b/drivers/platform/msm/mhi_dev/mhi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -34,13 +34,10 @@
#include "mhi_sm.h"
/* Wait time on the device for Host to set M0 state */
-#define MHI_M0_WAIT_MIN_USLEEP 20000000
-#define MHI_M0_WAIT_MAX_USLEEP 25000000
#define MHI_DEV_M0_MAX_CNT 30
/* Wait time before suspend/resume is complete */
-#define MHI_SUSPEND_WAIT_MIN 3100
-#define MHI_SUSPEND_WAIT_MAX 3200
-#define MHI_SUSPEND_WAIT_TIMEOUT 500
+#define MHI_SUSPEND_MIN 100
+#define MHI_SUSPEND_TIMEOUT 600
#define MHI_MASK_CH_EV_LEN 32
#define MHI_RING_CMD_ID 0
#define MHI_RING_PRIMARY_EVT_ID 1
@@ -59,6 +56,13 @@
#define HOST_ADDR_MSB(addr) ((addr >> 32) & 0xFFFFFFFF)
#define MHI_IPC_LOG_PAGES (100)
+#define MHI_REGLEN 0x100
+#define MHI_INIT 0
+#define MHI_REINIT 1
+
+#define TR_RING_ELEMENT_SZ sizeof(struct mhi_dev_transfer_ring_element)
+#define RING_ELEMENT_TYPE_SZ sizeof(union mhi_dev_ring_element_type)
+
enum mhi_msg_level mhi_msg_lvl = MHI_MSG_ERROR;
enum mhi_msg_level mhi_ipc_msg_lvl = MHI_MSG_VERBOSE;
void *mhi_ipc_log;
@@ -67,106 +71,213 @@
static void mhi_hwc_cb(void *priv, enum ipa_mhi_event_type event,
unsigned long data);
static void mhi_ring_init_cb(void *user_data);
+static void mhi_update_state_info(uint32_t info);
+static int mhi_deinit(struct mhi_dev *mhi);
+static void mhi_dev_resume_init_with_link_up(struct ep_pcie_notify *notify);
+static int mhi_dev_pcie_notify_event;
+static void mhi_dev_transfer_completion_cb(void *mreq);
-void mhi_dev_read_from_host(struct mhi_addr *host, dma_addr_t dev, size_t size)
+/*
+ * mhi_dev_ring_cache_completion_cb () - Call back function called
+ * by IPA driver when ring element cache is done
+ *
+ * @req : ring cache request
+ */
+static void mhi_dev_ring_cache_completion_cb(void *req)
{
- int rc = 0;
- uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0;
+ struct ring_cache_req *ring_req = NULL;
- host_addr_pa = ((u64) host->host_pa) | bit_40;
-
- mhi_log(MHI_MSG_ERROR, "device 0x%x <<-- host 0x%llx, size %d\n",
- dev, host_addr_pa, size);
-
- rc = ipa_dma_sync_memcpy((u64) dev, host_addr_pa, (int) size);
- if (rc)
- pr_err("error while reading from host:%d\n", rc);
+ if (req)
+ ring_req = (struct ring_cache_req *)req;
+ else {
+ pr_err("%s():ring cache req data is NULL\n", __func__);
+ return;
+ }
+ complete(ring_req->done);
}
-EXPORT_SYMBOL(mhi_dev_read_from_host);
-void mhi_dev_write_to_host(struct mhi_addr *host, void *dev, size_t size,
- struct mhi_dev *mhi)
+void mhi_dev_read_from_host(struct mhi_dev *mhi, struct mhi_addr *transfer)
{
int rc = 0;
- uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0;
+ uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0, offset = 0;
+ struct ring_cache_req ring_req;
+
+ DECLARE_COMPLETION(done);
+
+ ring_req.done = &done;
if (!mhi) {
pr_err("invalid MHI ctx\n");
return;
}
- host_addr_pa = ((u64) host->host_pa) | bit_40;
- /* Copy the device content to a local device physical address */
- memcpy(mhi->dma_cache, dev, size);
- mhi_log(MHI_MSG_ERROR, "device 0x%llx --> host 0x%llx, size %d\n",
- (uint64_t) mhi->cache_dma_handle, host_addr_pa, (int) size);
+ if (mhi->config_iatu) {
+ offset = (uint64_t) transfer->host_pa - mhi->ctrl_base.host_pa;
+ /* Mapping the translated physical address on the device */
+ host_addr_pa = (uint64_t) mhi->ctrl_base.device_pa + offset;
+ } else {
+ host_addr_pa = transfer->host_pa | bit_40;
+ }
- rc = ipa_dma_sync_memcpy(host_addr_pa, (u64) mhi->cache_dma_handle,
- (int) size);
+ mhi_log(MHI_MSG_VERBOSE,
+ "device 0x%x <<-- host 0x%llx, size %d\n",
+ transfer->phy_addr, host_addr_pa,
+ (int) transfer->size);
+ rc = ipa_dma_async_memcpy((u64)transfer->phy_addr, host_addr_pa,
+ (int)transfer->size,
+ mhi_dev_ring_cache_completion_cb, &ring_req);
if (rc)
pr_err("error while reading from host:%d\n", rc);
+
+ wait_for_completion(&done);
+}
+EXPORT_SYMBOL(mhi_dev_read_from_host);
+
+void mhi_dev_write_to_host(struct mhi_dev *mhi, struct mhi_addr *transfer,
+ struct event_req *ereq, enum mhi_dev_transfer_type tr_type)
+{
+ int rc = 0;
+ uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0, offset = 0;
+ dma_addr_t dma;
+
+ if (!mhi) {
+ pr_err("invalid MHI ctx\n");
+ return;
+ }
+ if (mhi->config_iatu) {
+ offset = (uint64_t) transfer->host_pa - mhi->ctrl_base.host_pa;
+ /* Mapping the translated physical address on the device */
+ host_addr_pa = (uint64_t) mhi->ctrl_base.device_pa + offset;
+ } else {
+ host_addr_pa = transfer->host_pa | bit_40;
+ }
+
+ mhi_log(MHI_MSG_VERBOSE,
+ "device 0x%llx --> host 0x%llx, size %d\n",
+ (uint64_t) mhi->cache_dma_handle, host_addr_pa,
+ (int) transfer->size);
+ if (tr_type == MHI_DEV_DMA_ASYNC) {
+ dma = dma_map_single(&mhi->pdev->dev,
+ transfer->virt_addr, transfer->size,
+ DMA_TO_DEVICE);
+ if (ereq->event_type == SEND_EVENT_BUFFER) {
+ ereq->dma = dma;
+ ereq->dma_len = transfer->size;
+ } else if (ereq->event_type == SEND_EVENT_RD_OFFSET) {
+ ereq->event_rd_dma = dma;
+ }
+ rc = ipa_dma_async_memcpy(host_addr_pa, (uint64_t) dma,
+ (int)transfer->size,
+ ereq->client_cb, ereq);
+ if (rc)
+ pr_err("error while writing to host:%d\n", rc);
+ } else if (tr_type == MHI_DEV_DMA_SYNC) {
+ /* Copy the device content to a local device
+ * physical address.
+ */
+ memcpy(mhi->dma_cache, transfer->virt_addr,
+ transfer->size);
+ rc = ipa_dma_sync_memcpy(host_addr_pa,
+ (u64) mhi->cache_dma_handle,
+ (int) transfer->size);
+ if (rc)
+ pr_err("error while writing to host:%d\n", rc);
+ }
}
EXPORT_SYMBOL(mhi_dev_write_to_host);
int mhi_transfer_host_to_device(void *dev, uint64_t host_pa, uint32_t len,
- struct mhi_dev *mhi)
+ struct mhi_dev *mhi, struct mhi_req *mreq)
{
int rc = 0;
- uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0;
+ uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0, offset = 0;
+ struct mhi_dev_ring *ring = NULL;
- if (!mhi) {
- pr_err("Invalid mhi device\n");
+
+ if (!mhi || !dev || !host_pa || !mreq) {
+ pr_err("%s():Invalid parameters\n", __func__);
return -EINVAL;
}
- if (!dev) {
- pr_err("Invalid virt device\n");
- return -EINVAL;
+ if (mhi->config_iatu) {
+ offset = (uint64_t)host_pa - mhi->data_base.host_pa;
+ /* Mapping the translated physical address on the device */
+ host_addr_pa = (uint64_t) mhi->data_base.device_pa + offset;
+ } else {
+ host_addr_pa = host_pa | bit_40;
}
- if (!host_pa) {
- pr_err("Invalid host pa device\n");
- return -EINVAL;
- }
-
- host_addr_pa = host_pa | bit_40;
- mhi_log(MHI_MSG_ERROR, "device 0x%llx <-- host 0x%llx, size %d\n",
+ mhi_log(MHI_MSG_VERBOSE, "device 0x%llx <-- host 0x%llx, size %d\n",
(uint64_t) mhi->read_dma_handle, host_addr_pa, (int) len);
- rc = ipa_dma_sync_memcpy((u64) mhi->read_dma_handle,
- host_addr_pa, (int) len);
- if (rc) {
- pr_err("error while reading from host:%d\n", rc);
- return rc;
+
+ if (mreq->mode == IPA_DMA_SYNC) {
+ rc = ipa_dma_sync_memcpy((u64) mhi->read_dma_handle,
+ host_addr_pa, (int) len);
+ if (rc) {
+ pr_err("error while reading chan using sync:%d\n", rc);
+ return rc;
+ }
+ memcpy(dev, mhi->read_handle, len);
+ } else if (mreq->mode == IPA_DMA_ASYNC) {
+ ring = mreq->client->channel->ring;
+ mreq->dma = dma_map_single(&mhi->pdev->dev, dev, len,
+ DMA_FROM_DEVICE);
+ mhi_dev_ring_inc_index(ring, ring->rd_offset);
+
+ if (ring->rd_offset == ring->wr_offset)
+ mreq->snd_cmpl = 1;
+ else
+ mreq->snd_cmpl = 0;
+ rc = ipa_dma_async_memcpy(mreq->dma, host_addr_pa,
+ (int) len, mhi_dev_transfer_completion_cb,
+ mreq);
+ if (rc) {
+ pr_err("error while reading chan using async:%d\n", rc);
+ return rc;
+ }
}
-
- memcpy(dev, mhi->read_handle, len);
-
return rc;
}
EXPORT_SYMBOL(mhi_transfer_host_to_device);
int mhi_transfer_device_to_host(uint64_t host_addr, void *dev, uint32_t len,
- struct mhi_dev *mhi)
+ struct mhi_dev *mhi, struct mhi_req *req)
{
int rc = 0;
- uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0;
+ uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0, offset = 0;
+ struct mhi_dev_ring *ring = NULL;
- if (!mhi || !dev || !host_addr) {
+ if (!mhi || !dev || !req || !host_addr) {
pr_err("%sInvalid parameters\n", __func__);
return -EINVAL;
}
- host_addr_pa = host_addr | bit_40;
- memcpy(mhi->write_handle, dev, len);
+ if (mhi->config_iatu) {
+ offset = (uint64_t)host_addr - mhi->data_base.host_pa;
+ /* Mapping the translated physical address on the device */
+ host_addr_pa = (uint64_t) mhi->data_base.device_pa + offset;
+ } else {
+ host_addr_pa = host_addr | bit_40;
+ }
+ mhi_log(MHI_MSG_VERBOSE, "device 0x%llx ---> host 0x%llx, size %d\n",
+ (uint64_t) mhi->write_dma_handle,
+ host_addr_pa, (int) len);
- mhi_log(MHI_MSG_ERROR, "device 0x%llx ---> host 0x%llx, size %d\n",
- (uint64_t) mhi->write_dma_handle, host_addr_pa, (int) len);
- rc = ipa_dma_sync_memcpy(host_addr_pa,
- (u64) mhi->write_dma_handle,
- (int) len);
- if (rc)
- pr_err("error while reading from host:%d\n", rc);
-
+ if (req->mode == IPA_DMA_SYNC) {
+ memcpy(mhi->write_handle, dev, len);
+ rc = ipa_dma_sync_memcpy(host_addr_pa,
+ (u64) mhi->write_dma_handle, (int) len);
+ } else if (req->mode == IPA_DMA_ASYNC) {
+ req->dma = dma_map_single(&mhi->pdev->dev, req->buf,
+ req->len, DMA_TO_DEVICE);
+ ring = req->client->channel->ring;
+ mhi_dev_ring_inc_index(ring, ring->rd_offset);
+ if (ring->rd_offset == ring->wr_offset)
+ req->snd_cmpl = 1;
+ rc = ipa_dma_async_memcpy(host_addr_pa,
+ (uint64_t) req->dma, (int) len,
+ mhi_dev_transfer_completion_cb, req);
+ }
return rc;
}
EXPORT_SYMBOL(mhi_transfer_device_to_host);
@@ -216,7 +327,7 @@
mhi_dev_get_erdb_db_cfg(mhi, &erdb_cfg);
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"Event rings 0x%x => er_base 0x%x, er_end %d\n",
mhi->cfg.event_rings, erdb_cfg.base, erdb_cfg.end);
erdb_cfg.tgt_addr = (uint32_t) mhi->ipa_uc_mbox_erdb;
@@ -247,7 +358,7 @@
}
mhi_dev_get_erdb_db_cfg(mhi, &erdb_cfg);
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"Event rings 0x%x => er_base 0x%x, er_end %d\n",
mhi->cfg.event_rings, erdb_cfg.base, erdb_cfg.end);
@@ -259,10 +370,18 @@
ipa_init_params.msi.mask = ((1 << cfg.msg_num) - 1);
ipa_init_params.first_er_idx = erdb_cfg.base;
ipa_init_params.first_ch_idx = HW_CHANNEL_BASE;
- ipa_init_params.mmio_addr = ((uint32_t) mhi_ctx->mmio_base_pa_addr);
- ipa_init_params.assert_bit40 = true;
- mhi_log(MHI_MSG_ERROR,
+ if (mhi_ctx->config_iatu)
+ ipa_init_params.mmio_addr =
+ ((uint32_t) mhi_ctx->mmio_base_pa_addr) + MHI_REGLEN;
+ else
+ ipa_init_params.mmio_addr =
+ ((uint32_t) mhi_ctx->mmio_base_pa_addr);
+
+ if (!mhi_ctx->config_iatu)
+ ipa_init_params.assert_bit40 = true;
+
+ mhi_log(MHI_MSG_VERBOSE,
"MMIO Addr 0x%x, MSI config: U:0x%x L: 0x%x D: 0x%x\n",
ipa_init_params.mmio_addr, cfg.upper, cfg.lower, cfg.data);
ipa_init_params.notify = mhi_hwc_cb;
@@ -284,10 +403,15 @@
memset(&ipa_start_params, 0, sizeof(ipa_start_params));
- ipa_start_params.channel_context_array_addr =
+ if (mhi->config_iatu) {
+ ipa_start_params.host_ctrl_addr = mhi->ctrl_base.device_pa;
+ ipa_start_params.host_data_addr = mhi->data_base.device_pa;
+ } else {
+ ipa_start_params.channel_context_array_addr =
mhi->ch_ctx_shadow.host_pa;
- ipa_start_params.event_context_array_addr =
+ ipa_start_params.event_context_array_addr =
mhi->ev_ctx_shadow.host_pa;
+ }
rc = ipa_mhi_start(&ipa_start_params);
if (rc)
@@ -303,7 +427,7 @@
switch (event) {
case IPA_MHI_EVENT_READY:
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_INFO,
"HW Channel uC is ready event=0x%X\n", event);
rc = mhi_hwc_start(mhi_ctx);
if (rc) {
@@ -329,6 +453,11 @@
pr_err("Failed to enable command db\n");
return;
}
+
+ mhi_update_state_info(MHI_STATE_CONNECTED);
+
+ ep_pcie_mask_irq_event(mhi_ctx->phandle,
+ EP_PCIE_INT_EVT_MHI_A7, true);
break;
case IPA_MHI_EVENT_DATA_AVAILABLE:
rc = mhi_dev_notify_sm_event(MHI_DEV_EVENT_HW_ACC_WAKEUP);
@@ -352,6 +481,7 @@
memset(&connect_params, 0, sizeof(connect_params));
switch (type) {
+ case MHI_DEV_RING_EL_RESET:
case MHI_DEV_RING_EL_STOP:
rc = ipa_mhi_disconnect_pipe(
mhi->ipa_clnt_hndl[chid-HW_CHANNEL_BASE]);
@@ -402,15 +532,18 @@
static void mhi_dev_fetch_ch_ctx(struct mhi_dev *mhi, uint32_t ch_id)
{
- struct mhi_addr addr;
+ struct mhi_addr data_transfer;
- addr.host_pa = mhi->ch_ctx_shadow.host_pa +
+ if (mhi->use_ipa) {
+ data_transfer.host_pa = mhi->ch_ctx_shadow.host_pa +
sizeof(struct mhi_dev_ch_ctx) * ch_id;
- addr.size = sizeof(struct mhi_dev_ch_ctx);
+ data_transfer.phy_addr = mhi->ch_ctx_cache_dma_handle +
+ sizeof(struct mhi_dev_ch_ctx) * ch_id;
+ }
+
+ data_transfer.size = sizeof(struct mhi_dev_ch_ctx);
/* Fetch the channel ctx (*dst, *src, size) */
- mhi_dev_read_from_host(&addr, mhi->ch_ctx_cache_dma_handle +
- (sizeof(struct mhi_dev_ch_ctx) * ch_id),
- sizeof(struct mhi_dev_ch_ctx));
+ mhi_dev_read_from_host(mhi, &data_transfer);
}
int mhi_dev_syserr(struct mhi_dev *mhi)
@@ -436,24 +569,21 @@
struct mhi_dev_ring *ring = &mhi->ring[evnt_ring_idx];
union mhi_dev_ring_ctx *ctx;
struct ep_pcie_msi_config cfg;
- struct mhi_addr msi_addr;
- uint32_t msi = 0;
- struct mhi_addr host_rp_addr;
+ struct mhi_addr transfer_addr;
- rc = ep_pcie_get_msi_config(mhi->phandle,
- &cfg);
- if (rc) {
- pr_err("Error retrieving pcie msi logic\n");
- return rc;
- }
+ rc = ep_pcie_get_msi_config(mhi->phandle, &cfg);
+ if (rc) {
+ pr_err("Error retrieving pcie msi logic\n");
+ return rc;
+ }
if (evnt_ring_idx > mhi->cfg.event_rings) {
pr_err("Invalid event ring idx: %lld\n", evnt_ring_idx);
return -EINVAL;
}
+ ctx = (union mhi_dev_ring_ctx *)&mhi->ev_ctx_cache[evnt_ring];
if (mhi_ring_get_state(ring) == RING_STATE_UINT) {
- ctx = (union mhi_dev_ring_ctx *)&mhi->ev_ctx_cache[evnt_ring];
rc = mhi_ring_start(ring, ctx, mhi);
if (rc) {
mhi_log(MHI_MSG_ERROR,
@@ -464,23 +594,30 @@
mutex_lock(&mhi->mhi_event_lock);
/* add the ring element */
- mhi_dev_add_element(ring, el);
+ mhi_dev_add_element(ring, el, NULL, 0);
ring->ring_ctx_shadow->ev.rp = (ring->rd_offset *
sizeof(union mhi_dev_ring_element_type)) +
ring->ring_ctx->generic.rbase;
- mhi_log(MHI_MSG_ERROR, "ev.rp = %llx for %lld\n",
+ mhi_log(MHI_MSG_VERBOSE, "ev.rp = %llx for %lld\n",
ring->ring_ctx_shadow->ev.rp, evnt_ring_idx);
- host_rp_addr.host_pa = (mhi->ev_ctx_shadow.host_pa +
+ if (mhi->use_ipa)
+ transfer_addr.host_pa = (mhi->ev_ctx_shadow.host_pa +
sizeof(struct mhi_dev_ev_ctx) *
evnt_ring) + (uint32_t) &ring->ring_ctx->ev.rp -
(uint32_t) ring->ring_ctx;
- mhi_dev_write_to_host(&host_rp_addr, &ring->ring_ctx_shadow->ev.rp,
- sizeof(uint64_t),
- mhi);
+ else
+ transfer_addr.device_va = (mhi->ev_ctx_shadow.device_va +
+ sizeof(struct mhi_dev_ev_ctx) *
+ evnt_ring) + (uint32_t) &ring->ring_ctx->ev.rp -
+ (uint32_t) ring->ring_ctx;
+ transfer_addr.virt_addr = &ring->ring_ctx_shadow->ev.rp;
+ transfer_addr.size = sizeof(uint64_t);
+
+ mhi_dev_write_to_host(mhi, &transfer_addr, NULL, MHI_DEV_DMA_SYNC);
/*
* rp update in host memory should be flushed
* before sending a MSI to the host
@@ -488,20 +625,141 @@
wmb();
mutex_unlock(&mhi->mhi_event_lock);
- mhi_log(MHI_MSG_ERROR, "event sent:\n");
- mhi_log(MHI_MSG_ERROR, "evnt ptr : 0x%llx\n", el->evt_tr_comp.ptr);
- mhi_log(MHI_MSG_ERROR, "evnt len : 0x%x\n", el->evt_tr_comp.len);
- mhi_log(MHI_MSG_ERROR, "evnt code :0x%x\n", el->evt_tr_comp.code);
- mhi_log(MHI_MSG_ERROR, "evnt type :0x%x\n", el->evt_tr_comp.type);
- mhi_log(MHI_MSG_ERROR, "evnt chid :0x%x\n", el->evt_tr_comp.chid);
+ mhi_log(MHI_MSG_VERBOSE, "event sent:\n");
+ mhi_log(MHI_MSG_VERBOSE, "evnt ptr : 0x%llx\n", el->evt_tr_comp.ptr);
+ mhi_log(MHI_MSG_VERBOSE, "evnt len : 0x%x\n", el->evt_tr_comp.len);
+ mhi_log(MHI_MSG_VERBOSE, "evnt code :0x%x\n", el->evt_tr_comp.code);
+ mhi_log(MHI_MSG_VERBOSE, "evnt type :0x%x\n", el->evt_tr_comp.type);
+ mhi_log(MHI_MSG_VERBOSE, "evnt chid :0x%x\n", el->evt_tr_comp.chid);
+ rc = ep_pcie_trigger_msi(mhi_ctx->phandle, ctx->ev.msivec);
+ if (rc) {
+ pr_err("%s: error sending msi\n", __func__);
+ return rc;
+ }
+ return rc;
+}
- msi_addr.host_pa = (uint64_t)((uint64_t)cfg.upper << 32) |
- (uint64_t)cfg.lower;
- msi = cfg.data + mhi_ctx->mhi_ep_msi_num;
- mhi_log(MHI_MSG_ERROR, "Sending MSI %d to 0x%llx as data = 0x%x\n",
- mhi_ctx->mhi_ep_msi_num, msi_addr.host_pa, msi);
- mhi_dev_write_to_host(&msi_addr, &msi, 4, mhi);
+/*
+ * mhi_dev_event_buf_completion_cb() -Cb function called by IPA driver
+ * when transfer completion event buffer copy is done.
+ *
+ * @req - event_req structure
+ */
+static void mhi_dev_event_buf_completion_cb(void *req)
+{
+ struct event_req *ereq = NULL;
+
+ if (req) {
+ ereq = (struct event_req *)req;
+ } else {
+ pr_err("%s():event req data is invalid\n", __func__);
+ return;
+ }
+ dma_unmap_single(&mhi_ctx->pdev->dev, ereq->dma,
+ ereq->dma_len, DMA_TO_DEVICE);
+}
+
+/**
+ * mhi_dev_event_rd_offset_completion_cb() -CB function called by IPA driver
+ * when event rd_offset transfer is done.
+ *
+ * @req - event_req structure
+ */
+
+static void mhi_dev_event_rd_offset_completion_cb(void *req)
+{
+ union mhi_dev_ring_ctx *ctx;
+ int rc = 0;
+ struct event_req *ereq = (struct event_req *)req;
+ struct mhi_dev_channel *ch = ereq->context;
+ struct mhi_dev *mhi = ch->ring->mhi_dev;
+ unsigned long flags;
+
+ dma_unmap_single(&mhi_ctx->pdev->dev, ereq->event_rd_dma,
+ sizeof(uint64_t), DMA_TO_DEVICE);
+ ctx = (union mhi_dev_ring_ctx *)&mhi->ev_ctx_cache[ereq->event_ring];
+ rc = ep_pcie_trigger_msi(mhi_ctx->phandle, ctx->ev.msivec);
+ if (rc)
+ pr_err("%s: error sending in msi\n", __func__);
+
+ /* return the event req to pre allocated pooled list */
+ spin_lock_irqsave(&mhi->lock, flags);
+ list_add_tail(&ereq->list, &ch->event_req_buffers);
+ spin_unlock_irqrestore(&mhi->lock, flags);
+}
+
+static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
+ struct event_req *ereq, uint32_t evt_len)
+{
+ int rc = 0;
+ uint64_t evnt_ring_idx = mhi->ev_ring_start + evnt_ring;
+ struct mhi_dev_ring *ring = &mhi->ring[evnt_ring_idx];
+ union mhi_dev_ring_ctx *ctx;
+ struct mhi_addr transfer_addr;
+ static int count;
+
+ if (!ereq) {
+ pr_err("%s(): invalid event req\n", __func__);
+ return -EINVAL;
+ }
+
+ if (count == 0) {
+ rc = ep_pcie_get_msi_config(mhi->phandle, &mhi->msi_cfg);
+ if (rc) {
+ pr_err("Error retrieving pcie msi logic\n");
+ return rc;
+ }
+ count++;
+ }
+
+ if (evnt_ring_idx > mhi->cfg.event_rings) {
+ pr_err("Invalid event ring idx: %lld\n", evnt_ring_idx);
+ return -EINVAL;
+ }
+
+ ctx = (union mhi_dev_ring_ctx *)&mhi->ev_ctx_cache[evnt_ring];
+ if (mhi_ring_get_state(ring) == RING_STATE_UINT) {
+ rc = mhi_ring_start(ring, ctx, mhi);
+ if (rc) {
+ mhi_log(MHI_MSG_ERROR,
+ "error starting event ring %d\n", evnt_ring);
+ return rc;
+ }
+ }
+
+ /* add the ring element */
+ ereq->client_cb = mhi_dev_event_buf_completion_cb;
+ ereq->event_type = SEND_EVENT_BUFFER;
+ rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len);
+ if (rc) {
+ pr_err("%s(): error in adding element rc %d\n", __func__, rc);
+ return rc;
+ }
+ ring->ring_ctx_shadow->ev.rp = (ring->rd_offset *
+ sizeof(union mhi_dev_ring_element_type)) +
+ ring->ring_ctx->generic.rbase;
+
+ mhi_log(MHI_MSG_VERBOSE, "ev.rp = %llx for %lld\n",
+ ring->ring_ctx_shadow->ev.rp, evnt_ring_idx);
+
+ if (mhi->use_ipa)
+ transfer_addr.host_pa = (mhi->ev_ctx_shadow.host_pa +
+ sizeof(struct mhi_dev_ev_ctx) *
+ evnt_ring) + (uint32_t)&ring->ring_ctx->ev.rp -
+ (uint32_t)ring->ring_ctx;
+ else
+ transfer_addr.device_va = (mhi->ev_ctx_shadow.device_va +
+ sizeof(struct mhi_dev_ev_ctx) *
+ evnt_ring) + (uint32_t)&ring->ring_ctx->ev.rp -
+ (uint32_t)ring->ring_ctx;
+
+ transfer_addr.virt_addr = &ring->ring_ctx_shadow->ev.rp;
+ transfer_addr.size = sizeof(uint64_t);
+ ereq->event_type = SEND_EVENT_RD_OFFSET;
+ ereq->client_cb = mhi_dev_event_rd_offset_completion_cb;
+ ereq->event_ring = evnt_ring;
+ mhi_dev_write_to_host(mhi, &transfer_addr, ereq, MHI_DEV_DMA_ASYNC);
return rc;
}
@@ -564,6 +822,21 @@
}
EXPORT_SYMBOL(mhi_dev_send_ee_event);
+static void mhi_dev_trigger_cb(void)
+{
+ struct mhi_dev_ready_cb_info *info;
+ uint32_t state_data;
+
+ mutex_lock(&mhi_ctx->mhi_lock);
+ list_for_each_entry(info, &mhi_ctx->client_cb_list, list)
+ if (info->cb) {
+ mhi_ctrl_state_info(&state_data);
+ info->cb_data.ctrl_info = state_data;
+ info->cb(&info->cb_data);
+ }
+ mutex_unlock(&mhi_ctx->mhi_lock);
+}
+
int mhi_dev_trigger_hw_acc_wakeup(struct mhi_dev *mhi)
{
int rc = 0;
@@ -591,7 +864,7 @@
event.evt_cmd_comp.ptr = mhi->cmd_ctx_cache->rbase
+ (mhi->ring[MHI_RING_CMD_ID].rd_offset *
(sizeof(union mhi_dev_ring_element_type)));
- mhi_log(MHI_MSG_ERROR, "evt cmd comp ptr :%d\n",
+ mhi_log(MHI_MSG_VERBOSE, "evt cmd comp ptr :%d\n",
(uint32_t) event.evt_cmd_comp.ptr);
event.evt_cmd_comp.type = MHI_DEV_RING_EL_CMD_COMPLETION_EVT;
event.evt_cmd_comp.code = MHI_CMD_COMPL_CODE_SUCCESS;
@@ -607,27 +880,38 @@
struct mhi_dev *mhi)
{
int rc = 0;
- struct mhi_addr host_addr;
+ struct mhi_addr data_transfer;
if (ring->rd_offset != ring->wr_offset &&
mhi->ch_ctx_cache[ch_id].ch_type ==
MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL) {
- mhi_log(MHI_MSG_INFO, "Pending transaction to be processed\n");
+ mhi_log(MHI_MSG_INFO, "Pending outbound transaction\n");
return 0;
} else if (mhi->ch_ctx_cache[ch_id].ch_type ==
MHI_DEV_CH_TYPE_INBOUND_CHANNEL &&
mhi->ch[ch_id].wr_request_active) {
+ mhi_log(MHI_MSG_INFO, "Pending inbound transaction\n");
return 0;
}
/* set the channel to stop */
mhi->ch_ctx_cache[ch_id].ch_state = MHI_DEV_CH_STATE_STOP;
+ mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED;
- host_addr.host_pa = mhi->ch_ctx_shadow.host_pa +
+ if (mhi->use_ipa) {
+ data_transfer.host_pa = mhi->ch_ctx_shadow.host_pa +
sizeof(struct mhi_dev_ch_ctx) * ch_id;
+ } else {
+ data_transfer.device_va = mhi->ch_ctx_shadow.device_va +
+ sizeof(struct mhi_dev_ch_ctx) * ch_id;
+ data_transfer.device_pa = mhi->ch_ctx_shadow.device_pa +
+ sizeof(struct mhi_dev_ch_ctx) * ch_id;
+ }
+ data_transfer.size = sizeof(enum mhi_dev_ch_ctx_state);
+ data_transfer.virt_addr = &mhi->ch_ctx_cache[ch_id].ch_state;
+
/* update the channel state in the host */
- mhi_dev_write_to_host(&host_addr, &mhi->ch_ctx_cache[ch_id].ch_state,
- sizeof(enum mhi_dev_ch_ctx_state), mhi);
+ mhi_dev_write_to_host(mhi, &data_transfer, NULL, MHI_DEV_DMA_SYNC);
/* send the completion event to the host */
rc = mhi_dev_send_cmd_comp_event(mhi);
@@ -644,14 +928,16 @@
uint32_t ch_id = 0;
union mhi_dev_ring_element_type event;
struct mhi_addr host_addr;
+ struct mhi_dev_channel *ch;
+ struct mhi_dev_ring *ring;
- mhi_log(MHI_MSG_ERROR, "for channel:%d and cmd:%d\n",
- ch_id, el->generic.type);
ch_id = el->generic.chid;
+ mhi_log(MHI_MSG_VERBOSE, "for channel:%d and cmd:%d\n",
+ ch_id, el->generic.type);
switch (el->generic.type) {
case MHI_DEV_RING_EL_START:
- mhi_log(MHI_MSG_ERROR, "recived start cmd for channel %d\n",
+ mhi_log(MHI_MSG_VERBOSE, "recived start cmd for channel %d\n",
ch_id);
if (ch_id >= (HW_CHANNEL_BASE)) {
rc = mhi_hwc_chcmd(mhi, ch_id, el->generic.type);
@@ -680,6 +966,7 @@
/* set the channel to running */
mhi->ch_ctx_cache[ch_id].ch_state = MHI_DEV_CH_STATE_RUNNING;
+ mhi->ch[ch_id].state = MHI_DEV_CH_STARTED;
mhi->ch[ch_id].ch_id = ch_id;
mhi->ch[ch_id].ring = &mhi->ring[mhi->ch_ring_start + ch_id];
mhi->ch[ch_id].ch_type = mhi->ch_ctx_cache[ch_id].ch_type;
@@ -691,17 +978,26 @@
return;
}
- host_addr.host_pa = mhi->ch_ctx_shadow.host_pa +
+ if (mhi->use_ipa)
+ host_addr.host_pa = mhi->ch_ctx_shadow.host_pa +
sizeof(struct mhi_dev_ch_ctx) * ch_id;
- mhi_dev_write_to_host(&host_addr,
- &mhi->ch_ctx_cache[ch_id].ch_state,
- sizeof(enum mhi_dev_ch_ctx_state), mhi);
+ else
+ host_addr.device_va = mhi->ch_ctx_shadow.device_va +
+ sizeof(struct mhi_dev_ch_ctx) * ch_id;
+
+ host_addr.virt_addr = &mhi->ch_ctx_cache[ch_id].ch_state;
+ host_addr.size = sizeof(enum mhi_dev_ch_ctx_state);
+
+ mhi_dev_write_to_host(mhi, &host_addr, NULL, MHI_DEV_DMA_SYNC);
send_start_completion_event:
rc = mhi_dev_send_cmd_comp_event(mhi);
if (rc)
pr_err("Error sending command completion event\n");
+ /* Trigger callback to clients */
+ mhi_dev_trigger_cb();
+
break;
case MHI_DEV_RING_EL_STOP:
if (ch_id >= HW_CHANNEL_BASE) {
@@ -738,32 +1034,99 @@
* channel command to check if one can suspend the
* command.
*/
+ ring = &mhi->ring[ch_id + mhi->ch_ring_start];
+ if (ring->state == RING_STATE_UINT) {
+ pr_err("Channel not opened for %d\n", ch_id);
+ return;
+ }
+
+ ch = &mhi->ch[ch_id];
+
+ mutex_lock(&ch->ch_lock);
+
mhi->ch[ch_id].state = MHI_DEV_CH_PENDING_STOP;
rc = mhi_dev_process_stop_cmd(
&mhi->ring[mhi->ch_ring_start + ch_id],
ch_id, mhi);
+ if (rc)
+ pr_err("stop event send failed\n");
+
+ mutex_unlock(&ch->ch_lock);
+ }
+ break;
+ case MHI_DEV_RING_EL_RESET:
+ mhi_log(MHI_MSG_VERBOSE,
+ "received reset cmd for channel %d\n", ch_id);
+ if (ch_id >= HW_CHANNEL_BASE) {
+ rc = mhi_hwc_chcmd(mhi, ch_id, el->generic.type);
+ if (rc) {
+ mhi_log(MHI_MSG_ERROR,
+ "send channel stop cmd event failed\n");
+ return;
+ }
+
+ /* send the completion event to the host */
+ event.evt_cmd_comp.ptr = mhi->cmd_ctx_cache->rbase +
+ (mhi->ring[MHI_RING_CMD_ID].rd_offset *
+ (sizeof(union mhi_dev_ring_element_type)));
+ event.evt_cmd_comp.type =
+ MHI_DEV_RING_EL_CMD_COMPLETION_EVT;
+ if (rc == 0)
+ event.evt_cmd_comp.code =
+ MHI_CMD_COMPL_CODE_SUCCESS;
+ else
+ event.evt_cmd_comp.code =
+ MHI_CMD_COMPL_CODE_UNDEFINED;
+
+ rc = mhi_dev_send_event(mhi, 0, &event);
if (rc) {
pr_err("stop event send failed\n");
return;
}
+ } else {
+
+ mhi_log(MHI_MSG_VERBOSE,
+ "received reset cmd for channel %d\n",
+ ch_id);
+
+ ring = &mhi->ring[ch_id + mhi->ch_ring_start];
+ if (ring->state == RING_STATE_UINT) {
+ pr_err("Channel not opened for %d\n", ch_id);
+ return;
+ }
+
+ ch = &mhi->ch[ch_id];
+
+ mutex_lock(&ch->ch_lock);
+
+ /* hard stop and set the channel to stop */
+ mhi->ch_ctx_cache[ch_id].ch_state =
+ MHI_DEV_CH_STATE_DISABLED;
+ mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED;
+ if (mhi->use_ipa)
+ host_addr.host_pa =
+ mhi->ch_ctx_shadow.host_pa +
+ (sizeof(struct mhi_dev_ch_ctx) * ch_id);
+ else
+ host_addr.device_va =
+ mhi->ch_ctx_shadow.device_va +
+ (sizeof(struct mhi_dev_ch_ctx) * ch_id);
+
+ host_addr.virt_addr =
+ &mhi->ch_ctx_cache[ch_id].ch_state;
+ host_addr.size = sizeof(enum mhi_dev_ch_ctx_state);
+
+ /* update the channel state in the host */
+ mhi_dev_write_to_host(mhi, &host_addr, NULL,
+ MHI_DEV_DMA_SYNC);
+
+ /* send the completion event to the host */
+ rc = mhi_dev_send_cmd_comp_event(mhi);
+ if (rc)
+ pr_err("Error sending command completion event\n");
+ mutex_unlock(&ch->ch_lock);
}
break;
- case MHI_DEV_RING_EL_RESET:
- /* hard stop and set the channel to stop */
- mhi->ch_ctx_cache[ch_id].ch_state = MHI_DEV_CH_STATE_STOP;
- host_addr.host_pa = mhi->ch_ctx_shadow.host_pa +
- sizeof(struct mhi_dev_ch_ctx) * ch_id;
-
- /* update the channel state in the host */
- mhi_dev_write_to_host(&host_addr,
- &mhi->ch_ctx_cache[ch_id].ch_state,
- sizeof(enum mhi_dev_ch_ctx_state), mhi);
-
- /* send the completion event to the host */
- rc = mhi_dev_send_cmd_comp_event(mhi);
- if (rc)
- pr_err("Error sending command completion event\n");
- break;
default:
pr_err("%s: Invalid command:%d\n", __func__, el->generic.type);
break;
@@ -778,7 +1141,7 @@
struct mhi_dev_client_cb_reason reason;
if (ring->id < mhi->ch_ring_start) {
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"invalid channel ring id (%d), should be < %d\n",
ring->id, mhi->ch_ring_start);
return;
@@ -816,7 +1179,7 @@
list_for_each_safe(cp, q, &mhi->process_ring_list) {
ring = list_entry(cp, struct mhi_dev_ring, list);
list_del(cp);
- mhi_log(MHI_MSG_ERROR, "processing ring %d\n", ring->id);
+ mhi_log(MHI_MSG_VERBOSE, "processing ring %d\n", ring->id);
rc = mhi_dev_process_ring(ring);
if (rc) {
mhi_log(MHI_MSG_ERROR,
@@ -879,7 +1242,7 @@
if (chintr_value & 1) {
ring = &mhi->ring[ch_num + mhi->ch_ring_start];
if (ring->state == RING_STATE_UINT) {
- pr_err("Channel not opened for %d\n", ch_num);
+ pr_debug("Channel not opened for %d\n", ch_num);
break;
}
mhi_ring_set_state(ring, RING_STATE_PENDING);
@@ -907,9 +1270,10 @@
for (i = 0; i < MHI_MASK_ROWS_CH_EV_DB; i++) {
ch_num = i * MHI_MASK_CH_EV_LEN;
- chintr_value = mhi->chdb[i].status;
+ /* Process channel status whose mask is enabled */
+ chintr_value = (mhi->chdb[i].status & mhi->chdb[i].mask);
if (chintr_value) {
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"processing id: %d, ch interrupt 0x%x\n",
i, chintr_value);
mhi_dev_queue_channel_db(mhi, chintr_value, ch_num);
@@ -923,6 +1287,153 @@
}
}
+static int mhi_dev_abort(struct mhi_dev *mhi)
+{
+ struct mhi_dev_channel *ch;
+ struct mhi_dev_ring *ring;
+ int ch_id = 0, rc = 0;
+
+ /* Hard stop all the channels */
+ for (ch_id = 0; ch_id < mhi->cfg.channels; ch_id++) {
+ ring = &mhi->ring[ch_id + mhi->ch_ring_start];
+ if (ring->state == RING_STATE_UINT)
+ continue;
+
+ ch = &mhi->ch[ch_id];
+ mutex_lock(&ch->ch_lock);
+ mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED;
+ mutex_unlock(&ch->ch_lock);
+ }
+
+ /* Update ctrl node */
+ mhi_update_state_info(MHI_STATE_DISCONNECTED);
+
+ flush_workqueue(mhi->ring_init_wq);
+ flush_workqueue(mhi->pending_ring_wq);
+
+ /* Initiate MHI IPA reset */
+ ipa_mhi_destroy();
+
+ /* Clean up initialized channels */
+ rc = mhi_deinit(mhi);
+ if (rc) {
+ pr_err("Error during mhi_deinit with %d\n", rc);
+ return rc;
+ }
+
+ rc = mhi_dev_mmio_mask_chdb_interrupts(mhi_ctx);
+ if (rc) {
+ pr_err("Failed to enable channel db\n");
+ return rc;
+ }
+
+ rc = mhi_dev_mmio_disable_ctrl_interrupt(mhi_ctx);
+ if (rc) {
+ pr_err("Failed to enable control interrupt\n");
+ return rc;
+ }
+
+ rc = mhi_dev_mmio_disable_cmdb_interrupt(mhi_ctx);
+ if (rc) {
+ pr_err("Failed to enable command db\n");
+ return rc;
+ }
+
+
+ atomic_set(&mhi_ctx->re_init_done, 0);
+
+ mhi_log(MHI_MSG_INFO,
+ "Register a PCIe callback during re-init\n");
+ mhi_ctx->event_reg.events = EP_PCIE_EVENT_LINKUP;
+ mhi_ctx->event_reg.user = mhi_ctx;
+ mhi_ctx->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK;
+ mhi_ctx->event_reg.callback = mhi_dev_resume_init_with_link_up;
+ mhi_ctx->event_reg.options = MHI_REINIT;
+
+ rc = ep_pcie_register_event(mhi_ctx->phandle,
+ &mhi_ctx->event_reg);
+ if (rc) {
+ pr_err("Failed to register for events from PCIe\n");
+ return rc;
+ }
+
+ /* Set RESET field to 0 */
+ mhi_dev_mmio_reset(mhi_ctx);
+
+ return rc;
+}
+
+static void mhi_dev_transfer_completion_cb(void *mreq)
+{
+ struct mhi_dev_channel *ch;
+ struct mhi_dev_client *client;
+ union mhi_dev_ring_element_type *el;
+ int rc = 0;
+ struct mhi_req *req = (struct mhi_req *)mreq;
+ struct mhi_req *local_req = NULL;
+ union mhi_dev_ring_element_type *compl_ev = NULL;
+ struct mhi_dev *mhi = NULL;
+ unsigned long flags;
+
+ client = req->client;
+ ch = client->channel;
+ mhi = ch->ring->mhi_dev;
+ el = req->el;
+ local_req = req;
+ ch->curr_ereq->context = ch;
+
+ dma_unmap_single(&mhi_ctx->pdev->dev, req->dma,
+ req->len, DMA_FROM_DEVICE);
+
+ /* Trigger client call back */
+ req->client_cb(req);
+
+ if (el->tre.ieot) {
+ compl_ev = ch->curr_ereq->tr_events + ch->curr_ereq->num_events;
+ compl_ev->evt_tr_comp.chid = ch->ch_id;
+ compl_ev->evt_tr_comp.type =
+ MHI_DEV_RING_EL_TRANSFER_COMPLETION_EVENT;
+ compl_ev->evt_tr_comp.len = el->tre.len;
+ compl_ev->evt_tr_comp.code = MHI_CMD_COMPL_CODE_EOT;
+ compl_ev->evt_tr_comp.ptr = ch->ring->ring_ctx->generic.rbase +
+ local_req->rd_offset * TR_RING_ELEMENT_SZ;
+ ch->curr_ereq->num_events++;
+
+ if (ch->curr_ereq->num_events >= MAX_TR_EVENTS ||
+ local_req->snd_cmpl){
+ mhi_log(MHI_MSG_VERBOSE,
+ "num of tr events %d for ch %d\n",
+ ch->curr_ereq->num_events, ch->ch_id);
+ rc = mhi_dev_send_multiple_tr_events(mhi,
+ mhi->ch_ctx_cache[ch->ch_id].err_indx,
+ ch->curr_ereq, (ch->curr_ereq->num_events*
+ sizeof(union mhi_dev_ring_element_type)));
+ if (rc)
+ mhi_log(MHI_MSG_ERROR,
+ "failed to send compl evts\n");
+ if (!list_empty(&ch->event_req_buffers)) {
+ ch->curr_ereq =
+ container_of(ch->event_req_buffers.next,
+ struct event_req, list);
+ spin_lock_irqsave(&mhi->lock, flags);
+ list_del_init(&ch->curr_ereq->list);
+ spin_unlock_irqrestore(&mhi->lock, flags);
+ ch->curr_ereq->num_events = 0;
+ } else
+ pr_err("%s evt req buffers empty\n", __func__);
+ }
+ } else
+ mhi_log(MHI_MSG_ERROR, "ieot is not valid\n");
+
+ if (ch->state == MHI_DEV_CH_PENDING_STOP) {
+ ch->state = MHI_DEV_CH_STOPPED;
+ rc = mhi_dev_process_stop_cmd(ch->ring, ch->ch_id, mhi_ctx);
+ if (rc)
+ mhi_log(MHI_MSG_ERROR,
+ "Error while stopping channel (%d)\n", ch->ch_id);
+ }
+}
+
static void mhi_dev_scheduler(struct work_struct *work)
{
struct mhi_dev *mhi = container_of(work,
@@ -932,38 +1443,48 @@
struct mhi_dev_ring *ring;
enum mhi_dev_state state;
enum mhi_dev_event event = 0;
+ bool mhi_reset = false;
mutex_lock(&mhi_ctx->mhi_lock);
/* Check for interrupts */
mhi_dev_core_ack_ctrl_interrupts(mhi, &int_value);
if (int_value & MHI_MMIO_CTRL_INT_STATUS_A7_MSK) {
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"processing ctrl interrupt with %d\n", int_value);
- rc = mhi_dev_mmio_get_mhi_state(mhi, &state);
+ rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset);
if (rc) {
pr_err("%s: get mhi state failed\n", __func__);
mutex_unlock(&mhi_ctx->mhi_lock);
return;
}
+ if (mhi_reset) {
+ mhi_log(MHI_MSG_VERBOSE,
+ "processing mhi device reset\n");
+ rc = mhi_dev_abort(mhi);
+ if (rc)
+ pr_err("device reset failed:%d\n", rc);
+ mutex_unlock(&mhi_ctx->mhi_lock);
+ queue_work(mhi->ring_init_wq, &mhi->re_init);
+ return;
+ }
+
rc = mhi_dev_get_event_notify(state, &event);
if (rc) {
pr_err("unsupported state :%d\n", state);
- mutex_unlock(&mhi_ctx->mhi_lock);
- return;
+ goto fail;
}
rc = mhi_dev_notify_sm_event(event);
if (rc) {
pr_err("error sending SM event\n");
- mutex_unlock(&mhi_ctx->mhi_lock);
- return;
+ goto fail;
}
}
if (int_value & MHI_MMIO_CTRL_CRDB_STATUS_MSK) {
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"processing cmd db interrupt with %d\n", int_value);
ring = &mhi->ring[MHI_RING_CMD_ID];
ring->state = RING_STATE_PENDING;
@@ -973,20 +1494,67 @@
/* get the specific channel interrupts */
mhi_dev_check_channel_interrupt(mhi);
+fail:
mutex_unlock(&mhi_ctx->mhi_lock);
- ep_pcie_mask_irq_event(mhi->phandle,
+
+ if (mhi->config_iatu || mhi->mhi_int)
+ enable_irq(mhi->mhi_irq);
+ else
+ ep_pcie_mask_irq_event(mhi->phandle,
EP_PCIE_INT_EVT_MHI_A7, true);
}
void mhi_dev_notify_a7_event(struct mhi_dev *mhi)
{
+
+ if (!atomic_read(&mhi->mhi_dev_wake)) {
+ pm_stay_awake(mhi->dev);
+ atomic_set(&mhi->mhi_dev_wake, 1);
+ }
+ mhi_log(MHI_MSG_VERBOSE, "acquiring mhi wakelock\n");
+
schedule_work(&mhi->chdb_ctrl_work);
- mhi_log(MHI_MSG_ERROR, "mhi irq triggered\n");
+ mhi_log(MHI_MSG_VERBOSE, "mhi irq triggered\n");
}
EXPORT_SYMBOL(mhi_dev_notify_a7_event);
+static irqreturn_t mhi_dev_isr(int irq, void *dev_id)
+{
+ struct mhi_dev *mhi = dev_id;
+
+ disable_irq_nosync(mhi->mhi_irq);
+ schedule_work(&mhi->chdb_ctrl_work);
+ mhi_log(MHI_MSG_VERBOSE, "mhi irq triggered\n");
+
+ return IRQ_HANDLED;
+}
+
int mhi_dev_config_outbound_iatu(struct mhi_dev *mhi)
{
+ struct ep_pcie_iatu control, data;
+ int rc = 0;
+ struct ep_pcie_iatu entries[MHI_HOST_REGION_NUM];
+
+ data.start = mhi->data_base.device_pa;
+ data.end = mhi->data_base.device_pa + mhi->data_base.size - 1;
+ data.tgt_lower = HOST_ADDR_LSB(mhi->data_base.host_pa);
+ data.tgt_upper = HOST_ADDR_MSB(mhi->data_base.host_pa);
+
+ control.start = mhi->ctrl_base.device_pa;
+ control.end = mhi->ctrl_base.device_pa + mhi->ctrl_base.size - 1;
+ control.tgt_lower = HOST_ADDR_LSB(mhi->ctrl_base.host_pa);
+ control.tgt_upper = HOST_ADDR_MSB(mhi->ctrl_base.host_pa);
+
+ entries[0] = data;
+ entries[1] = control;
+
+ rc = ep_pcie_config_outbound_iatu(mhi_ctx->phandle, entries,
+ MHI_HOST_REGION_NUM);
+ if (rc) {
+ pr_err("error configure iATU\n");
+ return rc;
+ }
+
return 0;
}
EXPORT_SYMBOL(mhi_dev_config_outbound_iatu);
@@ -996,6 +1564,7 @@
int rc = 0;
struct platform_device *pdev;
uint64_t addr1 = 0;
+ struct mhi_addr data_transfer;
pdev = mhi->pdev;
@@ -1014,6 +1583,37 @@
mhi->host_addr.data_limit_msb);
mhi->data_base.size = addr1 - mhi->data_base.host_pa;
+ if (mhi->config_iatu) {
+ if (mhi->ctrl_base.host_pa > mhi->data_base.host_pa) {
+ mhi->data_base.device_pa = mhi->device_local_pa_base;
+ mhi->ctrl_base.device_pa = mhi->device_local_pa_base +
+ mhi->ctrl_base.host_pa - mhi->data_base.host_pa;
+ } else {
+ mhi->ctrl_base.device_pa = mhi->device_local_pa_base;
+ mhi->data_base.device_pa = mhi->device_local_pa_base +
+ mhi->data_base.host_pa - mhi->ctrl_base.host_pa;
+ }
+
+ if (!mhi->use_ipa) {
+ mhi->ctrl_base.device_va =
+ (uintptr_t) devm_ioremap_nocache(&pdev->dev,
+ mhi->ctrl_base.device_pa,
+ mhi->ctrl_base.size);
+ if (!mhi->ctrl_base.device_va) {
+ pr_err("io remap failed for mhi address\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ if (mhi->config_iatu) {
+ rc = mhi_dev_config_outbound_iatu(mhi);
+ if (rc) {
+ pr_err("Configuring iATU failed\n");
+ return rc;
+ }
+ }
+
/* Get Channel, event and command context base pointer */
rc = mhi_dev_mmio_get_chc_base(mhi);
if (rc) {
@@ -1062,30 +1662,44 @@
GFP_KERNEL);
if (!mhi->ev_ctx_cache)
return -ENOMEM;
+ memset(mhi->ev_ctx_cache, 0, sizeof(struct mhi_dev_ev_ctx) *
+ mhi->cfg.event_rings);
mhi->ch_ctx_cache = dma_alloc_coherent(&pdev->dev,
sizeof(struct mhi_dev_ch_ctx) *
mhi->cfg.channels,
&mhi->ch_ctx_cache_dma_handle,
GFP_KERNEL);
- if (!mhi_ctx->ch_ctx_cache)
+ if (!mhi->ch_ctx_cache)
return -ENOMEM;
+ memset(mhi->ch_ctx_cache, 0, sizeof(struct mhi_dev_ch_ctx) *
+ mhi->cfg.channels);
+
+ if (mhi->use_ipa) {
+ data_transfer.phy_addr = mhi->cmd_ctx_cache_dma_handle;
+ data_transfer.host_pa = mhi->cmd_ctx_shadow.host_pa;
+ }
+
+ data_transfer.size = mhi->cmd_ctx_shadow.size;
/* Cache the command and event context */
- mhi_dev_read_from_host(&mhi->cmd_ctx_shadow,
- mhi->cmd_ctx_cache_dma_handle,
- mhi->cmd_ctx_shadow.size);
+ mhi_dev_read_from_host(mhi, &data_transfer);
- mhi_dev_read_from_host(&mhi->ev_ctx_shadow,
- mhi->ev_ctx_cache_dma_handle,
- mhi->ev_ctx_shadow.size);
+ if (mhi->use_ipa) {
+ data_transfer.phy_addr = mhi->ev_ctx_cache_dma_handle;
+ data_transfer.host_pa = mhi->ev_ctx_shadow.host_pa;
+ }
- mhi_log(MHI_MSG_ERROR,
+ data_transfer.size = mhi->ev_ctx_shadow.size;
+
+ mhi_dev_read_from_host(mhi, &data_transfer);
+
+ mhi_log(MHI_MSG_VERBOSE,
"cmd ring_base:0x%llx, rp:0x%llx, wp:0x%llx\n",
mhi->cmd_ctx_cache->rbase,
mhi->cmd_ctx_cache->rp,
mhi->cmd_ctx_cache->wp);
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"ev ring_base:0x%llx, rp:0x%llx, wp:0x%llx\n",
mhi_ctx->ev_ctx_cache->rbase,
mhi->ev_ctx_cache->rp,
@@ -1104,7 +1718,7 @@
int mhi_dev_suspend(struct mhi_dev *mhi)
{
int ch_id = 0, rc = 0;
- struct mhi_addr host_addr;
+ struct mhi_addr data_transfer;
mutex_lock(&mhi_ctx->mhi_write_test);
atomic_set(&mhi->is_suspended, 1);
@@ -1116,19 +1730,28 @@
mhi->ch_ctx_cache[ch_id].ch_state = MHI_DEV_CH_STATE_SUSPENDED;
- host_addr.host_pa = mhi->ch_ctx_shadow.host_pa +
+ if (mhi->use_ipa) {
+ data_transfer.host_pa = mhi->ch_ctx_shadow.host_pa +
sizeof(struct mhi_dev_ch_ctx) * ch_id;
+ } else {
+ data_transfer.device_va = mhi->ch_ctx_shadow.device_va +
+ sizeof(struct mhi_dev_ch_ctx) * ch_id;
+ data_transfer.device_pa = mhi->ch_ctx_shadow.device_pa +
+ sizeof(struct mhi_dev_ch_ctx) * ch_id;
+ }
+
+ data_transfer.size = sizeof(enum mhi_dev_ch_ctx_state);
+ data_transfer.virt_addr = &mhi->ch_ctx_cache[ch_id].ch_state;
/* update the channel state in the host */
- mhi_dev_write_to_host(&host_addr,
- &mhi->ch_ctx_cache[ch_id].ch_state,
- sizeof(enum mhi_dev_ch_ctx_state), mhi);
+ mhi_dev_write_to_host(mhi, &data_transfer, NULL,
+ MHI_DEV_DMA_SYNC);
}
- rc = ipa_dma_disable();
- if (rc)
- pr_err("Disable IPA failed\n");
+ atomic_set(&mhi->mhi_dev_wake, 0);
+ pm_relax(mhi->dev);
+ mhi_log(MHI_MSG_VERBOSE, "releasing mhi wakelock\n");
mutex_unlock(&mhi_ctx->mhi_write_test);
@@ -1139,13 +1762,7 @@
int mhi_dev_resume(struct mhi_dev *mhi)
{
int ch_id = 0, rc = 0;
- struct mhi_addr host_addr;
-
- rc = ipa_dma_enable();
- if (rc) {
- pr_err("IPA enable failed\n");
- return rc;
- }
+ struct mhi_addr data_transfer;
for (ch_id = 0; ch_id < mhi->cfg.channels; ch_id++) {
if (mhi->ch_ctx_cache[ch_id].ch_state !=
@@ -1153,14 +1770,24 @@
continue;
mhi->ch_ctx_cache[ch_id].ch_state = MHI_DEV_CH_STATE_RUNNING;
- host_addr.host_pa = mhi->ch_ctx_shadow.host_pa +
+ if (mhi->use_ipa) {
+ data_transfer.host_pa = mhi->ch_ctx_shadow.host_pa +
sizeof(struct mhi_dev_ch_ctx) * ch_id;
+ } else {
+ data_transfer.device_va = mhi->ch_ctx_shadow.device_va +
+ sizeof(struct mhi_dev_ch_ctx) * ch_id;
+ data_transfer.device_pa = mhi->ch_ctx_shadow.device_pa +
+ sizeof(struct mhi_dev_ch_ctx) * ch_id;
+ }
+
+ data_transfer.size = sizeof(enum mhi_dev_ch_ctx_state);
+ data_transfer.virt_addr = &mhi->ch_ctx_cache[ch_id].ch_state;
/* update the channel state in the host */
- mhi_dev_write_to_host(&host_addr,
- &mhi->ch_ctx_cache[ch_id].ch_state,
- sizeof(enum mhi_dev_ch_ctx_state), mhi);
+ mhi_dev_write_to_host(mhi, &data_transfer, NULL,
+ MHI_DEV_DMA_SYNC);
}
+ mhi_update_state_info(MHI_STATE_CONNECTED);
atomic_set(&mhi->is_suspended, 0);
@@ -1312,14 +1939,14 @@
mhi_dev_send_completion_event(ch,
ring->rd_offset, el->tre.len,
MHI_CMD_COMPL_CODE_EOB);
- *chain = 1;
+ *chain = 1;
} else {
if (el->tre.ieot)
mhi_dev_send_completion_event(
ch, ring->rd_offset, el->tre.len,
MHI_CMD_COMPL_CODE_EOT);
- td_done = 1;
- *chain = 0;
+ td_done = 1;
+ *chain = 0;
}
mhi_dev_ring_inc_index(ring, ring->rd_offset);
ch->tre_bytes_left = 0;
@@ -1329,53 +1956,67 @@
return td_done;
}
-int mhi_dev_read_channel(struct mhi_dev_client *handle_client,
- void *buf, uint32_t buf_size, uint32_t *chain)
+int mhi_dev_read_channel(struct mhi_req *mreq)
{
struct mhi_dev_channel *ch;
struct mhi_dev_ring *ring;
union mhi_dev_ring_element_type *el;
- uint32_t ch_id;
size_t bytes_to_read, addr_offset;
uint64_t read_from_loc;
ssize_t bytes_read = 0;
uint32_t write_to_loc = 0;
- size_t usr_buf_remaining = buf_size;
+ size_t usr_buf_remaining;
int td_done = 0, rc = 0;
+ struct mhi_dev_client *handle_client;
- if (!handle_client) {
- mhi_log(MHI_MSG_ERROR, "invalid client handle\n");
+ if (!mreq) {
+ mhi_log(MHI_MSG_ERROR, "invalid mhi request\n");
return -ENXIO;
}
+ if (mhi_ctx->ctrl_info != MHI_STATE_CONNECTED) {
+ pr_err("Channel not connected:%d\n", mhi_ctx->ctrl_info);
+ return -ENODEV;
+ }
+
+ if (!mreq->client) {
+ mhi_log(MHI_MSG_ERROR, "invalid mhi request\n");
+ return -ENXIO;
+ }
+ handle_client = mreq->client;
ch = handle_client->channel;
+ usr_buf_remaining = mreq->len;
ring = ch->ring;
- ch_id = ch->ch_id;
- *chain = 0;
+ mreq->chain = 0;
mutex_lock(&ch->ch_lock);
do {
el = &ring->ring_cache[ring->rd_offset];
+ mhi_log(MHI_MSG_VERBOSE, "evtptr : 0x%llx\n",
+ el->tre.data_buf_ptr);
+ mhi_log(MHI_MSG_VERBOSE, "evntlen : 0x%x, offset:%d\n",
+ el->tre.len, ring->rd_offset);
+
if (ch->tre_loc) {
bytes_to_read = min(usr_buf_remaining,
ch->tre_bytes_left);
- *chain = 1;
- mhi_log(MHI_MSG_ERROR,
+ mreq->chain = 1;
+ mhi_log(MHI_MSG_VERBOSE,
"remaining buffered data size %d\n",
(int) ch->tre_bytes_left);
} else {
if (ring->rd_offset == ring->wr_offset) {
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"nothing to read, returning\n");
bytes_read = 0;
goto exit;
}
if (ch->state == MHI_DEV_CH_STOPPED) {
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"channel (%d) already stopped\n",
- ch_id);
+ mreq->chan);
bytes_read = -1;
goto exit;
}
@@ -1384,35 +2025,51 @@
ch->tre_size = el->tre.len;
ch->tre_bytes_left = ch->tre_size;
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"user_buf_remaining %d, ch->tre_size %d\n",
usr_buf_remaining, ch->tre_size);
bytes_to_read = min(usr_buf_remaining, ch->tre_size);
}
+ bytes_read += bytes_to_read;
addr_offset = ch->tre_size - ch->tre_bytes_left;
read_from_loc = ch->tre_loc + addr_offset;
- write_to_loc = (uint32_t) buf + (buf_size - usr_buf_remaining);
-
- mhi_log(MHI_MSG_ERROR, "reading %d bytes from chan %d\n",
- bytes_to_read, ch_id);
-
- mhi_transfer_host_to_device((void *) write_to_loc,
- read_from_loc, bytes_to_read, mhi_ctx);
-
- bytes_read += bytes_to_read;
+ write_to_loc = (uint32_t) mreq->buf +
+ (mreq->len - usr_buf_remaining);
ch->tre_bytes_left -= bytes_to_read;
- usr_buf_remaining -= bytes_to_read;
- td_done = mhi_dev_check_tre_bytes_left(ch, ring, el, chain);
- } while (usr_buf_remaining && !td_done);
-
- if (td_done && ch->state == MHI_DEV_CH_PENDING_STOP) {
- ch->state = MHI_DEV_CH_STOPPED;
- rc = mhi_dev_process_stop_cmd(ring, ch_id, mhi_ctx);
+ mreq->el = el;
+ mreq->actual_len = bytes_read;
+ mreq->rd_offset = ring->rd_offset;
+ mhi_log(MHI_MSG_VERBOSE, "reading %d bytes from chan %d\n",
+ bytes_to_read, mreq->chan);
+ rc = mhi_transfer_host_to_device((void *) write_to_loc,
+ read_from_loc, bytes_to_read, mhi_ctx, mreq);
if (rc) {
mhi_log(MHI_MSG_ERROR,
- "Error while stopping channel (%d)\n", ch_id);
- bytes_read = -1;
+ "Error while reading chan (%d) rc %d\n",
+ mreq->chan, rc);
+ mutex_unlock(&ch->ch_lock);
+ return rc;
+ }
+ usr_buf_remaining -= bytes_to_read;
+
+ if (mreq->mode == IPA_DMA_ASYNC) {
+ ch->tre_bytes_left = 0;
+ ch->tre_loc = 0;
+ goto exit;
+ } else {
+ td_done = mhi_dev_check_tre_bytes_left(ch, ring,
+ el, &mreq->chain);
+ }
+ } while (usr_buf_remaining && !td_done);
+ if (td_done && ch->state == MHI_DEV_CH_PENDING_STOP) {
+ ch->state = MHI_DEV_CH_STOPPED;
+ rc = mhi_dev_process_stop_cmd(ring, mreq->chan, mhi_ctx);
+ if (rc) {
+ mhi_log(MHI_MSG_ERROR,
+ "Error while stopping channel (%d)\n",
+ mreq->chan);
+ bytes_read = -EIO;
}
}
exit:
@@ -1441,32 +2098,33 @@
}
}
-int mhi_dev_write_channel(struct mhi_dev_client *handle_client,
- void *buf, size_t buf_size)
+int mhi_dev_write_channel(struct mhi_req *wreq)
{
struct mhi_dev_channel *ch;
struct mhi_dev_ring *ring;
+ struct mhi_dev_client *handle_client;
union mhi_dev_ring_element_type *el;
enum mhi_dev_cmd_completion_code code = MHI_CMD_COMPL_CODE_INVALID;
int rc = 0;
- uint64_t ch_id, skip_tres = 0, write_to_loc;
+ uint64_t skip_tres = 0, write_to_loc;
uint32_t read_from_loc;
- size_t usr_buf_remaining = buf_size;
+ size_t usr_buf_remaining;
size_t usr_buf_offset = 0;
size_t bytes_to_write = 0;
size_t bytes_written = 0;
uint32_t tre_len = 0, suspend_wait_timeout = 0;
- if (!handle_client) {
- pr_err("%s: invalid client handle\n", __func__);
+ if (!wreq || !wreq->client || !wreq->buf) {
+ pr_err("%s: invalid parameters\n", __func__);
return -ENXIO;
}
- if (!buf) {
- pr_err("%s: invalid buffer to write data\n", __func__);
- return -ENXIO;
+ if (mhi_ctx->ctrl_info != MHI_STATE_CONNECTED) {
+ pr_err("Channel not connected:%d\n", mhi_ctx->ctrl_info);
+ return -ENODEV;
}
+ usr_buf_remaining = wreq->len;
mutex_lock(&mhi_ctx->mhi_write_test);
if (atomic_read(&mhi_ctx->is_suspended)) {
@@ -1482,31 +2140,29 @@
}
}
- atomic_inc(&mhi_ctx->write_active);
while (atomic_read(&mhi_ctx->is_suspended) &&
- suspend_wait_timeout < MHI_SUSPEND_WAIT_TIMEOUT) {
+ suspend_wait_timeout < MHI_SUSPEND_TIMEOUT) {
/* wait for the suspend to finish */
- usleep_range(MHI_SUSPEND_WAIT_MIN, MHI_SUSPEND_WAIT_MAX);
+ msleep(MHI_SUSPEND_MIN);
suspend_wait_timeout++;
}
-
+ handle_client = wreq->client;
ch = handle_client->channel;
ch->wr_request_active = true;
ring = ch->ring;
- ch_id = ch->ch_id;
mutex_lock(&ch->ch_lock);
if (ch->state == MHI_DEV_CH_STOPPED) {
mhi_log(MHI_MSG_ERROR,
- "channel (%lld) already stopped\n", ch_id);
+ "channel %d already stopped\n", wreq->chan);
bytes_written = -1;
goto exit;
}
if (ch->state == MHI_DEV_CH_PENDING_STOP) {
- if (mhi_dev_process_stop_cmd(ring, ch_id, mhi_ctx) < 0)
+ if (mhi_dev_process_stop_cmd(ring, wreq->chan, mhi_ctx) < 0)
bytes_written = -1;
goto exit;
}
@@ -1516,20 +2172,38 @@
do {
if (ring->rd_offset == ring->wr_offset) {
+ mhi_log(MHI_MSG_ERROR,
+ "%s():rd & wr offsets are equal\n",
+ __func__);
mhi_log(MHI_MSG_INFO, "No TREs available\n");
break;
}
el = &ring->ring_cache[ring->rd_offset];
tre_len = el->tre.len;
+ if (wreq->len > tre_len) {
+ pr_err("%s(): rlen = %d, tlen = %d: client buf > tre len\n",
+ __func__, wreq->len, tre_len);
+ bytes_written = -ENOMEM;
+ goto exit;
+ }
bytes_to_write = min(usr_buf_remaining, tre_len);
- usr_buf_offset = buf_size - bytes_to_write;
- read_from_loc = (uint32_t) buf + usr_buf_offset;
+ usr_buf_offset = wreq->len - bytes_to_write;
+ read_from_loc = (uint32_t) wreq->buf + usr_buf_offset;
write_to_loc = el->tre.data_buf_ptr;
- mhi_transfer_device_to_host(write_to_loc,
+ wreq->rd_offset = ring->rd_offset;
+ wreq->el = el;
+ rc = mhi_transfer_device_to_host(write_to_loc,
(void *) read_from_loc,
- bytes_to_write, mhi_ctx);
+ bytes_to_write,
+ mhi_ctx, wreq);
+ if (rc) {
+ mhi_log(MHI_MSG_ERROR,
+ "Error while writing chan (%d) rc %d\n",
+ wreq->chan, rc);
+ goto exit;
+ }
bytes_written += bytes_to_write;
usr_buf_remaining -= bytes_to_write;
@@ -1543,33 +2217,34 @@
skip_tres = 1;
code = MHI_CMD_COMPL_CODE_EOT;
}
-
- if (mhi_dev_send_completion_event(ch,
- ring->rd_offset, bytes_to_write, code) < 0) {
- mhi_log(MHI_MSG_ERROR,
- "error sending completion event ch_id:%lld\n",
- ch_id);
+ if (wreq->mode == IPA_DMA_SYNC) {
+ rc = mhi_dev_send_completion_event(ch,
+ ring->rd_offset, bytes_to_write, code);
+ if (rc)
+ mhi_log(MHI_MSG_VERBOSE,
+ "err in snding cmpl evt ch:%d\n",
+ wreq->chan);
+ mhi_dev_ring_inc_index(ring, ring->rd_offset);
}
if (ch->state == MHI_DEV_CH_PENDING_STOP)
break;
- mhi_dev_ring_inc_index(ring, ring->rd_offset);
} while (!skip_tres && usr_buf_remaining);
if (skip_tres)
skip_to_next_td(ch);
if (ch->state == MHI_DEV_CH_PENDING_STOP) {
- rc = mhi_dev_process_stop_cmd(ring, ch_id, mhi_ctx);
+ rc = mhi_dev_process_stop_cmd(ring, wreq->chan, mhi_ctx);
if (rc) {
mhi_log(MHI_MSG_ERROR,
- "channel (%lld) stop failed\n", ch_id);
+ "channel %d stop failed\n", wreq->chan);
}
}
exit:
+ ch->wr_request_active = false;
mutex_unlock(&ch->ch_lock);
- atomic_dec(&mhi_ctx->write_active);
mutex_unlock(&mhi_ctx->mhi_write_test);
return bytes_written;
}
@@ -1581,21 +2256,22 @@
struct ep_pcie_msi_config msi_cfg;
struct mhi_dev *mhi = container_of(work,
struct mhi_dev, ring_init_cb_work);
-
+ bool mhi_reset;
enum mhi_dev_state state;
- uint32_t max_cnt = 0;
+ uint32_t max_cnt = 0, bhi_intvec = 0;
+ if (mhi->use_ipa) {
+ rc = ipa_dma_init();
+ if (rc) {
+ pr_err("ipa dma init failed\n");
+ return;
+ }
- rc = ipa_dma_init();
- if (rc) {
- pr_err("ipa dma init failed\n");
- return;
- }
-
- rc = ipa_dma_enable();
- if (rc) {
- pr_err("ipa enable failed\n");
- return;
+ rc = ipa_dma_enable();
+ if (rc) {
+ pr_err("ipa enable failed\n");
+ return;
+ }
}
rc = mhi_dev_ring_init(mhi);
@@ -1604,34 +2280,39 @@
return;
}
- /* Invoke MHI SM when device is in RESET state */
- mhi_dev_sm_init(mhi);
-
- /* set the env before setting the ready bit */
- rc = mhi_dev_mmio_set_env(mhi, MHI_ENV_VALUE);
- if (rc) {
- pr_err("%s: env setting failed\n", __func__);
- return;
- }
- mhi_uci_init();
-
- /* All set...let's notify the host */
- mhi_dev_sm_set_ready();
-
- rc = ep_pcie_get_msi_config(mhi->phandle, &msi_cfg);
+ /*Enable MHI dev network stack Interface*/
+ rc = mhi_dev_net_interface_init();
if (rc)
- pr_warn("MHI: error geting msi configs\n");
+ pr_err("%s Failed to initialize mhi_dev_net iface\n", __func__);
- rc = mhi_dev_mmio_get_mhi_state(mhi, &state);
+ rc = mhi_dev_mmio_read(mhi, BHI_INTVEC, &bhi_intvec);
+ if (rc)
+ return;
+
+ if (bhi_intvec != 0xffffffff) {
+ /* Indicate the host that the device is ready */
+ rc = ep_pcie_get_msi_config(mhi->phandle, &msi_cfg);
+ if (!rc) {
+ rc = ep_pcie_trigger_msi(mhi_ctx->phandle, bhi_intvec);
+ if (rc) {
+ pr_err("%s: error sending msi\n", __func__);
+ return;
+ }
+ } else {
+ pr_err("MHI: error geting msi configs\n");
+ }
+ }
+
+ rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset);
if (rc) {
pr_err("%s: get mhi state failed\n", __func__);
return;
}
- while (state != MHI_DEV_M0_STATE && max_cnt < MHI_DEV_M0_MAX_CNT) {
+ while (state != MHI_DEV_M0_STATE && max_cnt < MHI_SUSPEND_TIMEOUT) {
/* Wait for Host to set the M0 state */
- usleep_range(MHI_M0_WAIT_MIN_USLEEP, MHI_M0_WAIT_MAX_USLEEP);
- rc = mhi_dev_mmio_get_mhi_state(mhi, &state);
+ msleep(MHI_SUSPEND_MIN);
+ rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset);
if (rc) {
pr_err("%s: get mhi state failed\n", __func__);
return;
@@ -1663,6 +2344,11 @@
pr_err("error during hwc_init\n");
return;
}
+
+ if (mhi_ctx->config_iatu || mhi_ctx->mhi_int)
+ enable_irq(mhi_ctx->mhi_irq);
+
+ mhi_update_state_info(MHI_STATE_CONNECTED);
}
static void mhi_ring_init_cb(void *data)
@@ -1677,6 +2363,78 @@
queue_work(mhi->ring_init_wq, &mhi->ring_init_cb_work);
}
+int mhi_register_state_cb(void (*mhi_state_cb)
+ (struct mhi_dev_client_cb_data *cb_data),
+ void *data, enum mhi_client_channel channel)
+{
+ struct mhi_dev_ready_cb_info *cb_info = NULL;
+
+ if (!mhi_ctx) {
+ pr_err("MHI device not ready\n");
+ return -ENXIO;
+ }
+
+ if (channel > MHI_MAX_CHANNELS) {
+ pr_err("Invalid channel :%d\n", channel);
+ return -EINVAL;
+ }
+
+ mutex_lock(&mhi_ctx->mhi_lock);
+ cb_info = kmalloc(sizeof(struct mhi_dev_ready_cb_info), GFP_KERNEL);
+ if (!cb_info) {
+ mutex_unlock(&mhi_ctx->mhi_lock);
+ return -ENOMEM;
+ }
+
+ cb_info->cb = mhi_state_cb;
+ cb_info->cb_data.user_data = data;
+ cb_info->cb_data.channel = channel;
+
+ list_add_tail(&cb_info->list, &mhi_ctx->client_cb_list);
+
+ /**
+ * If channel is open during registration, no callback is issued.
+ * Instead return -EEXIST to notify the client. Clients request
+ * is added to the list to notify future state change notification.
+ */
+ if (mhi_ctx->ch[channel].state == MHI_DEV_CH_STARTED) {
+ mutex_unlock(&mhi_ctx->mhi_lock);
+ return -EEXIST;
+ }
+
+ mutex_unlock(&mhi_ctx->mhi_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(mhi_register_state_cb);
+
+static void mhi_update_state_info(uint32_t info)
+{
+ struct mhi_dev_client_cb_reason reason;
+
+ mhi_ctx->ctrl_info = info;
+
+ if (info == MHI_STATE_CONNECTED)
+ return;
+
+ reason.reason = MHI_DEV_CTRL_UPDATE;
+ uci_ctrl_update(&reason);
+}
+
+int mhi_ctrl_state_info(uint32_t *info)
+{
+ if (!info) {
+ pr_err("Invalid info\n");
+ return -EINVAL;
+ }
+
+ *info = mhi_ctx->ctrl_info;
+ mhi_log(MHI_MSG_VERBOSE, "ctrl:%d", mhi_ctx->ctrl_info);
+
+ return 0;
+}
+EXPORT_SYMBOL(mhi_ctrl_state_info);
+
static int get_device_tree_data(struct platform_device *pdev)
{
struct mhi_dev *mhi;
@@ -1725,13 +2483,11 @@
}
mhi->ipa_uc_mbox_erdb = res_mem->start;
-
mhi_ctx = mhi;
rc = of_property_read_u32((&pdev->dev)->of_node,
"qcom,mhi-ifc-id",
&mhi_ctx->ifc_id);
-
if (rc) {
pr_err("qcom,mhi-ifc-id does not exist.\n");
return rc;
@@ -1753,22 +2509,90 @@
return rc;
}
+ mhi_ctx->use_ipa = of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,use-ipa-software-channel");
+
+ mhi_ctx->config_iatu = of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,mhi-config-iatu");
+
+ if (mhi_ctx->config_iatu) {
+ rc = of_property_read_u32((&pdev->dev)->of_node,
+ "qcom,mhi-local-pa-base",
+ &mhi_ctx->device_local_pa_base);
+ if (rc) {
+ pr_err("qcom,mhi-local-pa-base does not exist\n");
+ return rc;
+ }
+ }
+
+ mhi_ctx->mhi_int = of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,mhi-interrupt");
+
+ if (mhi->config_iatu || mhi_ctx->mhi_int) {
+ mhi->mhi_irq = platform_get_irq_byname(pdev, "mhi-device-inta");
+ if (mhi->mhi_irq < 0) {
+ pr_err("Invalid MHI device interrupt\n");
+ rc = mhi->mhi_irq;
+ return rc;
+ }
+ }
+
+ device_init_wakeup(mhi->dev, true);
+ /* MHI device will be woken up from PCIe event */
+ device_set_wakeup_capable(mhi->dev, false);
+ /* Hold a wakelock until completion of M0 */
+ pm_stay_awake(mhi->dev);
+ atomic_set(&mhi->mhi_dev_wake, 1);
+
+ mhi_log(MHI_MSG_VERBOSE, "acquiring wakelock\n");
+
return 0;
}
+static int mhi_deinit(struct mhi_dev *mhi)
+{
+ int rc = 0, i = 0, ring_id = 0;
+ struct mhi_dev_ring *ring;
+ struct platform_device *pdev = mhi->pdev;
+
+ ring_id = mhi->cfg.channels + mhi->cfg.event_rings + 1;
+
+ for (i = 0; i < ring_id; i++) {
+ ring = &mhi->ring[i];
+ if (ring->state == RING_STATE_UINT)
+ continue;
+
+ dma_free_coherent(mhi->dev, ring->ring_size *
+ sizeof(union mhi_dev_ring_element_type),
+ ring->ring_cache,
+ ring->ring_cache_dma_handle);
+ }
+
+ for (i = 0; i < mhi->cfg.channels; i++)
+ mutex_destroy(&mhi->ch[i].ch_lock);
+
+ devm_kfree(&pdev->dev, mhi->mmio_backup);
+ devm_kfree(&pdev->dev, mhi->ch);
+ devm_kfree(&pdev->dev, mhi->ring);
+
+ mhi_dev_sm_exit(mhi);
+
+ mhi->mmio_initialized = false;
+
+ return rc;
+}
+
static int mhi_init(struct mhi_dev *mhi)
{
int rc = 0, i = 0;
struct platform_device *pdev = mhi->pdev;
-
rc = mhi_dev_mmio_init(mhi);
if (rc) {
pr_err("Failed to update the MMIO init\n");
return rc;
}
-
mhi->ring = devm_kzalloc(&pdev->dev,
(sizeof(struct mhi_dev_ring) *
(mhi->cfg.channels + mhi->cfg.event_rings + 1)),
@@ -1782,46 +2606,148 @@
if (!mhi->ch)
return -ENOMEM;
- for (i = 0; i < mhi->cfg.channels; i++)
- mutex_init(&mhi->ch[i].ch_lock);
- mhi->mmio_backup = devm_kzalloc(&pdev->dev, MHI_DEV_MMIO_RANGE,
- GFP_KERNEL);
+ for (i = 0; i < mhi->cfg.channels; i++) {
+ mutex_init(&mhi->ch[i].ch_lock);
+ if (i == MHI_CLIENT_IP_SW_4_OUT || i == MHI_CLIENT_IP_SW_4_IN) {
+ int nreq = 0;
+
+ INIT_LIST_HEAD(&mhi->ch[i].event_req_buffers);
+ while (nreq < MHI_MAX_EVT_REQ) {
+ struct event_req *ereq;
+ /* Pre allocate event requests */
+ ereq = kzalloc(sizeof(struct event_req),
+ GFP_KERNEL);
+ if (!ereq)
+ return -ENOMEM;
+
+ /* pre allocate buffers to queue
+ * transfer completion events
+ */
+ ereq->tr_events = kzalloc(RING_ELEMENT_TYPE_SZ*
+ MAX_TR_EVENTS, GFP_KERNEL);
+ if (!ereq->tr_events) {
+ kfree(ereq);
+ return -ENOMEM;
+ }
+ list_add_tail(&ereq->list,
+ &mhi->ch[i].event_req_buffers);
+ nreq++;
+ }
+ mhi->ch[i].curr_ereq =
+ container_of(mhi->ch[i].event_req_buffers.next,
+ struct event_req, list);
+ list_del_init(&mhi->ch[i].curr_ereq->list);
+ }
+ }
+
+ spin_lock_init(&mhi->lock);
+ mhi->mmio_backup = devm_kzalloc(&pdev->dev,
+ MHI_DEV_MMIO_RANGE, GFP_KERNEL);
if (!mhi->mmio_backup)
return -ENOMEM;
- mhi_ipc_log = ipc_log_context_create(MHI_IPC_LOG_PAGES, "mhi", 0);
- if (mhi_ipc_log == NULL) {
- dev_err(&pdev->dev,
- "Failed to create IPC logging context\n");
- }
-
return 0;
}
-static int mhi_dev_probe(struct platform_device *pdev)
+static int mhi_dev_resume_mmio_mhi_reinit(struct mhi_dev *mhi_ctx)
{
int rc = 0;
- if (pdev->dev.of_node) {
- rc = get_device_tree_data(pdev);
- if (rc) {
- pr_err("Error reading MHI Dev DT\n");
- return rc;
+ mutex_lock(&mhi_ctx->mhi_lock);
+ if (atomic_read(&mhi_ctx->re_init_done)) {
+ mhi_log(MHI_MSG_INFO, "Re_init done, return\n");
+ mutex_unlock(&mhi_ctx->mhi_lock);
+ return 0;
+ }
+
+ rc = mhi_init(mhi_ctx);
+ if (rc) {
+ pr_err("Error initializing MHI MMIO with %d\n", rc);
+ goto fail;
+ }
+
+ mhi_ctx->event_reg.events = EP_PCIE_EVENT_PM_D3_HOT |
+ EP_PCIE_EVENT_PM_D3_COLD |
+ EP_PCIE_EVENT_PM_D0 |
+ EP_PCIE_EVENT_PM_RST_DEAST |
+ EP_PCIE_EVENT_MHI_A7 |
+ EP_PCIE_EVENT_LINKDOWN;
+ mhi_ctx->event_reg.user = mhi_ctx;
+ mhi_ctx->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK;
+ mhi_ctx->event_reg.callback = mhi_dev_sm_pcie_handler;
+
+ rc = ep_pcie_register_event(mhi_ctx->phandle, &mhi_ctx->event_reg);
+ if (rc) {
+ pr_err("Failed to register for events from PCIe\n");
+ goto fail;
+ }
+
+ rc = ipa_register_ipa_ready_cb(mhi_ring_init_cb, mhi_ctx);
+ if (rc < 0) {
+ if (rc == -EEXIST) {
+ mhi_ring_init_cb(mhi_ctx);
+ } else {
+ pr_err("Error calling IPA cb with %d\n", rc);
+ goto fail;
}
}
- mhi_ctx->phandle = ep_pcie_get_phandle(mhi_ctx->ifc_id);
- if (!mhi_ctx->phandle) {
- pr_err("PCIe driver is not ready yet.\n");
- return -EPROBE_DEFER;
+ /* Invoke MHI SM when device is in RESET state */
+ rc = mhi_dev_sm_init(mhi_ctx);
+ if (rc) {
+ pr_err("%s: Error during SM init\n", __func__);
+ goto fail;
}
- if (ep_pcie_get_linkstatus(mhi_ctx->phandle) != EP_PCIE_LINK_ENABLED) {
- pr_err("PCIe link is not ready to use.\n");
- return -EPROBE_DEFER;
+ /* set the env before setting the ready bit */
+ rc = mhi_dev_mmio_set_env(mhi_ctx, MHI_ENV_VALUE);
+ if (rc) {
+ pr_err("%s: env setting failed\n", __func__);
+ goto fail;
}
+ /* All set, notify the host */
+ rc = mhi_dev_sm_set_ready();
+ if (rc) {
+ pr_err("%s: unable to set ready bit\n", __func__);
+ goto fail;
+ }
+
+ atomic_set(&mhi_ctx->is_suspended, 0);
+fail:
+ atomic_set(&mhi_ctx->re_init_done, 1);
+ mutex_unlock(&mhi_ctx->mhi_lock);
+ return rc;
+}
+
+static void mhi_dev_reinit(struct work_struct *work)
+{
+ struct mhi_dev *mhi_ctx = container_of(work,
+ struct mhi_dev, re_init);
+ enum ep_pcie_link_status link_state;
+ int rc = 0;
+
+ link_state = ep_pcie_get_linkstatus(mhi_ctx->phandle);
+ if (link_state == EP_PCIE_LINK_ENABLED) {
+ /* PCIe link is up with BME set */
+ rc = mhi_dev_resume_mmio_mhi_reinit(mhi_ctx);
+ if (rc) {
+ pr_err("Failed to register for events from PCIe\n");
+ return;
+ }
+ }
+
+ mhi_log(MHI_MSG_VERBOSE, "Wait for PCIe linkup\n");
+}
+
+static int mhi_dev_resume_mmio_mhi_init(struct mhi_dev *mhi_ctx)
+{
+ struct platform_device *pdev;
+ int rc = 0;
+
+ pdev = mhi_ctx->pdev;
+
INIT_WORK(&mhi_ctx->chdb_ctrl_work, mhi_dev_scheduler);
mhi_ctx->pending_ring_wq = alloc_workqueue("mhi_pending_wq",
@@ -1835,6 +2761,8 @@
INIT_WORK(&mhi_ctx->ring_init_cb_work, mhi_dev_enable);
+ INIT_WORK(&mhi_ctx->re_init, mhi_dev_reinit);
+
mhi_ctx->ring_init_wq = alloc_workqueue("mhi_ring_init_cb_wq",
WQ_HIGHPRI, 0);
if (!mhi_ctx->ring_init_wq) {
@@ -1844,6 +2772,7 @@
INIT_LIST_HEAD(&mhi_ctx->event_ring_list);
INIT_LIST_HEAD(&mhi_ctx->process_ring_list);
+ INIT_LIST_HEAD(&mhi_ctx->client_cb_list);
mutex_init(&mhi_ctx->mhi_lock);
mutex_init(&mhi_ctx->mhi_event_lock);
mutex_init(&mhi_ctx->mhi_write_test);
@@ -1878,6 +2807,12 @@
return rc;
}
+ mhi_ctx->phandle = ep_pcie_get_phandle(mhi_ctx->ifc_id);
+ if (!mhi_ctx->phandle) {
+ pr_err("PCIe driver get handle failed.\n");
+ return -EINVAL;
+ }
+
mhi_ctx->event_reg.events = EP_PCIE_EVENT_PM_D3_HOT |
EP_PCIE_EVENT_PM_D3_COLD |
EP_PCIE_EVENT_PM_D0 |
@@ -1906,6 +2841,125 @@
}
}
+ /* Invoke MHI SM when device is in RESET state */
+ rc = mhi_dev_sm_init(mhi_ctx);
+ if (rc) {
+ pr_err("%s: Error during SM init\n", __func__);
+ return rc;
+ }
+
+ /* set the env before setting the ready bit */
+ rc = mhi_dev_mmio_set_env(mhi_ctx, MHI_ENV_VALUE);
+ if (rc) {
+ pr_err("%s: env setting failed\n", __func__);
+ return rc;
+ }
+
+ /* All set, notify the host */
+ mhi_dev_sm_set_ready();
+
+ if (mhi_ctx->config_iatu || mhi_ctx->mhi_int) {
+ rc = devm_request_irq(&pdev->dev, mhi_ctx->mhi_irq, mhi_dev_isr,
+ IRQF_TRIGGER_HIGH, "mhi_isr", mhi_ctx);
+ if (rc) {
+ dev_err(&pdev->dev, "request mhi irq failed %d\n", rc);
+ return -EINVAL;
+ }
+
+ disable_irq(mhi_ctx->mhi_irq);
+ }
+
+ return 0;
+}
+
+static void mhi_dev_resume_init_with_link_up(struct ep_pcie_notify *notify)
+{
+ if (!notify || !notify->user) {
+ pr_err("Null argument for notify\n");
+ return;
+ }
+
+ mhi_ctx = notify->user;
+ mhi_dev_pcie_notify_event = notify->options;
+ mhi_log(MHI_MSG_INFO,
+ "PCIe event=0x%x\n", notify->options);
+ queue_work(mhi_ctx->pcie_event_wq, &mhi_ctx->pcie_event);
+}
+
+static void mhi_dev_pcie_handle_event(struct work_struct *work)
+{
+ struct mhi_dev *mhi_ctx = container_of(work, struct mhi_dev,
+ pcie_event);
+ int rc = 0;
+
+ if (mhi_dev_pcie_notify_event == MHI_INIT) {
+ rc = mhi_dev_resume_mmio_mhi_init(mhi_ctx);
+ if (rc) {
+ pr_err("Error during MHI device initialization\n");
+ return;
+ }
+ } else if (mhi_dev_pcie_notify_event == MHI_REINIT) {
+ rc = mhi_dev_resume_mmio_mhi_reinit(mhi_ctx);
+ if (rc) {
+ pr_err("Error during MHI device re-initialization\n");
+ return;
+ }
+ }
+}
+
+static int mhi_dev_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+
+ if (pdev->dev.of_node) {
+ rc = get_device_tree_data(pdev);
+ if (rc) {
+ pr_err("Error reading MHI Dev DT\n");
+ return rc;
+ }
+ mhi_ipc_log = ipc_log_context_create(MHI_IPC_LOG_PAGES,
+ "mhi", 0);
+ if (mhi_ipc_log == NULL) {
+ dev_err(&pdev->dev,
+ "Failed to create IPC logging context\n");
+ }
+ mhi_uci_init();
+ mhi_update_state_info(MHI_STATE_CONFIGURED);
+ }
+
+ INIT_WORK(&mhi_ctx->pcie_event, mhi_dev_pcie_handle_event);
+ mhi_ctx->pcie_event_wq = alloc_workqueue("mhi_dev_pcie_event_wq",
+ WQ_HIGHPRI, 0);
+ if (!mhi_ctx->pcie_event_wq) {
+ pr_err("no memory\n");
+ rc = -ENOMEM;
+ return rc;
+ }
+
+ mhi_ctx->phandle = ep_pcie_get_phandle(mhi_ctx->ifc_id);
+ if (mhi_ctx->phandle) {
+ /* PCIe link is already up */
+ rc = mhi_dev_resume_mmio_mhi_init(mhi_ctx);
+ if (rc) {
+ pr_err("Error during MHI device initialization\n");
+ return rc;
+ }
+ } else {
+ pr_debug("Register a PCIe callback\n");
+ mhi_ctx->event_reg.events = EP_PCIE_EVENT_LINKUP;
+ mhi_ctx->event_reg.user = mhi_ctx;
+ mhi_ctx->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK;
+ mhi_ctx->event_reg.callback = mhi_dev_resume_init_with_link_up;
+ mhi_ctx->event_reg.options = MHI_INIT;
+
+ rc = ep_pcie_register_event(mhi_ctx->phandle,
+ &mhi_ctx->event_reg);
+ if (rc) {
+ pr_err("Failed to register for events from PCIe\n");
+ return rc;
+ }
+ }
+
return 0;
}
diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h
index 1a73d92..38e52e2 100644
--- a/drivers/platform/msm/mhi_dev/mhi.h
+++ b/drivers/platform/msm/mhi_dev/mhi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -274,7 +274,15 @@
#define HW_CHANNEL_END 107
#define MHI_ENV_VALUE 2
#define MHI_MASK_ROWS_CH_EV_DB 4
-#define TRB_MAX_DATA_SIZE 4096
+#define TRB_MAX_DATA_SIZE 8192
+#define MHI_CTRL_STATE 25
+#define IPA_DMA_SYNC 1
+#define IPA_DMA_ASYNC 0
+
+/*maximum trasnfer completion events buffer*/
+#define MAX_TR_EVENTS 50
+/*maximum event requests */
+#define MHI_MAX_EVT_REQ 50
/* Possible ring element types */
union mhi_dev_ring_element_type {
@@ -324,7 +332,10 @@
uint64_t host_pa;
uintptr_t device_pa;
uintptr_t device_va;
- uint32_t size;
+ size_t size;
+ dma_addr_t phy_addr;
+ void *virt_addr;
+ bool use_ipa_dma;
};
struct mhi_interrupt_state {
@@ -349,6 +360,23 @@
MHI_DEV_POLL,
};
+enum mhi_ctrl_info {
+ MHI_STATE_CONFIGURED = 0,
+ MHI_STATE_CONNECTED = 1,
+ MHI_STATE_DISCONNECTED = 2,
+ MHI_STATE_INVAL,
+};
+
+enum mhi_dev_tr_compl_evt_type {
+ SEND_EVENT_BUFFER,
+ SEND_EVENT_RD_OFFSET,
+};
+
+enum mhi_dev_transfer_type {
+ MHI_DEV_DMA_SYNC,
+ MHI_DEV_DMA_ASYNC,
+};
+
struct mhi_dev_channel;
struct mhi_dev_ring {
@@ -394,6 +422,7 @@
enum cb_reason {
MHI_DEV_TRE_AVAILABLE = 0,
+ MHI_DEV_CTRL_UPDATE,
};
struct mhi_dev_client_cb_reason {
@@ -423,14 +452,30 @@
uint32_t nr_iov;
};
+struct ring_cache_req {
+ struct completion *done;
+ void *context;
+};
+
+struct event_req {
+ union mhi_dev_ring_element_type *tr_events;
+ u32 num_events;
+ dma_addr_t dma;
+ u32 dma_len;
+ dma_addr_t event_rd_dma;
+ void *context;
+ enum mhi_dev_tr_compl_evt_type event_type;
+ u32 event_ring;
+ void (*client_cb)(void *req);
+ struct list_head list;
+};
+
struct mhi_dev_channel {
struct list_head list;
struct list_head clients;
/* synchronization for changing channel state,
* adding/removing clients, mhi_dev callbacks, etc
*/
- spinlock_t lock;
-
struct mhi_dev_ring *ring;
enum mhi_dev_channel_state state;
@@ -440,6 +485,9 @@
/* client which the current inbound/outbound message is for */
struct mhi_dev_client *active_client;
+ struct list_head event_req_buffers;
+ struct event_req *curr_ereq;
+
/* current TRE being processed */
uint64_t tre_loc;
/* current TRE size */
@@ -466,6 +514,7 @@
struct mhi_config cfg;
bool mmio_initialized;
+ spinlock_t lock;
/* Host control base information */
struct mhi_host_addr host_addr;
struct mhi_addr ctrl_base;
@@ -481,6 +530,7 @@
struct mhi_dev_ch_ctx *cmd_ctx_cache;
dma_addr_t cmd_ctx_cache_dma_handle;
struct mhi_dev_ring *ring;
+ int mhi_irq;
struct mhi_dev_channel *ch;
int ctrl_int;
@@ -491,6 +541,7 @@
/* Scheduler work */
struct work_struct chdb_ctrl_work;
+
struct mutex mhi_lock;
struct mutex mhi_event_lock;
@@ -509,15 +560,22 @@
u32 ipa_clnt_hndl[4];
struct workqueue_struct *ring_init_wq;
struct work_struct ring_init_cb_work;
+ struct work_struct re_init;
/* EP PCIe registration */
+ struct workqueue_struct *pcie_event_wq;
struct ep_pcie_register_event event_reg;
u32 ifc_id;
struct ep_pcie_hw *phandle;
+ struct work_struct pcie_event;
+ struct ep_pcie_msi_config msi_cfg;
atomic_t write_active;
atomic_t is_suspended;
+ atomic_t mhi_dev_wake;
+ atomic_t re_init_done;
struct mutex mhi_write_test;
+ u32 device_local_pa_base;
u32 mhi_ep_msi_num;
u32 mhi_version;
void *dma_cache;
@@ -535,6 +593,37 @@
* region from device used in mhi_write()
*/
dma_addr_t write_dma_handle;
+
+ /* Use IPA DMA for Software channel data transfer */
+ bool use_ipa;
+
+ /* iATU is required to map control and data region */
+ bool config_iatu;
+
+ /* MHI state info */
+ enum mhi_ctrl_info ctrl_info;
+
+ /*Register for interrupt */
+ bool mhi_int;
+ /* Registered client callback list */
+ struct list_head client_cb_list;
+};
+
+struct mhi_req {
+ u32 chan;
+ u32 mode;
+ u32 chain;
+ void *buf;
+ dma_addr_t dma;
+ u32 snd_cmpl;
+ void *context;
+ size_t len;
+ size_t actual_len;
+ uint32_t rd_offset;
+ struct mhi_dev_client *client;
+ struct list_head list;
+ union mhi_dev_ring_element_type *el;
+ void (*client_cb)(void *req);
};
enum mhi_msg_level {
@@ -609,7 +698,9 @@
MHI_CLIENT_CSVT_IN = 43,
MHI_CLIENT_SMCT_OUT = 44,
MHI_CLIENT_SMCT_IN = 45,
- MHI_MAX_SOFTWARE_CHANNELS = 46,
+ MHI_CLIENT_IP_SW_4_OUT = 46,
+ MHI_CLIENT_IP_SW_4_IN = 47,
+ MHI_MAX_SOFTWARE_CHANNELS = 48,
MHI_CLIENT_TEST_OUT = 60,
MHI_CLIENT_TEST_IN = 61,
MHI_CLIENT_RESERVED_1_LOWER = 62,
@@ -626,6 +717,20 @@
uint32_t buf_size;
};
+struct mhi_dev_client_cb_data {
+ void *user_data;
+ enum mhi_client_channel channel;
+ enum mhi_ctrl_info ctrl_info;
+};
+
+typedef void (*mhi_state_cb)(struct mhi_dev_client_cb_data *cb_dat);
+
+struct mhi_dev_ready_cb_info {
+ struct list_head list;
+ mhi_state_cb cb;
+ struct mhi_dev_client_cb_data cb_data;
+};
+
/**
* mhi_dev_open_channel() - Channel open for a given client done prior
* to read/write.
@@ -643,24 +748,21 @@
/**
* mhi_dev_read_channel() - Channel read for a given client
- * @handle_client: Client Handle issued during mhi_dev_open_channel
- * @buf: Pointer to the buffer used by the MHI core to copy the data received
- * from the Host.
- * @buf_size: Size of the buffer pointer.
- * @chain : Indicate if the received data is part of chained packet.
+ * @mreq: mreq is the client argument which includes meta info
+ * like write data location, buffer len, read offset, mode,
+ * chain and client call back function which will be invoked
+ * when data read is completed.
*/
-int mhi_dev_read_channel(struct mhi_dev_client *handle_client,
- void *buf, uint32_t buf_size, uint32_t *chain);
+int mhi_dev_read_channel(struct mhi_req *mreq);
/**
* mhi_dev_write_channel() - Channel write for a given software client.
- * @handle_client: Client Handle issued during mhi_dev_open_channel
- * @buf: Pointer to the buffer used by the MHI core to copy the data from the
- * device to the host.
- * @buf_size: Size of the buffer pointer.
+ * @wreq wreq is the client argument which includes meta info like
+ * client handle, read data location, buffer length, mode,
+ * and client call back function which will free the packet.
+ * when data write is completed.
*/
-int mhi_dev_write_channel(struct mhi_dev_client *handle_client, void *buf,
- uint32_t buf_size);
+int mhi_dev_write_channel(struct mhi_req *wreq);
/**
* mhi_dev_channel_isempty() - Checks if there is any pending TRE's to process.
@@ -733,8 +835,8 @@
* @element: Transfer ring element to be copied to the host memory.
*/
int mhi_dev_add_element(struct mhi_dev_ring *ring,
- union mhi_dev_ring_element_type *element);
-
+ union mhi_dev_ring_element_type *element,
+ struct event_req *ereq, int evt_offset);
/**
* mhi_transfer_device_to_host() - memcpy equivalent API to transfer data
* from device to the host.
@@ -742,9 +844,10 @@
* @src: Source virtual address.
* @len: Numer of bytes to be transferred.
* @mhi: MHI dev structure.
+ * @req: mhi_req structure
*/
int mhi_transfer_device_to_host(uint64_t dst_pa, void *src, uint32_t len,
- struct mhi_dev *mhi);
+ struct mhi_dev *mhi, struct mhi_req *req);
/**
* mhi_transfer_host_to_dev() - memcpy equivalent API to transfer data
@@ -753,19 +856,29 @@
* @src_pa: Source physical address.
* @len: Numer of bytes to be transferred.
* @mhi: MHI dev structure.
+ * @req: mhi_req structure
*/
int mhi_transfer_host_to_device(void *device, uint64_t src_pa, uint32_t len,
- struct mhi_dev *mhi);
+ struct mhi_dev *mhi, struct mhi_req *mreq);
/**
- * mhi_dev_write_to_host() - memcpy equivalent API to transfer data
- * from device to host.
+ * mhi_dev_write_to_host() - Transfer data from device to host.
+ * Based on support available, either IPA DMA or memcpy is used.
* @host: Host and device address details.
* @buf: Data buffer that needs to be written to the host.
* @size: Data buffer size.
*/
-void mhi_dev_write_to_host(struct mhi_addr *host, void *buf, size_t size,
- struct mhi_dev *mhi);
+void mhi_dev_write_to_host(struct mhi_dev *mhi, struct mhi_addr *mhi_transfer,
+ struct event_req *ereq, enum mhi_dev_transfer_type type);
+/**
+ * mhi_dev_read_from_host() - memcpy equivalent API to transfer data
+ * from host to device.
+ * @host: Host and device address details.
+ * @buf: Data buffer that needs to be read from the host.
+ * @size: Data buffer size.
+ */
+void mhi_dev_read_from_host(struct mhi_dev *mhi,
+ struct mhi_addr *mhi_transfer);
/**
* mhi_dev_read_from_host() - memcpy equivalent API to transfer data
@@ -774,15 +887,7 @@
* @buf: Data buffer that needs to be read from the host.
* @size: Data buffer size.
*/
-void mhi_dev_read_from_host(struct mhi_addr *dst, dma_addr_t buf, size_t size);
-/**
- * mhi_dev_read_from_host() - memcpy equivalent API to transfer data
- * from host to device.
- * @host: Host and device address details.
- * @buf: Data buffer that needs to be read from the host.
- * @size: Data buffer size.
- */
void mhi_ring_set_cb(struct mhi_dev_ring *ring,
void (*ring_cb)(struct mhi_dev *dev,
union mhi_dev_ring_element_type *el, void *ctx));
@@ -848,6 +953,7 @@
* mhi_dev_mmio_enable_ctrl_interrupt() - Enable Control interrupt.
* @dev: MHI device structure.
*/
+
int mhi_dev_mmio_enable_ctrl_interrupt(struct mhi_dev *dev);
/**
@@ -1021,8 +1127,10 @@
* mhi_dev_get_mhi_state() - Fetches the MHI state such as M0/M1/M2/M3.
* @dev: MHI device structure.
* @state: Pointer of type mhi_dev_state
+ * @mhi_reset: MHI device reset from host.
*/
-int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state);
+int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state,
+ bool *mhi_reset);
/**
* mhi_dev_mmio_init() - Initializes the MMIO and reads the Number of event
@@ -1121,6 +1229,48 @@
*/
int mhi_uci_init(void);
+/**
+ * mhi_dev_net_interface_init() - Initializes the mhi device network interface
+ * which exposes the virtual network interface (mhi_dev_net0).
+ * data packets will transfer between MHI host interface (mhi_swip)
+ * and mhi_dev_net interface using software path
+ */
+int mhi_dev_net_interface_init(void);
+
+/**
+ * mhi_dev_net_exit() - Clean up and close MHI Network interface module.
+ */
+void mhi_dev_net_exit(void);
+
+/**
+ * mhi_dev_notify_a7_event() - Used by PCIe driver to notify A7 MHI device
+ * interrupt after doorbell is received. Used by PCIe driver when MHI
+ * A7 interrupts are routed to PCIe instead of MHI device.
+ */
void mhi_dev_notify_a7_event(struct mhi_dev *mhi);
+/**
+ * mhi_ctrl_state_info() - Provide MHI state info
+ * MHI_STATE=CONFIGURED - MHI device is present but not ready
+ * for data traffic.
+ * MHI_STATE=CONNECTED - MHI device is ready for data transfer.
+ * MHI_STATE=DISCONNECTED - MHI device has its pipes suspended.
+ * exposes device nodes for the supported MHI software
+ * channels.
+ */
+int mhi_ctrl_state_info(uint32_t *info);
+
+/**
+ * uci_ctrl_update() - Update UCI once TRE's are available for clients to
+ * consume.
+ */
+void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason);
+
+/**
+ * mhi_register_state_cb() - Clients can register and receive callback after
+ * MHI channel is connected or disconnected.
+ */
+int mhi_register_state_cb(void (*mhi_state_cb)
+ (struct mhi_dev_client_cb_data *cb_data), void *data,
+ enum mhi_client_channel channel);
#endif /* _MHI_H_ */
diff --git a/drivers/platform/msm/mhi_dev/mhi_dev_net.c b/drivers/platform/msm/mhi_dev/mhi_dev_net.c
new file mode 100644
index 0000000..d8dc85f
--- /dev/null
+++ b/drivers/platform/msm/mhi_dev/mhi_dev_net.c
@@ -0,0 +1,667 @@
+/* Copyright (c) 2017-2018, 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.
+ */
+/*
+ * MHI Device Network interface
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ip.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/dma-mapping.h>
+#include <linux/ipc_logging.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/ktime.h>
+
+#include "mhi.h"
+
+#define MHI_NET_DRIVER_NAME "mhi_dev_net_drv"
+#define MHI_NET_DEV_NAME "mhi_dev_net%d"
+#define MHI_NET_DEFAULT_MTU 8192
+#define MHI_NET_IPC_PAGES (100)
+#define MHI_MAX_RX_REQ (128)
+#define MHI_MAX_TX_REQ (128)
+
+enum mhi_dev_net_dbg_lvl {
+ MHI_VERBOSE = 0x1,
+ MHI_INFO = 0x2,
+ MHI_DBG = 0x3,
+ MHI_WARNING = 0x4,
+ MHI_ERROR = 0x5,
+ MHI_CRITICAL = 0x6,
+ MSG_NET_reserved = 0x80000000
+};
+
+static enum mhi_dev_net_dbg_lvl mhi_net_msg_lvl = MHI_CRITICAL;
+static enum mhi_dev_net_dbg_lvl mhi_net_ipc_log_lvl = MHI_VERBOSE;
+static void *mhi_net_ipc_log;
+
+enum mhi_chan_dir {
+ MHI_DIR_INVALID = 0x0,
+ MHI_DIR_OUT = 0x1,
+ MHI_DIR_IN = 0x2,
+ MHI_DIR__reserved = 0x80000000
+};
+
+struct mhi_dev_net_chan_attr {
+ /* SW maintained channel id */
+ enum mhi_client_channel chan_id;
+ /* maximum buffer size for this channel */
+ size_t max_packet_size;
+ /* direction of the channel, see enum mhi_chan_dir */
+ enum mhi_chan_dir dir;
+};
+
+#define CHAN_TO_CLIENT(_CHAN_NR) (_CHAN_NR / 2)
+
+#define mhi_dev_net_log(_msg_lvl, _msg, ...) do { \
+ if (_msg_lvl >= mhi_net_msg_lvl) { \
+ pr_err("[%s] "_msg, __func__, ##__VA_ARGS__); \
+ } \
+ if (mhi_net_ipc_log && (_msg_lvl >= mhi_net_ipc_log_lvl)) { \
+ ipc_log_string(mhi_net_ipc_log, \
+ "[%s] " _msg, __func__, ##__VA_ARGS__); \
+ } \
+} while (0)
+
+module_param(mhi_net_msg_lvl, uint, 0644);
+MODULE_PARM_DESC(mhi_net_msg_lvl, "mhi dev net dbg lvl");
+
+module_param(mhi_net_ipc_log_lvl, uint, 0644);
+MODULE_PARM_DESC(mhi_net_ipc_log_lvl, "mhi dev net dbg lvl");
+
+struct mhi_dev_net_client {
+ /* write channel - always even*/
+ u32 out_chan;
+ /* read channel - always odd */
+ u32 in_chan;
+ struct mhi_dev_client *out_handle;
+ struct mhi_dev_client *in_handle;
+ /*process pendig packets */
+ struct workqueue_struct *pending_pckt_wq;
+ struct work_struct xmit_work;
+ /*Read data from host work queue*/
+ atomic_t rx_enabled;
+ atomic_t tx_enabled;
+ struct net_device *dev;
+ struct sk_buff_head tx_buffers;
+ struct list_head rx_buffers;
+ struct list_head wr_req_buffers;
+ struct mhi_dev_net_ctxt *net_ctxt;
+ /*To check write channel is empty or not*/
+ spinlock_t wrt_lock;
+ spinlock_t rd_lock;
+ struct mutex in_chan_lock;
+ struct mutex out_chan_lock;
+};
+
+struct mhi_dev_net_ctxt {
+ struct mhi_dev_net_chan_attr chan_attr[MHI_MAX_SOFTWARE_CHANNELS];
+ struct mhi_dev_net_client *client_handle;
+ void (*net_event_notifier)(struct mhi_dev_client_cb_reason *cb);
+};
+
+static struct mhi_dev_net_ctxt mhi_net_ctxt;
+static ssize_t mhi_dev_net_client_read(struct mhi_dev_net_client *);
+
+static int mhi_dev_net_init_ch_attributes(struct mhi_dev_net_ctxt *mhi_ctxt)
+{
+ u32 channel = 0;
+ struct mhi_dev_net_chan_attr *chan_attrib = NULL;
+
+ channel = MHI_CLIENT_IP_SW_4_OUT;
+ chan_attrib = &mhi_ctxt->chan_attr[channel];
+ chan_attrib->dir = MHI_DIR_OUT;
+ chan_attrib->chan_id = channel;
+ chan_attrib->max_packet_size = TRB_MAX_DATA_SIZE;
+ mhi_dev_net_log(MHI_INFO, "Write chan attributes dir %d chan_id %d\n",
+ chan_attrib->dir, chan_attrib->chan_id);
+
+ channel = MHI_CLIENT_IP_SW_4_IN;
+ chan_attrib = &mhi_ctxt->chan_attr[channel];
+ chan_attrib->dir = MHI_DIR_IN;
+ chan_attrib->chan_id = channel;
+ chan_attrib->max_packet_size = TRB_MAX_DATA_SIZE;
+ mhi_dev_net_log(MHI_INFO, "Read chan attributes dir %d chan_id %d\n",
+ chan_attrib->dir, chan_attrib->chan_id);
+ return 0;
+}
+
+static void mhi_dev_net_process_queue_packets(struct work_struct *work)
+{
+ struct mhi_dev_net_client *client = container_of(work,
+ struct mhi_dev_net_client, xmit_work);
+ unsigned long flags = 0;
+ int xfer_data = 0;
+ struct sk_buff *skb = NULL;
+ struct mhi_req *wreq = NULL;
+
+ if (mhi_dev_channel_isempty(client->in_handle)) {
+ mhi_dev_net_log(MHI_INFO, "%s stop network xmmit\n", __func__);
+ netif_stop_queue(client->dev);
+ return;
+ }
+ while (!((skb_queue_empty(&client->tx_buffers)) ||
+ (list_empty(&client->wr_req_buffers)))) {
+ spin_lock_irqsave(&client->wrt_lock, flags);
+ skb = skb_dequeue(&(client->tx_buffers));
+ if (!skb) {
+ mhi_dev_net_log(MHI_INFO,
+ "SKB is NULL from dequeue\n");
+ spin_unlock_irqrestore(&client->wrt_lock, flags);
+ return;
+ }
+ wreq = container_of(client->wr_req_buffers.next,
+ struct mhi_req, list);
+ list_del_init(&wreq->list);
+
+ wreq->client = client->in_handle;
+ wreq->context = skb;
+ wreq->buf = skb->data;
+ wreq->len = skb->len;
+ wreq->chan = client->in_chan;
+ wreq->mode = IPA_DMA_ASYNC;
+ if (skb_queue_empty(&client->tx_buffers) ||
+ list_empty(&client->wr_req_buffers)) {
+ wreq->snd_cmpl = 1;
+ } else
+ wreq->snd_cmpl = 0;
+ spin_unlock_irqrestore(&client->wrt_lock, flags);
+ xfer_data = mhi_dev_write_channel(wreq);
+ if (xfer_data <= 0) {
+ pr_err("%s(): Failed to write skb len %d\n",
+ __func__, skb->len);
+ kfree_skb(skb);
+ return;
+ }
+ client->dev->stats.tx_packets++;
+
+ /* Check if free buffers are available*/
+ if (mhi_dev_channel_isempty(client->in_handle)) {
+ mhi_dev_net_log(MHI_INFO,
+ "%s buffers are full stop xmit\n",
+ __func__);
+ netif_stop_queue(client->dev);
+ break;
+ }
+ } /* While TX queue is not empty */
+}
+
+static void mhi_dev_net_event_notifier(struct mhi_dev_client_cb_reason *reason)
+{
+ struct mhi_dev_net_client *client_handle = mhi_net_ctxt.client_handle;
+
+ if (reason->reason == MHI_DEV_TRE_AVAILABLE) {
+ if (reason->ch_id % 2) {
+ if (netif_queue_stopped(client_handle->dev)) {
+ netif_wake_queue(client_handle->dev);
+ queue_work(client_handle->pending_pckt_wq,
+ &client_handle->xmit_work);
+ }
+ } else
+ mhi_dev_net_client_read(client_handle);
+ }
+}
+
+static __be16 mhi_dev_net_eth_type_trans(struct sk_buff *skb)
+{
+ __be16 protocol = 0;
+ /* Determine L3 protocol */
+ switch (skb->data[0] & 0xf0) {
+ case 0x40:
+ protocol = htons(ETH_P_IP);
+ break;
+ case 0x60:
+ protocol = htons(ETH_P_IPV6);
+ break;
+ default:
+ /* Default is QMAP */
+ protocol = htons(ETH_P_MAP);
+ break;
+ }
+ return protocol;
+}
+
+static void mhi_dev_net_read_completion_cb(void *req)
+{
+ struct mhi_dev_net_client *net_handle =
+ mhi_net_ctxt.client_handle;
+ struct mhi_req *mreq =
+ (struct mhi_req *)req;
+ struct sk_buff *skb = mreq->context;
+ unsigned long flags;
+
+ skb->len = mreq->actual_len;
+ skb->protocol =
+ mhi_dev_net_eth_type_trans(skb);
+ skb_put(skb, mreq->actual_len);
+ net_handle->dev->stats.rx_packets++;
+ skb->dev = net_handle->dev;
+ netif_rx(skb);
+ spin_lock_irqsave(&net_handle->rd_lock, flags);
+ list_add_tail(&mreq->list, &net_handle->rx_buffers);
+ spin_unlock_irqrestore(&net_handle->rd_lock, flags);
+}
+
+static ssize_t mhi_dev_net_client_read(struct mhi_dev_net_client *mhi_handle)
+{
+ int bytes_avail = 0;
+ int ret_val = 0;
+ u32 chan = 0;
+ struct mhi_dev_client *client_handle = NULL;
+ struct mhi_req *req;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ client_handle = mhi_handle->out_handle;
+ chan = mhi_handle->out_chan;
+ if (!atomic_read(&mhi_handle->rx_enabled))
+ return -EPERM;
+ while (1) {
+ spin_lock_irqsave(&mhi_handle->rd_lock, flags);
+ if (list_empty(&mhi_handle->rx_buffers)) {
+ spin_unlock_irqrestore(&mhi_handle->rd_lock, flags);
+ break;
+ }
+
+ req = container_of(mhi_handle->rx_buffers.next,
+ struct mhi_req, list);
+ list_del_init(&req->list);
+ spin_unlock_irqrestore(&mhi_handle->rd_lock, flags);
+ skb = alloc_skb(MHI_NET_DEFAULT_MTU, GFP_ATOMIC);
+ if (skb == NULL) {
+ pr_err("%s(): skb alloc failed\n", __func__);
+ spin_lock_irqsave(&mhi_handle->rd_lock, flags);
+ list_add_tail(&req->list, &mhi_handle->rx_buffers);
+ spin_unlock_irqrestore(&mhi_handle->rd_lock, flags);
+ ret_val = -ENOMEM;
+ return ret_val;
+ }
+
+ req->client = client_handle;
+ req->chan = chan;
+ req->buf = skb->data;
+ req->len = MHI_NET_DEFAULT_MTU;
+ req->context = skb;
+ req->mode = IPA_DMA_ASYNC;
+ bytes_avail = mhi_dev_read_channel(req);
+
+ if (bytes_avail < 0) {
+ pr_err("Failed to read chan %d bytes_avail = %d\n",
+ chan, bytes_avail);
+ spin_lock_irqsave(&mhi_handle->rd_lock, flags);
+ kfree_skb(skb);
+ list_add_tail(&req->list, &mhi_handle->rx_buffers);
+ spin_unlock_irqrestore(&mhi_handle->rd_lock, flags);
+ ret_val = -EIO;
+ return 0;
+ }
+ /* no data to send to network stack, break */
+ if (!bytes_avail) {
+ spin_lock_irqsave(&mhi_handle->rd_lock, flags);
+ kfree_skb(skb);
+ list_add_tail(&req->list, &mhi_handle->rx_buffers);
+ spin_unlock_irqrestore(&mhi_handle->rd_lock, flags);
+ return 0;
+ }
+ }
+ /* coming out while only in case of no data or error */
+ return ret_val;
+
+}
+
+static void mhi_dev_net_write_completion_cb(void *req)
+{
+ struct mhi_dev_net_client *client_handle = mhi_net_ctxt.client_handle;
+ struct mhi_req *wreq = (struct mhi_req *)req;
+ struct sk_buff *skb = wreq->context;
+ unsigned long flags;
+
+ kfree_skb(skb);
+ spin_lock_irqsave(&client_handle->wrt_lock, flags);
+ list_add_tail(&wreq->list, &client_handle->wr_req_buffers);
+ spin_unlock_irqrestore(&client_handle->wrt_lock, flags);
+}
+
+static int mhi_dev_net_alloc_write_reqs(struct mhi_dev_net_client *client)
+{
+ int nreq = 0, rc = 0;
+ struct mhi_req *wreq;
+
+ while (nreq < MHI_MAX_TX_REQ) {
+ wreq = kzalloc(sizeof(struct mhi_req), GFP_ATOMIC);
+ if (!wreq)
+ return -ENOMEM;
+ wreq->client_cb = mhi_dev_net_write_completion_cb;
+ list_add_tail(&wreq->list, &client->wr_req_buffers);
+ nreq++;
+ }
+ mhi_dev_net_log(MHI_INFO,
+ "mhi write reqs allocation success\n");
+ return rc;
+
+}
+
+static int mhi_dev_net_alloc_read_reqs(struct mhi_dev_net_client *client)
+{
+ int nreq = 0, rc = 0;
+ struct mhi_req *mreq;
+
+ while (nreq < MHI_MAX_RX_REQ) {
+ mreq = kzalloc(sizeof(struct mhi_req), GFP_ATOMIC);
+ if (!mreq)
+ return -ENOMEM;
+ mreq->len = TRB_MAX_DATA_SIZE;
+ mreq->client_cb = mhi_dev_net_read_completion_cb;
+ list_add_tail(&mreq->list, &client->rx_buffers);
+ nreq++;
+ }
+ mhi_dev_net_log(MHI_INFO,
+ "mhi read reqs allocation success\n");
+ return rc;
+
+}
+
+static int mhi_dev_net_open(struct net_device *dev)
+{
+ struct mhi_dev_net_client *mhi_dev_net_ptr =
+ *(struct mhi_dev_net_client **)netdev_priv(dev);
+ mhi_dev_net_log(MHI_INFO,
+ "mhi_net_dev interface is up for IN %d OUT %d\n",
+ mhi_dev_net_ptr->out_chan,
+ mhi_dev_net_ptr->in_chan);
+ netif_start_queue(dev);
+ return 0;
+}
+
+static netdev_tx_t mhi_dev_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct mhi_dev_net_client *mhi_dev_net_ptr =
+ *(struct mhi_dev_net_client **)netdev_priv(dev);
+ unsigned long flags;
+
+ if (skb->len <= 0) {
+ mhi_dev_net_log(MHI_ERROR,
+ "Invalid skb received freeing skb\n");
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+ spin_lock_irqsave(&mhi_dev_net_ptr->wrt_lock, flags);
+ skb_queue_tail(&(mhi_dev_net_ptr->tx_buffers), skb);
+ spin_unlock_irqrestore(&mhi_dev_net_ptr->wrt_lock, flags);
+
+ queue_work(mhi_dev_net_ptr->pending_pckt_wq,
+ &mhi_dev_net_ptr->xmit_work);
+
+ return NETDEV_TX_OK;
+}
+
+static int mhi_dev_net_stop(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ mhi_dev_net_log(MHI_VERBOSE, "mhi_dev_net interface is down\n");
+ return 0;
+}
+
+static int mhi_dev_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (0 > new_mtu || MHI_NET_DEFAULT_MTU < new_mtu)
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+static const struct net_device_ops mhi_dev_net_ops_ip = {
+ .ndo_open = mhi_dev_net_open,
+ .ndo_stop = mhi_dev_net_stop,
+ .ndo_start_xmit = mhi_dev_net_xmit,
+ .ndo_change_mtu = mhi_dev_net_change_mtu,
+};
+
+static void mhi_dev_net_setup(struct net_device *dev)
+{
+ dev->netdev_ops = &mhi_dev_net_ops_ip;
+ ether_setup(dev);
+
+ /* set this after calling ether_setup */
+ dev->type = ARPHRD_RAWIP;
+ dev->hard_header_len = 0;
+ dev->mtu = MHI_NET_DEFAULT_MTU;
+ dev->addr_len = 0;
+ dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+}
+
+static int mhi_dev_net_enable_iface(struct mhi_dev_net_client *mhi_dev_net_ptr)
+{
+ int ret = 0;
+ struct mhi_dev_net_client **mhi_dev_net_ctxt = NULL;
+ struct net_device *netdev;
+
+ if (!mhi_dev_net_ptr)
+ return -EINVAL;
+
+ /* Initialize skb list head to queue the packets for mhi dev client */
+ skb_queue_head_init(&(mhi_dev_net_ptr->tx_buffers));
+
+ mhi_dev_net_log(MHI_INFO,
+ "mhi_dev_net interface registration\n");
+ netdev = alloc_netdev(sizeof(struct mhi_dev_net_client),
+ MHI_NET_DEV_NAME, NET_NAME_PREDICTABLE,
+ mhi_dev_net_setup);
+ if (!netdev) {
+ pr_err("Failed to allocate netdev for mhi_dev_net\n");
+ goto net_dev_alloc_fail;
+ }
+
+ mhi_dev_net_ctxt = netdev_priv(netdev);
+ mhi_dev_net_ptr->dev = netdev;
+ *mhi_dev_net_ctxt = mhi_dev_net_ptr;
+ ret = register_netdev(mhi_dev_net_ptr->dev);
+ if (ret) {
+ pr_err("Failed to register mhi_dev_net device\n");
+ goto net_dev_reg_fail;
+ }
+ mhi_dev_net_log(MHI_INFO, "Successfully registred mhi_dev_net\n");
+ return 0;
+
+net_dev_reg_fail:
+ free_netdev(mhi_dev_net_ptr->dev);
+net_dev_alloc_fail:
+ mhi_dev_close_channel(mhi_dev_net_ptr->in_handle);
+ mhi_dev_close_channel(mhi_dev_net_ptr->out_handle);
+ mhi_dev_net_ptr->dev = NULL;
+ return -ENOMEM;
+}
+
+static int mhi_dev_net_open_channels(struct mhi_dev_net_client *client)
+{
+ int rc = 0;
+ int ret = 0;
+ struct list_head *cp, *q;
+ struct mhi_req *mreq;
+
+ mhi_dev_net_log(MHI_DBG, "opening OUT %d IN %d channels\n",
+ client->out_chan,
+ client->in_chan);
+ mutex_lock(&client->out_chan_lock);
+ mutex_lock(&client->in_chan_lock);
+ mhi_dev_net_log(MHI_DBG,
+ "Initializing inbound chan %d.\n",
+ client->in_chan);
+
+ rc = mhi_dev_open_channel(client->out_chan, &client->out_handle,
+ mhi_net_ctxt.net_event_notifier);
+ if (rc < 0) {
+ mhi_dev_net_log(MHI_ERROR,
+ "Failed to open chan %d, ret 0x%x\n",
+ client->out_chan, rc);
+ goto handle_not_rdy_err;
+ } else
+ atomic_set(&client->rx_enabled, 1);
+
+ rc = mhi_dev_open_channel(client->in_chan, &client->in_handle,
+ mhi_net_ctxt.net_event_notifier);
+ if (rc < 0) {
+ mhi_dev_net_log(MHI_ERROR,
+ "Failed to open chan %d, ret 0x%x\n",
+ client->in_chan, rc);
+ goto handle_in_err;
+ } else
+ atomic_set(&client->tx_enabled, 1);
+
+ mutex_unlock(&client->in_chan_lock);
+ mutex_unlock(&client->out_chan_lock);
+ mhi_dev_net_log(MHI_INFO, "IN %d, OUT %d channels are opened",
+ client->in_chan, client->out_chan);
+
+ INIT_LIST_HEAD(&client->rx_buffers);
+ INIT_LIST_HEAD(&client->wr_req_buffers);
+ /* pre allocate read request buffer */
+
+ ret = mhi_dev_net_alloc_read_reqs(client);
+ if (ret) {
+ pr_err("failed to allocate rx req buffers\n");
+ goto rx_req_failed;
+ }
+ ret = mhi_dev_net_alloc_write_reqs(client);
+ if (ret) {
+ pr_err("failed to allocate write req buffers\n");
+ goto tx_req_failed;
+ }
+ if (atomic_read(&client->tx_enabled)) {
+ ret = mhi_dev_net_enable_iface(client);
+ if (ret < 0)
+ mhi_dev_net_log(MHI_ERROR,
+ "failed to enable mhi_dev_net iface\n");
+ }
+ return ret;
+tx_req_failed:
+ list_for_each_safe(cp, q, &client->rx_buffers);
+ mreq = list_entry(cp, struct mhi_req, list);
+ list_del(cp);
+ kfree(mreq);
+rx_req_failed:
+ mhi_dev_close_channel(client->in_handle);
+handle_in_err:
+ mhi_dev_close_channel(client->out_handle);
+handle_not_rdy_err:
+ mutex_unlock(&client->in_chan_lock);
+ mutex_unlock(&client->out_chan_lock);
+ return rc;
+}
+
+static int mhi_dev_net_close(void)
+{
+ struct mhi_dev_net_client *client;
+
+ mhi_dev_net_log(MHI_INFO,
+ "mhi_dev_net module is removed\n");
+ client = mhi_net_ctxt.client_handle;
+ mhi_dev_close_channel(client->out_handle);
+ mhi_dev_close_channel(client->in_handle);
+ atomic_set(&client->tx_enabled, 0);
+ atomic_set(&client->rx_enabled, 0);
+ if (client->dev != NULL) {
+ netif_stop_queue(client->dev);
+ unregister_netdev(client->dev);
+ free_netdev(client->dev);
+ client->dev = NULL;
+ }
+ /* freeing mhi client and IPC context */
+ kfree(client);
+ kfree(mhi_net_ipc_log);
+ return 0;
+}
+
+static int mhi_dev_net_rgstr_client(struct mhi_dev_net_client *client, int idx)
+{
+ client->out_chan = idx;
+ client->in_chan = idx + 1;
+ mutex_init(&client->in_chan_lock);
+ mutex_init(&client->out_chan_lock);
+ spin_lock_init(&client->wrt_lock);
+ spin_lock_init(&client->rd_lock);
+ mhi_dev_net_log(MHI_INFO, "Registering out %d, In %d channels\n",
+ client->out_chan, client->in_chan);
+
+ /* Open IN and OUT channels for Network client*/
+ mhi_dev_net_open_channels(client);
+ return 0;
+}
+
+int mhi_dev_net_interface_init(void)
+{
+ int ret_val = 0;
+ int index = 0;
+ struct mhi_dev_net_client *mhi_net_client = NULL;
+
+ mhi_net_client = kzalloc(sizeof(struct mhi_dev_net_client), GFP_KERNEL);
+ if (!mhi_net_client)
+ return -ENOMEM;
+
+ mhi_net_ipc_log = ipc_log_context_create(MHI_NET_IPC_PAGES,
+ "mhi-net", 0);
+ if (mhi_net_ipc_log == NULL)
+ mhi_dev_net_log(MHI_DBG,
+ "Failed to create IPC logging for mhi_dev_net\n");
+ mhi_net_ctxt.client_handle = mhi_net_client;
+
+ /*Process pending packet work queue*/
+ mhi_net_client->pending_pckt_wq =
+ create_singlethread_workqueue("pending_xmit_pckt_wq");
+ INIT_WORK(&mhi_net_client->xmit_work,
+ mhi_dev_net_process_queue_packets);
+
+ mhi_dev_net_log(MHI_INFO,
+ "Registering for MHI transfer events from host\n");
+ mhi_net_ctxt.net_event_notifier = mhi_dev_net_event_notifier;
+
+ ret_val = mhi_dev_net_init_ch_attributes(&mhi_net_ctxt);
+ if (ret_val < 0) {
+ mhi_dev_net_log(MHI_ERROR,
+ "Failed to init client attributes\n");
+ goto channel_init_fail;
+ }
+ mhi_dev_net_log(MHI_DBG, "Initializing client\n");
+ index = MHI_CLIENT_IP_SW_4_OUT;
+ ret_val = mhi_dev_net_rgstr_client(mhi_net_client, index);
+ if (ret_val) {
+ mhi_dev_net_log(MHI_CRITICAL,
+ "Failed to reg client %d ret 0\n", ret_val);
+ goto client_register_fail;
+ }
+ return ret_val;
+
+channel_init_fail:
+ kfree(mhi_net_client);
+ kfree(mhi_net_ipc_log);
+ return ret_val;
+client_register_fail:
+ kfree(mhi_net_client);
+ kfree(mhi_net_ipc_log);
+ return ret_val;
+}
+EXPORT_SYMBOL(mhi_dev_net_interface_init);
+
+void __exit mhi_dev_net_exit(void)
+{
+ mhi_dev_net_log(MHI_INFO,
+ "MHI Network Interface Module exited ");
+ mhi_dev_net_close();
+}
+EXPORT_SYMBOL(mhi_dev_net_exit);
diff --git a/drivers/platform/msm/mhi_dev/mhi_hwio.h b/drivers/platform/msm/mhi_dev/mhi_hwio.h
index 197713b..09a0118 100644
--- a/drivers/platform/msm/mhi_dev/mhi_hwio.h
+++ b/drivers/platform/msm/mhi_dev/mhi_hwio.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2017-2018 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
@@ -184,6 +184,10 @@
#define ERDB_HIGHER_n_ERDB_HIGHER_MASK 0xffffffff
#define ERDB_HIGHER_n_ERDB_HIGHER_SHIFT 0x0
+#define BHI_INTVEC (0x220)
+#define BHI_INTVEC_MASK 0xFFFFFFFF
+#define BHI_INTVEC_SHIFT 0
+
#define BHI_EXECENV (0x228)
#define BHI_EXECENV_MASK 0xFFFFFFFF
#define BHI_EXECENV_SHIFT 0
diff --git a/drivers/platform/msm/mhi_dev/mhi_mmio.c b/drivers/platform/msm/mhi_dev/mhi_mmio.c
index 4043e0b..559fa84 100644
--- a/drivers/platform/msm/mhi_dev/mhi_mmio.c
+++ b/drivers/platform/msm/mhi_dev/mhi_mmio.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2017-2018, 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
@@ -133,6 +133,11 @@
chid_mask = (1 << chid_shft);
chid_idx = chdb_id/32;
+ if (chid_idx >= MHI_MASK_ROWS_CH_EV_DB) {
+ pr_err("Invalid channel id:%d\n", chid_idx);
+ return -EINVAL;
+ }
+
if (enable)
val = 1;
@@ -143,6 +148,13 @@
return rc;
}
+ rc = mhi_dev_mmio_read(dev, MHI_CHDB_INT_MASK_A7_n(chid_idx),
+ &dev->chdb[chid_idx].mask);
+ if (rc) {
+ pr_err("Read channel db INT on row:%d failed\n", chid_idx);
+ return rc;
+ }
+
return rc;
}
@@ -246,7 +258,8 @@
}
EXPORT_SYMBOL(mhi_dev_mmio_disable_erdb_a7);
-int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state)
+int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state,
+ bool *mhi_reset)
{
uint32_t reg_value = 0;
int rc = 0;
@@ -265,6 +278,9 @@
if (rc)
return rc;
+ if (reg_value & MHICTRL_RESET_MASK)
+ *mhi_reset = true;
+
pr_debug("MHICTRL is 0x%x\n", reg_value);
return 0;
@@ -286,6 +302,7 @@
pr_err("Set channel db on row:%d failed\n", i);
return rc;
}
+ dev->chdb[i].mask = mask;
}
return rc;
@@ -850,6 +867,9 @@
mhi_dev_mmio_clear_interrupts(dev);
mhi_dev_mmio_enable_ctrl_interrupt(dev);
+ /*Enable chdb interrupt*/
+ mhi_dev_mmio_enable_chdb_interrupts(dev);
+
/* Mask and enable control interrupt */
mb();
diff --git a/drivers/platform/msm/mhi_dev/mhi_ring.c b/drivers/platform/msm/mhi_dev/mhi_ring.c
index 3007b5a..d6791ea 100644
--- a/drivers/platform/msm/mhi_dev/mhi_ring.c
+++ b/drivers/platform/msm/mhi_dev/mhi_ring.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -47,38 +47,36 @@
{
struct mhi_addr host_addr;
- host_addr.device_pa = ring->ring_shadow.device_pa
+ if (ring->mhi_dev->use_ipa) {
+ host_addr.host_pa = ring->ring_shadow.host_pa
+ sizeof(union mhi_dev_ring_element_type) * start;
- host_addr.device_va = ring->ring_shadow.device_va
+ host_addr.phy_addr = ring->ring_cache_dma_handle +
+ (sizeof(union mhi_dev_ring_element_type) * start);
+ } else {
+ host_addr.device_va = ring->ring_shadow.device_va
+ sizeof(union mhi_dev_ring_element_type) * start;
- host_addr.host_pa = ring->ring_shadow.host_pa
- + sizeof(union mhi_dev_ring_element_type) * start;
+ host_addr.virt_addr = &ring->ring_cache[start];
+ }
+ host_addr.size = (end-start) * sizeof(union mhi_dev_ring_element_type);
if (start < end) {
- mhi_dev_read_from_host(&host_addr,
- (ring->ring_cache_dma_handle +
- sizeof(union mhi_dev_ring_element_type) * start),
- (end-start) *
- sizeof(union mhi_dev_ring_element_type));
+ mhi_dev_read_from_host(ring->mhi_dev, &host_addr);
} else if (start > end) {
/* copy from 'start' to ring end, then ring start to 'end'*/
- mhi_dev_read_from_host(&host_addr,
- (ring->ring_cache_dma_handle +
- sizeof(union mhi_dev_ring_element_type) * start),
- (ring->ring_size-start) *
- sizeof(union mhi_dev_ring_element_type));
+ host_addr.size = (ring->ring_size-start) *
+ sizeof(union mhi_dev_ring_element_type);
+ mhi_dev_read_from_host(ring->mhi_dev, &host_addr);
if (end) {
/* wrapped around */
host_addr.device_pa = ring->ring_shadow.device_pa;
host_addr.device_va = ring->ring_shadow.device_va;
host_addr.host_pa = ring->ring_shadow.host_pa;
- mhi_dev_read_from_host(&host_addr,
- (ring->ring_cache_dma_handle +
- sizeof(union mhi_dev_ring_element_type) *
- start),
- end * sizeof(union mhi_dev_ring_element_type));
+ host_addr.virt_addr = &ring->ring_cache[0];
+ host_addr.phy_addr = ring->ring_cache_dma_handle;
+ host_addr.size = (end *
+ sizeof(union mhi_dev_ring_element_type));
+ mhi_dev_read_from_host(ring->mhi_dev, &host_addr);
}
}
-
return 0;
}
@@ -95,21 +93,16 @@
mhi_ctx = ring->mhi_dev;
if (ring->wr_offset == wr_offset) {
- mhi_log(MHI_MSG_INFO,
+ mhi_log(MHI_MSG_VERBOSE,
"nothing to cache for ring %d, local wr_ofst %d\n",
ring->id, ring->wr_offset);
- mhi_log(MHI_MSG_INFO,
+ mhi_log(MHI_MSG_VERBOSE,
"new wr_offset %d\n", wr_offset);
return 0;
}
old_offset = ring->wr_offset;
- mhi_log(MHI_MSG_ERROR,
- "caching - rng size :%d local ofst:%d new ofst: %d\n",
- (uint32_t) ring->ring_size, old_offset,
- ring->wr_offset);
-
/*
* copy the elements starting from old_offset to wr_offset
* take in to account wrap around case event rings are not
@@ -118,12 +111,12 @@
if (ring->id >= mhi_ctx->ev_ring_start &&
ring->id < (mhi_ctx->ev_ring_start +
mhi_ctx->cfg.event_rings)) {
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"not caching event ring %d\n", ring->id);
return 0;
}
- mhi_log(MHI_MSG_ERROR, "caching ring %d, start %d, end %d\n",
+ mhi_log(MHI_MSG_VERBOSE, "caching ring %d, start %d, end %d\n",
ring->id, old_offset, wr_offset);
if (mhi_dev_fetch_ring_elements(ring, old_offset, wr_offset)) {
@@ -155,7 +148,7 @@
pr_err("%s: CMD DB read failed\n", __func__);
return rc;
}
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"ring %d wr_offset from db 0x%x\n",
ring->id, (uint32_t) wr_offset);
break;
@@ -172,7 +165,7 @@
pr_err("%s: CH DB read failed\n", __func__);
return rc;
}
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"ring %d wr_offset from db 0x%x\n",
ring->id, (uint32_t) wr_offset);
break;
@@ -203,10 +196,14 @@
/* get the element and invoke the respective callback */
el = &ring->ring_cache[offset];
+ mhi_log(MHI_MSG_VERBOSE, "evnt ptr : 0x%llx\n", el->tre.data_buf_ptr);
+ mhi_log(MHI_MSG_VERBOSE, "evnt len : 0x%x, offset:%d\n",
+ el->tre.len, offset);
+
if (ring->ring_cb)
ring->ring_cb(ring->mhi_dev, el, (void *)ring);
else
- mhi_log(MHI_MSG_INFO, "No callback registered for ring %d\n",
+ mhi_log(MHI_MSG_ERROR, "No callback registered for ring %d\n",
ring->id);
return 0;
@@ -216,12 +213,17 @@
int mhi_dev_process_ring(struct mhi_dev_ring *ring)
{
int rc = 0;
+ union mhi_dev_ring_element_type *el;
if (!ring) {
pr_err("%s: Invalid ring context\n", __func__);
return -EINVAL;
}
+ mhi_log(MHI_MSG_VERBOSE,
+ "Before wr update ring_id (%d) element (%d) with wr:%d\n",
+ ring->id, ring->rd_offset, ring->wr_offset);
+
rc = mhi_dev_update_wr_offset(ring);
if (rc) {
mhi_log(MHI_MSG_ERROR,
@@ -230,6 +232,13 @@
return rc;
}
+ /* get the element and invoke the respective callback */
+ el = &ring->ring_cache[ring->wr_offset];
+
+ mhi_log(MHI_MSG_VERBOSE, "evnt ptr : 0x%llx\n", el->tre.data_buf_ptr);
+ mhi_log(MHI_MSG_VERBOSE, "evnt len : 0x%x, wr_offset:%d\n",
+ el->tre.len, ring->wr_offset);
+
if (ring->type == RING_TYPE_CH) {
/* notify the clients that there are elements in the ring */
rc = mhi_dev_process_ring_element(ring, ring->rd_offset);
@@ -237,6 +246,9 @@
pr_err("Error fetching elements\n");
return rc;
}
+ mhi_log(MHI_MSG_VERBOSE,
+ "After ring update ring_id (%d) element (%d) with wr:%d\n",
+ ring->id, ring->rd_offset, ring->wr_offset);
while (ring->rd_offset != ring->wr_offset) {
rc = mhi_dev_process_ring_element(ring, ring->rd_offset);
@@ -247,7 +259,7 @@
return rc;
}
- mhi_log(MHI_MSG_ERROR,
+ mhi_log(MHI_MSG_VERBOSE,
"Processing ring (%d) rd_offset:%d, wr_offset:%d\n",
ring->id, ring->rd_offset, ring->wr_offset);
@@ -265,10 +277,12 @@
EXPORT_SYMBOL(mhi_dev_process_ring);
int mhi_dev_add_element(struct mhi_dev_ring *ring,
- union mhi_dev_ring_element_type *element)
+ union mhi_dev_ring_element_type *element,
+ struct event_req *ereq, int evt_offset)
{
uint32_t old_offset = 0;
struct mhi_addr host_addr;
+ uint32_t num_elem = 0;
if (!ring || !element) {
pr_err("%s: Invalid context\n", __func__);
@@ -278,33 +292,53 @@
mhi_dev_update_wr_offset(ring);
if ((ring->rd_offset + 1) % ring->ring_size == ring->wr_offset) {
- mhi_log(MHI_MSG_INFO, "ring full to insert element\n");
+ mhi_log(MHI_MSG_VERBOSE, "ring full to insert element\n");
return -EINVAL;
}
old_offset = ring->rd_offset;
- mhi_dev_ring_inc_index(ring, ring->rd_offset);
+ if (evt_offset) {
+ num_elem = evt_offset /
+ (sizeof(union mhi_dev_ring_element_type));
+ ring->rd_offset += num_elem;
+ if (ring->rd_offset >= ring->ring_size)
+ ring->rd_offset -= ring->ring_size;
+ } else
+ mhi_dev_ring_inc_index(ring, ring->rd_offset);
ring->ring_ctx->generic.rp = (ring->rd_offset *
- sizeof(union mhi_dev_ring_element_type)) +
- ring->ring_ctx->generic.rbase;
+ sizeof(union mhi_dev_ring_element_type)) +
+ ring->ring_ctx->generic.rbase;
/*
* Write the element, ring_base has to be the
* iomap of the ring_base for memcpy
*/
- host_addr.host_pa = ring->ring_shadow.host_pa +
+
+ if (ring->mhi_dev->use_ipa)
+ host_addr.host_pa = ring->ring_shadow.host_pa +
sizeof(union mhi_dev_ring_element_type) * old_offset;
- host_addr.device_va = ring->ring_shadow.device_va +
+ else
+ host_addr.device_va = ring->ring_shadow.device_va +
sizeof(union mhi_dev_ring_element_type) * old_offset;
- mhi_log(MHI_MSG_ERROR, "adding element to ring (%d)\n", ring->id);
- mhi_log(MHI_MSG_ERROR, "rd_ofset %d\n", ring->rd_offset);
- mhi_log(MHI_MSG_ERROR, "type %d\n", element->generic.type);
+ host_addr.virt_addr = element;
- mhi_dev_write_to_host(&host_addr, element,
- sizeof(union mhi_dev_ring_element_type), ring->mhi_dev);
+ if (evt_offset)
+ host_addr.size = evt_offset;
+ else
+ host_addr.size = sizeof(union mhi_dev_ring_element_type);
+ mhi_log(MHI_MSG_VERBOSE, "adding element to ring (%d)\n", ring->id);
+ mhi_log(MHI_MSG_VERBOSE, "rd_ofset %d\n", ring->rd_offset);
+ mhi_log(MHI_MSG_VERBOSE, "type %d\n", element->generic.type);
+
+ if (ereq)
+ mhi_dev_write_to_host(ring->mhi_dev, &host_addr,
+ ereq, MHI_DEV_DMA_ASYNC);
+ else
+ mhi_dev_write_to_host(ring->mhi_dev, &host_addr,
+ NULL, MHI_DEV_DMA_SYNC);
return 0;
}
EXPORT_SYMBOL(mhi_dev_add_element);
@@ -362,16 +396,15 @@
(union mhi_dev_ring_ctx *) (mhi->ch_ctx_shadow.device_va +
(ring->id - mhi->ch_ring_start)*sizeof(union mhi_dev_ring_ctx));
-
ring->ring_ctx_shadow = ring->ring_ctx;
- if (ring->type != RING_TYPE_ER) {
+ if (ring->type != RING_TYPE_ER || ring->type != RING_TYPE_CH) {
rc = mhi_dev_cache_ring(ring, wr_offset);
if (rc)
return rc;
}
- mhi_log(MHI_MSG_ERROR, "ctx ring_base:0x%x, rp:0x%x, wp:0x%x\n",
+ mhi_log(MHI_MSG_VERBOSE, "ctx ring_base:0x%x, rp:0x%x, wp:0x%x\n",
(uint32_t)ring->ring_ctx->generic.rbase,
(uint32_t)ring->ring_ctx->generic.rp,
(uint32_t)ring->ring_ctx->generic.wp);
diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.c b/drivers/platform/msm/mhi_dev/mhi_sm.c
index 8179fad..1200a36 100644
--- a/drivers/platform/msm/mhi_dev/mhi_sm.c
+++ b/drivers/platform/msm/mhi_dev/mhi_sm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -396,7 +396,8 @@
res = true;
break;
case EP_PCIE_EVENT_PM_D3_HOT:
- res = (curr_mstate == MHI_DEV_M3_STATE &&
+ res = ((curr_mstate == MHI_DEV_M3_STATE ||
+ curr_mstate == MHI_DEV_READY_STATE) &&
curr_dstate != MHI_SM_EP_PCIE_LINK_DISABLE);
break;
case EP_PCIE_EVENT_PM_D3_COLD:
@@ -437,7 +438,7 @@
{
enum mhi_dev_state old_state;
struct ep_pcie_msi_config cfg;
- int res;
+ int res = -EINVAL;
MHI_SM_FUNC_ENTRY();
@@ -476,6 +477,30 @@
mhi_sm_mmio_set_mhistatus(MHI_DEV_M0_STATE);
/* Tell the host, device move to M0 */
+ if (old_state == MHI_DEV_M3_STATE) {
+ if (mhi_sm_ctx->mhi_dev->use_ipa) {
+ res = ipa_dma_enable();
+ if (res) {
+ MHI_SM_ERR("IPA enable failed\n");
+ return res;
+ }
+ }
+
+ res = mhi_dev_resume(mhi_sm_ctx->mhi_dev);
+ if (res) {
+ MHI_SM_ERR("Failed resuming mhi core, returned %d",
+ res);
+ goto exit;
+ }
+
+ res = ipa_mhi_resume();
+ if (res) {
+ MHI_SM_ERR("Failed resuming ipa_mhi, returned %d",
+ res);
+ goto exit;
+ }
+ }
+
res = mhi_dev_send_state_change_event(mhi_sm_ctx->mhi_dev,
MHI_DEV_M0_STATE);
if (res) {
@@ -491,20 +516,6 @@
MHI_SM_ERR("failed sending EE event to host\n");
goto exit;
}
- } else if (old_state == MHI_DEV_M3_STATE) {
- /*Resuming MHI operation*/
- res = mhi_dev_resume(mhi_sm_ctx->mhi_dev);
- if (res) {
- MHI_SM_ERR("Failed resuming mhi core, returned %d",
- res);
- goto exit;
- }
- res = ipa_mhi_resume();
- if (res) {
- MHI_SM_ERR("Failed resuming ipa_mhi, returned %d",
- res);
- goto exit;
- }
}
res = 0;
@@ -557,6 +568,14 @@
goto exit;
}
+ if (mhi_sm_ctx->mhi_dev->use_ipa) {
+ res = ipa_dma_disable();
+ if (res) {
+ MHI_SM_ERR("IPA disable failed\n");
+ return res;
+ }
+ }
+
exit:
MHI_SM_FUNC_EXIT();
return res;
@@ -579,9 +598,9 @@
if (mhi_sm_ctx->mhi_state == MHI_DEV_M3_STATE) {
/*
- * ep_pcie driver is responsible to send the right wakeup
- * event, assert WAKE#, according to Link state
- */
+ * ep_pcie driver is responsible to send the right wakeup
+ * event, assert WAKE#, according to Link state
+ */
res = ep_pcie_wakeup_host(mhi_sm_ctx->mhi_dev->phandle);
if (res) {
MHI_SM_ERR("Failed to wakeup MHI host, returned %d\n",
@@ -661,8 +680,8 @@
MHI_SM_ERR("EP-PCIE Link is disable cannot set MMIO to %s\n",
mhi_sm_mstate_str(MHI_DEV_SYSERR_STATE));
- MHI_SM_ERR("/n/n/nASSERT ON DEVICE !!!!/n/n/n");
- WARN_ON();
+ MHI_SM_ERR("/n/n/nError ON DEVICE !!!!/n/n/n");
+ WARN_ON(1);
MHI_SM_FUNC_EXIT();
return res;
@@ -918,6 +937,24 @@
}
EXPORT_SYMBOL(mhi_dev_sm_init);
+int mhi_dev_sm_exit(struct mhi_dev *mhi_dev)
+{
+ MHI_SM_FUNC_ENTRY();
+
+ atomic_set(&mhi_sm_ctx->pending_device_events, 0);
+ atomic_set(&mhi_sm_ctx->pending_pcie_events, 0);
+ mhi_sm_debugfs_destroy();
+ flush_workqueue(mhi_sm_ctx->mhi_sm_wq);
+ destroy_workqueue(mhi_sm_ctx->mhi_sm_wq);
+ ipa_dma_destroy();
+ mutex_destroy(&mhi_sm_ctx->mhi_state_lock);
+ devm_kfree(mhi_dev->dev, mhi_sm_ctx);
+ mhi_sm_ctx = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(mhi_dev_sm_exit);
+
/**
* mhi_dev_sm_get_mhi_state() -Get current MHI state.
* @state: return param
@@ -964,7 +1001,7 @@
*/
int mhi_dev_sm_set_ready(void)
{
- int res;
+ int res = 0;
int is_ready;
enum mhi_dev_state state;
@@ -1011,6 +1048,7 @@
goto unlock_and_exit;
}
mhi_sm_mmio_set_mhistatus(MHI_DEV_READY_STATE);
+ res = 0;
unlock_and_exit:
mutex_unlock(&mhi_sm_ctx->mhi_state_lock);
@@ -1153,6 +1191,7 @@
ep_pcie_mask_irq_event(mhi_sm_ctx->mhi_dev->phandle,
EP_PCIE_INT_EVT_MHI_A7, false);
mhi_dev_notify_a7_event(mhi_sm_ctx->mhi_dev);
+ kfree(dstate_change_evt);
goto exit;
default:
MHI_SM_ERR("Invalid ep_pcie event, received 0x%x event\n",
diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.h b/drivers/platform/msm/mhi_dev/mhi_sm.h
index d477880..01e127b 100644
--- a/drivers/platform/msm/mhi_dev/mhi_sm.h
+++ b/drivers/platform/msm/mhi_dev/mhi_sm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015,2017-2018 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -41,6 +41,7 @@
};
int mhi_dev_sm_init(struct mhi_dev *dev);
+int mhi_dev_sm_exit(struct mhi_dev *dev);
int mhi_dev_sm_set_ready(void);
int mhi_dev_notify_sm_event(enum mhi_dev_event event);
int mhi_dev_sm_get_mhi_state(enum mhi_dev_state *state);
diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c
index 3279fa8..244cf04 100644
--- a/drivers/platform/msm/mhi_dev/mhi_uci.c
+++ b/drivers/platform/msm/mhi_dev/mhi_uci.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015,2017-2018, 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
@@ -73,6 +73,12 @@
u32 uci_ownership;
};
+struct uci_ctrl {
+ wait_queue_head_t ctrl_wq;
+ struct mhi_uci_ctxt_t *uci_ctxt;
+ atomic_t ctrl_data_update;
+};
+
struct uci_client {
u32 client_index;
/* write channel - always odd*/
@@ -100,9 +106,13 @@
struct mhi_uci_ctxt_t {
struct chan_attr chan_attrib[MHI_MAX_SOFTWARE_CHANNELS];
struct uci_client client_handles[MHI_SOFTWARE_CLIENT_LIMIT];
+ struct uci_ctrl ctrl_handle;
void (*event_notifier)(struct mhi_dev_client_cb_reason *cb);
dev_t start_ctrl_nr;
struct cdev cdev[MHI_MAX_SOFTWARE_CHANNELS];
+ dev_t ctrl_nr;
+ struct cdev *cdev_ctrl;
+ struct device *dev;
struct class *mhi_uci_class;
atomic_t mhi_disabled;
atomic_t mhi_enable_notif_wq_active;
@@ -129,12 +139,16 @@
static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
size_t count, loff_t *offp);
+static ssize_t mhi_uci_ctrl_client_read(struct file *file, char __user *buf,
+ size_t count, loff_t *offp);
static ssize_t mhi_uci_client_write(struct file *file,
const char __user *buf, size_t count, loff_t *offp);
static int mhi_uci_client_open(struct inode *mhi_inode, struct file*);
+static int mhi_uci_ctrl_open(struct inode *mhi_inode, struct file*);
static int mhi_uci_client_release(struct inode *mhi_inode,
struct file *file_handle);
static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait);
+static unsigned int mhi_uci_ctrl_poll(struct file *file, poll_table *wait);
static struct mhi_uci_ctxt_t uci_ctxt;
static int mhi_init_read_chan(struct uci_client *client_handle,
@@ -184,6 +198,8 @@
uintptr_t memcpy_result = 0;
u32 data_inserted_so_far = 0;
struct uci_client *uci_handle;
+ struct mhi_req ureq;
+
uci_handle = container_of(client_handle, struct uci_client,
out_handle);
@@ -206,15 +222,43 @@
} else {
data_loc = buf;
}
+ ureq.client = *client_handle;
+ ureq.buf = data_loc;
+ ureq.len = size;
+ ureq.chan = uci_handle->out_chan;
+ ureq.mode = IPA_DMA_SYNC;
- data_inserted_so_far = mhi_dev_write_channel(*client_handle, data_loc,
- size);
+ data_inserted_so_far = mhi_dev_write_channel(&ureq);
error_memcpy:
kfree(data_loc);
return data_inserted_so_far;
}
+static unsigned int mhi_uci_ctrl_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask = 0;
+ struct uci_ctrl *uci_ctrl_handle;
+
+ uci_ctrl_handle = file->private_data;
+
+ if (!uci_ctrl_handle)
+ return -ENODEV;
+
+ poll_wait(file, &uci_ctrl_handle->ctrl_wq, wait);
+ if (!atomic_read(&uci_ctxt.mhi_disabled) &&
+ atomic_read(&uci_ctrl_handle->ctrl_data_update)) {
+ uci_log(UCI_DBG_VERBOSE, "Client can read ctrl_state");
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ uci_log(UCI_DBG_VERBOSE,
+ "Client attempted to poll ctrl returning mask 0x%x\n",
+ mask);
+
+ return mask;
+}
+
static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
@@ -297,6 +341,22 @@
return rc;
}
+static int mhi_uci_ctrl_open(struct inode *inode,
+ struct file *file_handle)
+{
+ struct uci_ctrl *uci_ctrl_handle;
+
+ uci_log(UCI_DBG_DBG, "Client opened ctrl file device node\n");
+
+ uci_ctrl_handle = &uci_ctxt.ctrl_handle;
+ if (!uci_ctrl_handle)
+ return -EINVAL;
+
+ file_handle->private_data = uci_ctrl_handle;
+
+ return 0;
+}
+
static int mhi_uci_client_open(struct inode *mhi_inode,
struct file *file_handle)
{
@@ -337,18 +397,20 @@
struct file *file_handle)
{
struct uci_client *uci_handle = file_handle->private_data;
- struct mhi_uci_ctxt_t *uci_ctxt = uci_handle->uci_ctxt;
+ struct mhi_uci_ctxt_t *uci_ctxt;
u32 nr_in_bufs = 0;
int rc = 0;
int in_chan = 0;
u32 buf_size = 0;
+ if (!uci_handle)
+ return -EINVAL;
+
+ uci_ctxt = uci_handle->uci_ctxt;
in_chan = iminor(mhi_inode) + 1;
nr_in_bufs = uci_ctxt->chan_attrib[in_chan].nr_trbs;
buf_size = uci_ctxt->chan_attrib[in_chan].max_packet_size;
- if (!uci_handle)
- return -EINVAL;
if (atomic_sub_return(1, &uci_handle->ref_count) == 0) {
uci_log(UCI_DBG_DBG,
"Last client left, closing channel 0x%x\n",
@@ -379,7 +441,54 @@
return rc;
}
-static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
+static ssize_t mhi_uci_ctrl_client_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *offp)
+{
+ uint32_t rc = 0, info;
+ int nbytes, size;
+ char buf[MHI_CTRL_STATE];
+ struct uci_ctrl *uci_ctrl_handle = NULL;
+
+ if (!file || !user_buf || !count ||
+ (count < MHI_CTRL_STATE) || !file->private_data)
+ return -EINVAL;
+
+ uci_ctrl_handle = file->private_data;
+ rc = mhi_ctrl_state_info(&info);
+ if (rc)
+ return -EINVAL;
+
+ switch (info) {
+ case MHI_STATE_CONFIGURED:
+ nbytes = scnprintf(buf, sizeof(buf),
+ "MHI_STATE=CONFIGURED");
+ break;
+ case MHI_STATE_CONNECTED:
+ nbytes = scnprintf(buf, sizeof(buf),
+ "MHI_STATE=CONNECTED");
+ break;
+ case MHI_STATE_DISCONNECTED:
+ nbytes = scnprintf(buf, sizeof(buf),
+ "MHI_STATE=DISCONNECTED");
+ break;
+ default:
+ pr_err("invalid info:%d\n", info);
+ return -EINVAL;
+ }
+
+
+ size = simple_read_from_buffer(user_buf, count, offp, buf, nbytes);
+
+ atomic_set(&uci_ctrl_handle->ctrl_data_update, 0);
+
+ if (size == 0)
+ *offp = 0;
+
+ return size;
+}
+
+static ssize_t mhi_uci_client_read(struct file *file, char __user *ubuf,
size_t uspace_buf_size, loff_t *bytes_pending)
{
struct uci_client *uci_handle = NULL;
@@ -387,39 +496,40 @@
int bytes_avail = 0;
int ret_val = 0;
struct mutex *mutex;
- u32 chan = 0;
ssize_t bytes_copied = 0;
u32 addr_offset = 0;
- uint32_t buf_size;
- uint32_t chained = 0;
void *local_buf = NULL;
+ struct mhi_req ureq;
- if (!file || !buf || !uspace_buf_size ||
+ if (!file || !ubuf || !uspace_buf_size ||
!file->private_data)
return -EINVAL;
uci_handle = file->private_data;
client_handle = uci_handle->in_handle;
mutex = &uci_handle->in_chan_lock;
- chan = uci_handle->in_chan;
+ ureq.chan = uci_handle->in_chan;
mutex_lock(mutex);
+ ureq.client = client_handle;
+ ureq.buf = uci_handle->in_buf_list[0].addr;
+ ureq.len = uci_handle->in_buf_list[0].buf_size;
+ ureq.mode = IPA_DMA_SYNC;
- local_buf = uci_handle->in_buf_list[0].addr;
- buf_size = uci_handle->in_buf_list[0].buf_size;
-
-
- uci_log(UCI_DBG_VERBOSE, "Client attempted read on chan %d\n", chan);
+ uci_log(UCI_DBG_VERBOSE, "Client attempted read on chan %d\n",
+ ureq.chan);
do {
if (!uci_handle->pkt_loc &&
!atomic_read(&uci_ctxt.mhi_disabled)) {
- bytes_avail = mhi_dev_read_channel(client_handle,
- local_buf, buf_size, &chained);
+ bytes_avail = mhi_dev_read_channel(&ureq);
uci_log(UCI_DBG_VERBOSE,
- "reading from mhi_core local_buf = %p,buf_size = 0x%x bytes_read = 0x%x\n",
- local_buf, buf_size, bytes_avail);
+ "reading from mhi_core local_buf = %p",
+ local_buf);
+ uci_log(UCI_DBG_VERBOSE,
+ "buf_size = 0x%x bytes_read = 0x%x\n",
+ ureq.len, bytes_avail);
if (bytes_avail < 0) {
uci_log(UCI_DBG_ERROR,
@@ -430,13 +540,14 @@
}
if (bytes_avail > 0) {
- uci_handle->pkt_loc = (void *)local_buf;
- uci_handle->pkt_size = bytes_avail;
+ uci_handle->pkt_loc = (void *) ureq.buf;
+ uci_handle->pkt_size = ureq.actual_len;
*bytes_pending = (loff_t)uci_handle->pkt_size;
uci_log(UCI_DBG_VERBOSE,
- "Got pkt of size 0x%x at addr %p, chan %d\n",
- uci_handle->pkt_size, local_buf, chan);
+ "Got pkt of sz 0x%x at adr %p, ch %d\n",
+ uci_handle->pkt_size,
+ ureq.buf, ureq.chan);
} else {
uci_handle->pkt_loc = 0;
uci_handle->pkt_size = 0;
@@ -448,7 +559,7 @@
uci_log(UCI_DBG_VERBOSE,
"No data read_data_ready %d, chan %d\n",
atomic_read(&uci_handle->read_data_ready),
- chan);
+ ureq.chan);
ret_val = wait_event_interruptible(uci_handle->read_wq,
(!mhi_dev_channel_isempty(client_handle)));
@@ -458,17 +569,17 @@
goto error;
}
uci_log(UCI_DBG_VERBOSE,
- "Thread woke up. Got data on chan %d read_data_ready %d\n",
- chan,
+ "wk up Got data on ch %d read_data_ready %d\n",
+ ureq.chan,
atomic_read(&uci_handle->read_data_ready));
/* A valid packet was returned from MHI */
} else if (bytes_avail > 0) {
uci_log(UCI_DBG_VERBOSE,
- "Got packet: avail pkts %d phy_adr %p, chan %d\n",
+ "Got packet: avail pkts %d phy_adr %p, ch %d\n",
atomic_read(&uci_handle->read_data_ready),
- local_buf,
- chan);
+ ureq.buf,
+ ureq.chan);
break;
/*
* MHI did not return a valid packet, but we have one
@@ -477,16 +588,16 @@
} else {
uci_log(UCI_DBG_CRITICAL,
"chan %d err: avail pkts %d phy_adr %p",
- chan,
+ ureq.chan,
atomic_read(&uci_handle->read_data_ready),
- local_buf);
+ ureq.buf);
return -EIO;
}
} while (!uci_handle->pkt_loc);
if (uspace_buf_size >= *bytes_pending) {
addr_offset = uci_handle->pkt_size - *bytes_pending;
- if (copy_to_user(buf, uci_handle->pkt_loc + addr_offset,
+ if (copy_to_user(ubuf, uci_handle->pkt_loc + addr_offset,
*bytes_pending)) {
ret_val = -EIO;
goto error;
@@ -495,10 +606,10 @@
bytes_copied = *bytes_pending;
*bytes_pending = 0;
uci_log(UCI_DBG_VERBOSE, "Copied 0x%x of 0x%x, chan %d\n",
- bytes_copied, (u32)*bytes_pending, chan);
+ bytes_copied, (u32)*bytes_pending, ureq.chan);
} else {
addr_offset = uci_handle->pkt_size - *bytes_pending;
- if (copy_to_user(buf, (void *) (uintptr_t)uci_handle->pkt_loc +
+ if (copy_to_user(ubuf, (void *) (uintptr_t)uci_handle->pkt_loc +
addr_offset, uspace_buf_size)) {
ret_val = -EIO;
goto error;
@@ -508,13 +619,13 @@
uci_log(UCI_DBG_VERBOSE, "Copied 0x%x of 0x%x,chan %d\n",
bytes_copied,
(u32)*bytes_pending,
- chan);
+ ureq.chan);
}
/* We finished with this buffer, map it back */
if (*bytes_pending == 0) {
uci_log(UCI_DBG_VERBOSE,
"All data consumed. Pkt loc %p ,chan %d\n",
- uci_handle->pkt_loc, chan);
+ uci_handle->pkt_loc, ureq.chan);
uci_handle->pkt_loc = 0;
uci_handle->pkt_size = 0;
}
@@ -599,6 +710,8 @@
case MHI_CLIENT_SAHARA_IN:
case MHI_CLIENT_EFS_OUT:
case MHI_CLIENT_EFS_IN:
+ case MHI_CLIENT_MBIM_OUT:
+ case MHI_CLIENT_MBIM_IN:
case MHI_CLIENT_QMI_OUT:
case MHI_CLIENT_QMI_IN:
case MHI_CLIENT_IP_CTRL_0_OUT:
@@ -634,6 +747,23 @@
return 0;
}
+void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason)
+{
+ struct uci_ctrl *uci_ctrl_handle = NULL;
+
+ if (reason->reason == MHI_DEV_CTRL_UPDATE) {
+ uci_ctrl_handle = &uci_ctxt.ctrl_handle;
+ if (!uci_ctrl_handle) {
+ pr_err("Invalid uci ctrl handle\n");
+ return;
+ }
+
+ uci_log(UCI_DBG_DBG, "received state change update\n");
+ wake_up(&uci_ctrl_handle->ctrl_wq);
+ atomic_set(&uci_ctrl_handle->ctrl_data_update, 1);
+ }
+}
+EXPORT_SYMBOL(uci_ctrl_update);
static void uci_event_notifier(struct mhi_dev_client_cb_reason *reason)
{
@@ -718,6 +848,12 @@
return rc;
}
+static const struct file_operations mhi_uci_ctrl_client_fops = {
+ .open = mhi_uci_ctrl_open,
+ .read = mhi_uci_ctrl_client_read,
+ .poll = mhi_uci_ctrl_poll,
+};
+
static const struct file_operations mhi_uci_client_fops = {
.read = mhi_uci_client_read,
.write = mhi_uci_client_write,
@@ -770,16 +906,25 @@
}
}
}
+
+ init_waitqueue_head(&uci_ctxt.ctrl_handle.ctrl_wq);
uci_log(UCI_DBG_INFO, "Allocating char devices.\n");
r = alloc_chrdev_region(&uci_ctxt.start_ctrl_nr,
0, MHI_MAX_SOFTWARE_CHANNELS,
DEVICE_NAME);
-
if (IS_ERR_VALUE(r)) {
uci_log(UCI_DBG_ERROR,
"Failed to alloc char devs, ret 0x%x\n", r);
goto failed_char_alloc;
}
+
+ r = alloc_chrdev_region(&uci_ctxt.ctrl_nr, 0, 1, DEVICE_NAME);
+ if (IS_ERR_VALUE(r)) {
+ uci_log(UCI_DBG_ERROR,
+ "Failed to alloc char ctrl devs, 0x%x\n", r);
+ goto failed_char_alloc;
+ }
+
uci_log(UCI_DBG_INFO, "Creating class\n");
uci_ctxt.mhi_uci_class = class_create(THIS_MODULE,
DEVICE_NAME);
@@ -803,12 +948,12 @@
i, r);
goto failed_char_add;
}
+
uci_ctxt.client_handles[i].dev =
device_create(uci_ctxt.mhi_uci_class, NULL,
uci_ctxt.start_ctrl_nr + i,
NULL, DEVICE_NAME "_pipe_%d",
i * 2);
-
if (IS_ERR(uci_ctxt.client_handles[i].dev)) {
uci_log(UCI_DBG_ERROR,
"Failed to add cdev %d\n", i);
@@ -817,6 +962,37 @@
}
}
}
+
+ /* Control node */
+ uci_ctxt.cdev_ctrl = cdev_alloc();
+ if (uci_ctxt.cdev_ctrl == NULL) {
+ pr_err("%s: ctrl cdev alloc failed\n", __func__);
+ return 0;
+ }
+
+ cdev_init(uci_ctxt.cdev_ctrl, &mhi_uci_ctrl_client_fops);
+ uci_ctxt.cdev_ctrl->owner = THIS_MODULE;
+ r = cdev_add(uci_ctxt.cdev_ctrl, uci_ctxt.ctrl_nr, 1);
+ if (IS_ERR_VALUE(r)) {
+ uci_log(UCI_DBG_ERROR,
+ "Failed to add ctrl cdev %d, ret 0x%x\n", i, r);
+ kfree(uci_ctxt.cdev_ctrl);
+ uci_ctxt.cdev_ctrl = NULL;
+ return 0;
+ }
+
+ uci_ctxt.dev =
+ device_create(uci_ctxt.mhi_uci_class, NULL,
+ uci_ctxt.ctrl_nr,
+ NULL, DEVICE_NAME "_ctrl");
+ if (IS_ERR(uci_ctxt.dev)) {
+ uci_log(UCI_DBG_ERROR,
+ "Failed to add ctrl cdev %d\n", i);
+ cdev_del(uci_ctxt.cdev_ctrl);
+ kfree(uci_ctxt.cdev_ctrl);
+ uci_ctxt.cdev_ctrl = NULL;
+ }
+
return 0;
failed_char_add:
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
index 05e8172..99c5f27 100644
--- a/drivers/platform/msm/qpnp-revid.c
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -50,6 +50,7 @@
[PM2433_SUBTYPE] = "PM2433",
[PMD9655_SUBTYPE] = "PMD9655",
[PM8950_SUBTYPE] = "PM8950",
+ [PM8953_SUBTYPE] = "PM8953",
[PMI8950_SUBTYPE] = "PMI8950",
[PMK8001_SUBTYPE] = "PMK8001",
[PMI8996_SUBTYPE] = "PMI8996",
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index dec698f..6314270 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -3313,7 +3313,7 @@
return ret;
}
-bool usb_bam_get_prod_granted(enum usb_ctrl bam_type, u8 idx)
+bool usb_bam_get_prod_granted(enum usb_ctrl bam_type)
{
return (info[bam_type].cur_prod_state == IPA_RM_RESOURCE_GRANTED);
}
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 2c2f02b..167d504 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -45,6 +45,7 @@
struct quirk_entry {
u8 touchpad_led;
+ u8 kbd_led_levels_off_1;
int needs_kbd_timeouts;
/*
@@ -75,6 +76,10 @@
.kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 },
};
+static struct quirk_entry quirk_dell_latitude_e6410 = {
+ .kbd_led_levels_off_1 = 1,
+};
+
static struct platform_driver platform_driver = {
.driver = {
.name = "dell-laptop",
@@ -270,6 +275,15 @@
},
.driver_data = &quirk_dell_xps13_9333,
},
+ {
+ .callback = dmi_matched,
+ .ident = "Dell Latitude E6410",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6410"),
+ },
+ .driver_data = &quirk_dell_latitude_e6410,
+ },
{ }
};
@@ -1170,6 +1184,9 @@
units = (buffer->output[2] >> 8) & 0xFF;
info->levels = (buffer->output[2] >> 16) & 0xFF;
+ if (quirks && quirks->kbd_led_levels_off_1 && info->levels)
+ info->levels--;
+
if (units & BIT(0))
info->seconds = (buffer->output[3] >> 0) & 0xFF;
if (units & BIT(1))
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
index 5c768c4..78e1bfe 100644
--- a/drivers/platform/x86/intel_mid_thermal.c
+++ b/drivers/platform/x86/intel_mid_thermal.c
@@ -415,6 +415,7 @@
return td_info;
}
+#ifdef CONFIG_PM_SLEEP
/**
* mid_thermal_resume - resume routine
* @dev: device structure
@@ -442,6 +443,7 @@
*/
return configure_adc(0);
}
+#endif
static SIMPLE_DEV_PM_OPS(mid_thermal_pm,
mid_thermal_suspend, mid_thermal_resume);
diff --git a/drivers/power/qcom/apm.c b/drivers/power/qcom/apm.c
index 3dfb439..ed3df00 100644
--- a/drivers/power/qcom/apm.c
+++ b/drivers/power/qcom/apm.c
@@ -638,9 +638,15 @@
#define MSM8953_APCC_APM_MODE 0x000002a8
#define MSM8953_APCC_APM_CTL_STS 0x000002b0
+/* 8953 constants */
+#define MSM8953_APM_SWITCH_TIMEOUT_US 500
+
+/* Register bit mask definitions */
+#define MSM8953_APM_CTL_STS_MASK 0x1f
+
static int msm8953_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev)
{
- int timeout = MSM_APM_SWITCH_TIMEOUT_US;
+ int timeout = MSM8953_APM_SWITCH_TIMEOUT_US;
u32 regval;
int ret = 0;
unsigned long flags;
@@ -657,7 +663,7 @@
while (timeout > 0) {
regval = readl_relaxed(ctrl_dev->reg_base +
MSM8953_APCC_APM_CTL_STS);
- if ((regval & MSM_APM_CTL_STS_MASK) ==
+ if ((regval & MSM8953_APM_CTL_STS_MASK) ==
MSM8953_APM_MX_DONE_VAL)
break;
@@ -681,7 +687,7 @@
static int msm8953_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev)
{
- int timeout = MSM_APM_SWITCH_TIMEOUT_US;
+ int timeout = MSM8953_APM_SWITCH_TIMEOUT_US;
u32 regval;
int ret = 0;
unsigned long flags;
@@ -698,7 +704,7 @@
while (timeout > 0) {
regval = readl_relaxed(ctrl_dev->reg_base +
MSM8953_APCC_APM_CTL_STS);
- if ((regval & MSM_APM_CTL_STS_MASK) ==
+ if ((regval & MSM8953_APM_CTL_STS_MASK) ==
MSM8953_APM_APCC_DONE_VAL)
break;
diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile
index 6c7fc78..662f18d 100644
--- a/drivers/power/supply/qcom/Makefile
+++ b/drivers/power/supply/qcom/Makefile
@@ -9,4 +9,4 @@
obj-$(CONFIG_QPNP_QG) += qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o
obj-$(CONFIG_QPNP_QNOVO) += qpnp-qnovo.o battery.o
obj-$(CONFIG_QPNP_TYPEC) += qpnp-typec.o
-obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o
+obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index a2a35c6..76bb974 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -86,6 +86,13 @@
#define MAX_CC_STEPS 20
+enum prof_load_status {
+ PROFILE_MISSING,
+ PROFILE_LOADED,
+ PROFILE_SKIPPED,
+ PROFILE_NOT_LOADED,
+};
+
/* Debug flag definitions */
enum fg_debug_flag {
FG_IRQ = BIT(0), /* Show interrupts */
@@ -175,8 +182,10 @@
FG_SRAM_DELTA_BSOC_THR,
FG_SRAM_RECHARGE_SOC_THR,
FG_SRAM_RECHARGE_VBATT_THR,
+ FG_SRAM_KI_COEFF_LOW_DISCHG,
FG_SRAM_KI_COEFF_MED_DISCHG,
FG_SRAM_KI_COEFF_HI_DISCHG,
+ FG_SRAM_KI_COEFF_HI_CHG,
FG_SRAM_KI_COEFF_FULL_SOC,
FG_SRAM_ESR_TIGHT_FILTER,
FG_SRAM_ESR_BROAD_FILTER,
@@ -292,6 +301,8 @@
int esr_meas_curr_ma;
int bmd_en_delay_ms;
int ki_coeff_full_soc_dischg;
+ int ki_coeff_low_dischg;
+ int ki_coeff_hi_chg;
int jeita_thresholds[NUM_JEITA_LEVELS];
int ki_coeff_soc[KI_COEFF_SOC_LEVELS];
int ki_coeff_med_dischg[KI_COEFF_SOC_LEVELS];
@@ -446,6 +457,7 @@
enum slope_limit_status slope_limit_sts;
bool profile_available;
bool profile_loaded;
+ enum prof_load_status profile_load_status;
bool battery_missing;
bool fg_restarting;
bool charge_full;
diff --git a/drivers/power/supply/qcom/qg-battery-profile.c b/drivers/power/supply/qcom/qg-battery-profile.c
index b86c7f5..441c759 100644
--- a/drivers/power/supply/qcom/qg-battery-profile.c
+++ b/drivers/power/supply/qcom/qg-battery-profile.c
@@ -163,7 +163,7 @@
}
break;
case BPIOCXVAR:
- if (bp.table_index < TABLE_Z1 || bp.table_index > TABLE_MAX) {
+ if (bp.table_index < TABLE_Z1 || bp.table_index >= TABLE_MAX) {
pr_err("Invalid table index %d for VAR lookup\n",
bp.table_index);
rc = -EINVAL;
diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h
index aadef7f..5ea9b78 100644
--- a/drivers/power/supply/qcom/qg-core.h
+++ b/drivers/power/supply/qcom/qg-core.h
@@ -43,6 +43,9 @@
int s3_exit_ibat_ua;
int delta_soc;
int rbat_conn_mohm;
+ int ignore_shutdown_soc_secs;
+ bool hold_soc_while_full;
+ bool linearize_soc;
};
struct qpnp_qg {
@@ -79,6 +82,7 @@
/* status variable */
u32 *debug_mask;
+ bool qg_device_open;
bool profile_loaded;
bool battery_missing;
bool data_ready;
@@ -87,15 +91,19 @@
bool charge_done;
bool parallel_enabled;
bool usb_present;
+ bool charge_full;
int charge_status;
int charge_type;
int next_wakeup_ms;
u32 wa_flags;
+ u32 seq_no;
+ u32 charge_counter_uah;
ktime_t last_user_update_time;
ktime_t last_fifo_update_time;
/* soc params */
int catch_up_soc;
+ int maint_soc;
int msoc;
int pon_soc;
struct alarm alarm_timer;
diff --git a/drivers/power/supply/qcom/qg-soc.c b/drivers/power/supply/qcom/qg-soc.c
index 4fdd258..660f6f1 100644
--- a/drivers/power/supply/qcom/qg-soc.c
+++ b/drivers/power/supply/qcom/qg-soc.c
@@ -13,6 +13,7 @@
#define pr_fmt(fmt) "QG-K: %s: " fmt, __func__
#include <linux/alarmtimer.h>
+#include <linux/module.h>
#include <linux/power_supply.h>
#include <uapi/linux/qg.h>
#include "qg-sdam.h"
@@ -23,31 +24,56 @@
#define DEFAULT_UPDATE_TIME_MS 64000
#define SOC_SCALE_HYST_MS 2000
-static void get_next_update_time(struct qpnp_qg *chip, int *time_ms)
+#define SOC_SCALE_LOW_TEMP_THRESHOLD 100
+
+static int qg_delta_soc_interval_ms = 20000;
+module_param_named(
+ delta_soc_interval_ms, qg_delta_soc_interval_ms, int, 0600
+);
+
+static void get_next_update_time(struct qpnp_qg *chip)
{
- int rc = 0, full_time_ms = 0, rt_time_ms = 0;
+ int soc_points = 0, batt_temp = 0;
+ int min_delta_soc_interval_ms = qg_delta_soc_interval_ms;
+ int rc = 0, rt_time_ms = 0, full_time_ms = DEFAULT_UPDATE_TIME_MS;
- *time_ms = DEFAULT_UPDATE_TIME_MS;
+ get_fifo_done_time(chip, false, &full_time_ms);
+ get_fifo_done_time(chip, true, &rt_time_ms);
- rc = get_fifo_done_time(chip, false, &full_time_ms);
+ full_time_ms = CAP(0, DEFAULT_UPDATE_TIME_MS,
+ full_time_ms - rt_time_ms);
+
+ soc_points = abs(chip->msoc - chip->catch_up_soc);
+ if (chip->maint_soc > 0)
+ soc_points = max(abs(chip->msoc - chip->maint_soc), soc_points);
+ soc_points /= chip->dt.delta_soc;
+
+ /* Lower the delta soc interval by half at cold */
+ rc = qg_get_battery_temp(chip, &batt_temp);
if (rc < 0)
- return;
+ pr_err("Failed to read battery temperature rc=%d\n", rc);
- rc = get_fifo_done_time(chip, true, &rt_time_ms);
- if (rc < 0)
- return;
+ if (batt_temp < SOC_SCALE_LOW_TEMP_THRESHOLD)
+ min_delta_soc_interval_ms = min_delta_soc_interval_ms / 2;
- *time_ms = full_time_ms - rt_time_ms;
+ chip->next_wakeup_ms = (full_time_ms / (soc_points + 1))
+ - SOC_SCALE_HYST_MS;
+ chip->next_wakeup_ms = max(chip->next_wakeup_ms,
+ min_delta_soc_interval_ms);
- if (*time_ms < 0)
- *time_ms = 0;
-
- qg_dbg(chip, QG_DEBUG_SOC, "SOC scale next-update-time %d secs\n",
- *time_ms / 1000);
+ qg_dbg(chip, QG_DEBUG_SOC, "fifo_full_time=%d secs fifo_real_time=%d secs soc_scale_points=%d\n",
+ full_time_ms / 1000, rt_time_ms / 1000, soc_points);
}
static bool is_scaling_required(struct qpnp_qg *chip)
{
+ if (!chip->profile_loaded)
+ return false;
+
+ if (chip->maint_soc > 0 &&
+ (abs(chip->maint_soc - chip->msoc) >= chip->dt.delta_soc))
+ return true;
+
if ((abs(chip->catch_up_soc - chip->msoc) < chip->dt.delta_soc) &&
chip->catch_up_soc != 0 && chip->catch_up_soc != 100)
return false;
@@ -72,25 +98,36 @@
/* SOC increased */
if (is_usb_present(chip)) /* Increment if USB is present */
chip->msoc += chip->dt.delta_soc;
- } else {
+ } else if (chip->catch_up_soc < chip->msoc) {
/* SOC dropped */
chip->msoc -= chip->dt.delta_soc;
}
chip->msoc = CAP(0, 100, chip->msoc);
+ if (chip->maint_soc > 0 && chip->msoc < chip->maint_soc) {
+ chip->maint_soc -= chip->dt.delta_soc;
+ chip->maint_soc = CAP(0, 100, chip->maint_soc);
+ }
+
+ /* maint_soc dropped below msoc, skip using it */
+ if (chip->maint_soc <= chip->msoc)
+ chip->maint_soc = -EINVAL;
+
/* update the SOC register */
rc = qg_write_monotonic_soc(chip, chip->msoc);
if (rc < 0)
pr_err("Failed to update MSOC register rc=%d\n", rc);
/* update SDAM with the new MSOC */
+ chip->sdam_data[SDAM_SOC] = chip->msoc;
rc = qg_sdam_write(SDAM_SOC, chip->msoc);
if (rc < 0)
pr_err("Failed to update SDAM with MSOC rc=%d\n", rc);
qg_dbg(chip, QG_DEBUG_SOC,
- "SOC scale: Update msoc=%d catch_up_soc=%d delta_soc=%d\n",
- chip->msoc, chip->catch_up_soc, chip->dt.delta_soc);
+ "SOC scale: Update maint_soc=%d msoc=%d catch_up_soc=%d delta_soc=%d\n",
+ chip->maint_soc, chip->msoc,
+ chip->catch_up_soc, chip->dt.delta_soc);
}
static void scale_soc_stop(struct qpnp_qg *chip)
@@ -152,8 +189,7 @@
int qg_scale_soc(struct qpnp_qg *chip, bool force_soc)
{
- int soc_points = 0;
- int rc = 0, time_ms = 0;
+ int rc = 0;
mutex_lock(&chip->soc_lock);
@@ -180,13 +216,7 @@
update_msoc(chip);
if (is_scaling_required(chip)) {
- get_next_update_time(chip, &time_ms);
- soc_points = abs(chip->msoc - chip->catch_up_soc)
- / chip->dt.delta_soc;
- chip->next_wakeup_ms = (time_ms / (soc_points + 1))
- - SOC_SCALE_HYST_MS;
- if (chip->next_wakeup_ms < 0)
- chip->next_wakeup_ms = 1; /* wake up immediately */
+ get_next_update_time(chip);
alarm_start_relative(&chip->alarm_timer,
ms_to_ktime(chip->next_wakeup_ms));
} else {
@@ -195,9 +225,9 @@
}
qg_dbg(chip, QG_DEBUG_SOC,
- "SOC scale: msoc=%d catch_up_soc=%d delta_soc=%d soc_points=%d next_wakeup=%d sec\n",
- chip->msoc, chip->catch_up_soc, chip->dt.delta_soc,
- soc_points, chip->next_wakeup_ms / 1000);
+ "SOC scale: msoc=%d catch_up_soc=%d delta_soc=%d next_wakeup=%d sec\n",
+ chip->msoc, chip->catch_up_soc, chip->dt.delta_soc,
+ chip->next_wakeup_ms / 1000);
done_psy:
power_supply_changed(chip->qg_psy);
diff --git a/drivers/power/supply/qcom/qg-util.c b/drivers/power/supply/qcom/qg-util.c
index 44e5048..d354799 100644
--- a/drivers/power/supply/qcom/qg-util.c
+++ b/drivers/power/supply/qcom/qg-util.c
@@ -15,6 +15,7 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/power_supply.h>
+#include <linux/qpnp/qpnp-adc.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <uapi/linux/qg.h>
@@ -22,6 +23,7 @@
#include "qg-core.h"
#include "qg-reg.h"
#include "qg-defs.h"
+#include "qg-util.h"
static inline bool is_sticky_register(u32 addr)
{
@@ -36,7 +38,14 @@
int rc, i;
u32 dummy = 0;
+ rc = regmap_bulk_read(chip->regmap, addr, val, len);
+ if (rc < 0) {
+ pr_err("Failed regmap_read for address %04x rc=%d\n", addr, rc);
+ return rc;
+ }
+
if (is_sticky_register(addr)) {
+ /* write to the sticky register to clear it */
rc = regmap_write(chip->regmap, addr, dummy);
if (rc < 0) {
pr_err("Failed regmap_write for %04x rc=%d\n",
@@ -45,12 +54,6 @@
}
}
- rc = regmap_bulk_read(chip->regmap, addr, val, len);
- if (rc < 0) {
- pr_err("Failed regmap_read for address %04x rc=%d\n", addr, rc);
- return rc;
- }
-
if (*chip->debug_mask & QG_DEBUG_BUS_READ) {
pr_info("length %d addr=%04x\n", len, addr);
for (i = 0; i < len; i++)
@@ -122,7 +125,7 @@
}
if (rt) {
- *fifo_length &= COUNT_FIFO_RT_MASK;
+ *fifo_length = reg & COUNT_FIFO_RT_MASK;
} else {
*fifo_length = (reg & FIFO_LENGTH_MASK) >> FIFO_LENGTH_SHIFT;
*fifo_length += 1;
@@ -289,3 +292,27 @@
return rc;
}
+
+int qg_get_battery_temp(struct qpnp_qg *chip, int *temp)
+{
+ int rc = 0;
+ struct qpnp_vadc_result result;
+
+ if (chip->battery_missing) {
+ *temp = 250;
+ return 0;
+ }
+
+ rc = qpnp_vadc_read(chip->vadc_dev, VADC_BAT_THERM_PU2, &result);
+ if (rc) {
+ pr_err("Failed reading adc channel=%d, rc=%d\n",
+ VADC_BAT_THERM_PU2, rc);
+ return rc;
+ }
+ pr_debug("batt_temp = %lld meas = 0x%llx\n",
+ result.physical, result.measurement);
+
+ *temp = (int)result.physical;
+
+ return rc;
+}
diff --git a/drivers/power/supply/qcom/qg-util.h b/drivers/power/supply/qcom/qg-util.h
index a3664e1..385c9e0 100644
--- a/drivers/power/supply/qcom/qg-util.h
+++ b/drivers/power/supply/qcom/qg-util.h
@@ -23,5 +23,6 @@
bool is_usb_present(struct qpnp_qg *chip);
bool is_parallel_enabled(struct qpnp_qg *chip);
int qg_write_monotonic_soc(struct qpnp_qg *chip, int msoc);
+int qg_get_battery_temp(struct qpnp_qg *chip, int *batt_temp);
#endif
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 0894f37..420f2fd 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -128,6 +128,8 @@
#define KI_COEFF_MED_DISCHG_v2_OFFSET 0
#define KI_COEFF_HI_DISCHG_v2_WORD 10
#define KI_COEFF_HI_DISCHG_v2_OFFSET 1
+#define KI_COEFF_HI_CHG_v2_WORD 11
+#define KI_COEFF_HI_CHG_v2_OFFSET 2
#define DELTA_BSOC_THR_v2_WORD 12
#define DELTA_BSOC_THR_v2_OFFSET 3
#define DELTA_MSOC_THR_v2_WORD 13
@@ -312,12 +314,18 @@
ESR_TIMER_CHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
PARAM(ESR_PULSE_THRESH, ESR_PULSE_THRESH_WORD, ESR_PULSE_THRESH_OFFSET,
1, 100000, 390625, 0, fg_encode_default, NULL),
+ PARAM(KI_COEFF_LOW_DISCHG, KI_COEFF_LOW_DISCHG_v2_WORD,
+ KI_COEFF_LOW_DISCHG_v2_OFFSET, 1, 1000, 244141, 0,
+ fg_encode_default, NULL),
PARAM(KI_COEFF_MED_DISCHG, KI_COEFF_MED_DISCHG_v2_WORD,
KI_COEFF_MED_DISCHG_v2_OFFSET, 1, 1000, 244141, 0,
fg_encode_default, NULL),
PARAM(KI_COEFF_HI_DISCHG, KI_COEFF_HI_DISCHG_v2_WORD,
KI_COEFF_HI_DISCHG_v2_OFFSET, 1, 1000, 244141, 0,
fg_encode_default, NULL),
+ PARAM(KI_COEFF_HI_CHG, KI_COEFF_HI_CHG_v2_WORD,
+ KI_COEFF_HI_CHG_v2_OFFSET, 1, 1000, 244141, 0,
+ fg_encode_default, NULL),
PARAM(KI_COEFF_FULL_SOC, KI_COEFF_FULL_SOC_WORD,
KI_COEFF_FULL_SOC_OFFSET, 1, 1000, 244141, 0,
fg_encode_default, NULL),
@@ -916,11 +924,16 @@
#define DEFAULT_BATT_TYPE "Unknown Battery"
#define MISSING_BATT_TYPE "Missing Battery"
#define LOADING_BATT_TYPE "Loading Battery"
+#define SKIP_BATT_TYPE "Skipped loading battery"
static const char *fg_get_battery_type(struct fg_chip *chip)
{
- if (chip->battery_missing)
+ if (chip->battery_missing ||
+ chip->profile_load_status == PROFILE_MISSING)
return MISSING_BATT_TYPE;
+ if (chip->profile_load_status == PROFILE_SKIPPED)
+ return SKIP_BATT_TYPE;
+
if (chip->bp.batt_type_str) {
if (chip->profile_loaded)
return chip->bp.batt_type_str;
@@ -1403,16 +1416,16 @@
QNOVO_CL_SKEW_DECIPCT, chip->cl.final_cc_uah);
chip->cl.final_cc_uah = chip->cl.final_cc_uah *
(1000 + QNOVO_CL_SKEW_DECIPCT);
- do_div(chip->cl.final_cc_uah, 1000);
+ div64_s64(chip->cl.final_cc_uah, 1000);
}
max_inc_val = chip->cl.learned_cc_uah
* (1000 + chip->dt.cl_max_cap_inc);
- do_div(max_inc_val, 1000);
+ div64_s64(max_inc_val, 1000);
min_dec_val = chip->cl.learned_cc_uah
* (1000 - chip->dt.cl_max_cap_dec);
- do_div(min_dec_val, 1000);
+ div64_s64(min_dec_val, 1000);
old_cap = chip->cl.learned_cc_uah;
if (chip->cl.final_cc_uah > max_inc_val)
@@ -1426,7 +1439,7 @@
if (chip->dt.cl_max_cap_limit) {
max_inc_val = (int64_t)chip->cl.nom_cap_uah * (1000 +
chip->dt.cl_max_cap_limit);
- do_div(max_inc_val, 1000);
+ div64_s64(max_inc_val, 1000);
if (chip->cl.final_cc_uah > max_inc_val) {
fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes above max limit %lld\n",
chip->cl.final_cc_uah, max_inc_val);
@@ -1437,7 +1450,7 @@
if (chip->dt.cl_min_cap_limit) {
min_dec_val = (int64_t)chip->cl.nom_cap_uah * (1000 -
chip->dt.cl_min_cap_limit);
- do_div(min_dec_val, 1000);
+ div64_s64(min_dec_val, 1000);
if (chip->cl.final_cc_uah < min_dec_val) {
fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes below min limit %lld\n",
chip->cl.final_cc_uah, min_dec_val);
@@ -1941,7 +1954,7 @@
}
val *= scaling_factor;
- do_div(val, 1000);
+ div64_s64(val, 1000);
rc = fg_sram_write(chip, ESR_RSLOW_CHG_WORD,
ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
if (rc < 0) {
@@ -1958,7 +1971,7 @@
}
val *= scaling_factor;
- do_div(val, 1000);
+ div64_s64(val, 1000);
rc = fg_sram_write(chip, ESR_RSLOW_DISCHG_WORD,
ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
if (rc < 0) {
@@ -2714,12 +2727,14 @@
buf, PROFILE_COMP_LEN, FG_IMA_DEFAULT);
if (rc < 0) {
pr_err("Error in reading battery profile, rc:%d\n", rc);
+ chip->profile_load_status = PROFILE_SKIPPED;
return false;
}
profiles_same = memcmp(chip->batt_profile, buf,
PROFILE_COMP_LEN) == 0;
if (profiles_same) {
fg_dbg(chip, FG_STATUS, "Battery profile is same, not loading it\n");
+ chip->profile_load_status = PROFILE_LOADED;
return false;
}
@@ -2733,6 +2748,7 @@
dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
PROFILE_LEN);
}
+ chip->profile_load_status = PROFILE_SKIPPED;
return false;
}
@@ -2876,6 +2892,7 @@
rc = fg_get_batt_profile(chip);
if (rc < 0) {
+ chip->profile_load_status = PROFILE_MISSING;
pr_warn("profile for batt_id=%dKOhms not found..using OTP, rc:%d\n",
chip->batt_id_ohms / 1000, rc);
goto out;
@@ -2927,6 +2944,7 @@
}
fg_dbg(chip, FG_STATUS, "SOC is ready\n");
+ chip->profile_load_status = PROFILE_LOADED;
done:
rc = fg_bp_params_config(chip);
if (rc < 0)
@@ -2952,7 +2970,10 @@
batt_psy_initialized(chip);
fg_notify_charger(chip);
- chip->profile_loaded = true;
+
+ if (chip->profile_load_status == PROFILE_LOADED)
+ chip->profile_loaded = true;
+
fg_dbg(chip, FG_STATUS, "profile loaded successfully");
out:
chip->soc_reporting_ready = true;
@@ -4208,6 +4229,35 @@
}
}
+ if (chip->dt.ki_coeff_low_dischg != -EINVAL) {
+ fg_encode(chip->sp, FG_SRAM_KI_COEFF_LOW_DISCHG,
+ chip->dt.ki_coeff_low_dischg, &val);
+ rc = fg_sram_write(chip,
+ chip->sp[FG_SRAM_KI_COEFF_LOW_DISCHG].addr_word,
+ chip->sp[FG_SRAM_KI_COEFF_LOW_DISCHG].addr_byte,
+ &val, chip->sp[FG_SRAM_KI_COEFF_LOW_DISCHG].len,
+ FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing ki_coeff_low_dischg, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ if (chip->dt.ki_coeff_hi_chg != -EINVAL) {
+ fg_encode(chip->sp, FG_SRAM_KI_COEFF_HI_CHG,
+ chip->dt.ki_coeff_hi_chg, &val);
+ rc = fg_sram_write(chip,
+ chip->sp[FG_SRAM_KI_COEFF_HI_CHG].addr_word,
+ chip->sp[FG_SRAM_KI_COEFF_HI_CHG].addr_byte,
+ &val, chip->sp[FG_SRAM_KI_COEFF_HI_CHG].len,
+ FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing ki_coeff_hi_chg, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
return 0;
}
@@ -4312,6 +4362,7 @@
if (chip->battery_missing) {
chip->profile_available = false;
chip->profile_loaded = false;
+ chip->profile_load_status = PROFILE_NOT_LOADED;
chip->soc_reporting_ready = false;
chip->batt_id_ohms = -EINVAL;
cancel_delayed_work_sync(&chip->pl_enable_work);
@@ -4669,6 +4720,16 @@
if (!rc)
chip->dt.ki_coeff_full_soc_dischg = temp;
+ chip->dt.ki_coeff_hi_chg = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,ki-coeff-hi-chg", &temp);
+ if (!rc)
+ chip->dt.ki_coeff_hi_chg = temp;
+
+ chip->dt.ki_coeff_low_dischg = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,ki-coeff-low-dischg", &temp);
+ if (!rc)
+ chip->dt.ki_coeff_low_dischg = temp;
+
rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg",
chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS);
if (rc < 0)
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
index 55cb5ef..3f05a53 100644
--- a/drivers/power/supply/qcom/qpnp-qg.c
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -41,8 +41,6 @@
debug_mask, qg_debug_mask, int, 0600
);
-static int qg_get_battery_temp(struct qpnp_qg *chip, int *batt_temp);
-
static bool is_battery_present(struct qpnp_qg *chip)
{
u8 reg = 0;
@@ -226,6 +224,8 @@
u8 v_fifo[MAX_FIFO_LENGTH * 2], i_fifo[MAX_FIFO_LENGTH * 2];
u32 sample_interval = 0, sample_count = 0, fifo_v = 0, fifo_i = 0;
+ chip->kdata.fifo_time = (u32)ktime_get_seconds();
+
if (!fifo_length) {
pr_debug("No FIFO data\n");
return 0;
@@ -245,6 +245,20 @@
return rc;
}
+ /*
+ * If there is pending data from suspend, append the new FIFO
+ * data to it.
+ */
+ if (chip->suspend_data) {
+ j = chip->kdata.fifo_length; /* append the data */
+ chip->suspend_data = false;
+ qg_dbg(chip, QG_DEBUG_FIFO,
+ "Pending suspend-data FIFO length=%d\n", j);
+ } else {
+ /* clear any old pending data */
+ chip->kdata.fifo_length = 0;
+ }
+
for (i = 0; i < fifo_length * 2; i = i + 2, j++) {
rc = qg_read(chip, chip->qg_base + QG_V_FIFO0_DATA0_REG + i,
&v_fifo[i], 2);
@@ -278,7 +292,8 @@
chip->kdata.fifo[j].count);
}
- chip->kdata.fifo_length = fifo_length;
+ chip->kdata.fifo_length += fifo_length;
+ chip->kdata.seq_no = chip->seq_no++ % U32_MAX;
return rc;
}
@@ -330,6 +345,9 @@
chip->kdata.fifo[index].count = count;
chip->kdata.fifo_length++;
+ if (chip->kdata.fifo_length == 1) /* Only accumulator data */
+ chip->kdata.seq_no = chip->seq_no++ % U32_MAX;
+
qg_dbg(chip, QG_DEBUG_FIFO, "ACC v_avg=%duV i_avg=%duA interval=%d count=%d\n",
chip->kdata.fifo[index].v,
(int)chip->kdata.fifo[index].i,
@@ -507,15 +525,11 @@
qg_dbg(chip, QG_DEBUG_SOC, "udata SOC=%d last SOC=%d\n",
chip->udata.param[QG_SOC].data, chip->catch_up_soc);
- /* Only scale if SOC has changed */
- if (chip->catch_up_soc != chip->udata.param[QG_SOC].data) {
- chip->catch_up_soc = chip->udata.param[QG_SOC].data;
- qg_scale_soc(chip, false);
- }
+ chip->catch_up_soc = chip->udata.param[QG_SOC].data;
+ qg_scale_soc(chip, false);
/* update parameters to SDAM */
- chip->sdam_data[SDAM_SOC] =
- chip->udata.param[QG_SOC].data;
+ chip->sdam_data[SDAM_SOC] = chip->msoc;
chip->sdam_data[SDAM_OCV_UV] =
chip->udata.param[QG_OCV_UV].data;
chip->sdam_data[SDAM_RBAT_MOHM] =
@@ -527,6 +541,10 @@
pr_err("Failed to update SDAM params, rc=%d\n", rc);
}
+ if (chip->udata.param[QG_CHARGE_COUNTER].valid)
+ chip->charge_counter_uah =
+ chip->udata.param[QG_CHARGE_COUNTER].data;
+
vote(chip->awake_votable, UDATA_READY_VOTER, false, 0);
}
@@ -650,6 +668,7 @@
static irqreturn_t qg_good_ocv_handler(int irq, void *data)
{
int rc;
+ u8 status = 0;
u32 ocv_uv;
struct qpnp_qg *chip = data;
@@ -657,6 +676,15 @@
mutex_lock(&chip->data_lock);
+ rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1);
+ if (rc < 0) {
+ pr_err("Failed to read status2 register rc=%d\n", rc);
+ goto done;
+ }
+
+ if (!(status & GOOD_OCV_BIT))
+ goto done;
+
rc = qg_read_ocv(chip, &ocv_uv, GOOD_OCV);
if (rc < 0) {
pr_err("Failed to read good_ocv, rc=%d\n", rc);
@@ -716,6 +744,10 @@
{
struct qpnp_qg *chip = data;
+ /* ignore if the QG device is not open */
+ if (!chip->qg_device_open)
+ return 0;
+
if (awake)
pm_stay_awake(chip->dev);
else
@@ -856,6 +888,7 @@
#define DEBUG_BATT_SOC 67
#define BATT_MISSING_SOC 50
#define EMPTY_SOC 0
+#define FULL_SOC 100
static int qg_get_battery_capacity(struct qpnp_qg *chip, int *soc)
{
if (is_debug_batt_id(chip)) {
@@ -868,33 +901,21 @@
return 0;
}
- *soc = chip->msoc;
-
- return 0;
-}
-
-static int qg_get_battery_temp(struct qpnp_qg *chip, int *temp)
-{
- int rc = 0;
- struct qpnp_vadc_result result;
-
- if (chip->battery_missing) {
- *temp = 250;
+ if (chip->charge_full) {
+ *soc = FULL_SOC;
return 0;
}
- rc = qpnp_vadc_read(chip->vadc_dev, VADC_BAT_THERM_PU2, &result);
- if (rc) {
- pr_err("Failed reading adc channel=%d, rc=%d\n",
- VADC_BAT_THERM_PU2, rc);
- return rc;
- }
- pr_debug("batt_temp = %lld meas = 0x%llx\n",
- result.physical, result.measurement);
+ mutex_lock(&chip->soc_lock);
- *temp = (int)result.physical;
+ if (chip->dt.linearize_soc && chip->maint_soc > 0)
+ *soc = chip->maint_soc;
+ else
+ *soc = chip->msoc;
- return rc;
+ mutex_unlock(&chip->soc_lock);
+
+ return 0;
}
static int qg_psy_set_property(struct power_supply *psy,
@@ -958,6 +979,9 @@
case POWER_SUPPLY_PROP_BATT_PROFILE_VERSION:
pval->intval = chip->bp.qg_profile_version;
break;
+ case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+ pval->intval = chip->charge_counter_uah;
+ break;
default:
pr_debug("Unsupported property %d\n", psp);
break;
@@ -978,6 +1002,7 @@
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_VOLTAGE_OCV,
POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CHARGE_COUNTER,
POWER_SUPPLY_PROP_RESISTANCE,
POWER_SUPPLY_PROP_RESISTANCE_ID,
POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE,
@@ -999,13 +1024,62 @@
.property_is_writeable = qg_property_is_writeable,
};
+#define DEFAULT_RECHARGE_SOC 95
static int qg_charge_full_update(struct qpnp_qg *chip)
{
+ union power_supply_propval prop = {0, };
+ int rc, recharge_soc, health;
vote(chip->good_ocv_irq_disable_votable,
QG_INIT_STATE_IRQ_DISABLE, !chip->charge_done, 0);
- /* TODO: add hold-soc-at-full logic */
+ if (!chip->dt.hold_soc_while_full)
+ goto out;
+
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_HEALTH, &prop);
+ if (rc < 0) {
+ pr_err("Failed to get battery health, rc=%d\n", rc);
+ goto out;
+ }
+ health = prop.intval;
+
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_RECHARGE_SOC, &prop);
+ if (rc < 0 || prop.intval < 0) {
+ pr_debug("Failed to get recharge-soc\n");
+ recharge_soc = DEFAULT_RECHARGE_SOC;
+ }
+ recharge_soc = prop.intval;
+
+ qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d health=%d charge_full=%d\n",
+ chip->msoc, health, chip->charge_full);
+ if (chip->charge_done && !chip->charge_full) {
+ if (chip->msoc >= 99 && health == POWER_SUPPLY_HEALTH_GOOD) {
+ chip->charge_full = true;
+ qg_dbg(chip, QG_DEBUG_STATUS, "Setting charge_full (0->1) @ msoc=%d\n",
+ chip->msoc);
+ } else {
+ qg_dbg(chip, QG_DEBUG_STATUS, "Terminated charging @ msoc=%d\n",
+ chip->msoc);
+ }
+ } else if ((!chip->charge_done || chip->msoc < recharge_soc)
+ && chip->charge_full) {
+ /*
+ * If recharge or discharge has started and
+ * if linearize soc dtsi property defined
+ * scale msoc from 100% for better UX.
+ */
+ if (chip->dt.linearize_soc && chip->msoc < 99) {
+ chip->maint_soc = FULL_SOC;
+ qg_scale_soc(chip, false);
+ }
+
+ qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d recharge_soc=%d charge_full (1->0)\n",
+ chip->msoc, recharge_soc);
+ chip->charge_full = false;
+ }
+out:
return 0;
}
@@ -1074,6 +1148,9 @@
else
chip->charge_done = prop.intval;
+ qg_dbg(chip, QG_DEBUG_STATUS, "charge_status=%d charge_done=%d\n",
+ chip->charge_status, chip->charge_done);
+
rc = qg_parallel_status_update(chip);
if (rc < 0)
pr_err("Failed to update parallel-status, rc=%d\n", rc);
@@ -1149,7 +1226,7 @@
/* non-blocking access, return */
if (!chip->data_ready && (file->f_flags & O_NONBLOCK))
- return -EAGAIN;
+ return 0;
/* blocking access wait on data_ready */
if (!(file->f_flags & O_NONBLOCK)) {
@@ -1169,6 +1246,7 @@
goto fail_read;
}
+
if (copy_to_user(buf, &chip->kdata, data_size)) {
pr_err("Failed in copy_to_user\n");
rc = -EFAULT;
@@ -1176,9 +1254,6 @@
}
chip->data_ready = false;
- /* clear data */
- memset(&chip->kdata, 0, sizeof(chip->kdata));
-
/* release all wake sources */
vote(chip->awake_votable, GOOD_OCV_VOTER, false, 0);
vote(chip->awake_votable, FIFO_DONE_VOTER, false, 0);
@@ -1186,7 +1261,11 @@
vote(chip->awake_votable, SUSPEND_DATA_VOTER, false, 0);
qg_dbg(chip, QG_DEBUG_DEVICE,
- "QG device read complete Size=%ld\n", data_size);
+ "QG device read complete Seq_no=%u Size=%ld\n",
+ chip->kdata.seq_no, data_size);
+
+ /* clear data */
+ memset(&chip->kdata, 0, sizeof(chip->kdata));
mutex_unlock(&chip->data_lock);
@@ -1211,7 +1290,7 @@
}
if (count != 0 && count < data_size) {
- pr_err("Invalid datasize %zu expected %zu\n", count, data_size);
+ pr_err("Invalid datasize %zu expected %lu\n", count, data_size);
goto fail;
}
@@ -1233,14 +1312,12 @@
static unsigned int qg_device_poll(struct file *file, poll_table *wait)
{
struct qpnp_qg *chip = file->private_data;
- unsigned int mask;
+ unsigned int mask = 0;
poll_wait(file, &chip->qg_wait_q, wait);
if (chip->data_ready)
mask = POLLIN | POLLRDNORM;
- else
- mask = POLLERR;
return mask;
}
@@ -1251,14 +1328,28 @@
struct qpnp_qg, qg_cdev);
file->private_data = chip;
+ chip->qg_device_open = true;
qg_dbg(chip, QG_DEBUG_DEVICE, "QG device opened!\n");
return 0;
}
+static int qg_device_release(struct inode *inode, struct file *file)
+{
+ struct qpnp_qg *chip = container_of(inode->i_cdev,
+ struct qpnp_qg, qg_cdev);
+
+ file->private_data = chip;
+ chip->qg_device_open = false;
+ qg_dbg(chip, QG_DEBUG_DEVICE, "QG device closed!\n");
+
+ return 0;
+}
+
static const struct file_operations qg_fops = {
.owner = THIS_MODULE,
.open = qg_device_open,
+ .release = qg_device_release,
.read = qg_device_read,
.write = qg_device_write,
.poll = qg_device_poll,
@@ -1323,7 +1414,7 @@
return rc;
}
- batt_id_mv = result.physical / 1000;
+ batt_id_mv = div_s64(result.physical, 1000);
if (batt_id_mv == 0) {
pr_debug("batt_id_mv = 0 from ADC\n");
return 0;
@@ -1437,9 +1528,9 @@
static int qg_determine_pon_soc(struct qpnp_qg *chip)
{
- u8 status;
- int rc, batt_temp = 0;
- bool use_pon_ocv = false;
+ u8 status = 0, ocv_type = 0;
+ int rc = 0, batt_temp = 0;
+ bool use_pon_ocv = true, use_shutdown_ocv = false;
unsigned long rtc_sec = 0;
u32 ocv_uv = 0, soc = 0, shutdown[SDAM_MAX] = {0};
@@ -1448,83 +1539,77 @@
return 0;
}
- rc = qg_get_battery_temp(chip, &batt_temp);
- if (rc) {
- pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc);
- return rc;
- }
-
- rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG,
- &status, 1);
+ rc = get_rtc_time(&rtc_sec);
if (rc < 0) {
- pr_err("Failed to read status2 register rc=%d\n", rc);
- return rc;
+ pr_err("Failed to read RTC time rc=%d\n", rc);
+ goto use_pon_ocv;
}
- if (status & GOOD_OCV_BIT) {
- qg_dbg(chip, QG_DEBUG_PON, "Using GOOD_OCV @ PON\n");
- rc = qg_read_ocv(chip, &ocv_uv, GOOD_OCV);
- if (rc < 0) {
- pr_err("Failed to read good_ocv rc=%d\n", rc);
- use_pon_ocv = true;
- } else {
- rc = lookup_soc_ocv(&soc, ocv_uv, batt_temp, false);
- if (rc < 0) {
- pr_err("Failed to lookup SOC (GOOD_OCV) @ PON rc=%d\n",
- rc);
- use_pon_ocv = true;
- }
- }
- } else {
- rc = get_rtc_time(&rtc_sec);
- if (rc < 0) {
- pr_err("Failed to read RTC time rc=%d\n", rc);
- use_pon_ocv = true;
+ rc = qg_sdam_read_all(shutdown);
+ if (rc < 0) {
+ pr_err("Failed to read shutdown params rc=%d\n", rc);
+ goto use_pon_ocv;
+ }
+
+ qg_dbg(chip, QG_DEBUG_PON, "Shutdown: Valid=%d SOC=%d OCV=%duV time=%dsecs, time_now=%ldsecs\n",
+ shutdown[SDAM_VALID],
+ shutdown[SDAM_SOC],
+ shutdown[SDAM_OCV_UV],
+ shutdown[SDAM_TIME_SEC],
+ rtc_sec);
+ /*
+ * Use the shutdown SOC if
+ * 1. The device was powered off for < ignore_shutdown_time
+ * 2. SDAM read is a success & SDAM data is valid
+ */
+ if (shutdown[SDAM_VALID] && is_between(0,
+ chip->dt.ignore_shutdown_soc_secs,
+ (rtc_sec - shutdown[SDAM_TIME_SEC]))) {
+ use_pon_ocv = false;
+ use_shutdown_ocv = true;
+ ocv_uv = shutdown[SDAM_OCV_UV];
+ soc = shutdown[SDAM_SOC];
+ qg_dbg(chip, QG_DEBUG_PON, "Using SHUTDOWN_SOC @ PON\n");
+ }
+
+use_pon_ocv:
+ if (use_pon_ocv == true) {
+ rc = qg_get_battery_temp(chip, &batt_temp);
+ if (rc) {
+ pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc);
goto done;
}
- rc = qg_sdam_read_all(shutdown);
+ rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1);
if (rc < 0) {
- pr_err("Failed to read shutdown params rc=%d\n", rc);
- use_pon_ocv = true;
+ pr_err("Failed to read status2 register rc=%d\n", rc);
goto done;
}
- qg_dbg(chip, QG_DEBUG_PON, "Shutdown: SOC=%d OCV=%duV time=%dsecs, time_now=%ldsecs\n",
- shutdown[SDAM_SOC],
- shutdown[SDAM_OCV_UV],
- shutdown[SDAM_TIME_SEC],
- rtc_sec);
- /*
- * Use the shutdown SOC if
- * 1. The device was powered off for < 180 seconds
- * 2. SDAM read is a success & SDAM data is valid
- */
- use_pon_ocv = true;
- if (!rc && shutdown[SDAM_VALID] &&
- ((rtc_sec - shutdown[SDAM_TIME_SEC]) < 180)) {
- use_pon_ocv = false;
- ocv_uv = shutdown[SDAM_OCV_UV];
- soc = shutdown[SDAM_SOC];
- qg_dbg(chip, QG_DEBUG_PON, "Using SHUTDOWN_SOC @ PON\n");
+
+ if (status & GOOD_OCV_BIT)
+ ocv_type = GOOD_OCV;
+ else
+ ocv_type = PON_OCV;
+
+ qg_dbg(chip, QG_DEBUG_PON, "Using %s @ PON\n",
+ ocv_type == GOOD_OCV ? "GOOD_OCV" : "PON_OCV");
+
+ rc = qg_read_ocv(chip, &ocv_uv, ocv_type);
+ if (rc < 0) {
+ pr_err("Failed to read ocv rc=%d\n", rc);
+ goto done;
+ }
+
+ rc = lookup_soc_ocv(&soc, ocv_uv, batt_temp, false);
+ if (rc < 0) {
+ pr_err("Failed to lookup SOC@PON rc=%d\n", rc);
+ goto done;
}
}
done:
- /*
- * Use PON OCV if
- * OCV_UV is not set or shutdown SOC is invalid.
- */
- if (use_pon_ocv || !ocv_uv || !rtc_sec) {
- qg_dbg(chip, QG_DEBUG_PON, "Using PON_OCV @ PON\n");
- rc = qg_read_ocv(chip, &ocv_uv, PON_OCV);
- if (rc < 0) {
- pr_err("Failed to read HW PON ocv rc=%d\n", rc);
- return rc;
- }
- rc = lookup_soc_ocv(&soc, ocv_uv, batt_temp, false);
- if (rc < 0) {
- pr_err("Failed to lookup SOC @ PON rc=%d\n", rc);
- soc = 50;
- }
+ if (rc < 0) {
+ pr_err("Failed to get SOC @ PON, rc=%d\n", rc);
+ return rc;
}
chip->pon_soc = chip->catch_up_soc = chip->msoc = soc;
@@ -1544,10 +1629,9 @@
if (rc < 0)
pr_err("Failed to update sdam params rc=%d\n", rc);
- pr_info("use_pon_ocv=%d good_ocv=%d ocv_uv=%duV temp=%d soc=%d\n",
+ pr_info("use_pon_ocv=%d use_good_ocv=%d use_shutdown_ocv=%d ocv_uv=%duV soc=%d\n",
use_pon_ocv, !!(status & GOOD_OCV_BIT),
- ocv_uv, batt_temp, chip->msoc);
-
+ use_shutdown_ocv, ocv_uv, chip->msoc);
return 0;
}
@@ -1857,6 +1941,7 @@
#define DEFAULT_S2_ACC_LENGTH 128
#define DEFAULT_S2_ACC_INTVL_MS 100
#define DEFAULT_DELTA_SOC 1
+#define DEFAULT_SHUTDOWN_SOC_SECS 360
static int qg_parse_dt(struct qpnp_qg *chip)
{
int rc = 0;
@@ -2014,6 +2099,18 @@
else
chip->dt.delta_soc = temp;
+ rc = of_property_read_u32(node, "qcom,ignore-shutdown-soc-secs", &temp);
+ if (rc < 0)
+ chip->dt.ignore_shutdown_soc_secs = DEFAULT_SHUTDOWN_SOC_SECS;
+ else
+ chip->dt.ignore_shutdown_soc_secs = temp;
+
+ chip->dt.hold_soc_while_full = of_property_read_bool(node,
+ "qcom,hold-soc-while-full");
+
+ chip->dt.linearize_soc = of_property_read_bool(node,
+ "qcom,linearize-soc");
+
rc = of_property_read_u32(node, "qcom,rbat-conn-mohm", &temp);
if (rc < 0)
chip->dt.rbat_conn_mohm = 0;
@@ -2029,9 +2126,16 @@
static int process_suspend(struct qpnp_qg *chip)
{
+ u8 status = 0;
int rc;
u32 fifo_rt_length = 0, sleep_fifo_length = 0;
+ /* skip if profile is not loaded */
+ if (!chip->profile_loaded)
+ return 0;
+
+ chip->suspend_data = false;
+
/* ignore any suspend processing if we are charging */
if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
qg_dbg(chip, QG_DEBUG_PM, "Charging @ suspend - ignore processing\n");
@@ -2081,6 +2185,9 @@
chip->suspend_data = true;
}
+ /* read STATUS2 register to clear its last state */
+ qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1);
+
qg_dbg(chip, QG_DEBUG_PM, "FIFO rt_length=%d sleep_fifo_length=%d default_s2_count=%d suspend_data=%d\n",
fifo_rt_length, sleep_fifo_length,
chip->dt.s2_fifo_length, chip->suspend_data);
@@ -2090,9 +2197,13 @@
static int process_resume(struct qpnp_qg *chip)
{
- int rc, batt_temp = 0;
u8 status2 = 0, rt_status = 0;
- u32 ocv_uv = 0, soc = 0;
+ u32 ocv_uv = 0;
+ int rc, batt_temp = 0;
+
+ /* skip if profile is not loaded */
+ if (!chip->profile_loaded)
+ return 0;
rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status2, 1);
if (rc < 0) {
@@ -2114,23 +2225,12 @@
chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
+ /* Clear suspend data as there has been a GOOD OCV */
chip->suspend_data = false;
- rc = lookup_soc_ocv(&soc, ocv_uv, batt_temp, false);
- if (rc < 0) {
- pr_err("Failed to lookup OCV, rc=%d\n", rc);
- return rc;
- }
- chip->catch_up_soc = soc;
- /* update the SOC immediately */
- qg_scale_soc(chip, true);
-
- qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV soc=%d\n",
- ocv_uv, soc);
+ qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV\n",
+ ocv_uv);
}
- /*
- * If the wakeup was not because of FIFO_DONE
- * send the pending data collected during suspend.
- */
+
rc = qg_read(chip, chip->qg_base + QG_INT_LATCHED_STS_REG,
&rt_status, 1);
if (rc < 0) {
@@ -2139,18 +2239,23 @@
}
rt_status &= FIFO_UPDATE_DONE_INT_LAT_STS_BIT;
- if (!rt_status && chip->suspend_data) {
+ qg_dbg(chip, QG_DEBUG_PM, "FIFO_DONE_STS=%d suspend_data=%d good_ocv=%d\n",
+ !!rt_status, chip->suspend_data,
+ chip->kdata.param[QG_GOOD_OCV_UV].valid);
+ /*
+ * If this is not a wakeup from FIFO-done,
+ * process the data immediately if - we have data from
+ * suspend or there is a good OCV.
+ */
+ if (!rt_status && (chip->suspend_data ||
+ chip->kdata.param[QG_GOOD_OCV_UV].valid)) {
vote(chip->awake_votable, SUSPEND_DATA_VOTER, true, 0);
/* signal the read thread */
chip->data_ready = true;
wake_up_interruptible(&chip->qg_wait_q);
+ chip->suspend_data = false;
}
- qg_dbg(chip, QG_DEBUG_PM, "fifo_done rt_status=%d suspend_data=%d data_ready=%d\n",
- !!rt_status, chip->suspend_data, chip->data_ready);
-
- chip->suspend_data = false;
-
return rc;
}
@@ -2225,6 +2330,7 @@
mutex_init(&chip->soc_lock);
mutex_init(&chip->data_lock);
init_waitqueue_head(&chip->qg_wait_q);
+ chip->maint_soc = -EINVAL;
rc = qg_parse_dt(chip);
if (rc < 0) {
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 74e80cd..f9a29aa 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -318,6 +318,9 @@
chip->dt.auto_recharge_soc = of_property_read_bool(node,
"qcom,auto-recharge-soc");
+ chg->use_extcon = of_property_read_bool(node,
+ "qcom,use-extcon");
+
chg->dcp_icl_ua = chip->dt.usb_icl_ua;
chg->suspend_input_on_debug_batt = of_property_read_bool(node,
diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
index b07efdf..b91850d 100644
--- a/drivers/power/supply/qcom/qpnp-smb5.c
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -27,6 +27,7 @@
#include <linux/pmic-voter.h>
#include "smb5-reg.h"
#include "smb5-lib.h"
+#include "schgm-flash.h"
static struct smb_params smb5_pmi632_params = {
.fcc = {
@@ -157,7 +158,8 @@
int chg_inhibit_thr_mv;
bool no_battery;
bool hvdcp_disable;
- bool auto_recharge_soc;
+ int auto_recharge_soc;
+ int auto_recharge_vbat_mv;
int wd_bark_time;
int batt_profile_fcc_ua;
int batt_profile_fv_uv;
@@ -328,8 +330,23 @@
return -EINVAL;
}
- chip->dt.auto_recharge_soc = of_property_read_bool(node,
- "qcom,auto-recharge-soc");
+ chip->dt.auto_recharge_soc = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,auto-recharge-soc",
+ &chip->dt.auto_recharge_soc);
+ if (!rc && (chip->dt.auto_recharge_soc < 0 ||
+ chip->dt.auto_recharge_soc > 100)) {
+ pr_err("qcom,auto-recharge-soc is incorrect\n");
+ return -EINVAL;
+ }
+ chg->auto_recharge_soc = chip->dt.auto_recharge_soc;
+
+ chip->dt.auto_recharge_vbat_mv = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,auto-recharge-vbat-mv",
+ &chip->dt.auto_recharge_vbat_mv);
+ if (!rc && (chip->dt.auto_recharge_vbat_mv < 0)) {
+ pr_err("qcom,auto-recharge-vbat-mv is incorrect\n");
+ return -EINVAL;
+ }
chg->dcp_icl_ua = chip->dt.usb_icl_ua;
@@ -371,6 +388,7 @@
POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
POWER_SUPPLY_PROP_CONNECTOR_TYPE,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_SCOPE,
};
static int smb5_usb_get_prop(struct power_supply *psy,
@@ -379,6 +397,7 @@
{
struct smb5 *chip = power_supply_get_drvdata(psy);
struct smb_charger *chg = &chip->chg;
+ union power_supply_propval pval;
int rc = 0;
switch (psp) {
@@ -476,6 +495,15 @@
case POWER_SUPPLY_PROP_CONNECTOR_TYPE:
val->intval = chg->connector_type;
break;
+ case POWER_SUPPLY_PROP_SCOPE:
+ val->intval = POWER_SUPPLY_SCOPE_UNKNOWN;
+ rc = smblib_get_prop_usb_present(chg, &pval);
+ if (rc < 0)
+ break;
+ val->intval = pval.intval ? POWER_SUPPLY_SCOPE_DEVICE
+ : chg->otg_present ? POWER_SUPPLY_SCOPE_SYSTEM
+ : POWER_SUPPLY_SCOPE_UNKNOWN;
+ break;
default:
pr_err("get prop %d is not supported in usb\n", psp);
rc = -EINVAL;
@@ -701,6 +729,8 @@
POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED,
POWER_SUPPLY_PROP_FCC_DELTA,
POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_FLASH_ACTIVE,
+ POWER_SUPPLY_PROP_FLASH_TRIGGER,
};
static int smb5_usb_main_get_prop(struct power_supply *psy,
@@ -734,6 +764,12 @@
case POWER_SUPPLY_PROP_CURRENT_MAX:
rc = smblib_get_icl_current(chg, &val->intval);
break;
+ case POWER_SUPPLY_PROP_FLASH_ACTIVE:
+ val->intval = chg->flash_active;
+ break;
+ case POWER_SUPPLY_PROP_FLASH_TRIGGER:
+ rc = schgm_flash_get_vreg_ok(chg, &val->intval);
+ break;
default:
pr_debug("get prop %d is not supported in usb-main\n", psp);
rc = -EINVAL;
@@ -765,6 +801,9 @@
case POWER_SUPPLY_PROP_CURRENT_MAX:
rc = smblib_set_icl_current(chg, val->intval);
break;
+ case POWER_SUPPLY_PROP_FLASH_ACTIVE:
+ chg->flash_active = val->intval;
+ break;
default:
pr_err("set prop %d is not supported\n", psp);
rc = -EINVAL;
@@ -933,6 +972,7 @@
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
POWER_SUPPLY_PROP_CHARGE_COUNTER,
+ POWER_SUPPLY_PROP_RECHARGE_SOC,
};
static int smb5_batt_get_prop(struct power_supply *psy,
@@ -1022,6 +1062,9 @@
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
rc = smblib_get_prop_batt_charge_counter(chg, val);
break;
+ case POWER_SUPPLY_PROP_RECHARGE_SOC:
+ val->intval = chg->auto_recharge_soc;
+ break;
default:
pr_err("batt power supply prop %d not supported\n", psp);
return -EINVAL;
@@ -1367,6 +1410,13 @@
: POWER_SUPPLY_CONNECTOR_TYPEC;
pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");
+ /*
+ * PMI632 based hw init:
+ * - Initialize flash module for PMI632
+ */
+ if (chg->smb_version == PMI632_SUBTYPE)
+ schgm_flash_init(chg);
+
smblib_rerun_apsd_if_required(chg);
/* vote 0mA on usb_icl for non battery platforms */
@@ -1525,15 +1575,66 @@
return rc;
}
- rc = smblib_masked_write(chg, CHGR_CFG2_REG,
- SOC_BASED_RECHG_BIT,
- chip->dt.auto_recharge_soc ? SOC_BASED_RECHG_BIT : 0);
+ rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
+ (chip->dt.auto_recharge_vbat_mv != -EINVAL) ?
+ VBAT_BASED_RECHG_BIT : 0);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't configure FG_UPDATE_CFG2_SEL_REG rc=%d\n",
+ dev_err(chg->dev, "Couldn't configure VBAT-rechg CHG_CFG2_REG rc=%d\n",
rc);
return rc;
}
+ /* program the auto-recharge VBAT threshold */
+ if (chip->dt.auto_recharge_vbat_mv != -EINVAL) {
+ u32 temp = VBAT_TO_VRAW_ADC(chip->dt.auto_recharge_vbat_mv);
+
+ temp = ((temp & 0xFF00) >> 8) | ((temp & 0xFF) << 8);
+ rc = smblib_batch_write(chg,
+ CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG, (u8 *)&temp, 2);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure ADC_RECHARGE_THRESHOLD REG rc=%d\n",
+ rc);
+ return rc;
+ }
+ /* Program the sample count for VBAT based recharge to 3 */
+ rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
+ NO_OF_SAMPLE_FOR_RCHG,
+ 2 << NO_OF_SAMPLE_FOR_RCHG_SHIFT);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
+ (chip->dt.auto_recharge_soc != -EINVAL) ?
+ SOC_BASED_RECHG_BIT : VBAT_BASED_RECHG_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure SOC-rechg CHG_CFG2_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ /* program the auto-recharge threshold */
+ if (chip->dt.auto_recharge_soc != -EINVAL) {
+ rc = smblib_write(chg, CHARGE_RCHG_SOC_THRESHOLD_CFG_REG,
+ (chip->dt.auto_recharge_soc * 255) / 100);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure CHG_RCHG_SOC_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+ /* Program the sample count for SOC based recharge to 1 */
+ rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
+ NO_OF_SAMPLE_FOR_RCHG, 0);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
if (chg->sw_jeita_enabled) {
rc = smblib_disable_hw_jeita(chg, true);
if (rc < 0) {
@@ -1609,30 +1710,25 @@
[CHG_STATE_CHANGE_IRQ] = {
.name = "chg-state-change",
.handler = chg_state_change_irq_handler,
+ .wake = true,
},
[STEP_CHG_STATE_CHANGE_IRQ] = {
.name = "step-chg-state-change",
- .handler = default_irq_handler,
},
[STEP_CHG_SOC_UPDATE_FAIL_IRQ] = {
.name = "step-chg-soc-update-fail",
- .handler = default_irq_handler,
},
[STEP_CHG_SOC_UPDATE_REQ_IRQ] = {
.name = "step-chg-soc-update-req",
- .handler = default_irq_handler,
},
[FG_FVCAL_QUALIFIED_IRQ] = {
.name = "fg-fvcal-qualified",
- .handler = default_irq_handler,
},
[VPH_ALARM_IRQ] = {
.name = "vph-alarm",
- .handler = default_irq_handler,
},
[VPH_DROP_PRECHG_IRQ] = {
.name = "vph-drop-prechg",
- .handler = default_irq_handler,
},
/* DCDC IRQs */
[OTG_FAIL_IRQ] = {
@@ -1641,19 +1737,17 @@
},
[OTG_OC_DISABLE_SW_IRQ] = {
.name = "otg-oc-disable-sw",
- .handler = default_irq_handler,
},
[OTG_OC_HICCUP_IRQ] = {
.name = "otg-oc-hiccup",
- .handler = default_irq_handler,
},
[BSM_ACTIVE_IRQ] = {
.name = "bsm-active",
- .handler = default_irq_handler,
},
[HIGH_DUTY_CYCLE_IRQ] = {
.name = "high-duty-cycle",
.handler = high_duty_cycle_irq_handler,
+ .wake = true,
},
[INPUT_CURRENT_LIMITING_IRQ] = {
.name = "input-current-limiting",
@@ -1661,7 +1755,6 @@
},
[CONCURRENT_MODE_DISABLE_IRQ] = {
.name = "concurrent-mode-disable",
- .handler = default_irq_handler,
},
[SWITCHER_POWER_OK_IRQ] = {
.name = "switcher-power-ok",
@@ -1671,10 +1764,10 @@
[BAT_TEMP_IRQ] = {
.name = "bat-temp",
.handler = batt_temp_changed_irq_handler,
+ .wake = true,
},
[ALL_CHNL_CONV_DONE_IRQ] = {
.name = "all-chnl-conv-done",
- .handler = default_irq_handler,
},
[BAT_OV_IRQ] = {
.name = "bat-ov",
@@ -1694,11 +1787,9 @@
},
[BUCK_OC_IRQ] = {
.name = "buck-oc",
- .handler = default_irq_handler,
},
[VPH_OV_IRQ] = {
.name = "vph-ov",
- .handler = default_irq_handler,
},
/* USB INPUT IRQs */
[USBIN_COLLAPSE_IRQ] = {
@@ -1720,23 +1811,24 @@
[USBIN_PLUGIN_IRQ] = {
.name = "usbin-plugin",
.handler = usb_plugin_irq_handler,
+ .wake = true,
},
[USBIN_REVI_CHANGE_IRQ] = {
.name = "usbin-revi-change",
- .handler = default_irq_handler,
},
[USBIN_SRC_CHANGE_IRQ] = {
.name = "usbin-src-change",
.handler = usb_source_change_irq_handler,
+ .wake = true,
},
[USBIN_ICL_CHANGE_IRQ] = {
.name = "usbin-icl-change",
.handler = icl_change_irq_handler,
+ .wake = true,
},
/* DC INPUT IRQs */
[DCIN_VASHDN_IRQ] = {
.name = "dcin-vashdn",
- .handler = default_irq_handler,
},
[DCIN_UV_IRQ] = {
.name = "dcin-uv",
@@ -1753,7 +1845,6 @@
},
[DCIN_REVI_IRQ] = {
.name = "dcin-revi",
- .handler = default_irq_handler,
},
[DCIN_PON_IRQ] = {
.name = "dcin-pon",
@@ -1767,14 +1858,15 @@
[TYPEC_OR_RID_DETECTION_CHANGE_IRQ] = {
.name = "typec-or-rid-detect-change",
.handler = typec_or_rid_detection_change_irq_handler,
+ .wake = true,
},
[TYPEC_VPD_DETECT_IRQ] = {
.name = "typec-vpd-detect",
- .handler = default_irq_handler,
},
[TYPEC_CC_STATE_CHANGE_IRQ] = {
.name = "typec-cc-state-change",
.handler = typec_state_change_irq_handler,
+ .wake = true,
},
[TYPEC_VCONN_OC_IRQ] = {
.name = "typec-vconn-oc",
@@ -1782,11 +1874,9 @@
},
[TYPEC_VBUS_CHANGE_IRQ] = {
.name = "typec-vbus-change",
- .handler = default_irq_handler,
},
[TYPEC_ATTACH_DETACH_IRQ] = {
.name = "typec-attach-detach",
- .handler = default_irq_handler,
},
[TYPEC_LEGACY_CABLE_DETECT_IRQ] = {
.name = "typec-legacy-cable-detect",
@@ -1794,12 +1884,10 @@
},
[TYPEC_TRY_SNK_SRC_DETECT_IRQ] = {
.name = "typec-try-snk-src-detect",
- .handler = default_irq_handler,
},
/* MISCELLANEOUS IRQs */
[WDOG_SNARL_IRQ] = {
.name = "wdog-snarl",
- .handler = NULL,
},
[WDOG_BARK_IRQ] = {
.name = "wdog-bark",
@@ -1807,7 +1895,6 @@
},
[AICL_FAIL_IRQ] = {
.name = "aicl-fail",
- .handler = default_irq_handler,
},
[AICL_DONE_IRQ] = {
.name = "aicl-done",
@@ -1815,19 +1902,42 @@
},
[SMB_EN_IRQ] = {
.name = "smb-en",
- .handler = default_irq_handler,
},
[IMP_TRIGGER_IRQ] = {
.name = "imp-trigger",
- .handler = default_irq_handler,
},
[TEMP_CHANGE_IRQ] = {
.name = "temp-change",
- .handler = default_irq_handler,
},
[TEMP_CHANGE_SMB_IRQ] = {
.name = "temp-change-smb",
- .handler = default_irq_handler,
+ },
+ /* FLASH */
+ [VREG_OK_IRQ] = {
+ .name = "vreg-ok",
+ },
+ [ILIM_S2_IRQ] = {
+ .name = "ilim2-s2",
+ .handler = schgm_flash_ilim2_irq_handler,
+ },
+ [ILIM_S1_IRQ] = {
+ .name = "ilim1-s1",
+ },
+ [VOUT_DOWN_IRQ] = {
+ .name = "vout-down",
+ },
+ [VOUT_UP_IRQ] = {
+ .name = "vout-up",
+ },
+ [FLASH_STATE_CHANGE_IRQ] = {
+ .name = "flash-state-change",
+ .handler = schgm_flash_state_change_irq_handler,
+ },
+ [TORCH_REQ_IRQ] = {
+ .name = "torch-req",
+ },
+ [FLASH_EN_IRQ] = {
+ .name = "flash-en",
},
};
diff --git a/drivers/power/supply/qcom/schgm-flash.c b/drivers/power/supply/qcom/schgm-flash.c
new file mode 100644
index 0000000..eed70d3
--- /dev/null
+++ b/drivers/power/supply/qcom/schgm-flash.c
@@ -0,0 +1,216 @@
+/* Copyright (c) 2018 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.
+ */
+
+#define pr_fmt(fmt) "SCHG-FLASH: %s: " fmt, __func__
+
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/power_supply.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/printk.h>
+#include <linux/pmic-voter.h>
+#include "smb5-lib.h"
+#include "schgm-flash.h"
+
+#define IS_BETWEEN(left, right, value) \
+ (((left) >= (right) && (left) >= (value) \
+ && (value) >= (right)) \
+ || ((left) <= (right) && (left) <= (value) \
+ && (value) <= (right)))
+
+irqreturn_t schgm_flash_default_irq_handler(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+
+ pr_debug("IRQ: %s\n", irq_data->name);
+
+ return IRQ_HANDLED;
+}
+
+irqreturn_t schgm_flash_ilim2_irq_handler(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+ int rc;
+
+ rc = smblib_write(chg, SCHGM_FLASH_S2_LATCH_RESET_CMD_REG,
+ FLASH_S2_LATCH_RESET_BIT);
+ if (rc < 0)
+ pr_err("Couldn't reset S2_LATCH reset rc=%d\n", rc);
+
+ return IRQ_HANDLED;
+}
+
+irqreturn_t schgm_flash_state_change_irq_handler(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+ int rc;
+ u8 reg;
+
+ rc = smblib_read(chg, SCHGM_FLASH_STATUS_3_REG, ®);
+ if (rc < 0)
+ pr_err("Couldn't read flash status_3 rc=%d\n", rc);
+ else
+ pr_debug("Flash status changed state=[%x]\n",
+ (reg && FLASH_STATE_MASK));
+
+ return IRQ_HANDLED;
+}
+
+#define FIXED_MODE 0
+#define ADAPTIVE_MODE 1
+static void schgm_flash_parse_dt(struct smb_charger *chg)
+{
+ struct device_node *node = chg->dev->of_node;
+ u32 val;
+ int rc;
+
+ chg->flash_derating_soc = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,flash-derating-soc", &val);
+ if (!rc) {
+ if (IS_BETWEEN(0, 100, val))
+ chg->flash_derating_soc = (val * 255) / 100;
+ }
+
+ chg->flash_disable_soc = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,flash-disable-soc", &val);
+ if (!rc) {
+ if (IS_BETWEEN(0, 100, val))
+ chg->flash_disable_soc = (val * 255) / 100;
+ }
+
+ chg->headroom_mode = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,headroom-mode", &val);
+ if (!rc) {
+ if (IS_BETWEEN(FIXED_MODE, ADAPTIVE_MODE, val))
+ chg->headroom_mode = val;
+ }
+}
+
+int schgm_flash_get_vreg_ok(struct smb_charger *chg, int *val)
+{
+ int rc, vreg_state;
+ u8 stat = 0;
+
+ if (!chg->flash_init_done)
+ return -EPERM;
+
+ rc = smblib_read(chg, SCHGM_FLASH_STATUS_2_REG, &stat);
+ if (rc < 0) {
+ pr_err("Couldn't read FLASH STATUS_2 rc=%d\n", rc);
+ return rc;
+ }
+ vreg_state = !!(stat & VREG_OK_BIT);
+
+ /* If VREG_OK is not set check for flash error */
+ if (!vreg_state) {
+ rc = smblib_read(chg, SCHGM_FLASH_STATUS_3_REG, &stat);
+ if (rc < 0) {
+ pr_err("Couldn't read FLASH_STATUS_3 rc=%d\n", rc);
+ return rc;
+ }
+ if ((stat & FLASH_STATE_MASK) == FLASH_ERROR_VAL) {
+ vreg_state = -EFAULT;
+ rc = smblib_read(chg, SCHGM_FLASH_STATUS_5_REG,
+ &stat);
+ if (rc < 0) {
+ pr_err("Couldn't read FLASH_STATUS_5 rc=%d\n",
+ rc);
+ return rc;
+ }
+ pr_debug("Flash error: status=%x\n", stat);
+ }
+ }
+
+ /*
+ * val can be one of the following:
+ * 1 - VREG_OK is set.
+ * 0 - VREG_OK is 0 but no Flash error.
+ * -EFAULT - Flash Error is set.
+ */
+ *val = vreg_state;
+
+ return 0;
+}
+
+int schgm_flash_init(struct smb_charger *chg)
+{
+ int rc;
+ u8 reg;
+
+ schgm_flash_parse_dt(chg);
+
+ if (chg->flash_derating_soc != -EINVAL) {
+ rc = smblib_write(chg, SCHGM_SOC_BASED_FLASH_DERATE_TH_CFG_REG,
+ chg->flash_derating_soc);
+ if (rc < 0) {
+ pr_err("Couldn't configure SOC for flash derating rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ if (chg->flash_disable_soc != -EINVAL) {
+ rc = smblib_write(chg, SCHGM_SOC_BASED_FLASH_DISABLE_TH_CFG_REG,
+ chg->flash_disable_soc);
+ if (rc < 0) {
+ pr_err("Couldn't configure SOC for flash disable rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ if (chg->headroom_mode != -EINVAL) {
+ /*
+ * configure headroom management policy for
+ * flash and torch mode.
+ */
+ reg = (chg->headroom_mode == FIXED_MODE)
+ ? FORCE_FLASH_BOOST_5V_BIT : 0;
+ rc = smblib_write(chg, SCHGM_FORCE_BOOST_CONTROL, reg);
+ if (rc < 0) {
+ pr_err("Couldn't write force boost control reg rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ reg = (chg->headroom_mode == FIXED_MODE)
+ ? TORCH_PRIORITY_CONTROL_BIT : 0;
+ rc = smblib_write(chg, SCHGM_TORCH_PRIORITY_CONTROL, reg);
+ if (rc < 0) {
+ pr_err("Couldn't force 5V boost in torch mode rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ if ((chg->flash_derating_soc != -EINVAL)
+ || (chg->flash_disable_soc != -EINVAL)) {
+ /* Check if SOC based derating/disable is enabled */
+ rc = smblib_read(chg, SCHGM_FLASH_CONTROL_REG, ®);
+ if (rc < 0) {
+ pr_err("Couldn't read flash control reg rc=%d\n", rc);
+ return rc;
+ }
+ if (!(reg & SOC_LOW_FOR_FLASH_EN_BIT))
+ pr_warn("Soc based flash derating not enabled\n");
+ }
+
+ chg->flash_init_done = true;
+
+ return 0;
+}
diff --git a/drivers/power/supply/qcom/schgm-flash.h b/drivers/power/supply/qcom/schgm-flash.h
new file mode 100644
index 0000000..b6fff6c
--- /dev/null
+++ b/drivers/power/supply/qcom/schgm-flash.h
@@ -0,0 +1,54 @@
+/* Copyright (c) 2018 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 __SCHGM_FLASH_H__
+#define __SCHGM_FLASH_H__
+
+#include <linux/bitops.h>
+
+#define SCHGM_FLASH_BASE 0xA600
+
+#define SCHGM_FLASH_STATUS_2_REG (SCHGM_FLASH_BASE + 0x07)
+#define VREG_OK_BIT BIT(4)
+
+#define SCHGM_FLASH_STATUS_3_REG (SCHGM_FLASH_BASE + 0x08)
+#define FLASH_STATE_MASK GENMASK(2, 0)
+#define FLASH_ERROR_VAL 0x7
+
+#define SCHGM_FLASH_INT_RT_STS_REG (SCHGM_FLASH_BASE + 0x10)
+
+#define SCHGM_FLASH_STATUS_5_REG (SCHGM_FLASH_BASE + 0x0B)
+
+#define SCHGM_FORCE_BOOST_CONTROL (SCHGM_FLASH_BASE + 0x41)
+#define FORCE_FLASH_BOOST_5V_BIT BIT(0)
+
+#define SCHGM_FLASH_S2_LATCH_RESET_CMD_REG (SCHGM_FLASH_BASE + 0x44)
+#define FLASH_S2_LATCH_RESET_BIT BIT(0)
+
+#define SCHGM_FLASH_CONTROL_REG (SCHGM_FLASH_BASE + 0x60)
+#define SOC_LOW_FOR_FLASH_EN_BIT BIT(7)
+
+#define SCHGM_TORCH_PRIORITY_CONTROL (SCHGM_FLASH_BASE + 0x63)
+#define TORCH_PRIORITY_CONTROL_BIT BIT(0)
+
+#define SCHGM_SOC_BASED_FLASH_DERATE_TH_CFG_REG (SCHGM_FLASH_BASE + 0x67)
+
+#define SCHGM_SOC_BASED_FLASH_DISABLE_TH_CFG_REG \
+ (SCHGM_FLASH_BASE + 0x68)
+
+int schgm_flash_get_vreg_ok(struct smb_charger *chg, int *val);
+int schgm_flash_init(struct smb_charger *chg);
+
+irqreturn_t schgm_flash_default_irq_handler(int irq, void *data);
+irqreturn_t schgm_flash_ilim2_irq_handler(int irq, void *data);
+irqreturn_t schgm_flash_state_change_irq_handler(int irq, void *data);
+#endif /* __SCHGM_FLASH_H__ */
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 496a276..fe7ae5f 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -688,6 +688,7 @@
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
+ vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
cancel_delayed_work_sync(&chg->hvdcp_detect_work);
@@ -2245,11 +2246,15 @@
pr_err("Failed to force 5V\n");
break;
case POWER_SUPPLY_DP_DM_FORCE_9V:
+ /* Force 1A ICL before requesting higher voltage */
+ vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, true, 1000000);
rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT);
if (rc < 0)
pr_err("Failed to force 9V\n");
break;
case POWER_SUPPLY_DP_DM_FORCE_12V:
+ /* Force 1A ICL before requesting higher voltage */
+ vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, true, 1000000);
rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT);
if (rc < 0)
pr_err("Failed to force 12V\n");
@@ -3607,10 +3612,12 @@
case QC_9V_BIT:
smblib_set_opt_freq_buck(chg,
chg->chg_freq.freq_9V);
+ vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
break;
case QC_12V_BIT:
smblib_set_opt_freq_buck(chg,
chg->chg_freq.freq_12V);
+ vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
break;
default:
smblib_set_opt_freq_buck(chg,
@@ -3817,13 +3824,11 @@
switch (apsd_result->bit) {
case SDP_CHARGER_BIT:
case CDP_CHARGER_BIT:
- if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
- extcon_set_cable_state_(chg->extcon, EXTCON_USB,
- true);
- /* if not DCP then no hvdcp timeout happens. Enable pd here */
+ /* if not DCP, Enable pd here */
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
false, 0);
- if (chg->use_extcon)
+ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB
+ || chg->use_extcon)
smblib_notify_device_mode(chg, true);
break;
case OCP_CHARGER_BIT:
@@ -4133,6 +4138,7 @@
vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
vote(chg->usb_icl_votable, CTM_VOTER, false, 0);
+ vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
/* reset hvdcp voters */
vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
@@ -4805,7 +4811,7 @@
if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
smblib_err(chg, "VCONN failed to enable after %d attempts\n",
- chg->otg_attempts - 1);
+ chg->vconn_attempts - 1);
chg->vconn_en = false;
chg->vconn_attempts = 0;
goto unlock;
@@ -4829,14 +4835,7 @@
chg->vconn_attempts = 0;
goto unlock;
}
-
smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
- if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
- smblib_err(chg, "VCONN failed to enable after %d attempts\n",
- chg->vconn_attempts - 1);
- chg->vconn_en = false;
- goto unlock;
- }
rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
if (rc < 0) {
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 00a4086..32f2b4d 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -69,6 +69,7 @@
#define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER"
#define WBC_VOTER "WBC_VOTER"
#define MOISTURE_VOTER "MOISTURE_VOTER"
+#define HVDCP2_ICL_VOTER "HVDCP2_ICL_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c
index dfedece..63d57fe 100644
--- a/drivers/power/supply/qcom/smb1351-charger.c
+++ b/drivers/power/supply/qcom/smb1351-charger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018 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
@@ -15,6 +15,7 @@
#include <linux/i2c.h>
#include <linux/debugfs.h>
#include <linux/errno.h>
+#include <linux/extcon.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -376,6 +377,7 @@
#define USB2_MAX_CURRENT_MA 500
#define USB3_MIN_CURRENT_MA 150
#define USB3_MAX_CURRENT_MA 900
+#define DCP_MAX_CURRENT_MA 1500
#define SMB1351_IRQ_REG_COUNT 8
#define SMB1351_CHG_PRE_MIN_MA 100
#define SMB1351_CHG_FAST_MIN_MA 1000
@@ -424,6 +426,12 @@
[SMB1351] = "SMB1351",
};
+static const unsigned int smb1351_extcon_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_NONE,
+};
+
struct smb1351_charger {
struct i2c_client *client;
struct device *dev;
@@ -472,6 +480,7 @@
enum chip_version version;
/* psy */
+ struct power_supply_desc usb_psy_d;
struct power_supply *usb_psy;
int usb_psy_ma;
struct power_supply *bms_psy;
@@ -505,6 +514,12 @@
/* pinctrl parameters */
const char *pinctrl_state_name;
struct pinctrl *smb_pinctrl;
+
+ /* standalone */
+ bool charger_present;
+ struct extcon_dev *extcon;
+ struct regulator *dpdm_reg;
+ enum power_supply_type charger_type;
};
struct smb_irq_info {
@@ -633,6 +648,65 @@
return rc;
}
+static int smb1351_get_closest_usb_setpoint(int val)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(usb_chg_current) - 1; i >= 0; i--) {
+ if (usb_chg_current[i] <= val)
+ break;
+ }
+ if (i < 0)
+ i = 0;
+
+ if (i >= ARRAY_SIZE(usb_chg_current) - 1)
+ return ARRAY_SIZE(usb_chg_current) - 1;
+
+ /* check what is closer, i or i + 1 */
+ if (abs(usb_chg_current[i] - val) < abs(usb_chg_current[i + 1] - val))
+ return i;
+ else
+ return i + 1;
+}
+
+static int smb1351_request_dpdm(struct smb1351_charger *chip, bool enable)
+{
+ int rc = 0;
+
+ /* fetch the DPDM regulator */
+ if (!chip->dpdm_reg && of_get_property(chip->dev->of_node,
+ "dpdm-supply", NULL)) {
+ chip->dpdm_reg = devm_regulator_get(chip->dev, "dpdm");
+ if (IS_ERR(chip->dpdm_reg)) {
+ rc = PTR_ERR(chip->dpdm_reg);
+ pr_err("Couldn't get dpdm regulator rc=%d\n",
+ rc);
+ chip->dpdm_reg = NULL;
+ return rc;
+ }
+ }
+
+ if (enable) {
+ if (chip->dpdm_reg && !regulator_is_enabled(chip->dpdm_reg)) {
+ pr_err("enabling DPDM regulator\n");
+ rc = regulator_enable(chip->dpdm_reg);
+ if (rc < 0)
+ pr_err("Couldn't enable dpdm regulator rc=%d\n",
+ rc);
+ }
+ } else {
+ if (chip->dpdm_reg && regulator_is_enabled(chip->dpdm_reg)) {
+ pr_err("disabling DPDM regulator\n");
+ rc = regulator_disable(chip->dpdm_reg);
+ if (rc < 0)
+ pr_err("Couldn't disable dpdm regulator rc=%d\n",
+ rc);
+ }
+ }
+
+ return rc;
+}
+
static int smb1351_usb_suspend(struct smb1351_charger *chip, int reason,
bool suspend)
{
@@ -1290,6 +1364,75 @@
return rc;
}
+static char *smb1351_usb_supplicants[] = {
+ "bms",
+};
+
+static enum power_supply_property smb1351_usb_properties[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_TYPE,
+};
+
+static int smb1351_usb_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct smb1351_charger *chip = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = chip->usb_psy_ma * 1000;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = chip->chg_present;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = chip->chg_present && !chip->usb_suspended_status;
+ break;
+ case POWER_SUPPLY_PROP_TYPE:
+ val->intval = chip->charger_type;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int smb1351_usb_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct smb1351_charger *chip = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ chip->usb_psy_ma = val->intval / 1000;
+ smb1351_enable_volatile_writes(chip);
+ smb1351_set_usb_chg_current(chip, chip->usb_psy_ma);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ power_supply_changed(psy);
+ return 0;
+}
+
+static int smb1351_usb_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int smb1351_batt_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
@@ -1535,27 +1678,6 @@
return 0;
}
-static int smb1351_get_closest_usb_setpoint(int val)
-{
- int i;
-
- for (i = ARRAY_SIZE(usb_chg_current) - 1; i >= 0; i--) {
- if (usb_chg_current[i] <= val)
- break;
- }
- if (i < 0)
- i = 0;
-
- if (i >= ARRAY_SIZE(usb_chg_current) - 1)
- return ARRAY_SIZE(usb_chg_current) - 1;
-
- /* check what is closer, i or i + 1 */
- if (abs(usb_chg_current[i] - val) < abs(usb_chg_current[i + 1] - val))
- return i;
- else
- return i + 1;
-}
-
static bool smb1351_is_input_current_limited(struct smb1351_charger *chip)
{
int rc;
@@ -2001,10 +2123,10 @@
static int smb1351_apsd_complete_handler(struct smb1351_charger *chip,
u8 status)
{
- int rc;
+ int rc, usb_psy_ma = 0;
u8 reg = 0;
- union power_supply_propval prop = {0, };
enum power_supply_type type = POWER_SUPPLY_TYPE_UNKNOWN;
+ union extcon_property_value val;
/*
* If apsd is disabled, charger detection is done by
@@ -2055,18 +2177,12 @@
type, chip->chg_present);
if (!chip->battery_missing && !chip->apsd_rerun) {
if (type == POWER_SUPPLY_TYPE_USB) {
- pr_debug("Setting usb psy dp=f dm=f SDP and rerun\n");
- prop.intval = POWER_SUPPLY_DP_DM_DPF_DMF;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_DP_DM, &prop);
+ smb1351_request_dpdm(chip, false);
+ smb1351_request_dpdm(chip, true);
chip->apsd_rerun = true;
rerun_apsd(chip);
return 0;
}
- pr_debug("Set usb psy dp=f dm=f DCP and no rerun\n");
- prop.intval = POWER_SUPPLY_DP_DM_DPF_DMF;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_DP_DM, &prop);
}
/*
* If defined force hvdcp 2p0 property,
@@ -2087,35 +2203,33 @@
msecs_to_jiffies(HVDCP_NOTIFY_MS));
}
- prop.intval = type;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_TYPE, &prop);
- /*
- * SMB is now done sampling the D+/D- lines,
- * indicate USB driver
- */
- pr_debug("updating usb_psy present=%d\n", chip->chg_present);
- prop.intval = chip->chg_present;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_PRESENT,
- &prop);
+ chip->charger_type = type;
+ if (type == POWER_SUPPLY_TYPE_USB
+ || type == POWER_SUPPLY_TYPE_USB_CDP) {
+ val.intval = true;
+ extcon_set_property(chip->extcon, EXTCON_USB,
+ EXTCON_PROP_USB_SS, val);
+ extcon_set_cable_state_(chip->extcon, EXTCON_USB, true);
+ }
chip->apsd_rerun = false;
+
+ /* set the charge current as required */
+ if (type == POWER_SUPPLY_TYPE_USB)
+ usb_psy_ma = USB2_MIN_CURRENT_MA;
+ else /* DCP */
+ usb_psy_ma = DCP_MAX_CURRENT_MA;
+
+ chip->usb_psy_ma = usb_psy_ma;
+ smb1351_enable_volatile_writes(chip);
+ rc = smb1351_set_usb_chg_current(chip, chip->usb_psy_ma);
+ if (rc < 0)
+ pr_err("Failed to set USB current rc=%d\n", rc);
+
} else if (!chip->apsd_rerun) {
/* Handle Charger removal */
- prop.intval = POWER_SUPPLY_TYPE_UNKNOWN;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_TYPE, &prop);
-
- chip->chg_present = false;
- prop.intval = chip->chg_present;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_PRESENT,
- &prop);
-
- pr_debug("Set usb psy dm=r df=r\n");
- prop.intval = POWER_SUPPLY_DP_DM_DPR_DMR;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_DP_DM, &prop);
+ chip->charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
+ extcon_set_cable_state_(chip->extcon, EXTCON_USB, false);
+ smb1351_request_dpdm(chip, false);
}
return 0;
@@ -2163,42 +2277,7 @@
static int smb1351_usbin_uv_handler(struct smb1351_charger *chip, u8 status)
{
- union power_supply_propval pval = {0, };
-
- /* use this to detect USB insertion only if !apsd */
- if (chip->disable_apsd) {
- /*
- * If APSD is disabled, src det interrupt won't trigger.
- * Hence use usbin_uv for removal and insertion notification
- */
- if (status == 0) {
- chip->chg_present = true;
- pr_debug("updating usb_psy present=%d\n",
- chip->chg_present);
- pval.intval = POWER_SUPPLY_TYPE_USB;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_TYPE, &pval);
-
- pval.intval = chip->chg_present;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_PRESENT,
- &pval);
- } else {
- chip->chg_present = false;
-
- pval.intval = POWER_SUPPLY_TYPE_UNKNOWN;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_TYPE, &pval);
-
- pr_debug("updating usb_psy present=%d\n",
- chip->chg_present);
- pval.intval = chip->chg_present;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_PRESENT,
- &pval);
- }
- return 0;
- }
+ smb1351_request_dpdm(chip, !!status);
if (status) {
cancel_delayed_work_sync(&chip->hvdcp_det_work);
@@ -2218,24 +2297,19 @@
{
int rc;
u8 reg = 0;
- union power_supply_propval pval = {0, };
rc = smb1351_read_reg(chip, IRQ_E_REG, ®);
if (rc)
pr_err("Couldn't read IRQ_E rc = %d\n", rc);
if (status != 0) {
- chip->chg_present = false;
chip->usbin_ov = true;
+ chip->charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
+ if (chip->chg_present)
+ extcon_set_cable_state_(chip->extcon, EXTCON_USB,
+ false);
+ chip->chg_present = false;
- pval.intval = POWER_SUPPLY_TYPE_UNKNOWN;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_TYPE, &pval);
-
- pval.intval = chip->chg_present;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_PRESENT,
- &pval);
} else {
chip->usbin_ov = false;
if (reg & IRQ_USBIN_UV_BIT)
@@ -2244,13 +2318,6 @@
smb1351_apsd_complete_handler(chip, 1);
}
- if (chip->usb_psy) {
- pval.intval = status ? POWER_SUPPLY_HEALTH_OVERVOLTAGE
- : POWER_SUPPLY_HEALTH_GOOD;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_HEALTH, &pval);
- pr_debug("chip ov status is %d\n", pval.intval);
- }
pr_debug("chip->chg_present = %d\n", chip->chg_present);
return 0;
@@ -2319,6 +2386,21 @@
return 0;
}
+static int smb1351_rid_handler(struct smb1351_charger *chip,
+ u8 status)
+{
+ union extcon_property_value val;
+
+ if (!!status) {
+ val.intval = true;
+ extcon_set_property(chip->extcon, EXTCON_USB_HOST,
+ EXTCON_PROP_USB_SS, val);
+ }
+ extcon_set_cable_state_(chip->extcon, EXTCON_USB_HOST, !!status);
+
+ return 0;
+}
+
static struct irq_handler_info handlers[] = {
[0] = {
.stat_reg = IRQ_A_REG,
@@ -2413,6 +2495,7 @@
{ .name = "otg_oc_retry",
},
{ .name = "rid",
+ .smb_irq = smb1351_rid_handler,
},
{ .name = "otg_fail",
},
@@ -2524,30 +2607,21 @@
{
struct smb1351_charger *chip = power_supply_get_drvdata(psy);
union power_supply_propval prop = {0,};
- int rc, current_limit = 0, online = 0;
+ int rc, current_limit = 0;
if (chip->bms_psy_name)
chip->bms_psy =
power_supply_get_by_name((char *)chip->bms_psy_name);
rc = power_supply_get_property(chip->usb_psy,
- POWER_SUPPLY_PROP_ONLINE, &prop);
- if (rc)
- pr_err("Couldn't read USB online property, rc=%d\n", rc);
- else
- online = prop.intval;
-
- rc = power_supply_get_property(chip->usb_psy,
POWER_SUPPLY_PROP_CURRENT_MAX, &prop);
if (rc)
pr_err("Couldn't read USB current_max property, rc=%d\n", rc);
else
current_limit = prop.intval / 1000;
- pr_debug("online = %d, current_limit = %d\n", online, current_limit);
+ pr_debug("current_limit = %d\n", current_limit);
- smb1351_enable_volatile_writes(chip);
- smb1351_set_usb_chg_current(chip, current_limit);
pr_debug("updating batt psy\n");
}
@@ -3002,28 +3076,65 @@
{
int rc;
struct smb1351_charger *chip;
- struct power_supply *usb_psy;
struct power_supply_config batt_psy_cfg = {};
+ struct power_supply_config usb_psy_cfg = {};
u8 reg = 0;
- usb_psy = power_supply_get_by_name("usb");
- if (!usb_psy) {
- pr_debug("USB psy not found; deferring probe\n");
- return -EPROBE_DEFER;
- }
-
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->client = client;
chip->dev = &client->dev;
- chip->usb_psy = usb_psy;
chip->fake_battery_soc = -EINVAL;
+
+ chip->extcon = devm_extcon_dev_allocate(chip->dev,
+ smb1351_extcon_cable);
+ if (IS_ERR(chip->extcon)) {
+ pr_err("failed to allocate extcon device\n");
+ rc = PTR_ERR(chip->extcon);
+ return rc;
+ }
+
+ rc = devm_extcon_dev_register(chip->dev, chip->extcon);
+ if (rc) {
+ pr_err("failed to register extcon device\n");
+ return rc;
+ }
+
+ rc = extcon_set_property_capability(chip->extcon,
+ EXTCON_USB, EXTCON_PROP_USB_SS);
+ rc |= extcon_set_property_capability(chip->extcon,
+ EXTCON_USB_HOST, EXTCON_PROP_USB_SS);
+ if (rc < 0) {
+ pr_err("Failed to register extcon capability rc=%d\n", rc);
+ return rc;
+ }
+
+ chip->usb_psy_d.name = "usb";
+ chip->usb_psy_d.type = POWER_SUPPLY_TYPE_USB;
+ chip->usb_psy_d.get_property = smb1351_usb_get_property;
+ chip->usb_psy_d.set_property = smb1351_usb_set_property;
+ chip->usb_psy_d.properties = smb1351_usb_properties;
+ chip->usb_psy_d.num_properties = ARRAY_SIZE(smb1351_usb_properties);
+ chip->usb_psy_d.property_is_writeable = smb1351_usb_is_writeable;
+
+ usb_psy_cfg.drv_data = chip;
+ usb_psy_cfg.supplied_to = smb1351_usb_supplicants;
+ usb_psy_cfg.num_supplicants = ARRAY_SIZE(smb1351_usb_supplicants);
+
+ chip->usb_psy = devm_power_supply_register(chip->dev,
+ &chip->usb_psy_d, &usb_psy_cfg);
+ if (IS_ERR(chip->usb_psy)) {
+ pr_err("Unable to register usb_psy rc = %ld\n",
+ PTR_ERR(chip->usb_psy));
+ rc = PTR_ERR(chip->usb_psy);
+ return rc;
+ }
+
INIT_DELAYED_WORK(&chip->chg_remove_work, smb1351_chg_remove_work);
INIT_DELAYED_WORK(&chip->hvdcp_det_work, smb1351_hvdcp_det_work);
device_init_wakeup(chip->dev, true);
-
/* probe the device to check if its actually connected */
rc = smb1351_read_reg(chip, CHG_REVISION_REG, ®);
if (rc) {
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
index dbadd95..d20607c 100644
--- a/drivers/power/supply/qcom/smb5-lib.c
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -62,11 +62,15 @@
return regmap_write(chg->regmap, addr, val);
}
+int smblib_batch_write(struct smb_charger *chg, u16 addr, u8 *val,
+ int count)
+{
+ return regmap_bulk_write(chg->regmap, addr, val, count);
+}
+
int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val)
{
-
return regmap_update_bits(chg->regmap, addr, mask, val);
-
}
int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
@@ -707,20 +711,21 @@
int rc;
union power_supply_propval val;
- if (!chg->suspend_input_on_debug_batt)
- return;
-
rc = power_supply_get_property(chg->bms_psy,
POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
if (rc < 0) {
smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc);
return;
}
-
- vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
- vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
- if (val.intval)
- pr_info("Input suspended: Fake battery\n");
+ if (chg->suspend_input_on_debug_batt) {
+ vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
+ vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
+ if (val.intval)
+ pr_info("Input suspended: Fake battery\n");
+ } else {
+ vote(chg->chg_disable_votable, DEBUG_BOARD_VOTER,
+ val.intval, 0);
+ }
}
int smblib_rerun_apsd_if_required(struct smb_charger *chg)
@@ -1204,6 +1209,7 @@
val->intval = POWER_SUPPLY_STATUS_FULL;
break;
case DISABLE_CHARGE:
+ case PAUSE_CHARGE:
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
break;
default:
diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h
index fa7381c..335764e 100644
--- a/drivers/power/supply/qcom/smb5-lib.h
+++ b/drivers/power/supply/qcom/smb5-lib.h
@@ -70,6 +70,8 @@
#define BOOST_BACK_STORM_COUNT 3
#define WEAK_CHG_STORM_COUNT 8
+#define VBAT_TO_VRAW_ADC(v) div_u64((u64)v * 1000000UL, 194637UL)
+
enum smb_mode {
PARALLEL_MASTER = 0,
PARALLEL_SLAVE,
@@ -143,6 +145,15 @@
IMP_TRIGGER_IRQ,
TEMP_CHANGE_IRQ,
TEMP_CHANGE_SMB_IRQ,
+ /* FLASH */
+ VREG_OK_IRQ,
+ ILIM_S2_IRQ,
+ ILIM_S1_IRQ,
+ VOUT_DOWN_IRQ,
+ VOUT_UP_IRQ,
+ FLASH_STATE_CHANGE_IRQ,
+ TORCH_REQ_IRQ,
+ FLASH_EN_IRQ,
/* END */
SMB_IRQ_MAX,
};
@@ -335,6 +346,7 @@
bool use_extcon;
bool otg_present;
int hw_max_icl_ua;
+ int auto_recharge_soc;
/* workaround flag */
u32 wa_flags;
@@ -351,11 +363,20 @@
int pulse_cnt;
int die_health;
+
+ /* flash */
+ u32 flash_derating_soc;
+ u32 flash_disable_soc;
+ u32 headroom_mode;
+ bool flash_init_done;
+ bool flash_active;
};
int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val);
int smblib_write(struct smb_charger *chg, u16 addr, u8 val);
+int smblib_batch_write(struct smb_charger *chg, u16 addr, u8 *val, int count);
+int smblib_batch_read(struct smb_charger *chg, u16 addr, u8 *val, int count);
int smblib_get_charge_param(struct smb_charger *chg,
struct smb_chg_param *param, int *val_u);
diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h
index 9a418c8..afc45ab 100644
--- a/drivers/power/supply/qcom/smb5-reg.h
+++ b/drivers/power/supply/qcom/smb5-reg.h
@@ -66,11 +66,17 @@
#define CHARGING_ENABLE_CMD_BIT BIT(0)
#define CHGR_CFG2_REG (CHGR_BASE + 0x51)
-#define SOC_BASED_RECHG_BIT BIT(1)
+#define RECHG_MASK GENMASK(2, 1)
+#define VBAT_BASED_RECHG_BIT BIT(2)
+#define SOC_BASED_RECHG_BIT GENMASK(2, 1)
#define CHARGER_INHIBIT_BIT BIT(0)
#define CHGR_FAST_CHARGE_CURRENT_CFG_REG (CHGR_BASE + 0x61)
+#define CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG (CHGR_BASE + 0x6B)
+#define NO_OF_SAMPLE_FOR_RCHG_SHIFT 2
+#define NO_OF_SAMPLE_FOR_RCHG GENMASK(3, 2)
+
#define CHGR_FLOAT_VOLTAGE_CFG_REG (CHGR_BASE + 0x70)
#define CHARGE_INHIBIT_THRESHOLD_CFG_REG (CHGR_BASE + 0x72)
@@ -80,6 +86,12 @@
#define INHIBIT_ANALOG_VFLT_MINUS_200MV 2
#define INHIBIT_ANALOG_VFLT_MINUS_300MV 3
+#define CHARGE_RCHG_SOC_THRESHOLD_CFG_REG (CHGR_BASE + 0x7D)
+
+#define CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG (CHGR_BASE + 0x7E)
+
+#define CHGR_ADC_RECHARGE_THRESHOLD_LSB_REG (CHGR_BASE + 0x7F)
+
#define JEITA_EN_CFG_REG (CHGR_BASE + 0x90)
#define JEITA_EN_HOT_SL_FCV_BIT BIT(3)
#define JEITA_EN_COLD_SL_FCV_BIT BIT(2)
diff --git a/drivers/pwm/pwm-qti-lpg.c b/drivers/pwm/pwm-qti-lpg.c
index 328f4b6..85a5ea0 100644
--- a/drivers/pwm/pwm-qti-lpg.c
+++ b/drivers/pwm/pwm-qti-lpg.c
@@ -28,6 +28,7 @@
#define REG_SIZE_PER_LPG 0x100
+#define REG_LPG_PERPH_SUBTYPE 0x05
#define REG_LPG_PWM_SIZE_CLK 0x41
#define REG_LPG_PWM_FREQ_PREDIV_CLK 0x42
#define REG_LPG_PWM_TYPE_CONFIG 0x43
@@ -36,9 +37,15 @@
#define REG_LPG_ENABLE_CONTROL 0x46
#define REG_LPG_PWM_SYNC 0x47
+/* REG_LPG_PERPH_SUBTYPE */
+#define SUBTYPE_PWM 0x0b
+#define SUBTYPE_LPG_LITE 0x11
+
/* REG_LPG_PWM_SIZE_CLK */
-#define LPG_PWM_SIZE_MASK BIT(4)
-#define LPG_PWM_SIZE_SHIFT 4
+#define LPG_PWM_SIZE_MASK_LPG BIT(4)
+#define LPG_PWM_SIZE_MASK_PWM BIT(2)
+#define LPG_PWM_SIZE_SHIFT_LPG 4
+#define LPG_PWM_SIZE_SHIFT_PWM 2
#define LPG_PWM_CLK_FREQ_SEL_MASK GENMASK(1, 0)
/* REG_LPG_PWM_FREQ_PREDIV_CLK */
@@ -95,6 +102,7 @@
u32 lpg_idx;
u32 reg_base;
u8 src_sel;
+ u8 subtype;
int current_period_ns;
int current_duty_ns;
};
@@ -108,6 +116,23 @@
u32 num_lpgs;
};
+static int qpnp_lpg_read(struct qpnp_lpg_channel *lpg, u16 addr, u8 *val)
+{
+ int rc;
+ unsigned int tmp;
+
+ mutex_lock(&lpg->chip->bus_lock);
+ rc = regmap_read(lpg->chip->regmap, lpg->reg_base + addr, &tmp);
+ if (rc < 0)
+ dev_err(lpg->chip->dev, "Read addr 0x%x failed, rc=%d\n",
+ lpg->reg_base + addr, rc);
+ else
+ *val = (u8)tmp;
+ mutex_unlock(&lpg->chip->bus_lock);
+
+ return rc;
+}
+
static int qpnp_lpg_write(struct qpnp_lpg_channel *lpg, u16 addr, u8 val)
{
int rc;
@@ -166,10 +191,24 @@
return -EINVAL;
}
+static int qpnp_lpg_set_glitch_removal(struct qpnp_lpg_channel *lpg, bool en)
+{
+ int rc;
+ u8 mask, val;
+
+ val = en ? LPG_PWM_EN_GLITCH_REMOVAL_MASK : 0;
+ mask = LPG_PWM_EN_GLITCH_REMOVAL_MASK;
+ rc = qpnp_lpg_masked_write(lpg, REG_LPG_PWM_TYPE_CONFIG, mask, val);
+ if (rc < 0)
+ dev_err(lpg->chip->dev, "Write LPG_PWM_TYPE_CONFIG failed, rc=%d\n",
+ rc);
+ return rc;
+}
+
static int qpnp_lpg_set_pwm_config(struct qpnp_lpg_channel *lpg)
{
int rc;
- u8 val, mask;
+ u8 val, mask, shift;
int pwm_size_idx, pwm_clk_idx, prediv_idx, clk_exp_idx;
pwm_size_idx = __find_index_in_array(lpg->pwm_config.pwm_size,
@@ -187,8 +226,16 @@
/* pwm_clk_idx is 1 bit lower than the register value */
pwm_clk_idx += 1;
- val = pwm_size_idx << LPG_PWM_SIZE_SHIFT | pwm_clk_idx;
- mask = LPG_PWM_SIZE_MASK | LPG_PWM_CLK_FREQ_SEL_MASK;
+ if (lpg->subtype == SUBTYPE_PWM) {
+ shift = LPG_PWM_SIZE_SHIFT_PWM;
+ mask = LPG_PWM_SIZE_MASK_PWM;
+ } else {
+ shift = LPG_PWM_SIZE_SHIFT_LPG;
+ mask = LPG_PWM_SIZE_MASK_LPG;
+ }
+
+ val = pwm_size_idx << shift | pwm_clk_idx;
+ mask |= LPG_PWM_CLK_FREQ_SEL_MASK;
rc = qpnp_lpg_masked_write(lpg, REG_LPG_PWM_SIZE_CLK, mask, val);
if (rc < 0) {
dev_err(lpg->chip->dev, "Write LPG_PWM_SIZE_CLK failed, rc=%d\n",
@@ -377,6 +424,13 @@
return -ENODEV;
}
+ rc = qpnp_lpg_set_glitch_removal(lpg, true);
+ if (rc < 0) {
+ dev_err(lpg->chip->dev, "Enable glitch-removal failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
mask = LPG_PWM_SRC_SELECT_MASK | LPG_EN_LPG_OUT_BIT;
val = lpg->src_sel << LPG_PWM_SRC_SELECT_SHIFT | LPG_EN_LPG_OUT_BIT;
@@ -405,9 +459,16 @@
val = lpg->src_sel << LPG_PWM_SRC_SELECT_SHIFT;
rc = qpnp_lpg_masked_write(lpg, REG_LPG_ENABLE_CONTROL, mask, val);
- if (rc < 0)
+ if (rc < 0) {
dev_err(pwm_chip->dev, "Disable PWM output failed for channel %d, rc=%d\n",
lpg->lpg_idx, rc);
+ return;
+ }
+
+ rc = qpnp_lpg_set_glitch_removal(lpg, false);
+ if (rc < 0)
+ dev_err(lpg->chip->dev, "Disable glitch-removal failed, rc=%d\n",
+ rc);
}
#ifdef CONFIG_DEBUG_FS
@@ -490,6 +551,12 @@
chip->lpgs[i].lpg_idx = i;
chip->lpgs[i].reg_base = base + i * REG_SIZE_PER_LPG;
chip->lpgs[i].src_sel = PWM_OUTPUT;
+ rc = qpnp_lpg_read(&chip->lpgs[i], REG_LPG_PERPH_SUBTYPE,
+ &chip->lpgs[i].subtype);
+ if (rc < 0) {
+ dev_err(chip->dev, "Read subtype failed, rc=%d\n", rc);
+ return rc;
+ }
}
return rc;
@@ -511,16 +578,15 @@
return -EINVAL;
}
+ mutex_init(&chip->bus_lock);
rc = qpnp_lpg_parse_dt(chip);
if (rc < 0) {
dev_err(chip->dev, "Devicetree properties parsing failed, rc=%d\n",
rc);
- return rc;
+ goto destroy;
}
dev_set_drvdata(chip->dev, chip);
-
- mutex_init(&chip->bus_lock);
chip->pwm_chip.dev = chip->dev;
chip->pwm_chip.base = -1;
chip->pwm_chip.npwm = chip->num_lpgs;
@@ -529,9 +595,12 @@
rc = pwmchip_add(&chip->pwm_chip);
if (rc < 0) {
dev_err(chip->dev, "Add pwmchip failed, rc=%d\n", rc);
- mutex_destroy(&chip->bus_lock);
+ goto destroy;
}
+ return 0;
+destroy:
+ mutex_destroy(&chip->bus_lock);
return rc;
}
diff --git a/drivers/regulator/cpr4-apss-regulator.c b/drivers/regulator/cpr4-apss-regulator.c
index a9602cb..1f8f8be 100644
--- a/drivers/regulator/cpr4-apss-regulator.c
+++ b/drivers/regulator/cpr4-apss-regulator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -36,9 +36,11 @@
#include "cpr3-regulator.h"
#define MSM8953_APSS_FUSE_CORNERS 4
+#define SDM632_POWER_APSS_FUSE_CORNERS 5
+#define SDM632_PERF_APSS_FUSE_CORNERS 3
/**
- * struct cpr4_msm8953_apss_fuses - APSS specific fuse data for MSM8953
+ * struct cpr4_apss_fuses - APSS specific fuse data
* @ro_sel: Ring oscillator select fuse parameter value for each
* fuse corner
* @init_voltage: Initial (i.e. open-loop) voltage fuse parameter value
@@ -61,11 +63,11 @@
*
* This struct holds the values for all of the fuses read from memory.
*/
-struct cpr4_msm8953_apss_fuses {
- u64 ro_sel[MSM8953_APSS_FUSE_CORNERS];
- u64 init_voltage[MSM8953_APSS_FUSE_CORNERS];
- u64 target_quot[MSM8953_APSS_FUSE_CORNERS];
- u64 quot_offset[MSM8953_APSS_FUSE_CORNERS];
+struct cpr4_apss_fuses {
+ u64 *ro_sel;
+ u64 *init_voltage;
+ u64 *target_quot;
+ u64 *quot_offset;
u64 speed_bin;
u64 cpr_fusing_rev;
u64 foundry_id;
@@ -80,6 +82,7 @@
* where: fusing revision = 0 - 7 and speed bin = 0 - 7
*/
#define CPR4_MSM8953_APSS_FUSE_COMBO_COUNT 64
+#define CPR4_SDM632_APSS_FUSE_COMBO_COUNT 64
/*
* Constants which define the name of each fuse corner.
@@ -98,6 +101,38 @@
[CPR4_MSM8953_APSS_FUSE_CORNER_TURBO_L1] = "TURBO_L1",
};
+enum cpr4_sdm632_power_apss_fuse_corner {
+ CPR4_SDM632_POWER_APSS_FUSE_CORNER_LOWSVS = 0,
+ CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS = 1,
+ CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS_L1 = 2,
+ CPR4_SDM632_POWER_APSS_FUSE_CORNER_NOM = 3,
+ CPR4_SDM632_POWER_APSS_FUSE_CORNER_TURBO_L1 = 4,
+};
+
+static const char * const cpr4_sdm632_power_apss_fuse_corner_name[] = {
+ [CPR4_SDM632_POWER_APSS_FUSE_CORNER_LOWSVS] = "LowSVS",
+ [CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS] = "SVS",
+ [CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS_L1] = "SVS_L1",
+ [CPR4_SDM632_POWER_APSS_FUSE_CORNER_NOM] = "NOM",
+ [CPR4_SDM632_POWER_APSS_FUSE_CORNER_TURBO_L1] = "TURBO_L1",
+};
+
+enum cpr4_sdm632_perf_apss_fuse_corner {
+ CPR4_SDM632_PERF_APSS_FUSE_CORNER_SVS_L1 = 0,
+ CPR4_SDM632_PERF_APSS_FUSE_CORNER_NOM = 1,
+ CPR4_SDM632_PERF_APSS_FUSE_CORNER_TURBO_L1 = 2,
+};
+
+static const char * const cpr4_sdm632_perf_apss_fuse_corner_name[] = {
+ [CPR4_SDM632_PERF_APSS_FUSE_CORNER_SVS_L1] = "SVS_L1",
+ [CPR4_SDM632_PERF_APSS_FUSE_CORNER_NOM] = "NOM",
+ [CPR4_SDM632_PERF_APSS_FUSE_CORNER_TURBO_L1] = "TURBO_L1",
+};
+
+/* APSS cluster thread IDs */
+#define CPR4_APSS_POWER_CLUSTER_ID 0
+#define CPR4_APSS_PERF_CLUSTER_ID 1
+
/*
* MSM8953 APSS fuse parameter locations:
*
@@ -179,12 +214,88 @@
};
/*
+ * SDM632 APSS fuse parameter locations:
+ *
+ * Structs are organized with the following dimensions:
+ * Outer: 0 to 3 for fuse corners from lowest to highest corner
+ * Inner: large enough to hold the longest set of parameter segments which
+ * fully defines a fuse parameter, +1 (for NULL termination).
+ * Each segment corresponds to a contiguous group of bits from a
+ * single fuse row. These segments are concatentated together in
+ * order to form the full fuse parameter value. The segments for
+ * a given parameter may correspond to different fuse rows.
+ */
+static const struct cpr3_fuse_param
+sdm632_apss_ro_sel_param[2][SDM632_POWER_APSS_FUSE_CORNERS][2] = {
+ [CPR4_APSS_POWER_CLUSTER_ID] = {
+ {{73, 28, 31}, {} },
+ {{73, 24, 27}, {} },
+ {{73, 20, 23}, {} },
+ {{73, 16, 19}, {} },
+ {{73, 12, 15}, {} },
+ },
+ [CPR4_APSS_PERF_CLUSTER_ID] = {
+ {{73, 8, 11}, {} },
+ {{73, 4, 7}, {} },
+ {{73, 0, 3}, {} },
+ },
+};
+
+static const struct cpr3_fuse_param
+sdm632_apss_init_voltage_param[2][SDM632_POWER_APSS_FUSE_CORNERS][2] = {
+ [CPR4_APSS_POWER_CLUSTER_ID] = {
+ {{74, 18, 23}, {} },
+ {{74, 12, 17}, {} },
+ {{71, 24, 29}, {} },
+ {{74, 6, 11}, {} },
+ {{74, 0, 5}, {} },
+ },
+ [CPR4_APSS_PERF_CLUSTER_ID] = {
+ {{71, 18, 23}, {} },
+ {{71, 12, 17}, {} },
+ {{71, 6, 11}, {} },
+ },
+};
+
+static const struct cpr3_fuse_param
+sdm632_apss_target_quot_param[2][SDM632_POWER_APSS_FUSE_CORNERS][2] = {
+ [CPR4_APSS_POWER_CLUSTER_ID] = {
+ {{75, 44, 55}, {} },
+ {{75, 32, 43}, {} },
+ {{72, 44, 55}, {} },
+ {{75, 20, 31}, {} },
+ {{75, 8, 19}, {} },
+ },
+ [CPR4_APSS_PERF_CLUSTER_ID] = {
+ {{72, 32, 43}, {} },
+ {{72, 20, 31}, {} },
+ {{72, 8, 19}, {} },
+ },
+};
+
+static const struct cpr3_fuse_param
+sdm632_apss_quot_offset_param[2][SDM632_POWER_APSS_FUSE_CORNERS][2] = {
+ [CPR4_APSS_POWER_CLUSTER_ID] = {
+ {{} },
+ {{74, 39, 45}, {} },
+ {{71, 46, 52}, {} },
+ {{74, 32, 38}, {} },
+ {{74, 24, 30}, {} },
+ },
+ [CPR4_APSS_PERF_CLUSTER_ID] = {
+ {{} },
+ {{71, 39, 45}, {} },
+ {{71, 32, 38}, {} },
+ },
+};
+
+/*
* The maximum number of fuse combinations possible for the selected fuse
* parameters in fuse combo map logic.
* Here, possible speed-bin values = 8, fuse revision values = 8, and foundry
* identifier values = 8. Total number of combinations = 512 (i.e., 8 * 8 * 8)
*/
-#define CPR4_MSM8953_APSS_FUSE_COMBO_MAP_MAX_COUNT 512
+#define CPR4_APSS_FUSE_COMBO_MAP_MAX_COUNT 512
/*
@@ -204,13 +315,37 @@
1065000,
};
-#define MSM8953_APSS_FUSE_STEP_VOLT 10000
-#define MSM8953_APSS_VOLTAGE_FUSE_SIZE 6
-#define MSM8953_APSS_QUOT_OFFSET_SCALE 5
+/*
+ * Open loop voltage fuse reference voltages in microvolts for SDM632
+ */
+static const int
+sdm632_apss_fuse_ref_volt[2][SDM632_POWER_APSS_FUSE_CORNERS] = {
+ [CPR4_APSS_POWER_CLUSTER_ID] = {
+ 645000,
+ 720000,
+ 790000,
+ 865000,
+ 1065000,
+ },
+ [CPR4_APSS_PERF_CLUSTER_ID] = {
+ 790000,
+ 865000,
+ 1065000,
+ },
+};
+
+#define CPR4_APSS_FUSE_STEP_VOLT 10000
+#define CPR4_APSS_VOLTAGE_FUSE_SIZE 6
+#define CPR4_APSS_QUOT_OFFSET_SCALE 5
#define MSM8953_APSS_CPR_SENSOR_COUNT 13
+#define SDM632_APSS_CPR_SENSOR_COUNT 16
+#define SDM632_APSS_THREAD0_SENSOR_MIN 0
+#define SDM632_APSS_THREAD0_SENSOR_MAX 6
+#define SDM632_APSS_THREAD1_SENSOR_MIN 7
+#define SDM632_APSS_THREAD1_SENSOR_MAX 15
-#define MSM8953_APSS_CPR_CLOCK_RATE 19200000
+#define CPR4_APSS_CPR_CLOCK_RATE 19200000
#define MSM8953_APSS_MAX_TEMP_POINTS 3
#define MSM8953_APSS_TEMP_SENSOR_ID_START 4
@@ -240,51 +375,31 @@
/* Use a very high value for max aging margin to be applied */
#define MSM8953_APSS_AGING_MAX_AGE_MARGIN_QUOT (-1000)
+/*
+ * SOC IDs
+ */
+enum soc_id {
+ MSM8953_SOC_ID = 1,
+ SDM632_SOC_ID = 2,
+};
+
/**
- * cpr4_msm8953_apss_read_fuse_data() - load APSS specific fuse parameter values
+ * cpr4_msm8953_apss_read_fuse_data() - load MSM8953 APSS specific fuse
+ * parameter values
* @vreg: Pointer to the CPR3 regulator
+ * @fuse: APSS specific fuse data
*
- * This function allocates a cpr4_msm8953_apss_fuses struct, fills it with
- * values read out of hardware fuses, and finally copies common fuse values
- * into the CPR3 regulator struct.
+ * This function fills cpr4_apss_fuses struct with values read out of hardware
+ * fuses.
*
* Return: 0 on success, errno on failure
*/
-static int cpr4_msm8953_apss_read_fuse_data(struct cpr3_regulator *vreg)
+static int cpr4_msm8953_apss_read_fuse_data(struct cpr3_regulator *vreg,
+ struct cpr4_apss_fuses *fuse)
{
void __iomem *base = vreg->thread->ctrl->fuse_base;
- struct cpr4_msm8953_apss_fuses *fuse;
int i, rc;
- fuse = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*fuse), GFP_KERNEL);
- if (!fuse)
- return -ENOMEM;
-
- rc = cpr3_read_fuse_param(base, msm8953_apss_speed_bin_param,
- &fuse->speed_bin);
- if (rc) {
- cpr3_err(vreg, "Unable to read speed bin fuse, rc=%d\n", rc);
- return rc;
- }
- cpr3_info(vreg, "speed bin = %llu\n", fuse->speed_bin);
-
- rc = cpr3_read_fuse_param(base, msm8953_cpr_fusing_rev_param,
- &fuse->cpr_fusing_rev);
- if (rc) {
- cpr3_err(vreg, "Unable to read CPR fusing revision fuse, rc=%d\n",
- rc);
- return rc;
- }
- cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev);
-
- rc = cpr3_read_fuse_param(base, msm8953_apss_foundry_id_param,
- &fuse->foundry_id);
- if (rc) {
- cpr3_err(vreg, "Unable to read foundry id fuse, rc=%d\n", rc);
- return rc;
- }
- cpr3_info(vreg, "foundry id = %llu\n", fuse->foundry_id);
-
rc = cpr3_read_fuse_param(base, msm8953_misc_fuse_volt_adj_param,
&fuse->misc);
if (rc) {
@@ -372,9 +487,180 @@
return -EINVAL;
}
+ return 0;
+}
+
+/**
+ * cpr4_sdm632_apss_read_fuse_data() - load SDM632 APSS specific fuse
+ * parameter values
+ * @vreg: Pointer to the CPR3 regulator
+ * @fuse: APSS specific fuse data
+ *
+ * This function fills cpr4_apss_fuses struct with values read out of hardware
+ * fuses.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cpr4_sdm632_apss_read_fuse_data(struct cpr3_regulator *vreg,
+ struct cpr4_apss_fuses *fuse)
+{
+ void __iomem *base = vreg->thread->ctrl->fuse_base;
+ int i, id, rc, fuse_corners;
+
+ id = vreg->thread->thread_id;
+ if (id == CPR4_APSS_POWER_CLUSTER_ID)
+ fuse_corners = SDM632_POWER_APSS_FUSE_CORNERS;
+ else
+ fuse_corners = SDM632_PERF_APSS_FUSE_CORNERS;
+
+ for (i = 0; i < fuse_corners; i++) {
+ rc = cpr3_read_fuse_param(base,
+ sdm632_apss_init_voltage_param[id][i],
+ &fuse->init_voltage[i]);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read fuse-corner %d initial voltage fuse, rc=%d\n",
+ i, rc);
+ return rc;
+ }
+
+ rc = cpr3_read_fuse_param(base,
+ sdm632_apss_target_quot_param[id][i],
+ &fuse->target_quot[i]);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read fuse-corner %d target quotient fuse, rc=%d\n",
+ i, rc);
+ return rc;
+ }
+
+ rc = cpr3_read_fuse_param(base,
+ sdm632_apss_ro_sel_param[id][i],
+ &fuse->ro_sel[i]);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read fuse-corner %d RO select fuse, rc=%d\n",
+ i, rc);
+ return rc;
+ }
+
+ rc = cpr3_read_fuse_param(base,
+ sdm632_apss_quot_offset_param[id][i],
+ &fuse->quot_offset[i]);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read fuse-corner %d quotient offset fuse, rc=%d\n",
+ i, rc);
+ return rc;
+ }
+ }
+
+ vreg->fuse_combo = fuse->cpr_fusing_rev + (8 * fuse->speed_bin);
+ if (vreg->fuse_combo >= CPR4_SDM632_APSS_FUSE_COMBO_COUNT) {
+ cpr3_err(vreg, "invalid CPR fuse combo = %d found\n",
+ vreg->fuse_combo);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * cpr4_apss_read_fuse_data() - load APSS specific fuse parameter values
+ * @vreg: Pointer to the CPR3 regulator
+ *
+ * This function allocates a cpr4_apss_fuses struct, fills it with
+ * values read out of hardware fuses, and finally copies common fuse values
+ * into the CPR3 regulator struct.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cpr4_apss_read_fuse_data(struct cpr3_regulator *vreg)
+{
+ void __iomem *base = vreg->thread->ctrl->fuse_base;
+ struct cpr4_apss_fuses *fuse;
+ int rc, fuse_corners;
+ enum soc_id soc_revision;
+
+ fuse = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*fuse), GFP_KERNEL);
+ if (!fuse)
+ return -ENOMEM;
+
+ soc_revision = vreg->thread->ctrl->soc_revision;
+ switch (soc_revision) {
+ case MSM8953_SOC_ID:
+ fuse_corners = MSM8953_APSS_FUSE_CORNERS;
+ break;
+ case SDM632_SOC_ID:
+ if (vreg->thread->thread_id == CPR4_APSS_POWER_CLUSTER_ID)
+ fuse_corners = SDM632_POWER_APSS_FUSE_CORNERS;
+ else
+ fuse_corners = SDM632_PERF_APSS_FUSE_CORNERS;
+ break;
+ default:
+ cpr3_err(vreg, "unsupported soc id = %d\n", soc_revision);
+ return -EINVAL;
+ }
+
+ fuse->ro_sel = devm_kcalloc(vreg->thread->ctrl->dev, fuse_corners,
+ sizeof(*fuse->ro_sel), GFP_KERNEL);
+ fuse->init_voltage = devm_kcalloc(vreg->thread->ctrl->dev, fuse_corners,
+ sizeof(*fuse->init_voltage), GFP_KERNEL);
+ fuse->target_quot = devm_kcalloc(vreg->thread->ctrl->dev, fuse_corners,
+ sizeof(*fuse->target_quot), GFP_KERNEL);
+ fuse->quot_offset = devm_kcalloc(vreg->thread->ctrl->dev, fuse_corners,
+ sizeof(*fuse->quot_offset), GFP_KERNEL);
+
+ if (!fuse->ro_sel || !fuse->init_voltage || !fuse->target_quot
+ || !fuse->quot_offset)
+ return -ENOMEM;
+
+ rc = cpr3_read_fuse_param(base, msm8953_apss_speed_bin_param,
+ &fuse->speed_bin);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read speed bin fuse, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = cpr3_read_fuse_param(base, msm8953_cpr_fusing_rev_param,
+ &fuse->cpr_fusing_rev);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read CPR fusing revision fuse, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = cpr3_read_fuse_param(base, msm8953_apss_foundry_id_param,
+ &fuse->foundry_id);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read foundry id fuse, rc=%d\n", rc);
+ return rc;
+ }
+ cpr3_info(vreg, "speed bin = %llu, CPR fusing revision = %llu, foundry id = %llu\n",
+ fuse->speed_bin, fuse->cpr_fusing_rev,
+ fuse->foundry_id);
+
+ switch (soc_revision) {
+ case MSM8953_SOC_ID:
+ rc = cpr4_msm8953_apss_read_fuse_data(vreg, fuse);
+ if (rc) {
+ cpr3_err(vreg, "msm8953 apss fuse data read failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+ break;
+ case SDM632_SOC_ID:
+ rc = cpr4_sdm632_apss_read_fuse_data(vreg, fuse);
+ if (rc) {
+ cpr3_err(vreg, "sdm632 apss fuse data read failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+ break;
+ default:
+ cpr3_err(vreg, "unsupported soc id = %d\n", soc_revision);
+ return -EINVAL;
+ }
+
vreg->speed_bin_fuse = fuse->speed_bin;
vreg->cpr_rev_fuse = fuse->cpr_fusing_rev;
- vreg->fuse_corner_count = MSM8953_APSS_FUSE_CORNERS;
+ vreg->fuse_corner_count = fuse_corners;
vreg->platform_fuses = fuse;
return 0;
@@ -426,7 +712,7 @@
struct cpr3_regulator *vreg, u32 *volt_adjust)
{
struct device_node *node = vreg->of_node;
- struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses;
+ struct cpr4_apss_fuses *fuse = vreg->platform_fuses;
int tuple_list_size = MSM8953_MISC_FUSE_VAL_COUNT;
int i, offset, rc, len = 0;
const char *prop_name = "qcom,cpr-misc-fuse-voltage-adjustment";
@@ -473,7 +759,7 @@
}
/**
- * cpr4_msm8953_apss_calculate_open_loop_voltages() - calculate the open-loop
+ * cpr4_apss_calculate_open_loop_voltages() - calculate the open-loop
* voltage for each corner of a CPR3 regulator
* @vreg: Pointer to the CPR3 regulator
*
@@ -489,16 +775,18 @@
*
* Return: 0 on success, errno on failure
*/
-static int cpr4_msm8953_apss_calculate_open_loop_voltages(
- struct cpr3_regulator *vreg)
+static int cpr4_apss_calculate_open_loop_voltages(struct cpr3_regulator *vreg)
{
struct device_node *node = vreg->of_node;
- struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses;
- int i, j, rc = 0;
+ struct cpr4_apss_fuses *fuse = vreg->platform_fuses;
+ int i, j, id, rc = 0;
bool allow_interpolation;
u64 freq_low, volt_low, freq_high, volt_high;
+ const int *ref_volt;
int *fuse_volt, *misc_adj_volt;
int *fmax_corner;
+ const char * const *corner_name;
+ enum soc_id soc_revision;
fuse_volt = kcalloc(vreg->fuse_corner_count, sizeof(*fuse_volt),
GFP_KERNEL);
@@ -509,15 +797,34 @@
goto done;
}
+ id = vreg->thread->thread_id;
+ soc_revision = vreg->thread->ctrl->soc_revision;
+
+ switch (soc_revision) {
+ case MSM8953_SOC_ID:
+ ref_volt = msm8953_apss_fuse_ref_volt;
+ corner_name = cpr4_msm8953_apss_fuse_corner_name;
+ break;
+ case SDM632_SOC_ID:
+ ref_volt = sdm632_apss_fuse_ref_volt[id];
+ if (id == CPR4_APSS_POWER_CLUSTER_ID)
+ corner_name = cpr4_sdm632_power_apss_fuse_corner_name;
+ else
+ corner_name = cpr4_sdm632_perf_apss_fuse_corner_name;
+ break;
+ default:
+ cpr3_err(vreg, "unsupported soc id = %d\n", soc_revision);
+ rc = -EINVAL;
+ goto done;
+ }
+
for (i = 0; i < vreg->fuse_corner_count; i++) {
- fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse(
- msm8953_apss_fuse_ref_volt[i],
- MSM8953_APSS_FUSE_STEP_VOLT, fuse->init_voltage[i],
- MSM8953_APSS_VOLTAGE_FUSE_SIZE);
+ fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse(ref_volt[i],
+ CPR4_APSS_FUSE_STEP_VOLT, fuse->init_voltage[i],
+ CPR4_APSS_VOLTAGE_FUSE_SIZE);
/* Log fused open-loop voltage values for debugging purposes. */
- cpr3_info(vreg, "fused %8s: open-loop=%7d uV\n",
- cpr4_msm8953_apss_fuse_corner_name[i],
+ cpr3_info(vreg, "fused %8s: open-loop=%7d uV\n", corner_name[i],
fuse_volt[i]);
}
@@ -643,7 +950,7 @@
struct cpr3_regulator *vreg, int *volt_adjust,
int *volt_adjust_fuse, int *ro_scale)
{
- struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses;
+ struct cpr4_apss_fuses *fuse = vreg->platform_fuses;
u32 quot, ro;
int quot_adjust;
int i, fuse_corner;
@@ -670,7 +977,7 @@
}
/**
- * cpr4_msm8953_apss_calculate_target_quotients() - calculate the CPR target
+ * cpr4_apss_calculate_target_quotients() - calculate the CPR target
* quotient for each corner of a CPR3 regulator
* @vreg: Pointer to the CPR3 regulator
*
@@ -686,10 +993,9 @@
*
* Return: 0 on success, errno on failure
*/
-static int cpr4_msm8953_apss_calculate_target_quotients(
- struct cpr3_regulator *vreg)
+static int cpr4_apss_calculate_target_quotients(struct cpr3_regulator *vreg)
{
- struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses;
+ struct cpr4_apss_fuses *fuse = vreg->platform_fuses;
int rc;
bool allow_interpolation;
u64 freq_low, freq_high, prev_quot;
@@ -700,18 +1006,45 @@
int *fmax_corner;
int *volt_adjust, *volt_adjust_fuse, *ro_scale;
int *voltage_adj_misc;
+ int lowest_fuse_corner, highest_fuse_corner;
+ const char * const *corner_name;
+ switch (vreg->thread->ctrl->soc_revision) {
+ case MSM8953_SOC_ID:
+ corner_name = cpr4_msm8953_apss_fuse_corner_name;
+ lowest_fuse_corner = CPR4_MSM8953_APSS_FUSE_CORNER_LOWSVS;
+ highest_fuse_corner = CPR4_MSM8953_APSS_FUSE_CORNER_TURBO_L1;
+ break;
+ case SDM632_SOC_ID:
+ if (vreg->thread->thread_id == CPR4_APSS_POWER_CLUSTER_ID) {
+ corner_name = cpr4_sdm632_power_apss_fuse_corner_name;
+ lowest_fuse_corner =
+ CPR4_SDM632_POWER_APSS_FUSE_CORNER_LOWSVS;
+ highest_fuse_corner =
+ CPR4_SDM632_POWER_APSS_FUSE_CORNER_TURBO_L1;
+ } else {
+ corner_name = cpr4_sdm632_perf_apss_fuse_corner_name;
+ lowest_fuse_corner =
+ CPR4_SDM632_PERF_APSS_FUSE_CORNER_SVS_L1;
+ highest_fuse_corner =
+ CPR4_SDM632_PERF_APSS_FUSE_CORNER_TURBO_L1;
+ }
+ break;
+ default:
+ cpr3_err(vreg, "unsupported soc id = %d\n",
+ vreg->thread->ctrl->soc_revision);
+ return -EINVAL;
+ }
/* Log fused quotient values for debugging purposes. */
- cpr3_info(vreg, "fused LowSVS: quot[%2llu]=%4llu\n",
- fuse->ro_sel[CPR4_MSM8953_APSS_FUSE_CORNER_LOWSVS],
- fuse->target_quot[CPR4_MSM8953_APSS_FUSE_CORNER_LOWSVS]);
- for (i = CPR4_MSM8953_APSS_FUSE_CORNER_SVS;
- i <= CPR4_MSM8953_APSS_FUSE_CORNER_TURBO_L1; i++)
+ cpr3_info(vreg, "fused %8s: quot[%2llu]=%4llu\n",
+ corner_name[lowest_fuse_corner],
+ fuse->ro_sel[lowest_fuse_corner],
+ fuse->target_quot[lowest_fuse_corner]);
+ for (i = lowest_fuse_corner + 1; i <= highest_fuse_corner; i++)
cpr3_info(vreg, "fused %8s: quot[%2llu]=%4llu, quot_offset[%2llu]=%4llu\n",
- cpr4_msm8953_apss_fuse_corner_name[i],
- fuse->ro_sel[i], fuse->target_quot[i],
+ corner_name[i], fuse->ro_sel[i], fuse->target_quot[i],
fuse->ro_sel[i], fuse->quot_offset[i] *
- MSM8953_APSS_QUOT_OFFSET_SCALE);
+ CPR4_APSS_QUOT_OFFSET_SCALE);
allow_interpolation = of_property_read_bool(vreg->of_node,
"qcom,allow-quotient-interpolation");
@@ -790,7 +1123,7 @@
* Interpolation is not possible for corners mapped to the lowest fuse
* corner so use the fuse corner value directly.
*/
- i = CPR4_MSM8953_APSS_FUSE_CORNER_LOWSVS;
+ i = lowest_fuse_corner;
quot_adjust = cpr3_quot_adjustment(ro_scale[i], volt_adjust_fuse[i]);
quot = fuse->target_quot[i] + quot_adjust;
quot_high[i] = quot_low[i] = quot;
@@ -799,19 +1132,17 @@
cpr3_debug(vreg, "adjusted fuse corner %d RO%u target quot: %llu --> %u (%d uV)\n",
i, ro, fuse->target_quot[i], quot, volt_adjust_fuse[i]);
- for (i = 0; i <= fmax_corner[CPR4_MSM8953_APSS_FUSE_CORNER_LOWSVS];
- i++)
+ for (i = 0; i <= fmax_corner[lowest_fuse_corner]; i++)
vreg->corner[i].target_quot[ro] = quot;
- for (i = CPR4_MSM8953_APSS_FUSE_CORNER_SVS;
- i < vreg->fuse_corner_count; i++) {
+ for (i = lowest_fuse_corner + 1; i < vreg->fuse_corner_count; i++) {
quot_high[i] = fuse->target_quot[i];
if (fuse->ro_sel[i] == fuse->ro_sel[i - 1])
quot_low[i] = quot_high[i - 1];
else
quot_low[i] = quot_high[i]
- fuse->quot_offset[i]
- * MSM8953_APSS_QUOT_OFFSET_SCALE;
+ * CPR4_APSS_QUOT_OFFSET_SCALE;
if (quot_high[i] < quot_low[i]) {
cpr3_debug(vreg, "quot_high[%d]=%llu < quot_low[%d]=%llu; overriding: quot_high[%d]=%llu\n",
i, quot_high[i], i, quot_low[i],
@@ -1029,7 +1360,7 @@
static int cpr4_apss_parse_boost_properties(struct cpr3_regulator *vreg)
{
struct cpr3_controller *ctrl = vreg->thread->ctrl;
- struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses;
+ struct cpr4_apss_fuses *fuse = vreg->platform_fuses;
struct cpr3_corner *corner;
int i, boost_voltage, final_boost_volt, rc = 0;
int *boost_table = NULL, *boost_temp_adj = NULL;
@@ -1054,9 +1385,9 @@
boost_voltage = cpr3_convert_open_loop_voltage_fuse(
MSM8953_APSS_BOOST_FUSE_REF_VOLT,
- MSM8953_APSS_FUSE_STEP_VOLT,
+ CPR4_APSS_FUSE_STEP_VOLT,
fuse->boost_voltage,
- MSM8953_APSS_VOLTAGE_FUSE_SIZE);
+ CPR4_APSS_VOLTAGE_FUSE_SIZE);
/* Log boost voltage value for debugging purposes. */
cpr3_info(vreg, "Boost open-loop=%7d uV\n", boost_voltage);
@@ -1174,11 +1505,11 @@
* Constants which define the selection fuse parameters used in fuse combo map
* logic.
*/
-enum cpr4_msm8953_apss_fuse_combo_parameters {
- MSM8953_APSS_SPEED_BIN = 0,
- MSM8953_APSS_CPR_FUSE_REV,
- MSM8953_APSS_FOUNDRY_ID,
- MSM8953_APSS_FUSE_COMBO_PARAM_COUNT,
+enum cpr4_apss_fuse_combo_parameters {
+ CPR4_APSS_SPEED_BIN = 0,
+ CPR4_APSS_CPR_FUSE_REV,
+ CPR4_APSS_FOUNDRY_ID,
+ CPR4_APSS_FUSE_COMBO_PARAM_COUNT,
};
/**
@@ -1190,20 +1521,20 @@
*/
static int cpr4_parse_fuse_combo_map(struct cpr3_regulator *vreg)
{
- struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses;
+ struct cpr4_apss_fuses *fuse = vreg->platform_fuses;
u64 *fuse_val;
int rc;
- fuse_val = kcalloc(MSM8953_APSS_FUSE_COMBO_PARAM_COUNT,
+ fuse_val = kcalloc(CPR4_APSS_FUSE_COMBO_PARAM_COUNT,
sizeof(*fuse_val), GFP_KERNEL);
if (!fuse_val)
return -ENOMEM;
- fuse_val[MSM8953_APSS_SPEED_BIN] = fuse->speed_bin;
- fuse_val[MSM8953_APSS_CPR_FUSE_REV] = fuse->cpr_fusing_rev;
- fuse_val[MSM8953_APSS_FOUNDRY_ID] = fuse->foundry_id;
+ fuse_val[CPR4_APSS_SPEED_BIN] = fuse->speed_bin;
+ fuse_val[CPR4_APSS_CPR_FUSE_REV] = fuse->cpr_fusing_rev;
+ fuse_val[CPR4_APSS_FOUNDRY_ID] = fuse->foundry_id;
rc = cpr3_parse_fuse_combo_map(vreg, fuse_val,
- MSM8953_APSS_FUSE_COMBO_PARAM_COUNT);
+ CPR4_APSS_FUSE_COMBO_PARAM_COUNT);
if (rc == -ENODEV) {
cpr3_debug(vreg, "using legacy fuse combo logic, rc=%d\n",
rc);
@@ -1211,8 +1542,7 @@
} else if (rc < 0) {
cpr3_err(vreg, "error reading fuse combo map data, rc=%d\n",
rc);
- } else if (vreg->fuse_combo >=
- CPR4_MSM8953_APSS_FUSE_COMBO_MAP_MAX_COUNT) {
+ } else if (vreg->fuse_combo >= CPR4_APSS_FUSE_COMBO_MAP_MAX_COUNT) {
cpr3_err(vreg, "invalid CPR fuse combo = %d found\n",
vreg->fuse_combo);
rc = -EINVAL;
@@ -1231,10 +1561,10 @@
*/
static int cpr4_apss_init_regulator(struct cpr3_regulator *vreg)
{
- struct cpr4_msm8953_apss_fuses *fuse;
+ struct cpr4_apss_fuses *fuse;
int rc;
- rc = cpr4_msm8953_apss_read_fuse_data(vreg);
+ rc = cpr4_apss_read_fuse_data(vreg);
if (rc) {
cpr3_err(vreg, "unable to read CPR fuse data, rc=%d\n", rc);
return rc;
@@ -1264,7 +1594,7 @@
return rc;
}
- rc = cpr4_msm8953_apss_calculate_open_loop_voltages(vreg);
+ rc = cpr4_apss_calculate_open_loop_voltages(vreg);
if (rc) {
cpr3_err(vreg, "unable to calculate open-loop voltages, rc=%d\n",
rc);
@@ -1286,7 +1616,7 @@
return rc;
}
- rc = cpr4_msm8953_apss_calculate_target_quotients(vreg);
+ rc = cpr4_apss_calculate_target_quotients(vreg);
if (rc) {
cpr3_err(vreg, "unable to calculate target quotients, rc=%d\n",
rc);
@@ -1329,7 +1659,7 @@
*/
static int cpr4_apss_init_aging(struct cpr3_controller *ctrl)
{
- struct cpr4_msm8953_apss_fuses *fuse = NULL;
+ struct cpr4_apss_fuses *fuse = NULL;
struct cpr3_regulator *vreg = NULL;
u32 aging_ro_scale;
int i, j, rc;
@@ -1404,7 +1734,7 @@
*/
static int cpr4_apss_init_controller(struct cpr3_controller *ctrl)
{
- int rc;
+ int i, rc;
rc = cpr3_parse_common_ctrl_data(ctrl);
if (rc) {
@@ -1471,10 +1801,20 @@
return rc;
}
- ctrl->sensor_count = MSM8953_APSS_CPR_SENSOR_COUNT;
+ switch (ctrl->soc_revision) {
+ case MSM8953_SOC_ID:
+ ctrl->sensor_count = MSM8953_APSS_CPR_SENSOR_COUNT;
+ break;
+ case SDM632_SOC_ID:
+ ctrl->sensor_count = SDM632_APSS_CPR_SENSOR_COUNT;
+ break;
+ default:
+ cpr3_err(ctrl, "unsupported soc id = %d\n", ctrl->soc_revision);
+ return -EINVAL;
+ }
/*
- * APSS only has one thread (0) per controller so the zeroed
+ * MSM8953 APSS only has one thread (0) per controller so the zeroed
* array does not need further modification.
*/
ctrl->sensor_owner = devm_kcalloc(ctrl->dev, ctrl->sensor_count,
@@ -1482,7 +1822,17 @@
if (!ctrl->sensor_owner)
return -ENOMEM;
- ctrl->cpr_clock_rate = MSM8953_APSS_CPR_CLOCK_RATE;
+ /* Specify sensor ownership for SDM632 APSS CPR */
+ if (ctrl->soc_revision == SDM632_SOC_ID) {
+ for (i = SDM632_APSS_THREAD0_SENSOR_MIN;
+ i <= SDM632_APSS_THREAD0_SENSOR_MAX; i++)
+ ctrl->sensor_owner[i] = 0;
+ for (i = SDM632_APSS_THREAD1_SENSOR_MIN;
+ i <= SDM632_APSS_THREAD1_SENSOR_MAX; i++)
+ ctrl->sensor_owner[i] = 1;
+ }
+
+ ctrl->cpr_clock_rate = CPR4_APSS_CPR_CLOCK_RATE;
ctrl->ctrl_type = CPR_CTRL_TYPE_CPR4;
ctrl->supports_hw_closed_loop = true;
ctrl->use_hw_closed_loop = of_property_read_bool(ctrl->dev->of_node,
@@ -1505,11 +1855,26 @@
return cpr3_regulator_resume(ctrl);
}
+/* Data corresponds to the SoC revision */
+static const struct of_device_id cpr4_regulator_match_table[] = {
+ {
+ .compatible = "qcom,cpr4-msm8953-apss-regulator",
+ .data = (void *)(uintptr_t)MSM8953_SOC_ID,
+ },
+ {
+ .compatible = "qcom,cpr4-sdm632-apss-regulator",
+ .data = (void *)(uintptr_t)SDM632_SOC_ID,
+ },
+ {}
+};
+
static int cpr4_apss_regulator_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct cpr3_controller *ctrl;
- int i, rc;
+ struct cpr3_regulator *vreg;
+ const struct of_device_id *match;
+ int i, j, rc, max_thread_id;
if (!dev->of_node) {
dev_err(dev, "Device tree node is missing\n");
@@ -1524,6 +1889,12 @@
/* Set to false later if anything precludes CPR operation. */
ctrl->cpr_allowed_hw = true;
+ match = of_match_node(cpr4_regulator_match_table, dev->of_node);
+ if (match)
+ ctrl->soc_revision = (uintptr_t)match->data;
+ else
+ cpr3_err(ctrl, "could not find compatible string match\n");
+
rc = of_property_read_string(dev->of_node, "qcom,cpr-ctrl-name",
&ctrl->name);
if (rc) {
@@ -1538,16 +1909,19 @@
return rc;
}
- rc = cpr3_allocate_threads(ctrl, 0, 0);
+ max_thread_id = 0;
+ /* SDM632 uses 2 CPR HW threads */
+ if (ctrl->soc_revision == SDM632_SOC_ID)
+ max_thread_id = 1;
+ rc = cpr3_allocate_threads(ctrl, 0, max_thread_id);
if (rc) {
cpr3_err(ctrl, "failed to allocate CPR thread array, rc=%d\n",
rc);
return rc;
}
- if (ctrl->thread_count != 1) {
- cpr3_err(ctrl, "expected 1 thread but found %d\n",
- ctrl->thread_count);
+ if (ctrl->thread_count < 1) {
+ cpr3_err(ctrl, "thread nodes are missing\n");
return -EINVAL;
}
@@ -1559,19 +1933,24 @@
return rc;
}
- rc = cpr4_apss_init_thread(&ctrl->thread[0]);
- if (rc) {
- cpr3_err(ctrl, "thread initialization failed, rc=%d\n", rc);
- return rc;
- }
-
- for (i = 0; i < ctrl->thread[0].vreg_count; i++) {
- rc = cpr4_apss_init_regulator(&ctrl->thread[0].vreg[i]);
+ for (i = 0; i < ctrl->thread_count; i++) {
+ rc = cpr4_apss_init_thread(&ctrl->thread[i]);
if (rc) {
- cpr3_err(&ctrl->thread[0].vreg[i], "regulator initialization failed, rc=%d\n",
- rc);
+ cpr3_err(ctrl, "thread %u initialization failed, rc=%d\n",
+ ctrl->thread[i].thread_id, rc);
return rc;
}
+
+ for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
+ vreg = &ctrl->thread[i].vreg[j];
+
+ rc = cpr4_apss_init_regulator(vreg);
+ if (rc) {
+ cpr3_err(vreg, "regulator initialization failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
}
rc = cpr4_apss_init_aging(ctrl);
@@ -1593,11 +1972,6 @@
return cpr3_regulator_unregister(ctrl);
}
-static const struct of_device_id cpr4_regulator_match_table[] = {
- { .compatible = "qcom,cpr4-msm8953-apss-regulator", },
- {}
-};
-
static struct platform_driver cpr4_apss_regulator_driver = {
.driver = {
.name = "qcom,cpr4-apss-regulator",
diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c
index 9fc5a4a..79d7cba 100644
--- a/drivers/regulator/qpnp-lcdb-regulator.c
+++ b/drivers/regulator/qpnp-lcdb-regulator.c
@@ -998,12 +998,13 @@
#define VOLTAGE_MIN_STEP_50_MV 4950
#define VOLTAGE_STEP_100_MV 100
#define VOLTAGE_STEP_50_MV 50
+#define VOLTAGE_STEP_25_MV 25
#define VOLTAGE_STEP_50MV_OFFSET 0xA
static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb,
int voltage_mv, u8 type)
{
int rc = 0;
- u8 val, mask = 0;
+ u8 val, voltage_step, mask = 0;
int bst_voltage_mv;
u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
struct ldo_regulator *ldo = &lcdb->ldo;
@@ -1020,10 +1021,16 @@
bst_voltage_mv = MAX_BST_VOLTAGE_MV;
if (bst_voltage_mv != bst->voltage_mv) {
+ if (pmic_subtype == PM660L_SUBTYPE) {
+ mask = PM660_BST_OUTPUT_VOLTAGE_MASK;
+ voltage_step = VOLTAGE_STEP_50_MV;
+ } else {
+ mask = BST_OUTPUT_VOLTAGE_MASK;
+ voltage_step = VOLTAGE_STEP_25_MV;
+ }
+
val = DIV_ROUND_UP(bst_voltage_mv - MIN_BST_VOLTAGE_MV,
- VOLTAGE_STEP_50_MV);
- mask = (pmic_subtype == PM660L_SUBTYPE) ?
- PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK;
+ voltage_step);
rc = qpnp_lcdb_masked_write(lcdb, lcdb->base +
LCDB_BST_OUTPUT_VOLTAGE_REG,
mask, val);
@@ -1044,7 +1051,7 @@
int *voltage_mv)
{
int rc;
- u8 val, mask = 0;
+ u8 val, voltage_step, mask = 0;
u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_BST_OUTPUT_VOLTAGE_REG,
@@ -1054,10 +1061,16 @@
return rc;
}
- mask = (pmic_subtype == PM660L_SUBTYPE) ?
- PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK;
+ if (pmic_subtype == PM660L_SUBTYPE) {
+ mask = PM660_BST_OUTPUT_VOLTAGE_MASK;
+ voltage_step = VOLTAGE_STEP_50_MV;
+ } else {
+ mask = BST_OUTPUT_VOLTAGE_MASK;
+ voltage_step = VOLTAGE_STEP_25_MV;
+ }
+
val &= mask;
- *voltage_mv = (val * VOLTAGE_STEP_50_MV) + MIN_BST_VOLTAGE_MV;
+ *voltage_mv = (val * voltage_step) + MIN_BST_VOLTAGE_MV;
return 0;
}
diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c
index ea20f62..e4324dc 100644
--- a/drivers/rtc/rtc-opal.c
+++ b/drivers/rtc/rtc-opal.c
@@ -58,6 +58,7 @@
static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm)
{
long rc = OPAL_BUSY;
+ int retries = 10;
u32 y_m_d;
u64 h_m_s_ms;
__be32 __y_m_d;
@@ -67,8 +68,11 @@
rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms);
if (rc == OPAL_BUSY_EVENT)
opal_poll_events(NULL);
- else
+ else if (retries-- && (rc == OPAL_HARDWARE
+ || rc == OPAL_INTERNAL_ERROR))
msleep(10);
+ else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT)
+ break;
}
if (rc != OPAL_SUCCESS)
@@ -84,6 +88,7 @@
static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm)
{
long rc = OPAL_BUSY;
+ int retries = 10;
u32 y_m_d = 0;
u64 h_m_s_ms = 0;
@@ -92,8 +97,11 @@
rc = opal_rtc_write(y_m_d, h_m_s_ms);
if (rc == OPAL_BUSY_EVENT)
opal_poll_events(NULL);
- else
+ else if (retries-- && (rc == OPAL_HARDWARE
+ || rc == OPAL_INTERNAL_ERROR))
msleep(10);
+ else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT)
+ break;
}
return rc == OPAL_SUCCESS ? 0 : -EIO;
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
index fac8355..5309edc 100644
--- a/drivers/rtc/rtc-pm8xxx.c
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -74,16 +74,18 @@
/*
* Steps to write the RTC registers.
* 1. Disable alarm if enabled.
- * 2. Write 0x00 to LSB.
- * 3. Write Byte[1], Byte[2], Byte[3] then Byte[0].
- * 4. Enable alarm if disabled in step 1.
+ * 2. Disable rtc if enabled.
+ * 3. Write 0x00 to LSB.
+ * 4. Write Byte[1], Byte[2], Byte[3] then Byte[0].
+ * 5. Enable rtc if disabled in step 2.
+ * 6. Enable alarm if disabled in step 1.
*/
static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
int rc, i;
unsigned long secs, irq_flags;
- u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0;
- unsigned int ctrl_reg;
+ u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, rtc_disabled = 0;
+ unsigned int ctrl_reg, rtc_ctrl_reg;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
@@ -92,23 +94,38 @@
rtc_tm_to_time(tm, &secs);
+ dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
+
for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
value[i] = secs & 0xFF;
secs >>= 8;
}
- dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
-
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
- rc = regmap_read(rtc_dd->regmap, regs->ctrl, &ctrl_reg);
+ rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
if (rc)
goto rtc_rw_fail;
if (ctrl_reg & regs->alarm_en) {
alarm_enabled = 1;
ctrl_reg &= ~regs->alarm_en;
- rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg);
+ rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
+ if (rc) {
+ dev_err(dev, "Write to RTC Alarm control register failed\n");
+ goto rtc_rw_fail;
+ }
+ }
+
+ /* Disable RTC H/w before writing on RTC register */
+ rc = regmap_read(rtc_dd->regmap, regs->ctrl, &rtc_ctrl_reg);
+ if (rc)
+ goto rtc_rw_fail;
+
+ if (rtc_ctrl_reg & PM8xxx_RTC_ENABLE) {
+ rtc_disabled = 1;
+ rtc_ctrl_reg &= ~PM8xxx_RTC_ENABLE;
+ rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
if (rc) {
dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
@@ -137,15 +154,25 @@
goto rtc_rw_fail;
}
- if (alarm_enabled) {
- ctrl_reg |= regs->alarm_en;
- rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg);
+ /* Enable RTC H/w after writing on RTC register */
+ if (rtc_disabled) {
+ rtc_ctrl_reg |= PM8xxx_RTC_ENABLE;
+ rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
if (rc) {
dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
}
+ if (alarm_enabled) {
+ ctrl_reg |= regs->alarm_en;
+ rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
+ if (rc) {
+ dev_err(dev, "Write to RTC Alarm control register failed\n");
+ goto rtc_rw_fail;
+ }
+ }
+
rtc_rw_fail:
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index a7a8847..0f5bc2f 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -521,10 +521,12 @@
pfxdata->validity.define_extent = 1;
/* private uid is kept up to date, conf_data may be outdated */
- if (startpriv->uid.type != UA_BASE_DEVICE) {
+ if (startpriv->uid.type == UA_BASE_PAV_ALIAS)
pfxdata->validity.verify_base = 1;
- if (startpriv->uid.type == UA_HYPER_PAV_ALIAS)
- pfxdata->validity.hyper_pav = 1;
+
+ if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) {
+ pfxdata->validity.verify_base = 1;
+ pfxdata->validity.hyper_pav = 1;
}
/* define extend data (mostly)*/
@@ -3471,10 +3473,12 @@
pfxdata.validity.define_extent = 1;
/* private uid is kept up to date, conf_data may be outdated */
- if (startpriv->uid.type != UA_BASE_DEVICE) {
+ if (startpriv->uid.type == UA_BASE_PAV_ALIAS)
pfxdata.validity.verify_base = 1;
- if (startpriv->uid.type == UA_HYPER_PAV_ALIAS)
- pfxdata.validity.hyper_pav = 1;
+
+ if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) {
+ pfxdata.validity.verify_base = 1;
+ pfxdata.validity.hyper_pav = 1;
}
switch (cmd) {
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index febbd83..24e57e7 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -6291,18 +6291,17 @@
static uchar
AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
{
- EXT_MSG sdtr_buf;
- uchar sdtr_period_index;
- PortAddr iop_base;
-
- iop_base = asc_dvc->iop_base;
- sdtr_buf.msg_type = EXTENDED_MESSAGE;
- sdtr_buf.msg_len = MS_SDTR_LEN;
- sdtr_buf.msg_req = EXTENDED_SDTR;
- sdtr_buf.xfer_period = sdtr_period;
+ PortAddr iop_base = asc_dvc->iop_base;
+ uchar sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+ EXT_MSG sdtr_buf = {
+ .msg_type = EXTENDED_MESSAGE,
+ .msg_len = MS_SDTR_LEN,
+ .msg_req = EXTENDED_SDTR,
+ .xfer_period = sdtr_period,
+ .req_ack_offset = sdtr_offset,
+ };
sdtr_offset &= ASC_SYN_MAX_OFFSET;
- sdtr_buf.req_ack_offset = sdtr_offset;
- sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+
if (sdtr_period_index <= asc_dvc->max_sdtr_index) {
AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG,
(uchar *)&sdtr_buf,
@@ -11030,6 +11029,9 @@
ASC_DBG(2, "AdvInitGetConfig()\n");
ret = AdvInitGetConfig(pdev, shost) ? -ENODEV : 0;
+#else
+ share_irq = 0;
+ ret = -ENODEV;
#endif /* CONFIG_PCI */
}
diff --git a/drivers/scsi/smartpqi/Makefile b/drivers/scsi/smartpqi/Makefile
index 0f42a22..e6b7799 100644
--- a/drivers/scsi/smartpqi/Makefile
+++ b/drivers/scsi/smartpqi/Makefile
@@ -1,3 +1,3 @@
ccflags-y += -I.
-obj-m += smartpqi.o
+obj-$(CONFIG_SCSI_SMARTPQI) += smartpqi.o
smartpqi-objs := smartpqi_init.o smartpqi_sis.o smartpqi_sas_transport.o
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index 11e11e4..1f3967d 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -954,6 +954,49 @@
hba->ufs_stats.power_mode_change_cnt);
seq_printf(file, "hibern8_exit_cnt = %d\n",
hba->ufs_stats.hibern8_exit_cnt);
+
+ seq_printf(file, "pa_err_cnt_total = %d\n",
+ hba->ufs_stats.pa_err_cnt_total);
+ seq_printf(file, "pa_lane_0_err_cnt = %d\n",
+ hba->ufs_stats.pa_err_cnt[UFS_EC_PA_LANE_0]);
+ seq_printf(file, "pa_lane_1_err_cnt = %d\n",
+ hba->ufs_stats.pa_err_cnt[UFS_EC_PA_LANE_1]);
+ seq_printf(file, "pa_line_reset_err_cnt = %d\n",
+ hba->ufs_stats.pa_err_cnt[UFS_EC_PA_LINE_RESET]);
+ seq_printf(file, "dl_err_cnt_total = %d\n",
+ hba->ufs_stats.dl_err_cnt_total);
+ seq_printf(file, "dl_nac_received_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_NAC_RECEIVED]);
+ seq_printf(file, "dl_tcx_replay_timer_expired_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_TCx_REPLAY_TIMER_EXPIRED]);
+ seq_printf(file, "dl_afcx_request_timer_expired_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_AFCx_REQUEST_TIMER_EXPIRED]);
+ seq_printf(file, "dl_fcx_protection_timer_expired_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_FCx_PROTECT_TIMER_EXPIRED]);
+ seq_printf(file, "dl_crc_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_CRC_ERROR]);
+ seq_printf(file, "dll_rx_buffer_overflow_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_RX_BUFFER_OVERFLOW]);
+ seq_printf(file, "dl_max_frame_length_exceeded_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_MAX_FRAME_LENGTH_EXCEEDED]);
+ seq_printf(file, "dl_wrong_sequence_number_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_WRONG_SEQUENCE_NUMBER]);
+ seq_printf(file, "dl_afc_frame_syntax_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_AFC_FRAME_SYNTAX_ERROR]);
+ seq_printf(file, "dl_nac_frame_syntax_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_NAC_FRAME_SYNTAX_ERROR]);
+ seq_printf(file, "dl_eof_syntax_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_EOF_SYNTAX_ERROR]);
+ seq_printf(file, "dl_frame_syntax_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_FRAME_SYNTAX_ERROR]);
+ seq_printf(file, "dl_bad_ctrl_symbol_type_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_BAD_CTRL_SYMBOL_TYPE]);
+ seq_printf(file, "dl_pa_init_err_cnt = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_PA_INIT_ERROR]);
+ seq_printf(file, "dl_pa_error_ind_received = %d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_PA_ERROR_IND_RECEIVED]);
+ seq_printf(file, "dme_err_cnt = %d\n", hba->ufs_stats.dme_err_cnt);
+
return 0;
}
diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
index d288e83..b1c86d4 100644
--- a/drivers/scsi/ufs/ufs-qcom-ice.c
+++ b/drivers/scsi/ufs/ufs-qcom-ice.c
@@ -172,15 +172,17 @@
static void ufs_qcom_ice_cfg_work(struct work_struct *work)
{
unsigned long flags;
+ struct ice_data_setting ice_set;
struct ufs_qcom_host *qcom_host =
container_of(work, struct ufs_qcom_host, ice_cfg_work);
+ struct request *req_pending = NULL;
if (!qcom_host->ice.vops->config_start)
return;
spin_lock_irqsave(&qcom_host->ice_work_lock, flags);
- if (!qcom_host->req_pending) {
- qcom_host->work_pending = false;
+ req_pending = qcom_host->req_pending;
+ if (!req_pending) {
spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
return;
}
@@ -189,15 +191,24 @@
/*
* config_start is called again as previous attempt returned -EAGAIN,
* this call shall now take care of the necessary key setup.
+ * 'ice_set' will not actually be used, instead the next call to
+ * config_start() for this request, in the normal call flow, will
+ * succeed as the key has now been setup.
*/
qcom_host->ice.vops->config_start(qcom_host->ice.pdev,
- qcom_host->req_pending, NULL, false);
+ qcom_host->req_pending, &ice_set, false);
spin_lock_irqsave(&qcom_host->ice_work_lock, flags);
qcom_host->req_pending = NULL;
- qcom_host->work_pending = false;
spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
+ /*
+ * Resume with requests processing. We assume config_start has been
+ * successful, but even if it wasn't we still must resume in order to
+ * allow for the request to be retried.
+ */
+ ufshcd_scsi_unblock_requests(qcom_host->hba);
+
}
/**
@@ -283,14 +294,18 @@
* requires a non-atomic context, this means we should
* call the function again from the worker thread to do
* the configuration. For this request the error will
- * propagate so it will be re-queued.
+ * propagate so it will be re-queued and until the
+ * configuration is is completed we block further
+ * request processing.
*/
if (err == -EAGAIN) {
dev_dbg(qcom_host->hba->dev,
"%s: scheduling task for ice setup\n",
__func__);
- if (!qcom_host->work_pending) {
+ if (!qcom_host->req_pending) {
+ ufshcd_scsi_block_requests(
+ qcom_host->hba);
qcom_host->req_pending = cmd->request;
if (!queue_work(ice_workqueue,
@@ -301,9 +316,10 @@
&qcom_host->ice_work_lock,
flags);
+ ufshcd_scsi_unblock_requests(
+ qcom_host->hba);
return err;
}
- qcom_host->work_pending = true;
}
} else {
@@ -402,7 +418,9 @@
* requires a non-atomic context, this means we should
* call the function again from the worker thread to do
* the configuration. For this request the error will
- * propagate so it will be re-queued.
+ * propagate so it will be re-queued and until the
+ * configuration is is completed we block further
+ * request processing.
*/
if (err == -EAGAIN) {
@@ -410,8 +428,9 @@
"%s: scheduling task for ice setup\n",
__func__);
- if (!qcom_host->work_pending) {
-
+ if (!qcom_host->req_pending) {
+ ufshcd_scsi_block_requests(
+ qcom_host->hba);
qcom_host->req_pending = cmd->request;
if (!queue_work(ice_workqueue,
&qcom_host->ice_cfg_work)) {
@@ -421,9 +440,10 @@
&qcom_host->ice_work_lock,
flags);
+ ufshcd_scsi_unblock_requests(
+ qcom_host->hba);
return err;
}
- qcom_host->work_pending = true;
}
} else {
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index ba44523..1ddfabf 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -2615,6 +2615,69 @@
kfree(testbus);
}
+static void ufs_qcom_print_utp_hci_testbus(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ u32 *testbus = NULL;
+ int i, nminor = 32, testbus_len = nminor * sizeof(u32);
+
+ testbus = kmalloc(testbus_len, GFP_KERNEL);
+ if (!testbus)
+ return;
+
+ host->testbus.select_major = TSTBUS_UTP_HCI;
+ for (i = 0; i <= nminor; i++) {
+ host->testbus.select_minor = i;
+ ufs_qcom_testbus_config(host);
+ testbus[i] = ufshcd_readl(hba, UFS_TEST_BUS);
+ }
+ print_hex_dump(KERN_ERR, "UTP_HCI_TEST_BUS ", DUMP_PREFIX_OFFSET,
+ 16, 4, testbus, testbus_len, false);
+ kfree(testbus);
+}
+
+void ufs_qcom_read_custom_testbus(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+
+ host->testbus.select_major = TSTBUS_UTP_HCI;
+ host->testbus.select_minor = 5;
+ ufs_qcom_testbus_config(host);
+ hba->tb_ah8_ctrl_0 = ufshcd_readl(hba, UFS_TEST_BUS);
+
+ host->testbus.select_major = TSTBUS_UNIPRO;
+ host->testbus.select_minor = 33;
+ ufs_qcom_testbus_config(host);
+ hba->tb_dme = ufshcd_readl(hba, UFS_TEST_BUS);
+
+ host->testbus.select_major = TSTBUS_UNIPRO;
+ host->testbus.select_minor = 37;
+ ufs_qcom_testbus_config(host);
+ hba->tb_pa_power_ctrl = ufshcd_readl(hba, UFS_TEST_BUS);
+
+ host->testbus.select_major = TSTBUS_UNIPRO;
+ host->testbus.select_minor = 55;
+ ufs_qcom_testbus_config(host);
+ hba->tb_pa_attr_1 = ufshcd_readl(hba, UFS_TEST_BUS);
+
+ host->testbus.select_major = TSTBUS_UNIPRO;
+ host->testbus.select_minor = 56;
+ ufs_qcom_testbus_config(host);
+ hba->tb_pa_attr_2 = ufshcd_readl(hba, UFS_TEST_BUS);
+}
+
+int ufs_qcom_read_pa_vs_status_reg1(struct ufs_hba *hba, u32 *pa_vs_status_reg1)
+{
+ int err;
+
+ err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_STATUS_REG1),
+ pa_vs_status_reg1);
+ if (err)
+ dev_err(hba->dev, "%s: couldn't read PA_VS_STATUS_REG1 %d\n",
+ __func__, err);
+ return err;
+}
+
static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba, bool no_sleep)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -2633,6 +2696,8 @@
usleep_range(1000, 1100);
ufs_qcom_print_unipro_testbus(hba);
usleep_range(1000, 1100);
+ ufs_qcom_print_utp_hci_testbus(hba);
+ usleep_range(1000, 1100);
ufs_qcom_phy_dbg_register_dump(phy);
usleep_range(1000, 1100);
ufs_qcom_ice_print_regs(host);
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 9da3d19..1c48a85 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -161,6 +161,7 @@
/* QUniPro Vendor specific attributes */
#define PA_VS_CONFIG_REG1 0x9000
+#define PA_VS_STATUS_REG1 0x9001
#define SAVECONFIGTIME_MODE_MASK 0x6000
#define PA_VS_CLK_CFG_REG 0x9004
@@ -375,7 +376,6 @@
struct work_struct ice_cfg_work;
struct request *req_pending;
struct ufs_vreg *vddp_ref_clk;
- bool work_pending;
};
static inline u32
@@ -397,6 +397,9 @@
void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba, void *priv,
void (*print_fn)(struct ufs_hba *hba, int offset, int num_regs,
char *str, void *priv));
+void ufs_qcom_read_custom_testbus(struct ufs_hba *hba);
+int ufs_qcom_read_pa_vs_status_reg1(struct ufs_hba *hba,
+ u32 *pa_vs_status_reg1);
static inline bool ufs_qcom_cap_qunipro(struct ufs_qcom_host *host)
{
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 02dfbcc..f3e79e3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3,7 +3,7 @@
*
* This code is based on drivers/scsi/ufs/ufshcd.c
* Copyright (C) 2011-2013 Samsung India Software Operations
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
*
* Authors:
* Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -54,6 +54,8 @@
#ifdef CONFIG_DEBUG_FS
+static u32 pa_vs_status_reg1;
+
static int ufshcd_tag_req_type(struct request *rq)
{
int rq_type = TS_WRITE;
@@ -172,6 +174,33 @@
}
#endif
+static void ufshcd_update_uic_error_cnt(struct ufs_hba *hba, u32 reg, int type)
+{
+ unsigned long err_bits;
+ int ec;
+
+ switch (type) {
+ case UFS_UIC_ERROR_PA:
+ err_bits = reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK;
+ for_each_set_bit(ec, &err_bits, UFS_EC_PA_MAX) {
+ hba->ufs_stats.pa_err_cnt[ec]++;
+ hba->ufs_stats.pa_err_cnt_total++;
+ }
+ break;
+ case UFS_UIC_ERROR_DL:
+ err_bits = reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK;
+ for_each_set_bit(ec, &err_bits, UFS_EC_DL_MAX) {
+ hba->ufs_stats.dl_err_cnt[ec]++;
+ hba->ufs_stats.dl_err_cnt_total++;
+ }
+ break;
+ case UFS_UIC_ERROR_DME:
+ hba->ufs_stats.dme_err_cnt++;
+ default:
+ break;
+ }
+}
+
#define PWR_INFO_MASK 0xF
#define PWR_RX_OFFSET 4
@@ -601,6 +630,23 @@
entry->tag = tag;
entry->tstamp = ktime_get();
entry->outstanding_reqs = hba->outstanding_reqs;
+ if (!strcmp(cmd_type, "custom")) {
+ ufs_qcom_read_custom_testbus(hba);
+ entry->tb_ah8_ctrl_0 = hba->tb_ah8_ctrl_0;
+ entry->tb_dme = hba->tb_dme;
+ entry->tb_pa_power_ctrl = hba->tb_pa_power_ctrl;
+ entry->tb_pa_attr_1 = hba->tb_pa_attr_1;
+ entry->tb_pa_attr_2 = hba->tb_pa_attr_2;
+ entry->pa_vs_status_reg1 = pa_vs_status_reg1;
+ pa_vs_status_reg1 = 0;
+ } else {
+ entry->tb_ah8_ctrl_0 = 0;
+ entry->tb_dme = 0;
+ entry->tb_pa_power_ctrl = 0;
+ entry->tb_pa_attr_1 = 0;
+ entry->tb_pa_attr_2 = 0;
+ entry->pa_vs_status_reg1 = 0;
+ }
entry->seq_num = hba->cmd_log.seq_num;
hba->cmd_log.seq_num++;
hba->cmd_log.pos =
@@ -620,6 +666,11 @@
ufshcd_cmd_log(hba, str, "dme", 0, cmd_id, 0);
}
+static void ufshcd_custom_cmd_log(struct ufs_hba *hba, char *str)
+{
+ ufshcd_cmd_log(hba, str, "custom", 0, 0, 0);
+}
+
static void ufshcd_print_cmd_log(struct ufs_hba *hba)
{
int i;
@@ -635,11 +686,14 @@
pos = (pos + 1) % UFSHCD_MAX_CMD_LOGGING;
if (ktime_to_us(p->tstamp)) {
- pr_err("%s: %s: seq_no=%u lun=0x%x cmd_id=0x%02x lba=0x%llx txfer_len=%d tag=%u, doorbell=0x%x outstanding=0x%x idn=%d time=%lld us\n",
+ pr_err("%s: %s: seq_no=%u lun=0x%x cmd_id=0x%02x lba=0x%llx txfer_len=%d tag=%u, doorbell=0x%x outstanding=0x%x idn=%d ah8_ctrl_0=0x%x dme=0x%x pa_power_ctrl=0x%x pa_attr_1=0x%x pa_attr_2=0x%x pa_vs_status_reg1=0x%x time=%lld us\n",
p->cmd_type, p->str, p->seq_num,
p->lun, p->cmd_id, (unsigned long long)p->lba,
p->transfer_len, p->tag, p->doorbell,
p->outstanding_reqs, p->idn,
+ p->tb_ah8_ctrl_0, p->tb_dme,
+ p->tb_pa_power_ctrl, p->tb_pa_attr_1,
+ p->tb_pa_attr_2, p->pa_vs_status_reg1,
ktime_to_us(p->tstamp));
usleep_range(1000, 1100);
}
@@ -658,7 +712,7 @@
entry.str = str;
entry.lba = lba;
- entry->cmd_id = cmd_id;
+ entry.cmd_id = cmd_id;
entry.transfer_len = transfer_len;
entry.doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
entry.tag = tag;
@@ -670,6 +724,10 @@
{
}
+static void ufshcd_custom_cmd_log(struct ufs_hba *hba, char *str)
+{
+}
+
static void ufshcd_print_cmd_log(struct ufs_hba *hba)
{
}
@@ -892,7 +950,7 @@
dev_err(hba->dev, "UFS Host state=%d\n", hba->ufshcd_state);
dev_err(hba->dev, "lrb in use=0x%lx, outstanding reqs=0x%lx tasks=0x%lx\n",
- hba->lrb_in_use, hba->outstanding_tasks, hba->outstanding_reqs);
+ hba->lrb_in_use, hba->outstanding_reqs, hba->outstanding_tasks);
dev_err(hba->dev, "saved_err=0x%x, saved_uic_err=0x%x, saved_ce_err=0x%x\n",
hba->saved_err, hba->saved_uic_err, hba->saved_ce_err);
dev_err(hba->dev, "Device power mode=%d, UIC link state=%d\n",
@@ -909,6 +967,33 @@
hba->capabilities, hba->caps);
dev_err(hba->dev, "quirks=0x%x, dev. quirks=0x%x\n", hba->quirks,
hba->dev_info.quirks);
+ dev_err(hba->dev, "pa_err_cnt_total=%d, pa_lane_0_err_cnt=%d, pa_lane_1_err_cnt=%d, pa_line_reset_err_cnt=%d\n",
+ hba->ufs_stats.pa_err_cnt_total,
+ hba->ufs_stats.pa_err_cnt[UFS_EC_PA_LANE_0],
+ hba->ufs_stats.pa_err_cnt[UFS_EC_PA_LANE_1],
+ hba->ufs_stats.pa_err_cnt[UFS_EC_PA_LINE_RESET]);
+ dev_err(hba->dev, "dl_err_cnt_total=%d, dl_nac_received_err_cnt=%d, dl_tcx_replay_timer_expired_err_cnt=%d\n",
+ hba->ufs_stats.dl_err_cnt_total,
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_NAC_RECEIVED],
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_TCx_REPLAY_TIMER_EXPIRED]);
+ dev_err(hba->dev, "dl_afcx_request_timer_expired_err_cnt=%d, dl_fcx_protection_timer_expired_err_cnt=%d, dl_crc_err_cnt=%d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_AFCx_REQUEST_TIMER_EXPIRED],
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_FCx_PROTECT_TIMER_EXPIRED],
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_CRC_ERROR]);
+ dev_err(hba->dev, "dll_rx_buffer_overflow_err_cnt=%d, dl_max_frame_length_exceeded_err_cnt=%d, dl_wrong_sequence_number_err_cnt=%d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_RX_BUFFER_OVERFLOW],
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_MAX_FRAME_LENGTH_EXCEEDED],
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_WRONG_SEQUENCE_NUMBER]);
+ dev_err(hba->dev, "dl_afc_frame_syntax_err_cnt=%d, dl_nac_frame_syntax_err_cnt=%d, dl_eof_syntax_err_cnt=%d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_AFC_FRAME_SYNTAX_ERROR],
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_NAC_FRAME_SYNTAX_ERROR],
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_EOF_SYNTAX_ERROR]);
+ dev_err(hba->dev, "dl_frame_syntax_err_cnt=%d, dl_bad_ctrl_symbol_type_err_cnt=%d, dl_pa_init_err_cnt=%d, dl_pa_error_ind_received=%d\n",
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_FRAME_SYNTAX_ERROR],
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_BAD_CTRL_SYMBOL_TYPE],
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_PA_INIT_ERROR],
+ hba->ufs_stats.dl_err_cnt[UFS_EC_DL_PA_ERROR_IND_RECEIVED]);
+ dev_err(hba->dev, "dme_err_cnt=%d\n", hba->ufs_stats.dme_err_cnt);
}
/**
@@ -5795,10 +5880,10 @@
completion = ktime_get();
delta_us = ktime_us_delta(completion,
req->lat_hist_io_start);
- /* rq_data_dir() => true if WRITE */
- blk_update_latency_hist(&hba->io_lat_s,
- (rq_data_dir(req) == READ),
- delta_us);
+ blk_update_latency_hist(
+ (rq_data_dir(req) == READ) ?
+ &hba->io_lat_read :
+ &hba->io_lat_write, delta_us);
}
}
/* Do not touch lrbp after scsi done */
@@ -6353,7 +6438,7 @@
* Dump controller state before resetting. Transfer requests state
* will be dump as part of the request completion.
*/
- if ((hba->saved_err & (INT_FATAL_ERRORS | UIC_ERROR)) ||
+ if ((hba->saved_err & (INT_FATAL_ERRORS | UIC_ERROR | UIC_LINK_LOST)) ||
hba->auto_h8_err) {
dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x",
__func__, hba->saved_err, hba->saved_uic_err);
@@ -6370,7 +6455,7 @@
hba->auto_h8_err = false;
}
- if ((hba->saved_err & INT_FATAL_ERRORS)
+ if ((hba->saved_err & (INT_FATAL_ERRORS | UIC_LINK_LOST))
|| hba->saved_ce_err || hba->force_host_reset ||
((hba->saved_err & UIC_ERROR) &&
(hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR |
@@ -6498,6 +6583,7 @@
hba = container_of(work, struct ufs_hba, rls_work);
ufshcd_scsi_block_requests(hba);
pm_runtime_get_sync(hba->dev);
+ down_write(&hba->lock);
ret = ufshcd_wait_for_doorbell_clr(hba, U64_MAX);
if (ret) {
dev_err(hba->dev,
@@ -6531,6 +6617,7 @@
hba->restore_needed = false;
out:
+ up_write(&hba->lock);
ufshcd_scsi_unblock_requests(hba);
pm_runtime_put_sync(hba->dev);
}
@@ -6558,6 +6645,7 @@
*/
dev_dbg(hba->dev, "%s: UIC Lane error reported, reg 0x%x\n",
__func__, reg);
+ ufshcd_update_uic_error_cnt(hba, reg, UFS_UIC_ERROR_PA);
ufshcd_update_uic_reg_hist(&hba->ufs_stats.pa_err, reg);
/*
@@ -6584,6 +6672,7 @@
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
if ((reg & UIC_DATA_LINK_LAYER_ERROR) &&
(reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK)) {
+ ufshcd_update_uic_error_cnt(hba, reg, UFS_UIC_ERROR_DL);
ufshcd_update_uic_reg_hist(&hba->ufs_stats.dl_err, reg);
if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) {
@@ -6621,6 +6710,7 @@
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME);
if ((reg & UIC_DME_ERROR) &&
(reg & UIC_DME_ERROR_CODE_MASK)) {
+ ufshcd_update_uic_error_cnt(hba, reg, UFS_UIC_ERROR_DME);
ufshcd_update_uic_reg_hist(&hba->ufs_stats.dme_err, reg);
hba->uic_error |= UFSHCD_UIC_DME_ERROR;
retval |= IRQ_HANDLED;
@@ -6647,6 +6737,12 @@
if (hba->errors & INT_FATAL_ERRORS || hba->ce_error)
queue_eh_work = true;
+ if (hba->errors & UIC_LINK_LOST) {
+ dev_err(hba->dev, "%s: UIC_LINK_LOST received, errors 0x%x\n",
+ __func__, hba->errors);
+ queue_eh_work = true;
+ }
+
if (hba->errors & UIC_ERROR) {
hba->uic_error = 0;
retval = ufshcd_update_uic_error(hba);
@@ -8950,7 +9046,8 @@
if (ufshcd_is_clkscaling_supported(hba)) {
if (hba->devfreq)
ufshcd_suspend_clkscaling(hba);
- destroy_workqueue(hba->clk_scaling.workq);
+ if (hba->clk_scaling.workq)
+ destroy_workqueue(hba->clk_scaling.workq);
}
ufshcd_disable_clocks(hba, false);
ufshcd_setup_hba_vreg(hba, false);
@@ -9846,9 +9943,10 @@
if (kstrtol(buf, 0, &value))
return -EINVAL;
- if (value == BLK_IO_LAT_HIST_ZERO)
- blk_zero_latency_hist(&hba->io_lat_s);
- else if (value == BLK_IO_LAT_HIST_ENABLE ||
+ if (value == BLK_IO_LAT_HIST_ZERO) {
+ memset(&hba->io_lat_read, 0, sizeof(hba->io_lat_read));
+ memset(&hba->io_lat_write, 0, sizeof(hba->io_lat_write));
+ } else if (value == BLK_IO_LAT_HIST_ENABLE ||
value == BLK_IO_LAT_HIST_DISABLE)
hba->latency_hist_enabled = value;
return count;
@@ -9859,8 +9957,14 @@
char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
+ size_t written_bytes;
- return blk_latency_hist_show(&hba->io_lat_s, buf);
+ written_bytes = blk_latency_hist_show("Read", &hba->io_lat_read,
+ buf, PAGE_SIZE);
+ written_bytes += blk_latency_hist_show("Write", &hba->io_lat_write,
+ buf + written_bytes, PAGE_SIZE - written_bytes);
+
+ return written_bytes;
}
static DEVICE_ATTR(latency_hist, S_IRUGO | S_IWUSR,
@@ -10131,11 +10235,16 @@
if (ret)
goto out;
+ ufs_qcom_read_pa_vs_status_reg1(hba, &pa_vs_status_reg1);
+ ufshcd_custom_cmd_log(hba, "waited-for-DB-clear");
+
/* scale down the gear before scaling down clocks */
if (!scale_up) {
ret = ufshcd_scale_gear(hba, false);
if (ret)
goto clk_scaling_unprepare;
+ ufs_qcom_read_pa_vs_status_reg1(hba, &pa_vs_status_reg1);
+ ufshcd_custom_cmd_log(hba, "Gear-scaled-down");
}
/*
@@ -10148,17 +10257,23 @@
if (ret)
/* link will be bad state so no need to scale_up_gear */
return ret;
+ ufs_qcom_read_pa_vs_status_reg1(hba, &pa_vs_status_reg1);
+ ufshcd_custom_cmd_log(hba, "Hibern8-entered");
}
ret = ufshcd_scale_clks(hba, scale_up);
if (ret)
goto scale_up_gear;
+ ufs_qcom_read_pa_vs_status_reg1(hba, &pa_vs_status_reg1);
+ ufshcd_custom_cmd_log(hba, "Clk-freq-switched");
if (ufshcd_is_auto_hibern8_supported(hba)) {
ret = ufshcd_uic_hibern8_exit(hba);
if (ret)
/* link will be bad state so no need to scale_up_gear */
return ret;
+ ufs_qcom_read_pa_vs_status_reg1(hba, &pa_vs_status_reg1);
+ ufshcd_custom_cmd_log(hba, "Hibern8-Exited");
}
/* scale up the gear after scaling up clocks */
@@ -10168,6 +10283,8 @@
ufshcd_scale_clks(hba, false);
goto clk_scaling_unprepare;
}
+ ufs_qcom_read_pa_vs_status_reg1(hba, &pa_vs_status_reg1);
+ ufshcd_custom_cmd_log(hba, "Gear-scaled-up");
}
if (!ret) {
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 1f5c404..a6b47aa 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -3,7 +3,7 @@
*
* This code is based on drivers/scsi/ufs/ufshcd.h
* Copyright (C) 2011-2013 Samsung India Software Operations
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
*
* Authors:
* Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -650,6 +650,11 @@
struct ufs_uic_err_reg_hist nl_err;
struct ufs_uic_err_reg_hist tl_err;
struct ufs_uic_err_reg_hist dme_err;
+ u32 pa_err_cnt_total;
+ u32 pa_err_cnt[UFS_EC_PA_MAX];
+ u32 dl_err_cnt_total;
+ u32 dl_err_cnt[UFS_EC_DL_MAX];
+ u32 dme_err_cnt;
};
/* UFS Host Controller debug print bitmask */
@@ -681,6 +686,12 @@
u32 seq_num;
unsigned int tag;
ktime_t tstamp;
+ u32 tb_ah8_ctrl_0;
+ u32 tb_dme;
+ u32 tb_pa_power_ctrl;
+ u32 tb_pa_attr_1;
+ u32 tb_pa_attr_2;
+ u32 pa_vs_status_reg1;
};
struct ufshcd_cmd_log {
@@ -986,9 +997,17 @@
struct pinctrl *pctrl;
int latency_hist_enabled;
- struct io_latency_state io_lat_s;
+ struct io_latency_state io_lat_read;
+ struct io_latency_state io_lat_write;
struct ufs_desc_size desc_size;
bool restore_needed;
+
+ /* Custom test bus data */
+ u32 tb_ah8_ctrl_0;
+ u32 tb_dme;
+ u32 tb_pa_power_ctrl;
+ u32 tb_pa_attr_1;
+ u32 tb_pa_attr_2;
};
static inline void ufshcd_mark_shutdown_ongoing(struct ufs_hba *hba)
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index c0e4650..fb18bc8 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -154,7 +154,7 @@
#define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK)
-#define UFSHCD_ERROR_MASK (UIC_ERROR |\
+#define UFSHCD_ERROR_MASK (UIC_ERROR | UIC_LINK_LOST |\
DEVICE_FATAL_ERROR |\
CONTROLLER_FATAL_ERROR |\
SYSTEM_BUS_FATAL_ERROR |\
@@ -183,6 +183,43 @@
PWR_FATAL_ERROR = 0x05,
};
+/* Host UIC error type */
+enum ufshcd_uic_err_type {
+ UFS_UIC_ERROR_PA,
+ UFS_UIC_ERROR_DL,
+ UFS_UIC_ERROR_DME,
+};
+
+/* Host UIC error code PHY adapter layer */
+enum ufshcd_ec_pa {
+ UFS_EC_PA_LANE_0,
+ UFS_EC_PA_LANE_1,
+ UFS_EC_PA_LANE_2,
+ UFS_EC_PA_LANE_3,
+ UFS_EC_PA_LINE_RESET,
+ UFS_EC_PA_MAX,
+};
+
+/* Host UIC error code data link layer */
+enum ufshcd_ec_dl {
+ UFS_EC_DL_NAC_RECEIVED,
+ UFS_EC_DL_TCx_REPLAY_TIMER_EXPIRED,
+ UFS_EC_DL_AFCx_REQUEST_TIMER_EXPIRED,
+ UFS_EC_DL_FCx_PROTECT_TIMER_EXPIRED,
+ UFS_EC_DL_CRC_ERROR,
+ UFS_EC_DL_RX_BUFFER_OVERFLOW,
+ UFS_EC_DL_MAX_FRAME_LENGTH_EXCEEDED,
+ UFS_EC_DL_WRONG_SEQUENCE_NUMBER,
+ UFS_EC_DL_AFC_FRAME_SYNTAX_ERROR,
+ UFS_EC_DL_NAC_FRAME_SYNTAX_ERROR,
+ UFS_EC_DL_EOF_SYNTAX_ERROR,
+ UFS_EC_DL_FRAME_SYNTAX_ERROR,
+ UFS_EC_DL_BAD_CTRL_SYMBOL_TYPE,
+ UFS_EC_DL_PA_INIT_ERROR,
+ UFS_EC_DL_PA_ERROR_IND_RECEIVED,
+ UFS_EC_DL_MAX,
+};
+
/* HCE - Host Controller Enable 34h */
#define CONTROLLER_ENABLE UFS_BIT(0)
#define CRYPTO_GENERAL_ENABLE UFS_BIT(1)
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 01779f9..24a3ccf 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -490,32 +490,26 @@
return SLIM_P_INPROGRESS;
}
-static int msm_slim_iommu_map(struct msm_slim_ctrl *dev, phys_addr_t iobuf,
+static dma_addr_t msm_slim_iommu_map(struct msm_slim_ctrl *dev, void *buf_addr,
u32 len)
{
- int ret;
+ dma_addr_t ret;
+ struct device *devp = dev->iommu_desc.cb_dev ? dev->iommu_desc.cb_dev :
+ dev->dev;
+ ret = dma_map_single(devp, buf_addr, len, DMA_BIDIRECTIONAL);
- if (!dev->iommu_desc.cb_dev)
- return 0;
+ if (dma_mapping_error(devp, ret))
+ return DMA_ERROR_CODE;
- ret = iommu_map(dev->iommu_desc.iommu_map->domain,
- rounddown(iobuf, PAGE_SIZE),
- rounddown(iobuf, PAGE_SIZE),
- roundup((len + (iobuf - rounddown(iobuf, PAGE_SIZE))),
- PAGE_SIZE), IOMMU_READ | IOMMU_WRITE);
return ret;
}
-static void msm_slim_iommu_unmap(struct msm_slim_ctrl *dev, phys_addr_t iobuf,
+static void msm_slim_iommu_unmap(struct msm_slim_ctrl *dev, dma_addr_t buf_addr,
u32 len)
{
- if (!dev->iommu_desc.cb_dev)
- return;
-
- iommu_unmap(dev->iommu_desc.iommu_map->domain,
- rounddown(iobuf, PAGE_SIZE),
- roundup((len + (iobuf - rounddown(iobuf, PAGE_SIZE))),
- PAGE_SIZE));
+ struct device *devp = dev->iommu_desc.cb_dev ? dev->iommu_desc.cb_dev :
+ dev->dev;
+ dma_unmap_single(devp, buf_addr, len, DMA_BIDIRECTIONAL);
}
static void msm_slim_port_cb(struct sps_event_notify *ev)
@@ -539,11 +533,12 @@
complete(comp);
}
-int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf,
+int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, void *buf,
u32 len, struct completion *comp)
{
struct sps_register_event sreg;
int ret;
+ dma_addr_t dma_buf;
struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
if (pn >= dev->port_nums)
@@ -552,9 +547,11 @@
if (!dev->pipes[pn].connected)
return -ENOTCONN;
- ret = msm_slim_iommu_map(dev, iobuf, len);
- if (ret)
- return ret;
+ dma_buf = msm_slim_iommu_map(dev, buf, len);
+ if (dma_buf == DMA_ERROR_CODE) {
+ dev_err(dev->dev, "error DMA mapping buffers\n");
+ return -ENOMEM;
+ }
sreg.options = (SPS_EVENT_DESC_DONE|SPS_EVENT_ERROR);
sreg.mode = SPS_TRIGGER_WAIT;
@@ -564,10 +561,10 @@
ret = sps_register_event(dev->pipes[pn].sps, &sreg);
if (ret) {
dev_dbg(dev->dev, "sps register event error:%x\n", ret);
- msm_slim_iommu_unmap(dev, iobuf, len);
+ msm_slim_iommu_unmap(dev, dma_buf, len);
return ret;
}
- ret = sps_transfer_one(dev->pipes[pn].sps, iobuf, len, comp,
+ ret = sps_transfer_one(dev->pipes[pn].sps, dma_buf, len, comp,
SPS_IOVEC_FLAG_INT);
dev_dbg(dev->dev, "sps submit xfer error code:%x\n", ret);
if (!ret) {
@@ -581,7 +578,7 @@
/* Make sure that port registers are updated before returning */
mb();
} else {
- msm_slim_iommu_unmap(dev, iobuf, len);
+ msm_slim_iommu_unmap(dev, dma_buf, len);
}
return ret;
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 5859c5f..edebfd9 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -423,7 +423,7 @@
int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn);
enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
u8 pn, phys_addr_t *done_buf, u32 *done_len);
-int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf,
+int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, void *buf,
u32 len, struct completion *comp);
int msm_send_msg_buf(struct msm_slim_ctrl *dev, u32 *buf, u8 len, u32 tx_reg);
u32 *msm_get_msg_buf(struct msm_slim_ctrl *dev, int len,
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index f34467b..1140b33 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -1600,14 +1600,14 @@
* Client will call slim_port_get_xfer_status to get error and/or number of
* bytes transferred if used asynchronously.
*/
-int slim_port_xfer(struct slim_device *sb, u32 ph, phys_addr_t iobuf, u32 len,
+int slim_port_xfer(struct slim_device *sb, u32 ph, void *buf, u32 len,
struct completion *comp)
{
struct slim_controller *ctrl = sb->ctrl;
u8 pn = SLIM_HDL_TO_PORT(ph);
dev_dbg(&ctrl->dev, "port xfer: num:%d", pn);
- return ctrl->port_xfer(ctrl, pn, iobuf, len, comp);
+ return ctrl->port_xfer(ctrl, pn, buf, len, comp);
}
EXPORT_SYMBOL(slim_port_xfer);
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 770f056..c5a15b2 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -646,6 +646,15 @@
monitor events that require the core to be awake and ready to
handle the event.
+config MSM_AVTIMER
+ tristate "Avtimer Driver"
+ default n
+ help
+ This driver gets the Q6 out of power collapsed state
+ and exposes ioctl control to read avtimer tick.
+ Enables camera to use for VT call to get avtimer
+ timestamp.
+
config MSM_PM
depends on PM
select MSM_IDLE_STATS if DEBUG_FS
@@ -786,4 +795,13 @@
sub-system to USB on APSS side. The driver acts as a bridge between the
MHI and USB interface. If unsure, say N.
+config MSM_BAM_DMUX
+ bool "BAM Data Mux Driver"
+ depends on SPS
+ help
+ Support Muxed Data Channels over BAM interface.
+ BAM has a limited number of pipes. This driver
+ provides a means to support more logical channels
+ via muxing than BAM could without muxing.
+
source "drivers/soc/qcom/wcnss/Kconfig"
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index c882403..c7c7f62 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -96,4 +96,5 @@
obj-$(CONFIG_MSM_REMOTEQDSS) += remoteqdss.o
obj-$(CONFIG_QSEE_IPC_IRQ_BRIDGE) += qsee_ipc_irq_bridge.o
obj-$(CONFIG_QCOM_QDSS_BRIDGE) += qdss_bridge.o
+obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o
obj-$(CONFIG_WCNSS_CORE) += wcnss/
diff --git a/drivers/soc/qcom/bam_dmux.c b/drivers/soc/qcom/bam_dmux.c
new file mode 100644
index 0000000..3b75e74
--- /dev/null
+++ b/drivers/soc/qcom/bam_dmux.c
@@ -0,0 +1,2853 @@
+/* Copyright (c) 2011-2016, 2018, 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.
+ *
+ */
+
+/*
+ * BAM DMUX module.
+ */
+
+#define DEBUG
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/clk.h>
+#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/ipc_logging.h>
+#include <linux/srcu.h>
+#include <linux/msm-sps.h>
+#include <linux/sizes.h>
+#include <soc/qcom/bam_dmux.h>
+#include <soc/qcom/smsm.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+
+#include "bam_dmux_private.h"
+
+#define BAM_CH_LOCAL_OPEN 0x1
+#define BAM_CH_REMOTE_OPEN 0x2
+#define BAM_CH_IN_RESET 0x4
+
+#define LOW_WATERMARK 2
+#define HIGH_WATERMARK 4
+#define DEFAULT_POLLING_MIN_SLEEP (950)
+#define MAX_POLLING_SLEEP (6050)
+#define MIN_POLLING_SLEEP (950)
+
+static int msm_bam_dmux_debug_enable;
+module_param_named(debug_enable, msm_bam_dmux_debug_enable, int, 0664);
+static int POLLING_MIN_SLEEP = 2950;
+module_param_named(min_sleep, POLLING_MIN_SLEEP, int, 0664);
+static int POLLING_MAX_SLEEP = 3050;
+module_param_named(max_sleep, POLLING_MAX_SLEEP, int, 0664);
+static int POLLING_INACTIVITY = 1;
+module_param_named(inactivity, POLLING_INACTIVITY, int, 0664);
+static int bam_adaptive_timer_enabled;
+module_param_named(adaptive_timer_enabled,
+ bam_adaptive_timer_enabled, int, 0664);
+
+static struct bam_ops_if bam_default_ops = {
+ /* smsm */
+ .smsm_change_state_ptr = &smsm_change_state,
+ .smsm_get_state_ptr = &smsm_get_state,
+ .smsm_state_cb_register_ptr = &smsm_state_cb_register,
+ .smsm_state_cb_deregister_ptr = &smsm_state_cb_deregister,
+
+ /* sps */
+ .sps_connect_ptr = &sps_connect,
+ .sps_disconnect_ptr = &sps_disconnect,
+ .sps_register_bam_device_ptr = &sps_register_bam_device,
+ .sps_deregister_bam_device_ptr = &sps_deregister_bam_device,
+ .sps_alloc_endpoint_ptr = &sps_alloc_endpoint,
+ .sps_free_endpoint_ptr = &sps_free_endpoint,
+ .sps_set_config_ptr = &sps_set_config,
+ .sps_get_config_ptr = &sps_get_config,
+ .sps_device_reset_ptr = &sps_device_reset,
+ .sps_register_event_ptr = &sps_register_event,
+ .sps_transfer_one_ptr = &sps_transfer_one,
+ .sps_get_iovec_ptr = &sps_get_iovec,
+ .sps_get_unused_desc_num_ptr = &sps_get_unused_desc_num,
+
+ .dma_to = DMA_TO_DEVICE,
+ .dma_from = DMA_FROM_DEVICE,
+};
+static struct bam_ops_if *bam_ops = &bam_default_ops;
+
+#if defined(DEBUG)
+static uint32_t bam_dmux_read_cnt;
+static uint32_t bam_dmux_write_cnt;
+static uint32_t bam_dmux_write_cpy_cnt;
+static uint32_t bam_dmux_write_cpy_bytes;
+static uint32_t bam_dmux_tx_sps_failure_cnt;
+static uint32_t bam_dmux_tx_stall_cnt;
+static atomic_t bam_dmux_ack_out_cnt = ATOMIC_INIT(0);
+static atomic_t bam_dmux_ack_in_cnt = ATOMIC_INIT(0);
+static atomic_t bam_dmux_a2_pwr_cntl_in_cnt = ATOMIC_INIT(0);
+
+#define DBG(x...) do { \
+ if (msm_bam_dmux_debug_enable) \
+ pr_debug(x); \
+ } while (0)
+
+#define DBG_INC_READ_CNT(x) do { \
+ bam_dmux_read_cnt += (x); \
+ if (msm_bam_dmux_debug_enable) \
+ pr_debug("%s: total read bytes %u\n", \
+ __func__, bam_dmux_read_cnt); \
+ } while (0)
+
+#define DBG_INC_WRITE_CNT(x) do { \
+ bam_dmux_write_cnt += (x); \
+ if (msm_bam_dmux_debug_enable) \
+ pr_debug("%s: total written bytes %u\n", \
+ __func__, bam_dmux_write_cnt); \
+ } while (0)
+
+#define DBG_INC_WRITE_CPY(x) do { \
+ bam_dmux_write_cpy_bytes += (x); \
+ bam_dmux_write_cpy_cnt++; \
+ if (msm_bam_dmux_debug_enable) \
+ pr_debug("%s: total write copy cnt %u, bytes %u\n", \
+ __func__, bam_dmux_write_cpy_cnt, \
+ bam_dmux_write_cpy_bytes); \
+ } while (0)
+
+#define DBG_INC_TX_SPS_FAILURE_CNT() (bam_dmux_tx_sps_failure_cnt++)
+
+#define DBG_INC_TX_STALL_CNT() (bam_dmux_tx_stall_cnt++)
+
+#define DBG_INC_ACK_OUT_CNT() \
+ atomic_inc(&bam_dmux_ack_out_cnt)
+
+#define DBG_INC_A2_POWER_CONTROL_IN_CNT() \
+ atomic_inc(&bam_dmux_a2_pwr_cntl_in_cnt)
+
+#define DBG_INC_ACK_IN_CNT() \
+ atomic_inc(&bam_dmux_ack_in_cnt)
+#else
+#define DBG(x...) do { } while (0)
+#define DBG_INC_READ_CNT(x...) do { } while (0)
+#define DBG_INC_WRITE_CNT(x...) do { } while (0)
+#define DBG_INC_WRITE_CPY(x...) do { } while (0)
+#define DBG_INC_TX_SPS_FAILURE_CNT() do { } while (0)
+#define DBG_INC_TX_STALL_CNT() do { } while (0)
+#define DBG_INC_ACK_OUT_CNT() do { } while (0)
+#define DBG_INC_A2_POWER_CONTROL_IN_CNT() \
+ do { } while (0)
+#define DBG_INC_ACK_IN_CNT() do { } while (0)
+#endif
+
+struct bam_ch_info {
+ uint32_t status;
+ void (*notify)(void *, int, unsigned long);
+ void *priv;
+ spinlock_t lock;
+ struct platform_device *pdev;
+ char name[BAM_DMUX_CH_NAME_MAX_LEN];
+ int num_tx_pkts;
+ int use_wm;
+};
+
+#define A2_NUM_PIPES 6
+#define A2_SUMMING_THRESHOLD 4096
+#define A2_PHYS_BASE 0x124C2000
+#define A2_PHYS_SIZE 0x2000
+#define DEFAULT_NUM_BUFFERS 32
+
+#ifndef A2_BAM_IRQ
+#define A2_BAM_IRQ -1
+#endif
+
+static phys_addr_t a2_phys_base;
+static uint32_t a2_phys_size;
+static int a2_bam_irq;
+static struct sps_bam_props a2_props;
+static unsigned long a2_device_handle;
+static struct sps_pipe *bam_tx_pipe;
+static struct sps_pipe *bam_rx_pipe;
+static struct sps_connect tx_connection;
+static struct sps_connect rx_connection;
+static struct sps_mem_buffer tx_desc_mem_buf;
+static struct sps_mem_buffer rx_desc_mem_buf;
+static struct sps_register_event tx_register_event;
+static struct sps_register_event rx_register_event;
+static bool satellite_mode;
+static uint32_t num_buffers;
+static unsigned long long last_rx_pkt_timestamp;
+static struct device *dma_dev;
+static bool dynamic_mtu_enabled;
+static uint16_t ul_mtu = DEFAULT_BUFFER_SIZE;
+static uint16_t dl_mtu = DEFAULT_BUFFER_SIZE;
+static uint16_t buffer_size = DEFAULT_BUFFER_SIZE;
+static bool no_cpu_affinity;
+
+static struct bam_ch_info bam_ch[BAM_DMUX_NUM_CHANNELS];
+static int bam_mux_initialized;
+
+static int polling_mode;
+static unsigned long rx_timer_interval;
+
+static LIST_HEAD(bam_rx_pool);
+static DEFINE_MUTEX(bam_rx_pool_mutexlock);
+static int bam_rx_pool_len;
+static LIST_HEAD(bam_tx_pool);
+static DEFINE_SPINLOCK(bam_tx_pool_spinlock);
+static DEFINE_MUTEX(bam_pdev_mutexlock);
+
+static void notify_all(int event, unsigned long data);
+static void bam_mux_write_done(struct work_struct *work);
+static void handle_bam_mux_cmd(struct work_struct *work);
+static void rx_timer_work_func(struct work_struct *work);
+static void queue_rx_work_func(struct work_struct *work);
+static int ssrestart_check(void);
+
+static DECLARE_WORK(rx_timer_work, rx_timer_work_func);
+static DECLARE_WORK(queue_rx_work, queue_rx_work_func);
+
+static struct workqueue_struct *bam_mux_rx_workqueue;
+static struct workqueue_struct *bam_mux_tx_workqueue;
+
+static struct srcu_struct bam_dmux_srcu;
+
+/* A2 power collaspe */
+#define UL_TIMEOUT_DELAY 1000 /* in ms */
+#define UL_FAST_TIMEOUT_DELAY 100 /* in ms */
+#define SHUTDOWN_TIMEOUT_MS 500
+#define UL_WAKEUP_TIMEOUT_MS 2000
+static uint32_t ul_timeout_delay = UL_TIMEOUT_DELAY;
+static void toggle_apps_ack(void);
+static void reconnect_to_bam(void);
+static void disconnect_to_bam(void);
+static void ul_wakeup(void);
+static void ul_timeout(struct work_struct *work);
+static void vote_dfab(void);
+static void unvote_dfab(void);
+static void kickoff_ul_wakeup_func(struct work_struct *work);
+static void grab_wakelock(void);
+static void release_wakelock(void);
+
+static int bam_is_connected;
+static DEFINE_MUTEX(wakeup_lock);
+static struct completion ul_wakeup_ack_completion;
+static struct completion bam_connection_completion;
+static struct delayed_work ul_timeout_work;
+static int ul_packet_written;
+static atomic_t ul_ondemand_vote = ATOMIC_INIT(0);
+static struct clk *dfab_clk, *xo_clk;
+static DEFINE_RWLOCK(ul_wakeup_lock);
+static DECLARE_WORK(kickoff_ul_wakeup, kickoff_ul_wakeup_func);
+static int bam_connection_is_active;
+static int wait_for_ack;
+static struct wakeup_source bam_wakelock;
+static int a2_pc_disabled;
+static DEFINE_MUTEX(dfab_status_lock);
+static int dfab_is_on;
+static int wait_for_dfab;
+static struct completion dfab_unvote_completion;
+static DEFINE_SPINLOCK(wakelock_reference_lock);
+static int wakelock_reference_count;
+static int a2_pc_disabled_wakelock_skipped;
+static LIST_HEAD(bam_other_notify_funcs);
+static DEFINE_MUTEX(smsm_cb_lock);
+static DEFINE_MUTEX(delayed_ul_vote_lock);
+static int need_delayed_ul_vote;
+static int ssr_skipped_disconnect;
+static struct completion shutdown_completion;
+
+struct outside_notify_func {
+ void (*notify)(void *, int, unsigned long);
+ void *priv;
+ struct list_head list_node;
+};
+/* End A2 power collaspe */
+
+/* subsystem restart */
+static int restart_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data);
+
+static struct notifier_block restart_notifier = {
+ .notifier_call = restart_notifier_cb,
+};
+static int in_global_reset;
+/* end subsystem restart */
+
+#define bam_ch_is_open(x) \
+ (bam_ch[(x)].status == (BAM_CH_LOCAL_OPEN | BAM_CH_REMOTE_OPEN))
+
+#define bam_ch_is_local_open(x) \
+ (bam_ch[(x)].status & BAM_CH_LOCAL_OPEN)
+
+#define bam_ch_is_remote_open(x) \
+ (bam_ch[(x)].status & BAM_CH_REMOTE_OPEN)
+
+#define bam_ch_is_in_reset(x) \
+ (bam_ch[(x)].status & BAM_CH_IN_RESET)
+
+static int bam_dmux_uplink_vote;
+static int bam_dmux_power_state;
+
+static void *bam_ipc_log_txt;
+
+#define BAM_IPC_LOG_PAGES 5
+
+/**
+ * Log a state change along with a small message.
+ * Complete size of message is limited to @todo.
+ * Logging is done using IPC Logging infrastructure.
+ *
+ * States
+ * D: 1 = Power collapse disabled
+ * R: 1 = in global reset
+ * P: 1 = BAM is powered up
+ * A: 1 = BAM initialized and ready for data
+ * V: 1 = Uplink vote for power
+ * U: 1 = Uplink active
+ * W: 1 = Uplink Wait-for-ack
+ * A: 1 = Uplink ACK received
+ * #: >=1 On-demand uplink vote
+ * D: 1 = Disconnect ACK active
+ */
+
+#define BAM_DMUX_LOG(fmt, args...) \
+do { \
+ if (bam_ipc_log_txt) { \
+ ipc_log_string(bam_ipc_log_txt, \
+ "<DMUX> %c%c%c%c %c%c%c%c%d " fmt, \
+ a2_pc_disabled ? 'D' : 'd', \
+ in_global_reset ? 'R' : 'r', \
+ bam_dmux_power_state ? 'P' : 'p', \
+ bam_connection_is_active ? 'A' : 'a', \
+ bam_dmux_uplink_vote ? 'V' : 'v', \
+ bam_is_connected ? 'U' : 'u', \
+ wait_for_ack ? 'W' : 'w', \
+ ul_wakeup_ack_completion.done ? 'A' : 'a', \
+ atomic_read(&ul_ondemand_vote), \
+ args); \
+ } \
+} while (0)
+
+#define DMUX_LOG_KERR(fmt, args...) \
+do { \
+ BAM_DMUX_LOG(fmt, args); \
+ pr_err(fmt, args); \
+} while (0)
+
+static inline void set_tx_timestamp(struct tx_pkt_info *pkt)
+{
+ unsigned long long t_now;
+
+ t_now = sched_clock();
+ pkt->ts_nsec = do_div(t_now, 1000000000U);
+ pkt->ts_sec = (unsigned int)t_now;
+}
+
+static inline void verify_tx_queue_is_empty(const char *func)
+{
+ unsigned long flags;
+ struct tx_pkt_info *info;
+ int reported = 0;
+
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+ list_for_each_entry(info, &bam_tx_pool, list_node) {
+ if (!reported) {
+ BAM_DMUX_LOG("%s: tx pool not empty\n", func);
+ if (!in_global_reset)
+ pr_err("%s: tx pool not empty\n", func);
+ reported = 1;
+ }
+ BAM_DMUX_LOG("%s: node=%pK ts=%u.%09lu\n", __func__,
+ &info->list_node, info->ts_sec, info->ts_nsec);
+ if (!in_global_reset)
+ pr_err("%s: node=%pK ts=%u.%09lu\n", __func__,
+ &info->list_node, info->ts_sec, info->ts_nsec);
+ }
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+}
+
+static void __queue_rx(gfp_t alloc_flags)
+{
+ void *ptr;
+ struct rx_pkt_info *info;
+ int ret;
+ int rx_len_cached;
+ uint16_t current_buffer_size;
+
+ mutex_lock(&bam_rx_pool_mutexlock);
+ rx_len_cached = bam_rx_pool_len;
+ current_buffer_size = buffer_size;
+ mutex_unlock(&bam_rx_pool_mutexlock);
+
+ while (bam_connection_is_active && rx_len_cached < num_buffers) {
+ if (in_global_reset)
+ goto fail;
+
+ info = kmalloc(sizeof(*info), alloc_flags);
+ if (!info)
+ goto fail;
+
+ info->len = current_buffer_size;
+
+ INIT_WORK(&info->work, handle_bam_mux_cmd);
+
+ info->skb = __dev_alloc_skb(info->len, alloc_flags);
+ if (info->skb == NULL)
+ goto fail_info;
+
+ ptr = skb_put(info->skb, info->len);
+
+ info->dma_address = dma_map_single(dma_dev, ptr, info->len,
+ bam_ops->dma_from);
+ if (info->dma_address == 0 || info->dma_address == ~0) {
+ DMUX_LOG_KERR("%s:dma_map_single failure %pK for %pK\n",
+ __func__, (void *)info->dma_address, ptr);
+ goto fail_skb;
+ }
+
+ mutex_lock(&bam_rx_pool_mutexlock);
+ list_add_tail(&info->list_node, &bam_rx_pool);
+ rx_len_cached = ++bam_rx_pool_len;
+ current_buffer_size = buffer_size;
+ ret = bam_ops->sps_transfer_one_ptr(bam_rx_pipe,
+ info->dma_address, info->len, info, 0);
+ if (ret) {
+ list_del(&info->list_node);
+ rx_len_cached = --bam_rx_pool_len;
+ mutex_unlock(&bam_rx_pool_mutexlock);
+ DMUX_LOG_KERR("%s: sps_transfer_one failed %d\n",
+ __func__, ret);
+
+ dma_unmap_single(dma_dev, info->dma_address,
+ info->len,
+ bam_ops->dma_from);
+
+ goto fail_skb;
+ }
+ mutex_unlock(&bam_rx_pool_mutexlock);
+
+ }
+ return;
+
+fail_skb:
+ dev_kfree_skb_any(info->skb);
+
+fail_info:
+ kfree(info);
+
+fail:
+ if (!in_global_reset) {
+ DMUX_LOG_KERR("%s: rescheduling\n", __func__);
+ schedule_work(&queue_rx_work);
+ }
+}
+
+static void queue_rx(void)
+{
+ /*
+ * Hot path. Delays waiting for the allocation to find memory if its
+ * not immediately available, and delays from logging allocation
+ * failures which cannot be tolerated at this time.
+ */
+ __queue_rx(GFP_NOWAIT | __GFP_NOWARN);
+}
+
+static void queue_rx_work_func(struct work_struct *work)
+{
+ /*
+ * Cold path. Delays can be tolerated. Use of GFP_KERNEL should
+ * guarantee the requested memory will be found, after some ammount of
+ * delay.
+ */
+ __queue_rx(GFP_KERNEL);
+}
+
+/**
+ * process_dynamic_mtu() - Process the dynamic MTU signal bit from data cmds
+ * @current_state: State of the dynamic MTU signal bit for the current
+ * data command packet.
+ */
+static void process_dynamic_mtu(bool current_state)
+{
+ static bool old_state;
+
+ if (!dynamic_mtu_enabled)
+ return;
+
+ if (old_state == current_state)
+ return;
+
+ mutex_lock(&bam_rx_pool_mutexlock);
+ if (current_state) {
+ buffer_size = dl_mtu;
+ BAM_DMUX_LOG("%s: switching to large mtu %x\n", __func__,
+ dl_mtu);
+ } else {
+ buffer_size = DEFAULT_BUFFER_SIZE;
+ BAM_DMUX_LOG("%s: switching to reg mtu %x\n", __func__,
+ DEFAULT_BUFFER_SIZE);
+ }
+ mutex_unlock(&bam_rx_pool_mutexlock);
+
+ old_state = current_state;
+}
+
+static void bam_mux_process_data(struct sk_buff *rx_skb)
+{
+ unsigned long flags;
+ struct bam_mux_hdr *rx_hdr;
+ unsigned long event_data;
+ uint8_t ch_id;
+ void (*notify)(void *, int, unsigned long);
+ void *priv;
+
+ rx_hdr = (struct bam_mux_hdr *)rx_skb->data;
+ ch_id = rx_hdr->ch_id;
+
+ process_dynamic_mtu(rx_hdr->signal & DYNAMIC_MTU_MASK);
+
+ rx_skb->data = (unsigned char *)(rx_hdr + 1);
+ skb_set_tail_pointer(rx_skb, rx_hdr->pkt_len);
+ rx_skb->len = rx_hdr->pkt_len;
+ rx_skb->truesize = rx_hdr->pkt_len + sizeof(struct sk_buff);
+
+ event_data = (unsigned long)(rx_skb);
+ notify = NULL;
+ priv = NULL;
+
+ spin_lock_irqsave(&bam_ch[ch_id].lock, flags);
+ if (bam_ch[ch_id].notify) {
+ notify = bam_ch[ch_id].notify;
+ priv = bam_ch[ch_id].priv;
+ }
+ spin_unlock_irqrestore(&bam_ch[ch_id].lock, flags);
+ if (notify)
+ notify(priv, BAM_DMUX_RECEIVE, event_data);
+ else
+ dev_kfree_skb_any(rx_skb);
+
+ queue_rx();
+}
+
+/**
+ * set_ul_mtu() - Converts the MTU code received from the remote side in the
+ * open cmd into a byte value.
+ * @mtu_code: MTU size code to translate.
+ * @reset: Reset the MTU.
+ */
+static void set_ul_mtu(int mtu_code, bool reset)
+{
+ static bool first = true;
+
+ if (reset) {
+ first = true;
+ ul_mtu = DEFAULT_BUFFER_SIZE;
+ return;
+ }
+
+ switch (mtu_code) {
+ case 0:
+ if (ul_mtu != SZ_2K && !first) {
+ BAM_DMUX_LOG("%s: bad request for 2k, ul_mtu is %d\n",
+ __func__, ul_mtu);
+ ssrestart_check();
+ }
+ ul_mtu = SZ_2K;
+ break;
+ case 1:
+ if (ul_mtu != SZ_4K && !first) {
+ BAM_DMUX_LOG("%s: bad request for 4k, ul_mtu is %d\n",
+ __func__, ul_mtu);
+ ssrestart_check();
+ }
+ ul_mtu = SZ_4K;
+ break;
+ case 2:
+ if (ul_mtu != SZ_8K && !first) {
+ BAM_DMUX_LOG("%s: bad request for 8k, ul_mtu is %d\n",
+ __func__, ul_mtu);
+ ssrestart_check();
+ }
+ ul_mtu = SZ_8K;
+ break;
+ case 3:
+ if (ul_mtu != SZ_16K && !first) {
+ BAM_DMUX_LOG("%s: bad request for 16k, ul_mtu is %d\n",
+ __func__, ul_mtu);
+ ssrestart_check();
+ }
+ ul_mtu = SZ_16K;
+ break;
+ default:
+ BAM_DMUX_LOG("%s: bad request %d\n", __func__, mtu_code);
+ ssrestart_check();
+ break;
+ }
+
+ first = false;
+}
+
+static inline void handle_bam_mux_cmd_open(struct bam_mux_hdr *rx_hdr)
+{
+ unsigned long flags;
+ int ret;
+
+ mutex_lock(&bam_pdev_mutexlock);
+ if (in_global_reset) {
+ BAM_DMUX_LOG("%s: open cid %d aborted due to ssr\n",
+ __func__, rx_hdr->ch_id);
+ mutex_unlock(&bam_pdev_mutexlock);
+ queue_rx();
+ return;
+ }
+ if (rx_hdr->signal & DYNAMIC_MTU_MASK) {
+ dynamic_mtu_enabled = true;
+ set_ul_mtu((rx_hdr->signal & MTU_SIZE_MASK) >> MTU_SIZE_SHIFT,
+ false);
+ } else {
+ set_ul_mtu(0, false);
+ }
+ spin_lock_irqsave(&bam_ch[rx_hdr->ch_id].lock, flags);
+ if (bam_ch_is_remote_open(rx_hdr->ch_id)) {
+ /*
+ * Receiving an open command for a channel that is already open
+ * is an invalid operation and likely signifies a significant
+ * issue within the A2 which should be caught immediately
+ * before it snowballs and the root cause is lost.
+ */
+ panic("A2 sent invalid duplicate open for channel %d\n",
+ rx_hdr->ch_id);
+ }
+ bam_ch[rx_hdr->ch_id].status |= BAM_CH_REMOTE_OPEN;
+ bam_ch[rx_hdr->ch_id].num_tx_pkts = 0;
+ spin_unlock_irqrestore(&bam_ch[rx_hdr->ch_id].lock, flags);
+ ret = platform_device_add(bam_ch[rx_hdr->ch_id].pdev);
+ if (ret)
+ pr_err("%s: platform_device_add() error: %d\n",
+ __func__, ret);
+ mutex_unlock(&bam_pdev_mutexlock);
+ queue_rx();
+}
+
+static void handle_bam_mux_cmd(struct work_struct *work)
+{
+ unsigned long flags;
+ struct bam_mux_hdr *rx_hdr;
+ struct rx_pkt_info *info;
+ struct sk_buff *rx_skb;
+ uint16_t sps_size;
+
+ info = container_of(work, struct rx_pkt_info, work);
+ rx_skb = info->skb;
+ dma_unmap_single(dma_dev, info->dma_address, info->len,
+ bam_ops->dma_from);
+ sps_size = info->sps_size;
+ kfree(info);
+
+ rx_hdr = (struct bam_mux_hdr *)rx_skb->data;
+
+ DBG_INC_READ_CNT(sizeof(struct bam_mux_hdr));
+ DBG("%s: magic %x signal %x cmd %d pad %d ch %d len %d\n", __func__,
+ rx_hdr->magic_num, rx_hdr->signal, rx_hdr->cmd,
+ rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
+ if (rx_hdr->magic_num != BAM_MUX_HDR_MAGIC_NO) {
+ DMUX_LOG_KERR(
+ "%s: dropping invalid hdr. magic %x signal %x cmd %d pad %d ch %d len %d\n",
+ __func__, rx_hdr->magic_num, rx_hdr->signal,
+ rx_hdr->cmd, rx_hdr->pad_len, rx_hdr->ch_id,
+ rx_hdr->pkt_len);
+ dev_kfree_skb_any(rx_skb);
+ queue_rx();
+ return;
+ }
+
+ if (rx_hdr->ch_id >= BAM_DMUX_NUM_CHANNELS) {
+ DMUX_LOG_KERR(
+ "%s: dropping invalid LCID %d signal %x cmd %d pad %d ch %d len %d\n",
+ __func__, rx_hdr->ch_id, rx_hdr->signal, rx_hdr->cmd,
+ rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
+ dev_kfree_skb_any(rx_skb);
+ queue_rx();
+ return;
+ }
+
+ switch (rx_hdr->cmd) {
+ case BAM_MUX_HDR_CMD_DATA:
+ if (rx_hdr->pkt_len == 0xffff)
+ /* SPS includes the header bytes, need just payload */
+ rx_hdr->pkt_len = sps_size - sizeof(*rx_hdr);
+ DBG_INC_READ_CNT(rx_hdr->pkt_len);
+ bam_mux_process_data(rx_skb);
+ break;
+ case BAM_MUX_HDR_CMD_OPEN:
+ BAM_DMUX_LOG("%s: opening cid %d PC enabled\n", __func__,
+ rx_hdr->ch_id);
+ handle_bam_mux_cmd_open(rx_hdr);
+ dev_kfree_skb_any(rx_skb);
+ break;
+ case BAM_MUX_HDR_CMD_OPEN_NO_A2_PC:
+ BAM_DMUX_LOG("%s: opening cid %d PC disabled\n", __func__,
+ rx_hdr->ch_id);
+
+ if (!a2_pc_disabled) {
+ a2_pc_disabled = 1;
+ ul_wakeup();
+ }
+
+ handle_bam_mux_cmd_open(rx_hdr);
+ dev_kfree_skb_any(rx_skb);
+ break;
+ case BAM_MUX_HDR_CMD_CLOSE:
+ /* probably should drop pending write */
+ BAM_DMUX_LOG("%s: closing cid %d\n", __func__,
+ rx_hdr->ch_id);
+ mutex_lock(&bam_pdev_mutexlock);
+ if (in_global_reset) {
+ BAM_DMUX_LOG("%s: close cid %d aborted due to ssr\n",
+ __func__, rx_hdr->ch_id);
+ mutex_unlock(&bam_pdev_mutexlock);
+ break;
+ }
+ spin_lock_irqsave(&bam_ch[rx_hdr->ch_id].lock, flags);
+ bam_ch[rx_hdr->ch_id].status &= ~BAM_CH_REMOTE_OPEN;
+ spin_unlock_irqrestore(&bam_ch[rx_hdr->ch_id].lock, flags);
+ platform_device_unregister(bam_ch[rx_hdr->ch_id].pdev);
+ bam_ch[rx_hdr->ch_id].pdev =
+ platform_device_alloc(bam_ch[rx_hdr->ch_id].name, 2);
+ if (!bam_ch[rx_hdr->ch_id].pdev)
+ pr_err("%s: platform_device_alloc failed\n", __func__);
+ mutex_unlock(&bam_pdev_mutexlock);
+ dev_kfree_skb_any(rx_skb);
+ queue_rx();
+ break;
+ default:
+ DMUX_LOG_KERR(
+ "%s: dropping invalid hdr. magic %x signal %x cmd %d pad %d ch %d len %d\n",
+ __func__, rx_hdr->magic_num, rx_hdr->signal,
+ rx_hdr->cmd, rx_hdr->pad_len, rx_hdr->ch_id,
+ rx_hdr->pkt_len);
+ dev_kfree_skb_any(rx_skb);
+ queue_rx();
+ return;
+ }
+}
+
+static int bam_mux_write_cmd(void *data, uint32_t len)
+{
+ int rc;
+ struct tx_pkt_info *pkt;
+ dma_addr_t dma_address;
+ unsigned long flags;
+
+ pkt = kmalloc(sizeof(struct tx_pkt_info), GFP_ATOMIC);
+ if (pkt == NULL) {
+ rc = -ENOMEM;
+ return rc;
+ }
+
+ dma_address = dma_map_single(dma_dev, data, len,
+ bam_ops->dma_to);
+ if (!dma_address) {
+ pr_err("%s: dma_map_single() failed\n", __func__);
+ kfree(pkt);
+ rc = -ENOMEM;
+ return rc;
+ }
+ pkt->skb = (struct sk_buff *)(data);
+ pkt->len = len;
+ pkt->dma_address = dma_address;
+ pkt->is_cmd = 1;
+ set_tx_timestamp(pkt);
+ INIT_WORK(&pkt->work, bam_mux_write_done);
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+ list_add_tail(&pkt->list_node, &bam_tx_pool);
+ rc = bam_ops->sps_transfer_one_ptr(bam_tx_pipe, dma_address, len,
+ pkt, SPS_IOVEC_FLAG_EOT);
+ if (rc) {
+ DMUX_LOG_KERR("%s sps_transfer_one failed rc=%d\n",
+ __func__, rc);
+ list_del(&pkt->list_node);
+ DBG_INC_TX_SPS_FAILURE_CNT();
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+ dma_unmap_single(dma_dev, pkt->dma_address,
+ pkt->len,
+ bam_ops->dma_to);
+ kfree(pkt);
+ } else {
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+ }
+
+ ul_packet_written = 1;
+ return rc;
+}
+
+static void bam_mux_write_done(struct work_struct *work)
+{
+ struct sk_buff *skb;
+ struct bam_mux_hdr *hdr;
+ struct tx_pkt_info *info;
+ struct tx_pkt_info *info_expected;
+ unsigned long event_data;
+ unsigned long flags;
+
+ if (in_global_reset)
+ return;
+
+ info = container_of(work, struct tx_pkt_info, work);
+
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+ info_expected = list_first_entry(&bam_tx_pool,
+ struct tx_pkt_info, list_node);
+ if (unlikely(info != info_expected)) {
+ struct tx_pkt_info *errant_pkt;
+
+ BAM_DMUX_LOG(
+ "%s: bam_tx_pool mismatch .next=%pK, list_node=%pK, ts=%u.%09lu\n",
+ __func__, bam_tx_pool.next, &info->list_node,
+ info->ts_sec, info->ts_nsec
+ );
+
+ list_for_each_entry(errant_pkt, &bam_tx_pool, list_node) {
+ BAM_DMUX_LOG("%s: node=%pK ts=%u.%09lu\n", __func__,
+ &errant_pkt->list_node, errant_pkt->ts_sec,
+ errant_pkt->ts_nsec);
+
+ }
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+ WARN_ON(1);
+ }
+ list_del(&info->list_node);
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
+ if (info->is_cmd) {
+ kfree(info->skb);
+ kfree(info);
+ return;
+ }
+ skb = info->skb;
+ kfree(info);
+ hdr = (struct bam_mux_hdr *)skb->data;
+ DBG_INC_WRITE_CNT(skb->len);
+ /* Restore skb for client */
+ skb_pull(skb, sizeof(*hdr));
+ if (hdr->pad_len)
+ skb_trim(skb, skb->len - hdr->pad_len);
+
+ event_data = (unsigned long)(skb);
+ spin_lock_irqsave(&bam_ch[hdr->ch_id].lock, flags);
+ bam_ch[hdr->ch_id].num_tx_pkts--;
+ spin_unlock_irqrestore(&bam_ch[hdr->ch_id].lock, flags);
+ if (bam_ch[hdr->ch_id].notify)
+ bam_ch[hdr->ch_id].notify(
+ bam_ch[hdr->ch_id].priv, BAM_DMUX_WRITE_DONE,
+ event_data);
+ else
+ dev_kfree_skb_any(skb);
+}
+
+int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb)
+{
+ int rc = 0;
+ struct bam_mux_hdr *hdr;
+ unsigned long flags;
+ struct sk_buff *new_skb = NULL;
+ dma_addr_t dma_address;
+ struct tx_pkt_info *pkt;
+ int rcu_id;
+
+ if (id >= BAM_DMUX_NUM_CHANNELS)
+ return -EINVAL;
+ if (!skb)
+ return -EINVAL;
+ if (!bam_mux_initialized)
+ return -ENODEV;
+
+ rcu_id = srcu_read_lock(&bam_dmux_srcu);
+ if (in_global_reset) {
+ BAM_DMUX_LOG("%s: In SSR... ch_id[%d]\n", __func__, id);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+ return -EFAULT;
+ }
+
+ DBG("%s: writing to ch %d len %d\n", __func__, id, skb->len);
+ spin_lock_irqsave(&bam_ch[id].lock, flags);
+ if (!bam_ch_is_open(id)) {
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+ pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+ return -ENODEV;
+ }
+
+ if (bam_ch[id].use_wm &&
+ (bam_ch[id].num_tx_pkts >= HIGH_WATERMARK)) {
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+ pr_err("%s: watermark exceeded: %d\n", __func__, id);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+ return -EAGAIN;
+ }
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+ read_lock(&ul_wakeup_lock);
+ if (!bam_is_connected) {
+ atomic_inc(&ul_ondemand_vote);
+ read_unlock(&ul_wakeup_lock);
+ ul_wakeup();
+ if (unlikely(in_global_reset == 1)) {
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+ atomic_dec(&ul_ondemand_vote);
+ return -EFAULT;
+ }
+ read_lock(&ul_wakeup_lock);
+ notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
+ atomic_dec(&ul_ondemand_vote);
+ }
+
+ /* if skb do not have any tailroom for padding,
+ * copy the skb into a new expanded skb
+ */
+ if ((skb->len & 0x3) && (skb_tailroom(skb) < (4 - (skb->len & 0x3)))) {
+ /* revisit, probably dev_alloc_skb and memcpy is effecient */
+ new_skb = skb_copy_expand(skb, skb_headroom(skb),
+ 4 - (skb->len & 0x3), GFP_ATOMIC);
+ if (new_skb == NULL) {
+ pr_err("%s: cannot allocate skb\n", __func__);
+ goto write_fail;
+ }
+ dev_kfree_skb_any(skb);
+ skb = new_skb;
+ DBG_INC_WRITE_CPY(skb->len);
+ }
+
+ hdr = (struct bam_mux_hdr *)skb_push(skb, sizeof(struct bam_mux_hdr));
+
+ /* caller should allocate for hdr and padding
+ * hdr is fine, padding is tricky
+ */
+ hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
+ hdr->cmd = BAM_MUX_HDR_CMD_DATA;
+ hdr->signal = 0;
+ hdr->ch_id = id;
+ hdr->pkt_len = skb->len - sizeof(struct bam_mux_hdr);
+ if (skb->len & 0x3)
+ skb_put(skb, 4 - (skb->len & 0x3));
+
+ hdr->pad_len = skb->len - (sizeof(struct bam_mux_hdr) + hdr->pkt_len);
+
+ DBG("%s: data %pK, tail %pK skb len %d pkt len %d pad len %d\n",
+ __func__, skb->data, skb_tail_pointer(skb), skb->len,
+ hdr->pkt_len, hdr->pad_len);
+
+ pkt = kmalloc(sizeof(struct tx_pkt_info), GFP_ATOMIC);
+ if (pkt == NULL)
+ goto write_fail2;
+
+ dma_address = dma_map_single(dma_dev, skb->data, skb->len,
+ bam_ops->dma_to);
+ if (!dma_address) {
+ pr_err("%s: dma_map_single() failed\n", __func__);
+ goto write_fail3;
+ }
+ pkt->skb = skb;
+ pkt->dma_address = dma_address;
+ pkt->is_cmd = 0;
+ set_tx_timestamp(pkt);
+ INIT_WORK(&pkt->work, bam_mux_write_done);
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+ list_add_tail(&pkt->list_node, &bam_tx_pool);
+ rc = bam_ops->sps_transfer_one_ptr(bam_tx_pipe, dma_address, skb->len,
+ pkt, SPS_IOVEC_FLAG_EOT);
+ if (rc) {
+ DMUX_LOG_KERR("%s sps_transfer_one failed rc=%d\n",
+ __func__, rc);
+ list_del(&pkt->list_node);
+ DBG_INC_TX_SPS_FAILURE_CNT();
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+ dma_unmap_single(dma_dev, pkt->dma_address,
+ pkt->skb->len, bam_ops->dma_to);
+ kfree(pkt);
+ if (new_skb)
+ dev_kfree_skb_any(new_skb);
+ } else {
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+ spin_lock_irqsave(&bam_ch[id].lock, flags);
+ bam_ch[id].num_tx_pkts++;
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+ }
+ ul_packet_written = 1;
+ read_unlock(&ul_wakeup_lock);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+ return rc;
+
+write_fail3:
+ kfree(pkt);
+write_fail2:
+ skb_pull(skb, sizeof(struct bam_mux_hdr));
+ if (new_skb)
+ dev_kfree_skb_any(new_skb);
+write_fail:
+ read_unlock(&ul_wakeup_lock);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+ return -ENOMEM;
+}
+
+/**
+ * create_open_signal() - Generate a proper signal field for outgoing open cmds
+ *
+ * A properly constructed signal field of the mux header for opem commands semt
+ * to the remote side depend on what has been locally configured, and what has
+ * been received from the remote side. The byte value to code translations
+ * must match the valid values in set_rx_buffer_ring_pool() and set_dl_mtu().
+ *
+ * Return: A properly constructed signal field for an outgoing mux open command.
+ */
+static uint8_t create_open_signal(void)
+{
+ uint8_t signal = 0;
+ uint8_t buff_count = 0;
+ uint8_t dl_size = 0;
+
+ if (!dynamic_mtu_enabled)
+ return signal;
+
+ signal = DYNAMIC_MTU_MASK;
+
+ switch (num_buffers) {
+ case SZ_256:
+ buff_count = 3;
+ break;
+ case SZ_128:
+ buff_count = 2;
+ break;
+ case SZ_64:
+ buff_count = 1;
+ break;
+ case SZ_32:
+ buff_count = 0;
+ break;
+ }
+
+ signal |= buff_count << DL_POOL_SIZE_SHIFT;
+
+ switch (dl_mtu) {
+ case SZ_16K:
+ dl_size = 3;
+ break;
+ case SZ_8K:
+ dl_size = 2;
+ break;
+ case SZ_4K:
+ dl_size = 1;
+ break;
+ case SZ_2K:
+ dl_size = 0;
+ break;
+ }
+
+ signal |= dl_size << MTU_SIZE_SHIFT;
+
+ return signal;
+}
+
+int msm_bam_dmux_open(uint32_t id, void *priv,
+ void (*notify)(void *, int, unsigned long))
+{
+ struct bam_mux_hdr *hdr;
+ unsigned long flags;
+ int rc = 0;
+
+ DBG("%s: opening ch %d\n", __func__, id);
+ if (!bam_mux_initialized) {
+ DBG("%s: not inititialized\n", __func__);
+ return -ENODEV;
+ }
+ if (id >= BAM_DMUX_NUM_CHANNELS) {
+ pr_err("%s: invalid channel id %d\n", __func__, id);
+ return -EINVAL;
+ }
+ if (notify == NULL) {
+ pr_err("%s: notify function is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ hdr = kmalloc(sizeof(struct bam_mux_hdr), GFP_KERNEL);
+ if (hdr == NULL)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&bam_ch[id].lock, flags);
+ if (bam_ch_is_open(id)) {
+ DBG("%s: Already opened %d\n", __func__, id);
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+ kfree(hdr);
+ goto open_done;
+ }
+ if (!bam_ch_is_remote_open(id)) {
+ DBG("%s: Remote not open; ch: %d\n", __func__, id);
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+ kfree(hdr);
+ return -ENODEV;
+ }
+
+ bam_ch[id].notify = notify;
+ bam_ch[id].priv = priv;
+ bam_ch[id].status |= BAM_CH_LOCAL_OPEN;
+ bam_ch[id].num_tx_pkts = 0;
+ bam_ch[id].use_wm = 0;
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+ notify(priv, BAM_DMUX_TRANSMIT_SIZE, ul_mtu);
+
+ read_lock(&ul_wakeup_lock);
+ if (!bam_is_connected) {
+ atomic_inc(&ul_ondemand_vote);
+ read_unlock(&ul_wakeup_lock);
+ ul_wakeup();
+ if (unlikely(in_global_reset == 1)) {
+ atomic_dec(&ul_ondemand_vote);
+ kfree(hdr);
+ return -EFAULT;
+ }
+ read_lock(&ul_wakeup_lock);
+ notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
+ atomic_dec(&ul_ondemand_vote);
+ }
+
+ hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
+ hdr->cmd = BAM_MUX_HDR_CMD_OPEN;
+ hdr->signal = create_open_signal();
+ hdr->ch_id = id;
+ hdr->pkt_len = 0;
+ hdr->pad_len = 0;
+
+ rc = bam_mux_write_cmd((void *)hdr, sizeof(struct bam_mux_hdr));
+ read_unlock(&ul_wakeup_lock);
+
+open_done:
+ DBG("%s: opened ch %d\n", __func__, id);
+ return rc;
+}
+
+int msm_bam_dmux_close(uint32_t id)
+{
+ struct bam_mux_hdr *hdr;
+ unsigned long flags;
+ int rc;
+
+ if (id >= BAM_DMUX_NUM_CHANNELS)
+ return -EINVAL;
+ DBG("%s: closing ch %d\n", __func__, id);
+ if (!bam_mux_initialized || !bam_ch_is_local_open(id))
+ return -ENODEV;
+
+ read_lock(&ul_wakeup_lock);
+ if (!bam_is_connected && !bam_ch_is_in_reset(id)) {
+ atomic_inc(&ul_ondemand_vote);
+ read_unlock(&ul_wakeup_lock);
+ ul_wakeup();
+ if (unlikely(in_global_reset == 1)) {
+ atomic_dec(&ul_ondemand_vote);
+ return -EFAULT;
+ }
+ read_lock(&ul_wakeup_lock);
+ notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
+ atomic_dec(&ul_ondemand_vote);
+ }
+
+ spin_lock_irqsave(&bam_ch[id].lock, flags);
+ bam_ch[id].notify = NULL;
+ bam_ch[id].priv = NULL;
+ bam_ch[id].status &= ~BAM_CH_LOCAL_OPEN;
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+ if (bam_ch_is_in_reset(id)) {
+ read_unlock(&ul_wakeup_lock);
+ bam_ch[id].status &= ~BAM_CH_IN_RESET;
+ return 0;
+ }
+
+ hdr = kmalloc(sizeof(struct bam_mux_hdr), GFP_ATOMIC);
+ if (hdr == NULL) {
+ read_unlock(&ul_wakeup_lock);
+ return -ENOMEM;
+ }
+ hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
+ hdr->cmd = BAM_MUX_HDR_CMD_CLOSE;
+ hdr->signal = 0;
+ hdr->ch_id = id;
+ hdr->pkt_len = 0;
+ hdr->pad_len = 0;
+
+ rc = bam_mux_write_cmd((void *)hdr, sizeof(struct bam_mux_hdr));
+ read_unlock(&ul_wakeup_lock);
+
+ DBG("%s: closed ch %d\n", __func__, id);
+ return rc;
+}
+
+int msm_bam_dmux_is_ch_full(uint32_t id)
+{
+ unsigned long flags;
+ int ret;
+
+ if (id >= BAM_DMUX_NUM_CHANNELS)
+ return -EINVAL;
+
+ spin_lock_irqsave(&bam_ch[id].lock, flags);
+ bam_ch[id].use_wm = 1;
+ ret = bam_ch[id].num_tx_pkts >= HIGH_WATERMARK;
+ DBG("%s: ch %d num tx pkts=%d, HWM=%d\n", __func__,
+ id, bam_ch[id].num_tx_pkts, ret);
+ if (!bam_ch_is_local_open(id)) {
+ ret = -ENODEV;
+ pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
+ }
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+ return ret;
+}
+
+int msm_bam_dmux_is_ch_low(uint32_t id)
+{
+ unsigned long flags;
+ int ret;
+
+ if (id >= BAM_DMUX_NUM_CHANNELS)
+ return -EINVAL;
+
+ spin_lock_irqsave(&bam_ch[id].lock, flags);
+ bam_ch[id].use_wm = 1;
+ ret = bam_ch[id].num_tx_pkts <= LOW_WATERMARK;
+ DBG("%s: ch %d num tx pkts=%d, LWM=%d\n", __func__,
+ id, bam_ch[id].num_tx_pkts, ret);
+ if (!bam_ch_is_local_open(id)) {
+ ret = -ENODEV;
+ pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
+ }
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+ return ret;
+}
+
+static void rx_switch_to_interrupt_mode(void)
+{
+ struct sps_connect cur_rx_conn;
+ struct sps_iovec iov;
+ struct rx_pkt_info *info;
+ int ret;
+
+ /*
+ * Attempt to enable interrupts - if this fails,
+ * continue polling and we will retry later.
+ */
+ ret = bam_ops->sps_get_config_ptr(bam_rx_pipe, &cur_rx_conn);
+ if (ret) {
+ pr_err("%s: sps_get_config() failed %d\n", __func__, ret);
+ goto fail;
+ }
+
+ rx_register_event.options = SPS_O_EOT;
+ ret = bam_ops->sps_register_event_ptr(bam_rx_pipe, &rx_register_event);
+ if (ret) {
+ pr_err("%s: sps_register_event() failed %d\n", __func__, ret);
+ goto fail;
+ }
+
+ cur_rx_conn.options = SPS_O_AUTO_ENABLE |
+ SPS_O_EOT | SPS_O_ACK_TRANSFERS;
+ ret = bam_ops->sps_set_config_ptr(bam_rx_pipe, &cur_rx_conn);
+ if (ret) {
+ pr_err("%s: sps_set_config() failed %d\n", __func__, ret);
+ goto fail;
+ }
+ polling_mode = 0;
+ complete_all(&shutdown_completion);
+ release_wakelock();
+
+ /* handle any rx packets before interrupt was enabled */
+ while (bam_connection_is_active && !polling_mode) {
+ ret = bam_ops->sps_get_iovec_ptr(bam_rx_pipe, &iov);
+ if (ret) {
+ pr_err("%s: sps_get_iovec failed %d\n",
+ __func__, ret);
+ break;
+ }
+ if (iov.addr == 0)
+ break;
+
+ mutex_lock(&bam_rx_pool_mutexlock);
+ if (unlikely(list_empty(&bam_rx_pool))) {
+ DMUX_LOG_KERR("%s: have iovec %pK but rx pool empty\n",
+ __func__, (void *)(uintptr_t)iov.addr);
+ mutex_unlock(&bam_rx_pool_mutexlock);
+ continue;
+ }
+ info = list_first_entry(&bam_rx_pool, struct rx_pkt_info,
+ list_node);
+ if (info->dma_address != iov.addr) {
+ DMUX_LOG_KERR("%s: iovec %pK != dma %pK\n",
+ __func__,
+ (void *)(uintptr_t)iov.addr,
+ (void *)(uintptr_t)info->dma_address);
+ list_for_each_entry(info, &bam_rx_pool, list_node) {
+ DMUX_LOG_KERR("%s: dma %pK\n", __func__,
+ (void *)(uintptr_t)info->dma_address);
+ if (iov.addr == info->dma_address)
+ break;
+ }
+ }
+ WARN_ON(info->dma_address != iov.addr);
+ list_del(&info->list_node);
+ --bam_rx_pool_len;
+ mutex_unlock(&bam_rx_pool_mutexlock);
+ info->sps_size = iov.size;
+ handle_bam_mux_cmd(&info->work);
+ }
+ return;
+
+fail:
+ pr_err("%s: reverting to polling\n", __func__);
+ if (no_cpu_affinity)
+ queue_work(bam_mux_rx_workqueue, &rx_timer_work);
+ else
+ queue_work_on(0, bam_mux_rx_workqueue, &rx_timer_work);
+}
+
+/**
+ * store_rx_timestamp() - store the current raw time as as a timestamp for when
+ * the last rx packet was processed
+ */
+static void store_rx_timestamp(void)
+{
+ last_rx_pkt_timestamp = sched_clock();
+}
+
+/**
+ * log_rx_timestamp() - Log the stored rx pkt timestamp in a human readable
+ * format
+ */
+static void log_rx_timestamp(void)
+{
+ unsigned long long t = last_rx_pkt_timestamp;
+ unsigned long nanosec_rem;
+
+ nanosec_rem = do_div(t, 1000000000U);
+ BAM_DMUX_LOG("Last rx pkt processed at [%6u.%09lu]\n", (unsigned int)t,
+ nanosec_rem);
+}
+
+static void rx_timer_work_func(struct work_struct *work)
+{
+ struct sps_iovec iov;
+ struct rx_pkt_info *info;
+ int inactive_cycles = 0;
+ int ret;
+ u32 buffs_unused, buffs_used;
+
+ BAM_DMUX_LOG("%s: polling start\n", __func__);
+ while (bam_connection_is_active) { /* timer loop */
+ ++inactive_cycles;
+ while (bam_connection_is_active) { /* deplete queue loop */
+ if (in_global_reset) {
+ BAM_DMUX_LOG(
+ "%s: polling exit, global reset detected\n",
+ __func__);
+ return;
+ }
+
+ ret = bam_ops->sps_get_iovec_ptr(bam_rx_pipe, &iov);
+ if (ret) {
+ DMUX_LOG_KERR("%s: sps_get_iovec failed %d\n",
+ __func__, ret);
+ break;
+ }
+ if (iov.addr == 0)
+ break;
+ store_rx_timestamp();
+ inactive_cycles = 0;
+ mutex_lock(&bam_rx_pool_mutexlock);
+ if (unlikely(list_empty(&bam_rx_pool))) {
+ DMUX_LOG_KERR(
+ "%s:have iovec %pK but rx pool empty\n",
+ __func__, (void *)(uintptr_t)iov.addr);
+ mutex_unlock(&bam_rx_pool_mutexlock);
+ continue;
+ }
+ info = list_first_entry(&bam_rx_pool,
+ struct rx_pkt_info, list_node);
+ if (info->dma_address != iov.addr) {
+ DMUX_LOG_KERR("%s: iovec %pK != dma %pK\n",
+ __func__,
+ (void *)(uintptr_t)iov.addr,
+ (void *)(uintptr_t)info->dma_address);
+ list_for_each_entry(info, &bam_rx_pool,
+ list_node) {
+ DMUX_LOG_KERR("%s: dma %pK\n", __func__,
+ (void *)(uintptr_t)
+ info->dma_address);
+ if (iov.addr == info->dma_address)
+ break;
+ }
+ }
+ WARN_ON(info->dma_address != iov.addr);
+ list_del(&info->list_node);
+ --bam_rx_pool_len;
+ mutex_unlock(&bam_rx_pool_mutexlock);
+ info->sps_size = iov.size;
+ handle_bam_mux_cmd(&info->work);
+ }
+
+ if (inactive_cycles >= POLLING_INACTIVITY) {
+ BAM_DMUX_LOG("%s: polling exit, no data\n", __func__);
+ rx_switch_to_interrupt_mode();
+ break;
+ }
+
+ if (bam_adaptive_timer_enabled) {
+ usleep_range(rx_timer_interval, rx_timer_interval + 50);
+
+ ret = bam_ops->sps_get_unused_desc_num_ptr(bam_rx_pipe,
+ &buffs_unused);
+
+ if (ret) {
+ DMUX_LOG_KERR(
+ "%s: error getting num buffers unused after sleep\n",
+ __func__);
+
+ break;
+ }
+
+ buffs_used = num_buffers - buffs_unused;
+
+ if (buffs_unused == 0) {
+ rx_timer_interval = MIN_POLLING_SLEEP;
+ } else {
+ if (buffs_used > 0) {
+ rx_timer_interval =
+ (2 * num_buffers *
+ rx_timer_interval)/
+ (3 * buffs_used);
+ } else {
+ rx_timer_interval =
+ MAX_POLLING_SLEEP;
+ }
+ }
+
+ if (rx_timer_interval > MAX_POLLING_SLEEP)
+ rx_timer_interval = MAX_POLLING_SLEEP;
+ else if (rx_timer_interval < MIN_POLLING_SLEEP)
+ rx_timer_interval = MIN_POLLING_SLEEP;
+ } else {
+ usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
+ }
+ }
+}
+
+static void bam_mux_tx_notify(struct sps_event_notify *notify)
+{
+ struct tx_pkt_info *pkt;
+
+ DBG("%s: event %d notified\n", __func__, notify->event_id);
+
+ if (in_global_reset)
+ return;
+
+ switch (notify->event_id) {
+ case SPS_EVENT_EOT:
+ pkt = notify->data.transfer.user;
+ if (!pkt->is_cmd)
+ dma_unmap_single(dma_dev, pkt->dma_address,
+ pkt->skb->len,
+ bam_ops->dma_to);
+ else
+ dma_unmap_single(dma_dev, pkt->dma_address,
+ pkt->len,
+ bam_ops->dma_to);
+ queue_work(bam_mux_tx_workqueue, &pkt->work);
+ break;
+ default:
+ pr_err("%s: received unexpected event id %d\n", __func__,
+ notify->event_id);
+ }
+}
+
+static void bam_mux_rx_notify(struct sps_event_notify *notify)
+{
+ int ret;
+ struct sps_connect cur_rx_conn;
+
+ DBG("%s: event %d notified\n", __func__, notify->event_id);
+
+ if (in_global_reset)
+ return;
+
+ switch (notify->event_id) {
+ case SPS_EVENT_EOT:
+ /* attempt to disable interrupts in this pipe */
+ if (!polling_mode) {
+ ret = bam_ops->sps_get_config_ptr(bam_rx_pipe,
+ &cur_rx_conn);
+ if (ret) {
+ pr_err("%s: sps_get_config() failed %d, interrupts not disabled\n",
+ __func__, ret);
+ break;
+ }
+ cur_rx_conn.options = SPS_O_AUTO_ENABLE |
+ SPS_O_ACK_TRANSFERS | SPS_O_POLL;
+ ret = bam_ops->sps_set_config_ptr(bam_rx_pipe,
+ &cur_rx_conn);
+ if (ret) {
+ pr_err("%s: sps_set_config() failed %d, interrupts not disabled\n",
+ __func__, ret);
+ break;
+ }
+ reinit_completion(&shutdown_completion);
+ grab_wakelock();
+ polling_mode = 1;
+ /*
+ * run on core 0 so that netif_rx() in rmnet uses only
+ * one queue if RPS enable use no_cpu_affinity
+ */
+ if (no_cpu_affinity)
+ queue_work(bam_mux_rx_workqueue,
+ &rx_timer_work);
+ else
+ queue_work_on(0, bam_mux_rx_workqueue,
+ &rx_timer_work);
+ }
+ break;
+ default:
+ pr_err("%s: received unexpected event id %d\n", __func__,
+ notify->event_id);
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+static int debug_tbl(char *buf, int max)
+{
+ int i = 0;
+ int j;
+
+ for (j = 0; j < BAM_DMUX_NUM_CHANNELS; ++j) {
+ i += scnprintf(buf + i, max - i,
+ "ch%02d local open=%s remote open=%s\n",
+ j, bam_ch_is_local_open(j) ? "Y" : "N",
+ bam_ch_is_remote_open(j) ? "Y" : "N");
+ }
+
+ return i;
+}
+
+static int debug_ul_pkt_cnt(char *buf, int max)
+{
+ struct list_head *p;
+ unsigned long flags;
+ int n = 0;
+
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+ list_for_each(p, &bam_tx_pool) {
+ ++n;
+ }
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
+ return scnprintf(buf, max, "Number of UL packets in flight: %d\n", n);
+}
+
+static int debug_stats(char *buf, int max)
+{
+ int i = 0;
+
+ i += scnprintf(buf + i, max - i,
+ "skb read cnt: %u\n"
+ "skb write cnt: %u\n"
+ "skb copy cnt: %u\n"
+ "skb copy bytes: %u\n"
+ "sps tx failures: %u\n"
+ "sps tx stalls: %u\n"
+ "rx queue len: %d\n"
+ "a2 ack out cnt: %d\n"
+ "a2 ack in cnt: %d\n"
+ "a2 pwr cntl in: %d\n",
+ bam_dmux_read_cnt,
+ bam_dmux_write_cnt,
+ bam_dmux_write_cpy_cnt,
+ bam_dmux_write_cpy_bytes,
+ bam_dmux_tx_sps_failure_cnt,
+ bam_dmux_tx_stall_cnt,
+ bam_rx_pool_len,
+ atomic_read(&bam_dmux_ack_out_cnt),
+ atomic_read(&bam_dmux_ack_in_cnt),
+ atomic_read(&bam_dmux_a2_pwr_cntl_in_cnt)
+ );
+
+ return i;
+}
+
+#define DEBUG_BUFMAX 4096
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int (*fill)(char *buf, int max) = file->private_data;
+ int bsize = fill(debug_buffer, DEBUG_BUFMAX);
+
+ return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+
+static const struct file_operations debug_ops = {
+ .read = debug_read,
+ .open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+ struct dentry *dent,
+ int (*fill)(char *buf, int max))
+{
+ struct dentry *file;
+
+ file = debugfs_create_file(name, mode, dent, fill, &debug_ops);
+ if (IS_ERR(file))
+ pr_err("%s: debugfs create failed %d\n", __func__,
+ (int)PTR_ERR(file));
+}
+
+#endif
+
+static void notify_all(int event, unsigned long data)
+{
+ int i;
+ unsigned long flags;
+ struct list_head *temp;
+ struct outside_notify_func *func;
+ void (*notify)(void *, int, unsigned long);
+ void *priv;
+
+ BAM_DMUX_LOG("%s: event=%d, data=%lu\n", __func__, event, data);
+
+ for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
+ notify = NULL;
+ priv = NULL;
+ spin_lock_irqsave(&bam_ch[i].lock, flags);
+ if (bam_ch_is_open(i)) {
+ notify = bam_ch[i].notify;
+ priv = bam_ch[i].priv;
+ }
+ spin_unlock_irqrestore(&bam_ch[i].lock, flags);
+ if (notify)
+ notify(priv, event, data);
+ }
+
+ list_for_each(temp, &bam_other_notify_funcs) {
+ func = container_of(temp, struct outside_notify_func,
+ list_node);
+ func->notify(func->priv, event, data);
+ }
+}
+
+static void kickoff_ul_wakeup_func(struct work_struct *work)
+{
+ read_lock(&ul_wakeup_lock);
+ if (!bam_is_connected) {
+ atomic_inc(&ul_ondemand_vote);
+ read_unlock(&ul_wakeup_lock);
+ ul_wakeup();
+ if (unlikely(in_global_reset == 1)) {
+ atomic_dec(&ul_ondemand_vote);
+ return;
+ }
+ read_lock(&ul_wakeup_lock);
+ ul_packet_written = 1;
+ notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
+ atomic_dec(&ul_ondemand_vote);
+ }
+ read_unlock(&ul_wakeup_lock);
+}
+
+int msm_bam_dmux_kickoff_ul_wakeup(void)
+{
+ int is_connected;
+
+ read_lock(&ul_wakeup_lock);
+ ul_packet_written = 1;
+ is_connected = bam_is_connected;
+ if (!is_connected)
+ queue_work(bam_mux_tx_workqueue, &kickoff_ul_wakeup);
+ read_unlock(&ul_wakeup_lock);
+
+ return is_connected;
+}
+
+static void power_vote(int vote)
+{
+ BAM_DMUX_LOG("%s: curr=%d, vote=%d\n", __func__,
+ bam_dmux_uplink_vote, vote);
+
+ if (bam_dmux_uplink_vote == vote)
+ BAM_DMUX_LOG("%s: warning - duplicate power vote\n", __func__);
+
+ bam_dmux_uplink_vote = vote;
+ if (vote)
+ bam_ops->smsm_change_state_ptr(SMSM_APPS_STATE,
+ 0, SMSM_A2_POWER_CONTROL);
+ else
+ bam_ops->smsm_change_state_ptr(SMSM_APPS_STATE,
+ SMSM_A2_POWER_CONTROL, 0);
+}
+
+/*
+ * @note: Must be called with ul_wakeup_lock locked.
+ */
+static inline void ul_powerdown(void)
+{
+ BAM_DMUX_LOG("%s: powerdown\n", __func__);
+ verify_tx_queue_is_empty(__func__);
+
+ if (a2_pc_disabled) {
+ wait_for_dfab = 1;
+ reinit_completion(&dfab_unvote_completion);
+ release_wakelock();
+ } else {
+ wait_for_ack = 1;
+ reinit_completion(&ul_wakeup_ack_completion);
+ power_vote(0);
+ }
+ bam_is_connected = 0;
+ notify_all(BAM_DMUX_UL_DISCONNECTED, (unsigned long)(NULL));
+}
+
+static inline void ul_powerdown_finish(void)
+{
+ if (a2_pc_disabled && wait_for_dfab) {
+ unvote_dfab();
+ complete_all(&dfab_unvote_completion);
+ wait_for_dfab = 0;
+ }
+}
+
+/*
+ * Votes for UL power and returns current power state.
+ *
+ * @returns true if currently connected
+ */
+int msm_bam_dmux_ul_power_vote(void)
+{
+ int is_connected;
+
+ read_lock(&ul_wakeup_lock);
+ atomic_inc(&ul_ondemand_vote);
+ is_connected = bam_is_connected;
+ if (!is_connected)
+ queue_work(bam_mux_tx_workqueue, &kickoff_ul_wakeup);
+ read_unlock(&ul_wakeup_lock);
+
+ return is_connected;
+}
+
+/*
+ * Unvotes for UL power.
+ *
+ * @returns true if vote count is 0 (UL shutdown possible)
+ */
+int msm_bam_dmux_ul_power_unvote(void)
+{
+ int vote;
+
+ read_lock(&ul_wakeup_lock);
+ vote = atomic_dec_return(&ul_ondemand_vote);
+ if (unlikely(vote < 0))
+ DMUX_LOG_KERR("%s: invalid power vote %d\n", __func__, vote);
+ read_unlock(&ul_wakeup_lock);
+
+ return vote == 0;
+}
+
+int msm_bam_dmux_reg_notify(void *priv,
+ void (*notify)(void *priv, int event_type,
+ unsigned long data))
+{
+ struct outside_notify_func *func;
+
+ if (!notify)
+ return -EINVAL;
+
+ func = kmalloc(sizeof(struct outside_notify_func), GFP_KERNEL);
+ if (!func)
+ return -ENOMEM;
+
+ func->notify = notify;
+ func->priv = priv;
+ list_add(&func->list_node, &bam_other_notify_funcs);
+
+ return 0;
+}
+
+static void ul_timeout(struct work_struct *work)
+{
+ unsigned long flags;
+ int ret;
+
+ if (in_global_reset)
+ return;
+ ret = write_trylock_irqsave(&ul_wakeup_lock, flags);
+ if (!ret) { /* failed to grab lock, reschedule and bail */
+ schedule_delayed_work(&ul_timeout_work,
+ msecs_to_jiffies(ul_timeout_delay));
+ return;
+ }
+ if (bam_is_connected) {
+ if (!ul_packet_written) {
+ spin_lock(&bam_tx_pool_spinlock);
+ if (!list_empty(&bam_tx_pool)) {
+ struct tx_pkt_info *info;
+
+ info = list_first_entry(&bam_tx_pool,
+ struct tx_pkt_info, list_node);
+ DMUX_LOG_KERR("%s: UL delayed ts=%u.%09lu\n",
+ __func__, info->ts_sec, info->ts_nsec);
+ DBG_INC_TX_STALL_CNT();
+ ul_packet_written = 1;
+ }
+ spin_unlock(&bam_tx_pool_spinlock);
+ }
+
+ if (ul_packet_written || atomic_read(&ul_ondemand_vote)) {
+ BAM_DMUX_LOG("%s: pkt written %d\n",
+ __func__, ul_packet_written);
+ ul_packet_written = 0;
+ schedule_delayed_work(&ul_timeout_work,
+ msecs_to_jiffies(ul_timeout_delay));
+ } else {
+ ul_powerdown();
+ }
+ }
+ write_unlock_irqrestore(&ul_wakeup_lock, flags);
+ ul_powerdown_finish();
+}
+
+static int ssrestart_check(void)
+{
+ int ret = 0;
+
+ if (in_global_reset) {
+ DMUX_LOG_KERR("%s: already in SSR\n",
+ __func__);
+ return 1;
+ }
+
+ DMUX_LOG_KERR(
+ "%s: fatal modem interaction: BAM DMUX disabled for SSR\n",
+ __func__);
+ in_global_reset = 1;
+ ret = subsystem_restart("modem");
+ if (ret == -ENODEV)
+ panic("modem subsystem restart failed\n");
+ return 1;
+}
+
+static void ul_wakeup(void)
+{
+ int ret;
+ int do_vote_dfab = 0;
+
+ mutex_lock(&wakeup_lock);
+ if (bam_is_connected) { /* bam got connected before lock grabbed */
+ BAM_DMUX_LOG("%s Already awake\n", __func__);
+ mutex_unlock(&wakeup_lock);
+ return;
+ }
+
+ /*
+ * if this gets hit, that means restart_notifier_cb() has started
+ * but probably not finished, thus we know SSR has happened, but
+ * haven't been able to send that info to our clients yet.
+ * in that case, abort the ul_wakeup() so that we don't undo any
+ * work restart_notifier_cb() has done. The clients will be notified
+ * shortly. No cleanup necessary (reschedule the wakeup) as our and
+ * their SSR handling will cover it
+ */
+ if (unlikely(in_global_reset == 1)) {
+ mutex_unlock(&wakeup_lock);
+ return;
+ }
+
+ /*
+ * if someone is voting for UL before bam is inited (modem up first
+ * time), set flag for init to kickoff ul wakeup once bam is inited
+ */
+ mutex_lock(&delayed_ul_vote_lock);
+ if (unlikely(!bam_mux_initialized)) {
+ need_delayed_ul_vote = 1;
+ mutex_unlock(&delayed_ul_vote_lock);
+ mutex_unlock(&wakeup_lock);
+ return;
+ }
+ mutex_unlock(&delayed_ul_vote_lock);
+
+ if (a2_pc_disabled) {
+ /*
+ * don't grab the wakelock the first time because it is
+ * already grabbed when a2 powers on
+ */
+ if (likely(a2_pc_disabled_wakelock_skipped)) {
+ grab_wakelock();
+ do_vote_dfab = 1; /* vote must occur after wait */
+ } else {
+ a2_pc_disabled_wakelock_skipped = 1;
+ }
+ if (wait_for_dfab) {
+ ret = wait_for_completion_timeout(
+ &dfab_unvote_completion, HZ);
+ WARN_ON(ret == 0);
+ }
+ if (likely(do_vote_dfab))
+ vote_dfab();
+ schedule_delayed_work(&ul_timeout_work,
+ msecs_to_jiffies(ul_timeout_delay));
+ bam_is_connected = 1;
+ mutex_unlock(&wakeup_lock);
+ return;
+ }
+
+ /*
+ * must wait for the previous power down request to have been acked
+ * chances are it already came in and this will just fall through
+ * instead of waiting
+ */
+ if (wait_for_ack) {
+ BAM_DMUX_LOG("%s waiting for previous ack\n", __func__);
+ ret = wait_for_completion_timeout(
+ &ul_wakeup_ack_completion,
+ msecs_to_jiffies(UL_WAKEUP_TIMEOUT_MS));
+ wait_for_ack = 0;
+ if (unlikely(in_global_reset == 1)
+ || (unlikely(ret == 0) && ssrestart_check())) {
+ mutex_unlock(&wakeup_lock);
+ BAM_DMUX_LOG("%s timeout previous ack\n", __func__);
+ return;
+ }
+ }
+ reinit_completion(&ul_wakeup_ack_completion);
+ power_vote(1);
+ BAM_DMUX_LOG("%s waiting for wakeup ack\n", __func__);
+ ret = wait_for_completion_timeout(&ul_wakeup_ack_completion,
+ msecs_to_jiffies(UL_WAKEUP_TIMEOUT_MS));
+ if (unlikely(in_global_reset == 1)
+ || (unlikely(ret == 0) && ssrestart_check())) {
+ mutex_unlock(&wakeup_lock);
+ BAM_DMUX_LOG("%s timeout wakeup ack\n", __func__);
+ return;
+ }
+ BAM_DMUX_LOG("%s waiting completion\n", __func__);
+ ret = wait_for_completion_timeout(&bam_connection_completion,
+ msecs_to_jiffies(UL_WAKEUP_TIMEOUT_MS));
+ if (unlikely(in_global_reset == 1)
+ || (unlikely(ret == 0) && ssrestart_check())) {
+ mutex_unlock(&wakeup_lock);
+ BAM_DMUX_LOG("%s timeout power on\n", __func__);
+ return;
+ }
+
+ bam_is_connected = 1;
+ BAM_DMUX_LOG("%s complete\n", __func__);
+ schedule_delayed_work(&ul_timeout_work,
+ msecs_to_jiffies(ul_timeout_delay));
+ mutex_unlock(&wakeup_lock);
+}
+
+static void reconnect_to_bam(void)
+{
+ int i;
+
+ if (in_global_reset) {
+ BAM_DMUX_LOG("%s: skipping due to SSR\n", __func__);
+ return;
+ }
+
+ vote_dfab();
+
+ if (ssr_skipped_disconnect) {
+ /* delayed to here to prevent bus stall */
+ bam_ops->sps_disconnect_ptr(bam_tx_pipe);
+ bam_ops->sps_disconnect_ptr(bam_rx_pipe);
+ memset(rx_desc_mem_buf.base, 0, rx_desc_mem_buf.size);
+ memset(tx_desc_mem_buf.base, 0, tx_desc_mem_buf.size);
+ }
+ ssr_skipped_disconnect = 0;
+ i = bam_ops->sps_device_reset_ptr(a2_device_handle);
+ if (i)
+ pr_err("%s: device reset failed rc = %d\n", __func__,
+ i);
+ i = bam_ops->sps_connect_ptr(bam_tx_pipe, &tx_connection);
+ if (i)
+ pr_err("%s: tx connection failed rc = %d\n", __func__,
+ i);
+ i = bam_ops->sps_connect_ptr(bam_rx_pipe, &rx_connection);
+ if (i)
+ pr_err("%s: rx connection failed rc = %d\n", __func__,
+ i);
+ i = bam_ops->sps_register_event_ptr(bam_tx_pipe,
+ &tx_register_event);
+ if (i)
+ pr_err("%s: tx event reg failed rc = %d\n", __func__,
+ i);
+ i = bam_ops->sps_register_event_ptr(bam_rx_pipe,
+ &rx_register_event);
+ if (i)
+ pr_err("%s: rx event reg failed rc = %d\n", __func__,
+ i);
+ bam_connection_is_active = 1;
+
+ if (polling_mode)
+ rx_switch_to_interrupt_mode();
+
+ toggle_apps_ack();
+ complete_all(&bam_connection_completion);
+ queue_rx();
+}
+
+static void disconnect_to_bam(void)
+{
+ struct list_head *node;
+ struct rx_pkt_info *info;
+ unsigned long flags;
+ unsigned long time_remaining;
+
+ if (!in_global_reset) {
+ time_remaining = wait_for_completion_timeout(
+ &shutdown_completion,
+ msecs_to_jiffies(SHUTDOWN_TIMEOUT_MS));
+ if (time_remaining == 0) {
+ DMUX_LOG_KERR("%s: shutdown completion timed out\n",
+ __func__);
+ log_rx_timestamp();
+ ssrestart_check();
+ }
+ }
+
+ bam_connection_is_active = 0;
+
+ /* handle disconnect during active UL */
+ write_lock_irqsave(&ul_wakeup_lock, flags);
+ if (bam_is_connected) {
+ BAM_DMUX_LOG("%s: UL active - forcing powerdown\n", __func__);
+ ul_powerdown();
+ }
+ write_unlock_irqrestore(&ul_wakeup_lock, flags);
+ ul_powerdown_finish();
+
+ /* tear down BAM connection */
+ reinit_completion(&bam_connection_completion);
+
+ /* documentation/assumptions found in restart_notifier_cb */
+ if (likely(!in_global_reset)) {
+ BAM_DMUX_LOG("%s: disconnect tx\n", __func__);
+ bam_ops->sps_disconnect_ptr(bam_tx_pipe);
+ BAM_DMUX_LOG("%s: disconnect rx\n", __func__);
+ bam_ops->sps_disconnect_ptr(bam_rx_pipe);
+ memset(rx_desc_mem_buf.base, 0, rx_desc_mem_buf.size);
+ memset(tx_desc_mem_buf.base, 0, tx_desc_mem_buf.size);
+ BAM_DMUX_LOG("%s: device reset\n", __func__);
+ bam_ops->sps_device_reset_ptr(a2_device_handle);
+ } else {
+ ssr_skipped_disconnect = 1;
+ }
+ unvote_dfab();
+
+ mutex_lock(&bam_rx_pool_mutexlock);
+ while (!list_empty(&bam_rx_pool)) {
+ node = bam_rx_pool.next;
+ list_del(node);
+ info = container_of(node, struct rx_pkt_info, list_node);
+ dma_unmap_single(dma_dev, info->dma_address, info->len,
+ bam_ops->dma_from);
+ dev_kfree_skb_any(info->skb);
+ kfree(info);
+ }
+ bam_rx_pool_len = 0;
+ mutex_unlock(&bam_rx_pool_mutexlock);
+ toggle_apps_ack();
+ verify_tx_queue_is_empty(__func__);
+}
+
+static void vote_dfab(void)
+{
+ int rc;
+
+ BAM_DMUX_LOG("%s\n", __func__);
+ mutex_lock(&dfab_status_lock);
+ if (dfab_is_on) {
+ BAM_DMUX_LOG("%s: dfab is already on\n", __func__);
+ mutex_unlock(&dfab_status_lock);
+ return;
+ }
+ if (dfab_clk) {
+ rc = clk_prepare_enable(dfab_clk);
+ if (rc)
+ DMUX_LOG_KERR("bam_dmux vote for dfab failed rc = %d\n",
+ rc);
+ }
+ if (xo_clk) {
+ rc = clk_prepare_enable(xo_clk);
+ if (rc)
+ DMUX_LOG_KERR("bam_dmux vote for xo failed rc = %d\n",
+ rc);
+ }
+ dfab_is_on = 1;
+ mutex_unlock(&dfab_status_lock);
+}
+
+static void unvote_dfab(void)
+{
+ BAM_DMUX_LOG("%s\n", __func__);
+ mutex_lock(&dfab_status_lock);
+ if (!dfab_is_on) {
+ DMUX_LOG_KERR("%s: dfab is already off\n", __func__);
+ dump_stack();
+ mutex_unlock(&dfab_status_lock);
+ return;
+ }
+ if (dfab_clk)
+ clk_disable_unprepare(dfab_clk);
+ if (xo_clk)
+ clk_disable_unprepare(xo_clk);
+ dfab_is_on = 0;
+ mutex_unlock(&dfab_status_lock);
+}
+
+/* reference counting wrapper around wakelock */
+static void grab_wakelock(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wakelock_reference_lock, flags);
+ BAM_DMUX_LOG("%s: ref count = %d\n", __func__,
+ wakelock_reference_count);
+ if (wakelock_reference_count == 0)
+ __pm_stay_awake(&bam_wakelock);
+ ++wakelock_reference_count;
+ spin_unlock_irqrestore(&wakelock_reference_lock, flags);
+}
+
+static void release_wakelock(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wakelock_reference_lock, flags);
+ if (wakelock_reference_count == 0) {
+ DMUX_LOG_KERR("%s: bam_dmux wakelock not locked\n", __func__);
+ dump_stack();
+ spin_unlock_irqrestore(&wakelock_reference_lock, flags);
+ return;
+ }
+ BAM_DMUX_LOG("%s: ref count = %d\n", __func__,
+ wakelock_reference_count);
+ --wakelock_reference_count;
+ if (wakelock_reference_count == 0)
+ __pm_relax(&bam_wakelock);
+ spin_unlock_irqrestore(&wakelock_reference_lock, flags);
+}
+
+static int restart_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data)
+{
+ int i;
+ struct list_head *node;
+ struct tx_pkt_info *info;
+ int temp_remote_status;
+ unsigned long flags;
+
+ /*
+ * Bam_dmux counts on the fact that the BEFORE_SHUTDOWN level of
+ * notifications are guaranteed to execute before the AFTER_SHUTDOWN
+ * level of notifications, and that BEFORE_SHUTDOWN always occurs in
+ * all SSR events, no matter what triggered the SSR. Also, bam_dmux
+ * assumes that SMD does its SSR processing in the AFTER_SHUTDOWN level
+ * thus bam_dmux is guaranteed to detect SSR before SMD, since the
+ * callbacks for all the drivers within the AFTER_SHUTDOWN level could
+ * occur in any order. Bam_dmux uses this knowledge to skip accessing
+ * the bam hardware when disconnect_to_bam() is triggered by SMD's SSR
+ * processing. We do not wat to access the bam hardware during SSR
+ * because a watchdog crash from a bus stall would likely occur.
+ */
+ if (code == SUBSYS_BEFORE_SHUTDOWN) {
+ BAM_DMUX_LOG("%s: begin\n", __func__);
+ in_global_reset = 1;
+ /* wakeup ul_wakeup() thread*/
+ complete_all(&ul_wakeup_ack_completion);
+ complete_all(&bam_connection_completion);
+ /* sync to ensure the driver sees SSR */
+ synchronize_srcu(&bam_dmux_srcu);
+ BAM_DMUX_LOG("%s: ssr signaling complete\n", __func__);
+ flush_workqueue(bam_mux_rx_workqueue);
+ }
+ if (code == SUBSYS_BEFORE_POWERUP)
+ in_global_reset = 0;
+ if (code != SUBSYS_AFTER_SHUTDOWN)
+ return NOTIFY_DONE;
+
+ /* Handle uplink Powerdown */
+ write_lock_irqsave(&ul_wakeup_lock, flags);
+ if (bam_is_connected) {
+ ul_powerdown();
+ wait_for_ack = 0;
+ }
+ /*
+ * if modem crash during ul_wakeup(), power_vote is 1, needs to be
+ * reset to 0. harmless if bam_is_connected check above passes
+ */
+ power_vote(0);
+ write_unlock_irqrestore(&ul_wakeup_lock, flags);
+ ul_powerdown_finish();
+ a2_pc_disabled = 0;
+ a2_pc_disabled_wakelock_skipped = 0;
+ process_dynamic_mtu(false);
+ set_ul_mtu(0, true);
+ dynamic_mtu_enabled = false;
+
+ /* Cleanup Channel States */
+ mutex_lock(&bam_pdev_mutexlock);
+ for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
+ temp_remote_status = bam_ch_is_remote_open(i);
+ bam_ch[i].status &= ~BAM_CH_REMOTE_OPEN;
+ bam_ch[i].num_tx_pkts = 0;
+ if (bam_ch_is_local_open(i))
+ bam_ch[i].status |= BAM_CH_IN_RESET;
+ if (temp_remote_status) {
+ platform_device_unregister(bam_ch[i].pdev);
+ bam_ch[i].pdev = platform_device_alloc(
+ bam_ch[i].name, 2);
+ }
+ }
+ mutex_unlock(&bam_pdev_mutexlock);
+
+ /* Cleanup pending UL data */
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+ while (!list_empty(&bam_tx_pool)) {
+ node = bam_tx_pool.next;
+ list_del(node);
+ info = container_of(node, struct tx_pkt_info,
+ list_node);
+ if (!info->is_cmd) {
+ dma_unmap_single(dma_dev, info->dma_address,
+ info->skb->len,
+ bam_ops->dma_to);
+ dev_kfree_skb_any(info->skb);
+ } else {
+ dma_unmap_single(dma_dev, info->dma_address,
+ info->len,
+ bam_ops->dma_to);
+ kfree(info->skb);
+ }
+ kfree(info);
+ }
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
+ BAM_DMUX_LOG("%s: complete\n", __func__);
+ return NOTIFY_DONE;
+}
+
+static int bam_init(void)
+{
+ unsigned long h;
+ dma_addr_t dma_addr;
+ int ret;
+ void *a2_virt_addr;
+ int skip_iounmap = 0;
+
+ in_global_reset = 0;
+ vote_dfab();
+ /* init BAM */
+ a2_virt_addr = ioremap_nocache(a2_phys_base, a2_phys_size);
+ if (!a2_virt_addr) {
+ pr_err("%s: ioremap failed\n", __func__);
+ ret = -ENOMEM;
+ goto ioremap_failed;
+ }
+ a2_props.phys_addr = a2_phys_base;
+ a2_props.virt_addr = a2_virt_addr;
+ a2_props.virt_size = a2_phys_size;
+ a2_props.irq = a2_bam_irq;
+ a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP | SPS_BAM_HOLD_MEM;
+ a2_props.num_pipes = A2_NUM_PIPES;
+ a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
+ a2_props.constrained_logging = true;
+ a2_props.logging_number = 1;
+ a2_props.ipc_loglevel = 3;
+ if (satellite_mode)
+ a2_props.manage = SPS_BAM_MGR_DEVICE_REMOTE;
+ /* need to free on tear down */
+ ret = bam_ops->sps_register_bam_device_ptr(&a2_props, &h);
+ if (ret < 0) {
+ pr_err("%s: register bam error %d\n", __func__, ret);
+ goto register_bam_failed;
+ }
+ a2_device_handle = h;
+
+ bam_tx_pipe = bam_ops->sps_alloc_endpoint_ptr();
+ if (bam_tx_pipe == NULL) {
+ pr_err("%s: tx alloc endpoint failed\n", __func__);
+ ret = -ENOMEM;
+ goto tx_alloc_endpoint_failed;
+ }
+ ret = bam_ops->sps_get_config_ptr(bam_tx_pipe, &tx_connection);
+ if (ret) {
+ pr_err("%s: tx get config failed %d\n", __func__, ret);
+ goto tx_get_config_failed;
+ }
+
+ tx_connection.source = SPS_DEV_HANDLE_MEM;
+ tx_connection.src_pipe_index = 0;
+ tx_connection.destination = h;
+ tx_connection.dest_pipe_index = 4;
+ tx_connection.mode = SPS_MODE_DEST;
+ tx_connection.options = SPS_O_AUTO_ENABLE | SPS_O_EOT;
+ tx_desc_mem_buf.size = 0x800; /* 2k */
+ tx_desc_mem_buf.base = dma_alloc_coherent(dma_dev, tx_desc_mem_buf.size,
+ &dma_addr, 0);
+ if (tx_desc_mem_buf.base == NULL) {
+ ret = -ENOMEM;
+ goto tx_get_config_failed;
+ }
+ tx_desc_mem_buf.phys_base = dma_addr;
+ memset(tx_desc_mem_buf.base, 0x0, tx_desc_mem_buf.size);
+ tx_connection.desc = tx_desc_mem_buf;
+ tx_connection.event_thresh = 0x10;
+
+ ret = bam_ops->sps_connect_ptr(bam_tx_pipe, &tx_connection);
+ if (ret < 0) {
+ pr_err("%s: tx connect error %d\n", __func__, ret);
+ goto tx_connect_failed;
+ }
+
+ bam_rx_pipe = bam_ops->sps_alloc_endpoint_ptr();
+ if (bam_rx_pipe == NULL) {
+ pr_err("%s: rx alloc endpoint failed\n", __func__);
+ ret = -ENOMEM;
+ goto rx_alloc_endpoint_failed;
+ }
+ ret = bam_ops->sps_get_config_ptr(bam_rx_pipe, &rx_connection);
+ if (ret) {
+ pr_err("%s: rx get config failed %d\n", __func__, ret);
+ goto rx_get_config_failed;
+ }
+
+ rx_connection.source = h;
+ rx_connection.src_pipe_index = 5;
+ rx_connection.destination = SPS_DEV_HANDLE_MEM;
+ rx_connection.dest_pipe_index = 1;
+ rx_connection.mode = SPS_MODE_SRC;
+ rx_connection.options = SPS_O_AUTO_ENABLE | SPS_O_EOT |
+ SPS_O_ACK_TRANSFERS;
+ rx_desc_mem_buf.size = 0x800; /* 2k */
+ rx_desc_mem_buf.base = dma_alloc_coherent(dma_dev, rx_desc_mem_buf.size,
+ &dma_addr, 0);
+ if (rx_desc_mem_buf.base == NULL) {
+ ret = -ENOMEM;
+ goto rx_mem_failed;
+ }
+ rx_desc_mem_buf.phys_base = dma_addr;
+ memset(rx_desc_mem_buf.base, 0x0, rx_desc_mem_buf.size);
+ rx_connection.desc = rx_desc_mem_buf;
+ rx_connection.event_thresh = 0x10;
+
+ ret = bam_ops->sps_connect_ptr(bam_rx_pipe, &rx_connection);
+ if (ret < 0) {
+ pr_err("%s: rx connect error %d\n", __func__, ret);
+ goto rx_connect_failed;
+ }
+
+ tx_register_event.options = SPS_O_EOT;
+ tx_register_event.mode = SPS_TRIGGER_CALLBACK;
+ tx_register_event.xfer_done = NULL;
+ tx_register_event.callback = bam_mux_tx_notify;
+ tx_register_event.user = NULL;
+ ret = bam_ops->sps_register_event_ptr(bam_tx_pipe, &tx_register_event);
+ if (ret < 0) {
+ pr_err("%s: tx register event error %d\n", __func__, ret);
+ goto rx_event_reg_failed;
+ }
+
+ rx_register_event.options = SPS_O_EOT;
+ rx_register_event.mode = SPS_TRIGGER_CALLBACK;
+ rx_register_event.xfer_done = NULL;
+ rx_register_event.callback = bam_mux_rx_notify;
+ rx_register_event.user = NULL;
+ ret = bam_ops->sps_register_event_ptr(bam_rx_pipe, &rx_register_event);
+ if (ret < 0) {
+ pr_err("%s: tx register event error %d\n", __func__, ret);
+ goto rx_event_reg_failed;
+ }
+
+ mutex_lock(&delayed_ul_vote_lock);
+ bam_mux_initialized = 1;
+ if (need_delayed_ul_vote) {
+ need_delayed_ul_vote = 0;
+ msm_bam_dmux_kickoff_ul_wakeup();
+ }
+ mutex_unlock(&delayed_ul_vote_lock);
+ toggle_apps_ack();
+ bam_connection_is_active = 1;
+ complete_all(&bam_connection_completion);
+ queue_rx();
+ return 0;
+
+rx_event_reg_failed:
+ bam_ops->sps_disconnect_ptr(bam_rx_pipe);
+rx_connect_failed:
+ dma_free_coherent(dma_dev, rx_desc_mem_buf.size, rx_desc_mem_buf.base,
+ rx_desc_mem_buf.phys_base);
+rx_mem_failed:
+rx_get_config_failed:
+ bam_ops->sps_free_endpoint_ptr(bam_rx_pipe);
+rx_alloc_endpoint_failed:
+ bam_ops->sps_disconnect_ptr(bam_tx_pipe);
+tx_connect_failed:
+ dma_free_coherent(dma_dev, tx_desc_mem_buf.size, tx_desc_mem_buf.base,
+ tx_desc_mem_buf.phys_base);
+tx_get_config_failed:
+ bam_ops->sps_free_endpoint_ptr(bam_tx_pipe);
+tx_alloc_endpoint_failed:
+ bam_ops->sps_deregister_bam_device_ptr(h);
+ /*
+ * sps_deregister_bam_device() calls iounmap. calling iounmap on the
+ * same handle below will cause a crash, so skip it if we've freed
+ * the handle here.
+ */
+ skip_iounmap = 1;
+register_bam_failed:
+ if (!skip_iounmap)
+ iounmap(a2_virt_addr);
+ioremap_failed:
+ /*destroy_workqueue(bam_mux_workqueue);*/
+ return ret;
+}
+
+static void toggle_apps_ack(void)
+{
+ static unsigned int clear_bit; /* 0 = set the bit, else clear bit */
+
+ if (in_global_reset) {
+ BAM_DMUX_LOG("%s: skipped due to SSR\n", __func__);
+ return;
+ }
+
+ BAM_DMUX_LOG("%s: apps ack %d->%d\n", __func__,
+ clear_bit & 0x1, ~clear_bit & 0x1);
+ bam_ops->smsm_change_state_ptr(SMSM_APPS_STATE,
+ clear_bit & SMSM_A2_POWER_CONTROL_ACK,
+ ~clear_bit & SMSM_A2_POWER_CONTROL_ACK);
+ clear_bit = ~clear_bit;
+ DBG_INC_ACK_OUT_CNT();
+}
+
+static void bam_dmux_smsm_cb(void *priv, uint32_t old_state, uint32_t new_state)
+{
+ static int last_processed_state;
+ int rcu_id;
+
+ rcu_id = srcu_read_lock(&bam_dmux_srcu);
+ mutex_lock(&smsm_cb_lock);
+ bam_dmux_power_state = new_state & SMSM_A2_POWER_CONTROL ? 1 : 0;
+ DBG_INC_A2_POWER_CONTROL_IN_CNT();
+ BAM_DMUX_LOG("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
+ new_state);
+ if (last_processed_state == (new_state & SMSM_A2_POWER_CONTROL)) {
+ BAM_DMUX_LOG("%s: already processed this state\n", __func__);
+ mutex_unlock(&smsm_cb_lock);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+ return;
+ }
+
+ last_processed_state = new_state & SMSM_A2_POWER_CONTROL;
+
+ if (bam_mux_initialized && new_state & SMSM_A2_POWER_CONTROL) {
+ BAM_DMUX_LOG("%s: reconnect\n", __func__);
+ grab_wakelock();
+ reconnect_to_bam();
+ } else if (bam_mux_initialized &&
+ !(new_state & SMSM_A2_POWER_CONTROL)) {
+ BAM_DMUX_LOG("%s: disconnect\n", __func__);
+ disconnect_to_bam();
+ release_wakelock();
+ } else if (new_state & SMSM_A2_POWER_CONTROL) {
+ BAM_DMUX_LOG("%s: init\n", __func__);
+ grab_wakelock();
+ bam_init();
+ } else {
+ BAM_DMUX_LOG("%s: bad state change\n", __func__);
+ pr_err("%s: unsupported state change\n", __func__);
+ }
+ mutex_unlock(&smsm_cb_lock);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+}
+
+static void bam_dmux_smsm_ack_cb(void *priv, uint32_t old_state,
+ uint32_t new_state)
+{
+ int rcu_id;
+
+ rcu_id = srcu_read_lock(&bam_dmux_srcu);
+ DBG_INC_ACK_IN_CNT();
+ BAM_DMUX_LOG("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
+ new_state);
+ complete_all(&ul_wakeup_ack_completion);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+}
+
+/**
+ * msm_bam_dmux_set_bam_ops() - sets the bam_ops
+ * @ops: bam_ops_if to set
+ *
+ * Sets bam_ops to allow switching of runtime behavior. Preconditon, bam dmux
+ * must be in an idle state. If input ops is NULL, then bam_ops will be
+ * restored to their default state.
+ */
+void msm_bam_dmux_set_bam_ops(struct bam_ops_if *ops)
+{
+ if (ops != NULL)
+ bam_ops = ops;
+ else
+ bam_ops = &bam_default_ops;
+}
+EXPORT_SYMBOL(msm_bam_dmux_set_bam_ops);
+
+/**
+ * msm_bam_dmux_deinit() - puts bam dmux into a deinited state
+ *
+ * Puts bam dmux into a deinitialized state by simulating an ssr.
+ */
+void msm_bam_dmux_deinit(void)
+{
+ restart_notifier_cb(NULL, SUBSYS_BEFORE_SHUTDOWN, NULL);
+ restart_notifier_cb(NULL, SUBSYS_AFTER_SHUTDOWN, NULL);
+ restart_notifier_cb(NULL, SUBSYS_BEFORE_POWERUP, NULL);
+ restart_notifier_cb(NULL, SUBSYS_AFTER_POWERUP, NULL);
+ in_global_reset = 0;
+}
+EXPORT_SYMBOL(msm_bam_dmux_deinit);
+
+/**
+ * msm_bam_dmux_reinit() - reinitializes bam dmux
+ */
+void msm_bam_dmux_reinit(void)
+{
+ bam_mux_initialized = 0;
+ bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+ SMSM_A2_POWER_CONTROL,
+ bam_dmux_smsm_cb, NULL);
+ bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+ SMSM_A2_POWER_CONTROL_ACK,
+ bam_dmux_smsm_ack_cb, NULL);
+}
+EXPORT_SYMBOL(msm_bam_dmux_reinit);
+
+/**
+ * set_rx_buffer_ring_pool() - Configure the size of the rx ring pool to a
+ * supported value.
+ * @requested_buffs: Desired pool size.
+ *
+ * The requested size will be reduced to the largest supported size. The
+ * supported sizes must match the values in create_open_signal() for proper
+ * signal field construction in that function.
+ */
+static void set_rx_buffer_ring_pool(int requested_buffs)
+{
+ if (requested_buffs >= SZ_256) {
+ num_buffers = SZ_256;
+ return;
+ }
+
+ if (requested_buffs >= SZ_128) {
+ num_buffers = SZ_128;
+ return;
+ }
+
+ if (requested_buffs >= SZ_64) {
+ num_buffers = SZ_64;
+ return;
+ }
+
+ num_buffers = SZ_32;
+}
+
+/**
+ * set_dl_mtu() - Configure the non-default MTU to a supported value.
+ * @requested_mtu: Desired MTU size.
+ *
+ * Sets the dynamic receive MTU which can be enabled via negotiation with the
+ * remote side. Until the dynamic MTU is enabled, the default MTU will be used.
+ * The requested size will be reduced to the largest supported size. The
+ * supported sizes must match the values in create_open_signal() for proper
+ * signal field construction in that function.
+ */
+static void set_dl_mtu(int requested_mtu)
+{
+ if (requested_mtu >= SZ_16K) {
+ dl_mtu = SZ_16K;
+ return;
+ }
+
+ if (requested_mtu >= SZ_8K) {
+ dl_mtu = SZ_8K;
+ return;
+ }
+
+ if (requested_mtu >= SZ_4K) {
+ dl_mtu = SZ_4K;
+ return;
+ }
+
+ dl_mtu = SZ_2K;
+}
+
+static int bam_dmux_probe(struct platform_device *pdev)
+{
+ int rc;
+ struct resource *r;
+ void *subsys_h;
+ uint32_t requested_dl_mtu;
+
+ DBG("%s probe called\n", __func__);
+ if (bam_mux_initialized)
+ return 0;
+
+ if (pdev->dev.of_node) {
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ pr_err("%s: reg field missing\n", __func__);
+ return -ENODEV;
+ }
+ a2_phys_base = r->start;
+ a2_phys_size = (uint32_t)(resource_size(r));
+ a2_bam_irq = platform_get_irq(pdev, 0);
+ if (a2_bam_irq == -ENXIO) {
+ pr_err("%s: irq field missing\n", __func__);
+ return -ENODEV;
+ }
+ satellite_mode = of_property_read_bool(pdev->dev.of_node,
+ "qcom,satellite-mode");
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,rx-ring-size",
+ &num_buffers);
+ if (rc) {
+ DBG("%s: falling back to num_buffs default, rc:%d\n",
+ __func__, rc);
+ num_buffers = DEFAULT_NUM_BUFFERS;
+ }
+
+ set_rx_buffer_ring_pool(num_buffers);
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,max-rx-mtu",
+ &requested_dl_mtu);
+ if (rc) {
+ DBG("%s: falling back to dl_mtu default, rc:%d\n",
+ __func__, rc);
+ requested_dl_mtu = 0;
+ }
+
+ set_dl_mtu(requested_dl_mtu);
+
+ no_cpu_affinity = of_property_read_bool(pdev->dev.of_node,
+ "qcom,no-cpu-affinity");
+
+ rc = of_property_read_bool(pdev->dev.of_node,
+ "qcom,fast-shutdown");
+ if (rc)
+ ul_timeout_delay = UL_FAST_TIMEOUT_DELAY;
+
+ BAM_DMUX_LOG(
+ "%s: base:%pK size:%x irq:%d satellite:%d num_buffs:%d dl_mtu:%x cpu-affinity:%d ul_timeout_delay:%d\n",
+ __func__,
+ (void *)(uintptr_t)a2_phys_base,
+ a2_phys_size,
+ a2_bam_irq,
+ satellite_mode,
+ num_buffers,
+ dl_mtu,
+ no_cpu_affinity,
+ ul_timeout_delay);
+ } else { /* fallback to default init data */
+ a2_phys_base = A2_PHYS_BASE;
+ a2_phys_size = A2_PHYS_SIZE;
+ a2_bam_irq = A2_BAM_IRQ;
+ num_buffers = DEFAULT_NUM_BUFFERS;
+ set_rx_buffer_ring_pool(num_buffers);
+ }
+
+ dma_dev = &pdev->dev;
+ /* The BAM only suports 32 bits of address */
+ dma_dev->dma_mask = kmalloc(sizeof(*dma_dev->dma_mask), GFP_KERNEL);
+ if (!dma_dev->dma_mask)
+ return -ENOMEM;
+
+ *dma_dev->dma_mask = DMA_BIT_MASK(32);
+ dma_dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ xo_clk = clk_get(&pdev->dev, "xo");
+ if (IS_ERR(xo_clk)) {
+ BAM_DMUX_LOG("%s: did not get xo clock\n", __func__);
+ xo_clk = NULL;
+ }
+ dfab_clk = clk_get(&pdev->dev, "bus_clk");
+ if (IS_ERR(dfab_clk)) {
+ BAM_DMUX_LOG("%s: did not get dfab clock\n", __func__);
+ dfab_clk = NULL;
+ } else {
+ rc = clk_set_rate(dfab_clk, 64000000);
+ if (rc)
+ pr_err("%s: unable to set dfab clock rate\n", __func__);
+ }
+
+ /*
+ * setup the workqueue so that it can be pinned to core 0 and not
+ * block the watchdog pet function, so that netif_rx() in rmnet
+ * only uses one queue.
+ */
+ if (no_cpu_affinity)
+ bam_mux_rx_workqueue =
+ create_singlethread_workqueue("bam_dmux_rx");
+ else
+ bam_mux_rx_workqueue = alloc_workqueue("bam_dmux_rx",
+ WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+ if (!bam_mux_rx_workqueue)
+ return -ENOMEM;
+
+ bam_mux_tx_workqueue = create_singlethread_workqueue("bam_dmux_tx");
+ if (!bam_mux_tx_workqueue) {
+ destroy_workqueue(bam_mux_rx_workqueue);
+ return -ENOMEM;
+ }
+
+ for (rc = 0; rc < BAM_DMUX_NUM_CHANNELS; ++rc) {
+ spin_lock_init(&bam_ch[rc].lock);
+ scnprintf(bam_ch[rc].name, BAM_DMUX_CH_NAME_MAX_LEN,
+ "bam_dmux_ch_%d", rc);
+ /* bus 2, ie a2 stream 2 */
+ bam_ch[rc].pdev = platform_device_alloc(bam_ch[rc].name, 2);
+ if (!bam_ch[rc].pdev) {
+ pr_err("%s: platform device alloc failed\n", __func__);
+ destroy_workqueue(bam_mux_rx_workqueue);
+ destroy_workqueue(bam_mux_tx_workqueue);
+ return -ENOMEM;
+ }
+ }
+
+ init_completion(&ul_wakeup_ack_completion);
+ init_completion(&bam_connection_completion);
+ init_completion(&dfab_unvote_completion);
+ init_completion(&shutdown_completion);
+ complete_all(&shutdown_completion);
+ INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
+ wakeup_source_init(&bam_wakelock, "bam_dmux_wakelock");
+ init_srcu_struct(&bam_dmux_srcu);
+
+ subsys_h = subsys_notif_register_notifier("modem", &restart_notifier);
+ if (IS_ERR(subsys_h)) {
+ destroy_workqueue(bam_mux_rx_workqueue);
+ destroy_workqueue(bam_mux_tx_workqueue);
+ rc = (int)PTR_ERR(subsys_h);
+ pr_err("%s: failed to register for ssr rc: %d\n", __func__, rc);
+ return rc;
+ }
+
+ rc = bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+ SMSM_A2_POWER_CONTROL,
+ bam_dmux_smsm_cb, NULL);
+
+ if (rc) {
+ subsys_notif_unregister_notifier(subsys_h, &restart_notifier);
+ destroy_workqueue(bam_mux_rx_workqueue);
+ destroy_workqueue(bam_mux_tx_workqueue);
+ pr_err("%s: smsm cb register failed, rc: %d\n", __func__, rc);
+ return -ENOMEM;
+ }
+
+ rc = bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+ SMSM_A2_POWER_CONTROL_ACK,
+ bam_dmux_smsm_ack_cb, NULL);
+
+ if (rc) {
+ subsys_notif_unregister_notifier(subsys_h, &restart_notifier);
+ destroy_workqueue(bam_mux_rx_workqueue);
+ destroy_workqueue(bam_mux_tx_workqueue);
+ bam_ops->smsm_state_cb_deregister_ptr(SMSM_MODEM_STATE,
+ SMSM_A2_POWER_CONTROL,
+ bam_dmux_smsm_cb, NULL);
+ pr_err("%s: smsm ack cb register failed, rc: %d\n", __func__,
+ rc);
+ for (rc = 0; rc < BAM_DMUX_NUM_CHANNELS; ++rc)
+ platform_device_put(bam_ch[rc].pdev);
+ return -ENOMEM;
+ }
+
+ if (bam_ops->smsm_get_state_ptr(SMSM_MODEM_STATE) &
+ SMSM_A2_POWER_CONTROL)
+ bam_dmux_smsm_cb(NULL, 0,
+ bam_ops->smsm_get_state_ptr(SMSM_MODEM_STATE));
+
+ return 0;
+}
+
+static const struct of_device_id msm_match_table[] = {
+ {.compatible = "qcom,bam_dmux"},
+ {},
+};
+
+static struct platform_driver bam_dmux_driver = {
+ .probe = bam_dmux_probe,
+ .driver = {
+ .name = "BAM_RMNT",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_match_table,
+ },
+};
+
+static int __init bam_dmux_init(void)
+{
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dent;
+
+ dent = debugfs_create_dir("bam_dmux", 0);
+ if (!IS_ERR(dent)) {
+ debug_create("tbl", 0444, dent, debug_tbl);
+ debug_create("ul_pkt_cnt", 0444, dent, debug_ul_pkt_cnt);
+ debug_create("stats", 0444, dent, debug_stats);
+ }
+#endif
+
+ bam_ipc_log_txt = ipc_log_context_create(BAM_IPC_LOG_PAGES, "bam_dmux",
+ 0);
+ if (!bam_ipc_log_txt)
+ pr_err("%s : unable to create IPC Logging Context", __func__);
+
+ rx_timer_interval = DEFAULT_POLLING_MIN_SLEEP;
+
+ return platform_driver_register(&bam_dmux_driver);
+}
+
+late_initcall(bam_dmux_init); /* needs to init after SMD */
+MODULE_DESCRIPTION("MSM BAM DMUX");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/bam_dmux_private.h b/drivers/soc/qcom/bam_dmux_private.h
new file mode 100644
index 0000000..4f39076
--- /dev/null
+++ b/drivers/soc/qcom/bam_dmux_private.h
@@ -0,0 +1,182 @@
+/* Copyright (c) 2013-2014, 2018, 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 _BAM_DMUX_PRIVATE_H
+#define _BAM_DMUX_PRIVATE_H
+
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/msm-sps.h>
+
+#define BAM_MUX_HDR_MAGIC_NO 0x33fc
+#define BAM_MUX_HDR_CMD_DATA 0
+#define BAM_MUX_HDR_CMD_OPEN 1
+#define BAM_MUX_HDR_CMD_CLOSE 2
+#define BAM_MUX_HDR_CMD_STATUS 3 /* unused */
+#define BAM_MUX_HDR_CMD_OPEN_NO_A2_PC 4
+#define DEFAULT_BUFFER_SIZE SZ_2K
+
+#define DYNAMIC_MTU_MASK 0x2
+#define MTU_SIZE_MASK 0xc0
+#define MTU_SIZE_SHIFT 0x6
+#define DL_POOL_SIZE_SHIFT 0x4
+
+/**
+ * struct bam_ops_if - collection of function pointers to allow swappable
+ * runtime functionality
+ * @smsm_change_state_ptr: pointer to smsm_change_state function
+ * @smsm_get_state_ptr: pointer to smsm_get_state function
+ * @smsm_state_cb_register_ptr: pointer to smsm_state_cb_register function
+ * @smsm_state_cb_deregister_ptr: pointer to smsm_state_cb_deregister function
+ * @sps_connect_ptr: pointer to sps_connect function
+ * @sps_disconnect_ptr: pointer to sps_disconnect function
+ * @sps_register_bam_device_ptr: pointer to sps_register_bam_device
+ * @sps_deregister_bam_device_ptr: pointer to sps_deregister_bam_device
+ * function
+ * @sps_alloc_endpoint_ptr: pointer to sps_alloc_endpoint function
+ * @sps_free_endpoint_ptr: pointer to sps_free_endpoint function
+ * @sps_set_config_ptr: pointer to sps_set_config function
+ * @sps_get_config_ptr: pointer to sps_get_config function
+ * @sps_device_reset_ptr: pointer to sps_device_reset function
+ * @sps_register_event_ptr: pointer to sps_register_event function
+ * @sps_transfer_one_ptr: pointer to sps_transfer_one function
+ * @sps_get_iovec_ptr: pointer to sps_get_iovec function
+ * @sps_get_unused_desc_num_ptr: pointer to sps_get_unused_desc_num function
+ * @dma_to: enum for the direction of dma operations to device
+ * @dma_from: enum for the direction of dma operations from device
+ *
+ * This struct contains the interface from bam_dmux to smsm and sps. The
+ * pointers can be swapped out at run time to provide different functionality.
+ */
+struct bam_ops_if {
+ /* smsm */
+ int (*smsm_change_state_ptr)(uint32_t smsm_entry,
+ uint32_t clear_mask, uint32_t set_mask);
+
+ uint32_t (*smsm_get_state_ptr)(uint32_t smsm_entry);
+
+ int (*smsm_state_cb_register_ptr)(uint32_t smsm_entry, uint32_t mask,
+ void (*notify)(void *, uint32_t old_state, uint32_t new_state),
+ void *data);
+
+ int (*smsm_state_cb_deregister_ptr)(uint32_t smsm_entry, uint32_t mask,
+ void (*notify)(void *, uint32_t, uint32_t), void *data);
+
+ /* sps */
+ int (*sps_connect_ptr)(struct sps_pipe *h, struct sps_connect *connect);
+
+ int (*sps_disconnect_ptr)(struct sps_pipe *h);
+
+ int (*sps_register_bam_device_ptr)(
+ const struct sps_bam_props *bam_props,
+ unsigned long *dev_handle);
+
+ int (*sps_deregister_bam_device_ptr)(unsigned long dev_handle);
+
+ struct sps_pipe *(*sps_alloc_endpoint_ptr)(void);
+
+ int (*sps_free_endpoint_ptr)(struct sps_pipe *h);
+
+ int (*sps_set_config_ptr)(struct sps_pipe *h,
+ struct sps_connect *config);
+
+ int (*sps_get_config_ptr)(struct sps_pipe *h,
+ struct sps_connect *config);
+
+ int (*sps_device_reset_ptr)(unsigned long dev);
+
+ int (*sps_register_event_ptr)(struct sps_pipe *h,
+ struct sps_register_event *reg);
+
+ int (*sps_transfer_one_ptr)(struct sps_pipe *h,
+ phys_addr_t addr, u32 size,
+ void *user, u32 flags);
+
+ int (*sps_get_iovec_ptr)(struct sps_pipe *h,
+ struct sps_iovec *iovec);
+
+ int (*sps_get_unused_desc_num_ptr)(struct sps_pipe *h,
+ u32 *desc_num);
+
+ enum dma_data_direction dma_to;
+
+ enum dma_data_direction dma_from;
+};
+
+/**
+ * struct bam_mux_hdr - struct which contains bam dmux header info
+ * @magic_num: magic number placed at start to ensure that it is actually a
+ * valid bam dmux header
+ * @signal: optional signaling bits with commmand type specific definitions
+ * @cmd: the command
+ * @pad_len: the length of padding
+ * @ch_id: the id of the bam dmux channel that this is sent on
+ * @pkt_len: the length of the packet that this is the header of
+ */
+struct bam_mux_hdr {
+ uint16_t magic_num;
+ uint8_t signal;
+ uint8_t cmd;
+ uint8_t pad_len;
+ uint8_t ch_id;
+ uint16_t pkt_len;
+};
+
+/**
+ * struct rx_pkt_info - struct describing an rx packet
+ * @skb: socket buffer containing the packet
+ * @dma_address: dma mapped address of the packet
+ * @work: work_struct for processing the packet
+ * @list_node: list_head for placing this on a list
+ * @sps_size: size of the sps_iovec for this packet
+ * @len: total length of the buffer containing this packet
+ */
+struct rx_pkt_info {
+ struct sk_buff *skb;
+ dma_addr_t dma_address;
+ struct work_struct work;
+ struct list_head list_node;
+ uint16_t sps_size;
+ uint16_t len;
+};
+
+/**
+ * struct tx_pkt_info - struct describing a tx packet
+ * @skb: socket buffer containing the packet
+ * @dma_address: dma mapped address of the packet
+ * @is_cmd: signifies whether this is a command or data packet
+ * @len: length og the packet
+ * @work: work_struct for processing this packet
+ * @list_node: list_head for placing this on a list
+ * @ts_sec: seconds portion of the timestamp
+ * @ts_nsec: nanoseconds portion of the timestamp
+ *
+ */
+struct tx_pkt_info {
+ struct sk_buff *skb;
+ dma_addr_t dma_address;
+ char is_cmd;
+ uint32_t len;
+ struct work_struct work;
+ struct list_head list_node;
+ unsigned int ts_sec;
+ unsigned long ts_nsec;
+};
+
+void msm_bam_dmux_set_bam_ops(struct bam_ops_if *ops);
+
+void msm_bam_dmux_deinit(void);
+
+void msm_bam_dmux_reinit(void);
+
+#endif /* _BAM_DMUX_PRIVATE_H */
diff --git a/drivers/soc/qcom/dcc.c b/drivers/soc/qcom/dcc.c
index 43dddb4..a687286 100644
--- a/drivers/soc/qcom/dcc.c
+++ b/drivers/soc/qcom/dcc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -554,7 +554,8 @@
if (strlen(buf) >= 10)
return -EINVAL;
- strlcpy(str, buf, sizeof(str));
+ if (sscanf(buf, "%9s", str) != 1)
+ return -EINVAL;
mutex_lock(&drvdata->mutex);
if (drvdata->enable) {
@@ -599,7 +600,8 @@
if (strlen(buf) >= 10)
return -EINVAL;
- strlcpy(str, buf, sizeof(str));
+ if (sscanf(buf, "%9s", str) != 1)
+ return -EINVAL;
mutex_lock(&drvdata->mutex);
if (drvdata->enable) {
diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c
index 59897ea..4892f50 100644
--- a/drivers/soc/qcom/glink.c
+++ b/drivers/soc/qcom/glink.c
@@ -37,6 +37,7 @@
#define GLINK_QOS_DEF_NUM_PRIORITY 1
#define GLINK_QOS_DEF_MTU 2048
+#define GLINK_CH_XPRT_NAME_SIZE ((3 * GLINK_NAME_SIZE) + 4)
#define GLINK_KTHREAD_PRIO 1
/**
@@ -1274,8 +1275,7 @@
spin_unlock_irqrestore(&ctx->rmt_rx_intent_lst_lock_lhc2, flags);
GLINK_DBG_CH(ctx, "%s: R[%u]:%zu Pushed remote intent\n", __func__,
- intent->id,
- intent->intent_size);
+ riid, size);
}
/**
@@ -2905,6 +2905,7 @@
size_t intent_size;
bool is_atomic =
tx_flags & (GLINK_TX_SINGLE_THREADED | GLINK_TX_ATOMIC);
+ char glink_name[GLINK_CH_XPRT_NAME_SIZE];
unsigned long flags;
void *cookie = NULL;
@@ -2946,21 +2947,22 @@
tracer_pkt_log_event(data, GLINK_CORE_TX);
}
+ scnprintf(glink_name, GLINK_CH_XPRT_NAME_SIZE, "%s_%s_%s", ctx->name,
+ ctx->transport_ptr->edge, ctx->transport_ptr->name);
/* find matching rx intent (first-fit algorithm for now) */
if (ch_pop_remote_rx_intent(ctx, size, &riid, &intent_size, &cookie)) {
if (!(tx_flags & GLINK_TX_REQ_INTENT)) {
/* no rx intent available */
- GLINK_ERR_CH(ctx,
- "%s: R[%u]:%zu Intent not present for lcid\n",
- __func__, riid, size);
+ GLINK_ERR(
+ "%s: %s: R[%u]:%zu Intent not present\n",
+ glink_name, __func__, riid, size);
ret = -EAGAIN;
goto glink_tx_common_err;
}
if (is_atomic && !(ctx->transport_ptr->capabilities &
GCAP_AUTO_QUEUE_RX_INT)) {
- GLINK_ERR_CH(ctx,
- "%s: Cannot request intent in atomic context\n",
- __func__);
+ GLINK_ERR("%s: %s: %s\n", glink_name, __func__,
+ "Cannot request intent in atomic context");
ret = -EINVAL;
goto glink_tx_common_err;
}
@@ -2970,8 +2972,8 @@
ret = ctx->transport_ptr->ops->tx_cmd_rx_intent_req(
ctx->transport_ptr->ops, ctx->lcid, size);
if (ret) {
- GLINK_ERR_CH(ctx, "%s: Request intent failed %d\n",
- __func__, ret);
+ GLINK_ERR("%s: %s: Request intent failed %d\n",
+ glink_name, __func__, ret);
goto glink_tx_common_err;
}
@@ -2979,18 +2981,18 @@
&intent_size, &cookie)) {
rwref_read_put(&ctx->ch_state_lhb2);
if (is_atomic) {
- GLINK_ERR_CH(ctx,
- "%s Intent of size %zu not ready\n",
- __func__, size);
+ GLINK_ERR("%s: %s: Intent of size %zu %s\n",
+ glink_name, __func__, size,
+ "not ready");
ret = -EAGAIN;
goto glink_tx_common_err_2;
}
if (ctx->transport_ptr->local_state == GLINK_XPRT_DOWN
|| !ch_is_fully_opened(ctx)) {
- GLINK_ERR_CH(ctx,
- "%s: Channel closed while waiting for intent\n",
- __func__);
+ GLINK_ERR("%s: %s: %s %s\n", glink_name,
+ __func__, "Channel closed while",
+ "waiting for intent");
ret = -EBUSY;
goto glink_tx_common_err_2;
}
@@ -3000,17 +3002,17 @@
&ctx->int_req_ack_complete,
ctx->rx_intent_req_timeout_jiffies)) {
GLINK_ERR(
- "%s: Intent request ack with size: %zu not granted for lcid\n",
- __func__, size);
+ "%s: %s: %s %zu not granted for lcid\n",
+ glink_name, __func__,
+ "Intent request ack with size:", size);
ret = -ETIMEDOUT;
goto glink_tx_common_err_2;
}
if (!ctx->int_req_ack) {
- GLINK_ERR_CH(ctx,
- "%s: Intent Request with size: %zu %s",
- __func__, size,
- "not granted for lcid\n");
+ GLINK_ERR("%s: %s: %s %zu %s\n", glink_name,
+ __func__, "Intent Request with size:",
+ size, "not granted for lcid");
ret = -EAGAIN;
goto glink_tx_common_err_2;
}
@@ -3019,9 +3021,9 @@
if (!wait_for_completion_timeout(
&ctx->int_req_complete,
ctx->rx_intent_req_timeout_jiffies)) {
- GLINK_ERR(
- "%s: Intent request with size: %zu not granted for lcid\n",
- __func__, size);
+ GLINK_ERR("%s: %s: %s %zu %s\n", glink_name,
+ __func__, "Intent request with size: ",
+ size, "not granted for lcid");
ret = -ETIMEDOUT;
goto glink_tx_common_err_2;
}
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index da122fc..d9cd0fa 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -53,6 +53,8 @@
#define RPM_FIFO_ADDR_ALIGN_BYTES 3
#define TRACER_PKT_FEATURE BIT(2)
#define DEFERRED_CMDS_THRESHOLD 25
+#define NUM_LOG_PAGES 4
+
/**
* enum command_types - definition of the types of commands sent/received
* @VERSION_CMD: Version and feature set supported
@@ -169,6 +171,7 @@
* @tx_blocked_signal_sent: Flag to indicate the flush signal has already
* been sent, and a response is pending from the
* remote side. Protected by @write_lock.
+ * @debug_mask mask to set debugging level.
* @kwork: Work to be executed when an irq is received.
* @kworker: Handle to the entity processing of
deferred commands.
@@ -189,6 +192,7 @@
* @ramp_time_us: Array of ramp times in microseconds where array
* index position represents a power state.
* @mailbox: Mailbox transport channel description reference.
+ * @log_ctx: Pointer to log context.
*/
struct edge_info {
struct glink_transport_if xprt_if;
@@ -214,6 +218,7 @@
wait_queue_head_t tx_blocked_queue;
bool tx_resume_needed;
bool tx_blocked_signal_sent;
+ unsigned int debug_mask;
struct kthread_work kwork;
struct kthread_worker kworker;
struct task_struct *task;
@@ -229,6 +234,7 @@
uint32_t readback;
unsigned long *ramp_time_us;
struct mailbox_config_info *mailbox;
+ void *log_ctx;
};
/**
@@ -261,6 +267,27 @@
{1, TRACER_PKT_FEATURE, negotiate_features_v1},
};
+#define SMEM_IPC_LOG(einfo, str, id, param1, param2) do { \
+ if ((glink_xprt_debug_mask & QCOM_GLINK_DEBUG_ENABLE) \
+ && (einfo->debug_mask & QCOM_GLINK_DEBUG_ENABLE)) \
+ ipc_log_string(einfo->log_ctx, \
+ "%s: Rx:%x:%x Tx:%x:%x Cmd:%x P1:%x P2:%x\n", \
+ str, einfo->rx_ch_desc->read_index, \
+ einfo->rx_ch_desc->write_index, \
+ einfo->tx_ch_desc->read_index, \
+ einfo->tx_ch_desc->write_index, \
+ id, param1, param2); \
+} while (0) \
+
+enum {
+ QCOM_GLINK_DEBUG_ENABLE = 1U << 0,
+ QCOM_GLINK_DEBUG_DISABLE = 1U << 1,
+};
+
+static unsigned int glink_xprt_debug_mask = QCOM_GLINK_DEBUG_ENABLE;
+module_param_named(debug_mask, glink_xprt_debug_mask,
+ uint, 0664);
+
/**
* send_irq() - send an irq to a remote entity as an event signal
* @einfo: Which remote entity that should receive the irq.
@@ -640,6 +667,7 @@
read_notif_req.reserved = 0;
read_notif_req.reserved2 = 0;
+ SMEM_IPC_LOG(einfo, __func__, READ_NOTIF_CMD, 0, 0);
if (!einfo->tx_blocked_signal_sent) {
einfo->tx_blocked_signal_sent = true;
fifo_write(einfo, &read_notif_req, sizeof(read_notif_req));
@@ -968,8 +996,12 @@
cmd.param2 = d_cmd->param2;
cmd_data = d_cmd->data;
kfree(d_cmd);
+ SMEM_IPC_LOG(einfo, "kthread", cmd.id, cmd.param1,
+ cmd.param2);
} else {
fifo_read(einfo, &cmd, sizeof(cmd));
+ SMEM_IPC_LOG(einfo, "IRQ", cmd.id, cmd.param1,
+ cmd.param2);
cmd_data = NULL;
}
@@ -1297,6 +1329,7 @@
cmd.version = version;
cmd.features = features;
+ SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.version, cmd.features);
fifo_tx(einfo, &cmd, sizeof(cmd));
srcu_read_unlock(&einfo->use_ref, rcu_id);
}
@@ -1332,6 +1365,7 @@
cmd.version = version;
cmd.features = features;
+ SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.version, cmd.features);
fifo_tx(einfo, &cmd, sizeof(cmd));
srcu_read_unlock(&einfo->use_ref, rcu_id);
}
@@ -1417,6 +1451,7 @@
memcpy(buf, &cmd, sizeof(cmd));
memcpy(buf + sizeof(cmd), name, cmd.length);
+ SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.length);
fifo_tx(einfo, buf, buf_size);
kfree(buf);
@@ -1455,6 +1490,7 @@
cmd.lcid = lcid;
cmd.reserved = 0;
+ SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.reserved);
fifo_tx(einfo, &cmd, sizeof(cmd));
srcu_read_unlock(&einfo->use_ref, rcu_id);
@@ -1492,6 +1528,7 @@
cmd.rcid = rcid;
cmd.reserved = 0;
+ SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.rcid, cmd.reserved);
fifo_tx(einfo, &cmd, sizeof(cmd));
srcu_read_unlock(&einfo->use_ref, rcu_id);
}
@@ -1526,6 +1563,7 @@
cmd.rcid = rcid;
cmd.reserved = 0;
+ SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.rcid, cmd.reserved);
fifo_tx(einfo, &cmd, sizeof(cmd));
srcu_read_unlock(&einfo->use_ref, rcu_id);
}
@@ -1686,6 +1724,7 @@
cmd.size = size;
cmd.liid = liid;
+ SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.count);
fifo_tx(einfo, &cmd, sizeof(cmd));
srcu_read_unlock(&einfo->use_ref, rcu_id);
@@ -1726,6 +1765,7 @@
cmd.lcid = lcid;
cmd.liid = liid;
+ SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.liid);
fifo_tx(einfo, &cmd, sizeof(cmd));
srcu_read_unlock(&einfo->use_ref, rcu_id);
}
@@ -1771,6 +1811,7 @@
cmd.lcid = lcid;
cmd.size = size;
+ SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.size);
fifo_tx(einfo, &cmd, sizeof(cmd));
srcu_read_unlock(&einfo->use_ref, rcu_id);
@@ -1816,6 +1857,7 @@
else
cmd.response = 0;
+ SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.response);
fifo_tx(einfo, &cmd, sizeof(cmd));
srcu_read_unlock(&einfo->use_ref, rcu_id);
@@ -1854,6 +1896,7 @@
cmd.lcid = lcid;
cmd.sigs = sigs;
+ SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.sigs);
fifo_tx(einfo, &cmd, sizeof(cmd));
srcu_read_unlock(&einfo->use_ref, rcu_id);
@@ -2051,6 +2094,7 @@
return ret;
}
+ SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.riid);
GLINK_DBG("%s %s: lcid[%u] riid[%u] cmd[%d], size[%d], size_left[%d]\n",
"<SMEM>", __func__, cmd.lcid, cmd.riid, cmd.id, cmd.size,
cmd.size_left);
@@ -2370,6 +2414,7 @@
uint32_t irq_mask;
struct resource *r;
u32 *cpu_array;
+ char log_name[GLINK_NAME_SIZE*2+7] = {0};
node = pdev->dev.of_node;
@@ -2529,6 +2574,16 @@
kfree(cpu_array);
}
+ einfo->debug_mask = QCOM_GLINK_DEBUG_ENABLE;
+ snprintf(log_name, sizeof(log_name), "%s_%s_xprt",
+ einfo->xprt_cfg.edge, einfo->xprt_cfg.name);
+ if (einfo->debug_mask & QCOM_GLINK_DEBUG_ENABLE)
+ einfo->log_ctx =
+ ipc_log_context_create(NUM_LOG_PAGES, log_name, 0);
+ if (!einfo->log_ctx)
+ GLINK_ERR("%s: unable to create log context for [%s:%s]\n",
+ __func__, einfo->xprt_cfg.edge,
+ einfo->xprt_cfg.name);
register_debugfs_info(einfo);
/* fake an interrupt on this edge to see if the remote side is up */
irq_handler(0, einfo);
@@ -2570,6 +2625,7 @@
char toc[RPM_TOC_SIZE];
uint32_t *tocp;
uint32_t num_toc_entries;
+ char log_name[GLINK_NAME_SIZE*2+7] = {0};
node = pdev->dev.of_node;
@@ -2776,7 +2832,16 @@
if (rc < 0)
pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
irq_line);
-
+ einfo->debug_mask = QCOM_GLINK_DEBUG_DISABLE;
+ snprintf(log_name, sizeof(log_name), "%s_%s_xprt",
+ einfo->xprt_cfg.edge, einfo->xprt_cfg.name);
+ if (einfo->debug_mask & QCOM_GLINK_DEBUG_ENABLE)
+ einfo->log_ctx =
+ ipc_log_context_create(NUM_LOG_PAGES, log_name, 0);
+ if (!einfo->log_ctx)
+ GLINK_ERR("%s: unable to create log context for [%s:%s]\n",
+ __func__, einfo->xprt_cfg.edge,
+ einfo->xprt_cfg.name);
register_debugfs_info(einfo);
einfo->xprt_if.glink_core_if_ptr->link_up(&einfo->xprt_if);
return 0;
@@ -2822,6 +2887,7 @@
struct mailbox_config_info *mbox_cfg;
uint32_t mbox_cfg_size;
phys_addr_t cfg_p_addr;
+ char log_name[GLINK_NAME_SIZE*2+7] = {0};
node = pdev->dev.of_node;
@@ -3020,7 +3086,16 @@
if (rc < 0)
pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
irq_line);
-
+ einfo->debug_mask = QCOM_GLINK_DEBUG_DISABLE;
+ snprintf(log_name, sizeof(log_name), "%s_%s_xprt",
+ einfo->xprt_cfg.edge, einfo->xprt_cfg.name);
+ if (einfo->debug_mask & QCOM_GLINK_DEBUG_ENABLE)
+ einfo->log_ctx =
+ ipc_log_context_create(NUM_LOG_PAGES, log_name, 0);
+ if (!einfo->log_ctx)
+ GLINK_ERR("%s: unable to create log context for [%s:%s]\n",
+ __func__, einfo->xprt_cfg.edge,
+ einfo->xprt_cfg.name);
register_debugfs_info(einfo);
writel_relaxed(mbox_cfg_size, mbox_size);
diff --git a/drivers/soc/qcom/glink_ssr.c b/drivers/soc/qcom/glink_ssr.c
index 239f2c1..7f97ab0 100644
--- a/drivers/soc/qcom/glink_ssr.c
+++ b/drivers/soc/qcom/glink_ssr.c
@@ -529,7 +529,6 @@
* only modified during setup.
*/
atomic_set(&responses_remaining, ss_info->notify_list_len);
- init_waitqueue_head(&waitqueue);
notifications_successful = true;
list_for_each_entry(ss_leaf_entry, &ss_info->notify_list,
@@ -935,7 +934,7 @@
ss_info->cb_data = NULL;
spin_lock_init(&ss_info->link_up_lock);
spin_lock_init(&ss_info->cb_lock);
-
+ init_waitqueue_head(&waitqueue);
nb = kmalloc(sizeof(struct restart_notifier_block), GFP_KERNEL);
if (!nb) {
GLINK_SSR_ERR("<SSR> %s: Could not allocate notifier block\n",
diff --git a/drivers/soc/qcom/lpm-stats.c b/drivers/soc/qcom/lpm-stats.c
index a4d59f4..97c2f51 100644
--- a/drivers/soc/qcom/lpm-stats.c
+++ b/drivers/soc/qcom/lpm-stats.c
@@ -694,9 +694,10 @@
{
struct list_head *centry = NULL;
struct lpm_stats *pos = NULL;
+ struct lpm_stats *n = NULL;
centry = &stats->child;
- list_for_each_entry_reverse(pos, centry, sibling) {
+ list_for_each_entry_safe_reverse(pos, n, centry, sibling) {
if (!list_empty(&pos->child)) {
cleanup_stats(pos);
continue;
diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c
index e58fa2e..77a76d2 100644
--- a/drivers/soc/qcom/memshare/msm_memshare.c
+++ b/drivers/soc/qcom/memshare/msm_memshare.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -270,6 +270,9 @@
{
int i = 0, ret;
char *client_name = NULL;
+ u32 source_vmlist[1] = {VMID_MSS_MSA};
+ int dest_vmids[1] = {VMID_HLOS};
+ int dest_perms[1] = {PERM_READ|PERM_WRITE|PERM_EXEC};
for (i = 0; i < num_clients; i++) {
@@ -296,6 +299,33 @@
continue;
}
+ if (memblock[i].hyp_mapping &&
+ memblock[i].peripheral ==
+ DHMS_MEM_PROC_MPSS_V01) {
+ pr_debug("memshare: hypervisor unmapping for client id: %d\n",
+ memblock[i].client_id);
+ if (memblock[i].alloc_request)
+ continue;
+ ret = hyp_assign_phys(
+ memblock[i].phy_addr,
+ memblock[i].size,
+ source_vmlist,
+ 1, dest_vmids,
+ dest_perms, 1);
+ if (ret) {
+ /*
+ * This is an error case as hyp
+ * mapping was successful
+ * earlier but during unmap
+ * it lead to failure.
+ */
+ pr_err("memshare: %s, failed to map the region to APPS\n",
+ __func__);
+ } else {
+ memblock[i].hyp_mapping = 0;
+ }
+ }
+
ramdump_segments_tmp = kcalloc(1,
sizeof(struct ramdump_segment),
GFP_KERNEL);
@@ -322,9 +352,8 @@
static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
void *_cmd)
{
- int i;
- int ret;
- u32 source_vmlist[2] = {VMID_HLOS, VMID_MSS_MSA};
+ int i, ret;
+ u32 source_vmlist[1] = {VMID_MSS_MSA};
int dest_vmids[1] = {VMID_HLOS};
int dest_perms[1] = {PERM_READ|PERM_WRITE|PERM_EXEC};
struct notif_data *notifdata = NULL;
@@ -335,6 +364,8 @@
case SUBSYS_BEFORE_SHUTDOWN:
bootup_request++;
+ for (i = 0; i < MAX_CLIENTS; i++)
+ memblock[i].alloc_request = 0;
break;
case SUBSYS_RAMDUMP_NOTIFICATION:
@@ -370,18 +401,20 @@
memblock[i].client_id);
}
- if (memblock[i].free_memory == 0) {
- if (memblock[i].peripheral ==
- DHMS_MEM_PROC_MPSS_V01 &&
- !memblock[i].guarantee &&
- memblock[i].allotted) {
- pr_debug("memshare: hypervisor unmapping for client id: %d\n",
- memblock[i].client_id);
+ if (memblock[i].free_memory == 0 &&
+ memblock[i].peripheral ==
+ DHMS_MEM_PROC_MPSS_V01 &&
+ !memblock[i].guarantee &&
+ memblock[i].allotted &&
+ !memblock[i].alloc_request) {
+ pr_debug("memshare: hypervisor unmapping for client id: %d\n",
+ memblock[i].client_id);
+ if (memblock[i].hyp_mapping) {
ret = hyp_assign_phys(
memblock[i].phy_addr,
memblock[i].size,
source_vmlist,
- 2, dest_vmids,
+ 1, dest_vmids,
dest_perms, 1);
if (ret &&
memblock[i].hyp_mapping == 1) {
@@ -393,17 +426,16 @@
*/
pr_err("memshare: %s, failed to unmap the region\n",
__func__);
- memblock[i].hyp_mapping = 1;
} else {
memblock[i].hyp_mapping = 0;
}
- dma_free_attrs(memsh_drv->dev,
- memblock[i].size,
- memblock[i].virtual_addr,
- memblock[i].phy_addr,
- attrs);
- free_client(i);
}
+ dma_free_attrs(memsh_drv->dev,
+ memblock[i].size,
+ memblock[i].virtual_addr,
+ memblock[i].phy_addr,
+ attrs);
+ free_client(i);
}
}
bootup_request++;
@@ -425,9 +457,8 @@
{
int ret;
u32 source_vmlist[1] = {VMID_HLOS};
- int dest_vmids[2] = {VMID_HLOS, VMID_MSS_MSA};
- int dest_perms[2] = {PERM_READ|PERM_WRITE,
- PERM_READ|PERM_WRITE};
+ int dest_vmids[1] = {VMID_MSS_MSA};
+ int dest_perms[1] = {PERM_READ|PERM_WRITE};
if (client_id == DHMS_MEM_CLIENT_INVALID) {
pr_err("memshare: %s, Invalid Client\n", __func__);
@@ -437,7 +468,7 @@
ret = hyp_assign_phys(memblock[client_id].phy_addr,
memblock[client_id].size,
source_vmlist, 1, dest_vmids,
- dest_perms, 2);
+ dest_perms, 1);
if (ret != 0) {
pr_err("memshare: hyp_assign_phys failed size=%u err=%d\n",
@@ -546,6 +577,7 @@
memblock[client_id].free_memory);
memblock[client_id].sequence_id = alloc_req->sequence_id;
+ memblock[client_id].alloc_request = 1;
fill_alloc_response(alloc_resp, client_id, &resp);
/*
@@ -603,9 +635,11 @@
{
struct mem_free_generic_req_msg_v01 *free_req;
struct mem_free_generic_resp_msg_v01 free_resp;
- int rc;
- int flag = 0;
+ int rc, flag = 0, ret = 0;
uint32_t client_id;
+ u32 source_vmlist[1] = {VMID_MSS_MSA};
+ int dest_vmids[1] = {VMID_HLOS};
+ int dest_perms[1] = {PERM_READ|PERM_WRITE|PERM_EXEC};
mutex_lock(&memsh_drv->mem_free);
free_req = (struct mem_free_generic_req_msg_v01 *)req;
@@ -624,6 +658,17 @@
memblock[client_id].allotted) {
pr_debug("memshare: %s: size: %d",
__func__, memblock[client_id].size);
+ ret = hyp_assign_phys(memblock[client_id].phy_addr,
+ memblock[client_id].size, source_vmlist, 1,
+ dest_vmids, dest_perms, 1);
+ if (ret && memblock[client_id].hyp_mapping == 1) {
+ /*
+ * This is an error case as hyp mapping was successful
+ * earlier but during unmap it lead to failure.
+ */
+ pr_err("memshare: %s, failed to unmap the region\n",
+ __func__);
+ }
dma_free_attrs(memsh_drv->dev, memblock[client_id].size,
memblock[client_id].virtual_addr,
memblock[client_id].phy_addr,
diff --git a/drivers/soc/qcom/memshare/msm_memshare.h b/drivers/soc/qcom/memshare/msm_memshare.h
index ca11137..6b54652 100644
--- a/drivers/soc/qcom/memshare/msm_memshare.h
+++ b/drivers/soc/qcom/memshare/msm_memshare.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -39,6 +39,8 @@
uint32_t guarantee;
/* Memory alloted or not */
uint32_t allotted;
+ /* Memory allocation request received or not */
+ uint32_t alloc_request;
/* Size required for client */
uint32_t size;
/*
diff --git a/drivers/soc/qcom/microdump_collector.c b/drivers/soc/qcom/microdump_collector.c
index 47f3336..4a22b4d 100644
--- a/drivers/soc/qcom/microdump_collector.c
+++ b/drivers/soc/qcom/microdump_collector.c
@@ -41,7 +41,7 @@
unsigned int smem_id = 611;
struct ramdump_segment segment[2];
- if (code == SUBSYS_RAMDUMP_NOTIFICATION) {
+ if (SUBSYS_RAMDUMP_NOTIFICATION == code || SUBSYS_SOC_RESET == code) {
memset(segment, 0, sizeof(segment));
diff --git a/drivers/soc/qcom/msm_bus/Makefile b/drivers/soc/qcom/msm_bus/Makefile
index 15569b1..c2ef70c 100644
--- a/drivers/soc/qcom/msm_bus/Makefile
+++ b/drivers/soc/qcom/msm_bus/Makefile
@@ -7,7 +7,7 @@
ifdef CONFIG_QCOM_BUS_CONFIG_RPMH
obj-y += msm_bus_fabric_rpmh.o msm_bus_arb_rpmh.o msm_bus_rules.o \
- msm_bus_bimc_rpmh.o msm_bus_noc_rpmh.o
+ msm_bus_bimc_rpmh.o msm_bus_noc_rpmh.o msm_bus_proxy_client.o
obj-$(CONFIG_OF) += msm_bus_of_rpmh.o
else
obj-y += msm_bus_fabric_adhoc.o msm_bus_arb_adhoc.o msm_bus_rules.o \
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 437984c..8af9b5a 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -1133,7 +1133,7 @@
}
curr = client->curr;
- if (curr >= pdata->num_usecases) {
+ if (curr >= pdata->num_usecases || curr < 0) {
MSM_BUS_ERR("Invalid index Defaulting curr to 0");
curr = 0;
}
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_proxy_client.c b/drivers/soc/qcom/msm_bus/msm_bus_proxy_client.c
new file mode 100644
index 0000000..cdf61f6
--- /dev/null
+++ b/drivers/soc/qcom/msm_bus/msm_bus_proxy_client.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2018, 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/msm-bus.h>
+
+struct proxy_client {
+ struct msm_bus_scale_pdata *pdata;
+ unsigned int client_handle;
+};
+
+static struct proxy_client proxy_client_info;
+
+static int msm_bus_device_proxy_client_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ proxy_client_info.pdata = msm_bus_cl_get_pdata(pdev);
+
+ if (!proxy_client_info.pdata)
+ return 0;
+
+ proxy_client_info.client_handle =
+ msm_bus_scale_register_client(proxy_client_info.pdata);
+
+ if (!proxy_client_info.client_handle) {
+ dev_err(&pdev->dev, "Unable to register bus client\n");
+ return -ENODEV;
+ }
+
+ ret = msm_bus_scale_client_update_request(
+ proxy_client_info.client_handle, 1);
+ if (ret)
+ dev_err(&pdev->dev, "Bandwidth update failed (%d)\n", ret);
+
+ return ret;
+}
+
+static const struct of_device_id proxy_client_match[] = {
+ {.compatible = "qcom,bus-proxy-client"},
+ {}
+};
+
+static struct platform_driver msm_bus_proxy_client_driver = {
+ .probe = msm_bus_device_proxy_client_probe,
+ .driver = {
+ .name = "msm_bus_proxy_client_device",
+ .owner = THIS_MODULE,
+ .of_match_table = proxy_client_match,
+ },
+};
+
+static int __init msm_bus_proxy_client_init_driver(void)
+{
+ int rc;
+
+ rc = platform_driver_register(&msm_bus_proxy_client_driver);
+ if (rc) {
+ pr_err("Failed to register proxy client device driver");
+ return rc;
+ }
+
+ return rc;
+}
+
+static int __init msm_bus_proxy_client_unvote(void)
+{
+ int ret;
+
+ if (!proxy_client_info.pdata || !proxy_client_info.client_handle)
+ return 0;
+
+ ret = msm_bus_scale_client_update_request(
+ proxy_client_info.client_handle, 0);
+ if (ret)
+ pr_err("%s: bandwidth update request failed (%d)\n",
+ __func__, ret);
+
+ msm_bus_scale_unregister_client(proxy_client_info.client_handle);
+
+ return 0;
+}
+
+subsys_initcall_sync(msm_bus_proxy_client_init_driver);
+late_initcall_sync(msm_bus_proxy_client_unvote);
diff --git a/drivers/soc/qcom/msm_performance.c b/drivers/soc/qcom/msm_performance.c
index b5ce753..fb3af15 100644
--- a/drivers/soc/qcom/msm_performance.c
+++ b/drivers/soc/qcom/msm_performance.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, 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
@@ -26,59 +26,6 @@
#include <linux/input.h>
#include <linux/kthread.h>
-static struct mutex managed_cpus_lock;
-
-/* Maximum number to clusters that this module will manage */
-static unsigned int num_clusters;
-struct cluster {
- cpumask_var_t cpus;
- /* stats for load detection */
- /* IO */
- u64 last_io_check_ts;
- unsigned int iowait_enter_cycle_cnt;
- unsigned int iowait_exit_cycle_cnt;
- spinlock_t iowait_lock;
- unsigned int cur_io_busy;
- bool io_change;
- /* CPU */
- unsigned int mode;
- bool mode_change;
- u64 last_mode_check_ts;
- unsigned int single_enter_cycle_cnt;
- unsigned int single_exit_cycle_cnt;
- unsigned int multi_enter_cycle_cnt;
- unsigned int multi_exit_cycle_cnt;
- spinlock_t mode_lock;
- /* Perf Cluster Peak Loads */
- unsigned int perf_cl_peak;
- u64 last_perf_cl_check_ts;
- bool perf_cl_detect_state_change;
- unsigned int perf_cl_peak_enter_cycle_cnt;
- unsigned int perf_cl_peak_exit_cycle_cnt;
- spinlock_t perf_cl_peak_lock;
- /* Tunables */
- unsigned int single_enter_load;
- unsigned int pcpu_multi_enter_load;
- unsigned int perf_cl_peak_enter_load;
- unsigned int single_exit_load;
- unsigned int pcpu_multi_exit_load;
- unsigned int perf_cl_peak_exit_load;
- unsigned int single_enter_cycles;
- unsigned int single_exit_cycles;
- unsigned int multi_enter_cycles;
- unsigned int multi_exit_cycles;
- unsigned int perf_cl_peak_enter_cycles;
- unsigned int perf_cl_peak_exit_cycles;
- unsigned int current_freq;
- spinlock_t timer_lock;
- unsigned int timer_rate;
- struct timer_list mode_exit_timer;
- struct timer_list perf_cl_peak_mode_exit_timer;
-};
-
-static struct cluster **managed_clusters;
-static bool clusters_inited;
-
/* To handle cpufreq min/max request */
struct cpu_status {
@@ -87,8 +34,6 @@
};
static DEFINE_PER_CPU(struct cpu_status, cpu_stats);
-static int init_cluster_control(void);
-static int init_events_group(void);
struct events {
spinlock_t cpu_hotplug_lock;
bool cpu_hotplug;
@@ -97,176 +42,7 @@
static struct events events_group;
static struct task_struct *events_notify_thread;
-#define LAST_UPDATE_TOL USEC_PER_MSEC
-
-struct input_events {
- unsigned int evt_x_cnt;
- unsigned int evt_y_cnt;
- unsigned int evt_pres_cnt;
- unsigned int evt_dist_cnt;
-};
-struct trig_thr {
- unsigned int pwr_cl_trigger_threshold;
- unsigned int perf_cl_trigger_threshold;
- unsigned int ip_evt_threshold;
-};
-struct load_stats {
- u64 last_wallclock;
- /* IO wait related */
- u64 last_iowait;
- unsigned int last_iopercent;
- /* CPU load related */
- unsigned int cpu_load;
- /* CPU Freq */
- unsigned int freq;
-};
-static bool input_events_handler_registered;
-static struct input_events *ip_evts;
-static struct trig_thr thr;
-static unsigned int use_input_evts_with_hi_slvt_detect;
-static int register_input_handler(void);
-static void unregister_input_handler(void);
-static DEFINE_PER_CPU(struct load_stats, cpu_load_stats);
-
-/* Bitmask to keep track of the workloads being detected */
-static unsigned int workload_detect;
-#define IO_DETECT 1
-#define MODE_DETECT 2
-#define PERF_CL_PEAK_DETECT 4
-
-/* IOwait related tunables */
-static unsigned int io_enter_cycles = 4;
-static unsigned int io_exit_cycles = 4;
-static u64 iowait_ceiling_pct = 25;
-static u64 iowait_floor_pct = 8;
-#define LAST_IO_CHECK_TOL (3 * USEC_PER_MSEC)
-
-static unsigned int aggr_iobusy;
-static unsigned int aggr_mode;
-
-static struct task_struct *notify_thread;
-
-static struct input_handler *handler;
-
-/* CPU workload detection related */
-#define NO_MODE (0)
-#define SINGLE (1)
-#define MULTI (2)
-#define MIXED (3)
-#define PERF_CL_PEAK (4)
-#define DEF_SINGLE_ENT 90
-#define DEF_PCPU_MULTI_ENT 85
-#define DEF_PERF_CL_PEAK_ENT 80
-#define DEF_SINGLE_EX 60
-#define DEF_PCPU_MULTI_EX 50
-#define DEF_PERF_CL_PEAK_EX 70
-#define DEF_SINGLE_ENTER_CYCLE 4
-#define DEF_SINGLE_EXIT_CYCLE 4
-#define DEF_MULTI_ENTER_CYCLE 4
-#define DEF_MULTI_EXIT_CYCLE 4
-#define DEF_PERF_CL_PEAK_ENTER_CYCLE 100
-#define DEF_PERF_CL_PEAK_EXIT_CYCLE 20
-#define LAST_LD_CHECK_TOL (2 * USEC_PER_MSEC)
-#define CLUSTER_0_THRESHOLD_FREQ 147000
-#define CLUSTER_1_THRESHOLD_FREQ 190000
-#define INPUT_EVENT_CNT_THRESHOLD 15
-#define MAX_LENGTH_CPU_STRING 256
-
/**************************sysfs start********************************/
-
-static int set_num_clusters(const char *buf, const struct kernel_param *kp)
-{
- unsigned int val;
-
- if (sscanf(buf, "%u\n", &val) != 1)
- return -EINVAL;
- if (num_clusters)
- return -EINVAL;
-
- num_clusters = val;
-
- if (init_cluster_control()) {
- num_clusters = 0;
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static int get_num_clusters(char *buf, const struct kernel_param *kp)
-{
- return snprintf(buf, PAGE_SIZE, "%u", num_clusters);
-}
-
-static const struct kernel_param_ops param_ops_num_clusters = {
- .set = set_num_clusters,
- .get = get_num_clusters,
-};
-device_param_cb(num_clusters, ¶m_ops_num_clusters, NULL, 0644);
-
-
-static int set_managed_cpus(const char *buf, const struct kernel_param *kp)
-{
- int i, ret;
- struct cpumask tmp_mask;
-
- if (!clusters_inited)
- return -EINVAL;
-
- ret = cpulist_parse(buf, &tmp_mask);
-
- if (ret)
- return ret;
-
- for (i = 0; i < num_clusters; i++) {
- if (cpumask_empty(managed_clusters[i]->cpus)) {
- mutex_lock(&managed_cpus_lock);
- cpumask_copy(managed_clusters[i]->cpus, &tmp_mask);
- mutex_unlock(&managed_cpus_lock);
- break;
- }
- }
-
- return ret;
-}
-
-static int get_managed_cpus(char *buf, const struct kernel_param *kp)
-{
- int i, cnt = 0, total_cnt = 0;
- char tmp[MAX_LENGTH_CPU_STRING] = "";
-
- if (!clusters_inited)
- return cnt;
-
- for (i = 0; i < num_clusters; i++) {
- cnt = cpumap_print_to_pagebuf(true, buf,
- managed_clusters[i]->cpus);
- if ((i + 1) < num_clusters &&
- (total_cnt + cnt + 1) <= MAX_LENGTH_CPU_STRING) {
- snprintf(tmp + total_cnt, cnt, "%s", buf);
- tmp[cnt-1] = ':';
- tmp[cnt] = '\0';
- total_cnt += cnt;
- } else if ((i + 1) == num_clusters &&
- (total_cnt + cnt) <= MAX_LENGTH_CPU_STRING) {
- snprintf(tmp + total_cnt, cnt, "%s", buf);
- total_cnt += cnt;
- } else {
- pr_err("invalid string for managed_cpu:%s%s\n", tmp,
- buf);
- break;
- }
- }
- snprintf(buf, PAGE_SIZE, "%s", tmp);
- return total_cnt;
-}
-
-static const struct kernel_param_ops param_ops_managed_cpus = {
- .set = set_managed_cpus,
- .get = get_managed_cpus,
-};
-device_param_cb(managed_cpus, ¶m_ops_managed_cpus, NULL, 0644);
-
/*
* Userspace sends cpu#:min_freq_value to vote for min_freq_value as the new
* scaling_min. To withdraw its vote it needs to enter cpu#:0
@@ -425,1716 +201,8 @@
};
module_param_cb(cpu_max_freq, ¶m_ops_cpu_max_freq, NULL, 0644);
-static int set_ip_evt_trigger_threshold(const char *buf,
- const struct kernel_param *kp)
-{
- unsigned int val;
-
- if (sscanf(buf, "%u\n", &val) != 1)
- return -EINVAL;
-
- thr.ip_evt_threshold = val;
- return 0;
-}
-
-static int get_ip_evt_trigger_threshold(char *buf,
- const struct kernel_param *kp)
-{
- return snprintf(buf, PAGE_SIZE, "%u", thr.ip_evt_threshold);
-}
-
-static const struct kernel_param_ops param_ops_ip_evt_trig_thr = {
- .set = set_ip_evt_trigger_threshold,
- .get = get_ip_evt_trigger_threshold,
-};
-device_param_cb(ip_evt_trig_thr, ¶m_ops_ip_evt_trig_thr, NULL, 0644);
-
-
-static int set_perf_cl_trigger_threshold(const char *buf,
- const struct kernel_param *kp)
-{
- unsigned int val;
-
- if (sscanf(buf, "%u\n", &val) != 1)
- return -EINVAL;
-
- thr.perf_cl_trigger_threshold = val;
- return 0;
-}
-
-static int get_perf_cl_trigger_threshold(char *buf,
- const struct kernel_param *kp)
-{
- return snprintf(buf, PAGE_SIZE, "%u", thr.perf_cl_trigger_threshold);
-}
-
-static const struct kernel_param_ops param_ops_perf_trig_thr = {
- .set = set_perf_cl_trigger_threshold,
- .get = get_perf_cl_trigger_threshold,
-};
-device_param_cb(perf_cl_trig_thr, ¶m_ops_perf_trig_thr, NULL, 0644);
-
-
-static int set_pwr_cl_trigger_threshold(const char *buf,
- const struct kernel_param *kp)
-{
- unsigned int val;
-
- if (sscanf(buf, "%u\n", &val) != 1)
- return -EINVAL;
-
- thr.pwr_cl_trigger_threshold = val;
- return 0;
-}
-
-static int get_pwr_cl_trigger_threshold(char *buf,
- const struct kernel_param *kp)
-{
- return snprintf(buf, PAGE_SIZE, "%u", thr.pwr_cl_trigger_threshold);
-}
-
-static const struct kernel_param_ops param_ops_pwr_trig_thr = {
- .set = set_pwr_cl_trigger_threshold,
- .get = get_pwr_cl_trigger_threshold,
-};
-device_param_cb(pwr_cl_trig_thr, ¶m_ops_pwr_trig_thr, NULL, 0644);
-
-static int freq_greater_than_threshold(struct cluster *cl, int idx)
-{
- int rc = 0;
- /* Check for Cluster 0 */
- if (!idx && cl->current_freq >= thr.pwr_cl_trigger_threshold)
- rc = 1;
- /* Check for Cluster 1 */
- if (idx && cl->current_freq >= thr.perf_cl_trigger_threshold)
- rc = 1;
- return rc;
-}
-
-static bool input_events_greater_than_threshold(void)
-{
-
- bool rc = false;
-
- if ((ip_evts->evt_x_cnt >= thr.ip_evt_threshold) ||
- (ip_evts->evt_y_cnt >= thr.ip_evt_threshold) ||
- !use_input_evts_with_hi_slvt_detect)
- rc = true;
-
- return rc;
-}
-
-static int set_single_enter_load(const char *buf, const struct kernel_param *kp)
-{
- unsigned int val, i, ntokens = 0;
- const char *cp = buf;
- unsigned int bytes_left;
-
- if (!clusters_inited)
- return -EINVAL;
-
- while ((cp = strpbrk(cp + 1, ":")))
- ntokens++;
-
- if (ntokens != (num_clusters - 1))
- return -EINVAL;
-
- cp = buf;
- for (i = 0; i < num_clusters; i++) {
-
- if (sscanf(cp, "%u\n", &val) != 1)
- return -EINVAL;
-
- if (val < managed_clusters[i]->single_exit_load)
- return -EINVAL;
-
- managed_clusters[i]->single_enter_load = val;
-
- bytes_left = PAGE_SIZE - (cp - buf);
- cp = strnchr(cp, bytes_left, ':');
- cp++;
- }
-
- return 0;
-}
-
-static int get_single_enter_load(char *buf, const struct kernel_param *kp)
-{
- int i, cnt = 0;
-
- if (!clusters_inited)
- return cnt;
-
- for (i = 0; i < num_clusters; i++)
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
- "%u:", managed_clusters[i]->single_enter_load);
- cnt--;
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
- return cnt;
-}
-
-static const struct kernel_param_ops param_ops_single_enter_load = {
- .set = set_single_enter_load,
- .get = get_single_enter_load,
-};
-device_param_cb(single_enter_load, ¶m_ops_single_enter_load, NULL, 0644);
-
-static int set_single_exit_load(const char *buf, const struct kernel_param *kp)
-{
- unsigned int val, i, ntokens = 0;
- const char *cp = buf;
- unsigned int bytes_left;
-
- if (!clusters_inited)
- return -EINVAL;
-
- while ((cp = strpbrk(cp + 1, ":")))
- ntokens++;
-
- if (ntokens != (num_clusters - 1))
- return -EINVAL;
-
- cp = buf;
- for (i = 0; i < num_clusters; i++) {
-
- if (sscanf(cp, "%u\n", &val) != 1)
- return -EINVAL;
-
- if (val > managed_clusters[i]->single_enter_load)
- return -EINVAL;
-
- managed_clusters[i]->single_exit_load = val;
-
- bytes_left = PAGE_SIZE - (cp - buf);
- cp = strnchr(cp, bytes_left, ':');
- cp++;
- }
-
- return 0;
-}
-
-static int get_single_exit_load(char *buf, const struct kernel_param *kp)
-{
- int i, cnt = 0;
-
- if (!clusters_inited)
- return cnt;
-
- for (i = 0; i < num_clusters; i++)
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
- "%u:", managed_clusters[i]->single_exit_load);
- cnt--;
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
- return cnt;
-}
-
-static const struct kernel_param_ops param_ops_single_exit_load = {
- .set = set_single_exit_load,
- .get = get_single_exit_load,
-};
-device_param_cb(single_exit_load, ¶m_ops_single_exit_load, NULL, 0644);
-
-static int set_pcpu_multi_enter_load(const char *buf,
- const struct kernel_param *kp)
-{
- unsigned int val, i, ntokens = 0;
- const char *cp = buf;
- unsigned int bytes_left;
-
- if (!clusters_inited)
- return -EINVAL;
-
- while ((cp = strpbrk(cp + 1, ":")))
- ntokens++;
-
- if (ntokens != (num_clusters - 1))
- return -EINVAL;
-
- cp = buf;
- for (i = 0; i < num_clusters; i++) {
-
- if (sscanf(cp, "%u\n", &val) != 1)
- return -EINVAL;
-
- if (val < managed_clusters[i]->pcpu_multi_exit_load)
- return -EINVAL;
-
- managed_clusters[i]->pcpu_multi_enter_load = val;
-
- bytes_left = PAGE_SIZE - (cp - buf);
- cp = strnchr(cp, bytes_left, ':');
- cp++;
- }
-
- return 0;
-}
-
-static int get_pcpu_multi_enter_load(char *buf, const struct kernel_param *kp)
-{
- int i, cnt = 0;
-
- if (!clusters_inited)
- return cnt;
-
- for (i = 0; i < num_clusters; i++)
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
- "%u:", managed_clusters[i]->pcpu_multi_enter_load);
- cnt--;
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
- return cnt;
-}
-
-static const struct kernel_param_ops param_ops_pcpu_multi_enter_load = {
- .set = set_pcpu_multi_enter_load,
- .get = get_pcpu_multi_enter_load,
-};
-device_param_cb(pcpu_multi_enter_load, ¶m_ops_pcpu_multi_enter_load,
- NULL, 0644);
-
-static int set_pcpu_multi_exit_load(const char *buf,
- const struct kernel_param *kp)
-{
- unsigned int val, i, ntokens = 0;
- const char *cp = buf;
- unsigned int bytes_left;
-
- if (!clusters_inited)
- return -EINVAL;
-
- while ((cp = strpbrk(cp + 1, ":")))
- ntokens++;
-
- if (ntokens != (num_clusters - 1))
- return -EINVAL;
-
- cp = buf;
- for (i = 0; i < num_clusters; i++) {
-
- if (sscanf(cp, "%u\n", &val) != 1)
- return -EINVAL;
-
- if (val > managed_clusters[i]->pcpu_multi_enter_load)
- return -EINVAL;
-
- managed_clusters[i]->pcpu_multi_exit_load = val;
-
- bytes_left = PAGE_SIZE - (cp - buf);
- cp = strnchr(cp, bytes_left, ':');
- cp++;
- }
-
- return 0;
-}
-
-static int get_pcpu_multi_exit_load(char *buf, const struct kernel_param *kp)
-{
- int i, cnt = 0;
-
- if (!clusters_inited)
- return cnt;
-
- for (i = 0; i < num_clusters; i++)
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
- "%u:", managed_clusters[i]->pcpu_multi_exit_load);
- cnt--;
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
- return cnt;
-}
-
-static const struct kernel_param_ops param_ops_pcpu_multi_exit_load = {
- .set = set_pcpu_multi_exit_load,
- .get = get_pcpu_multi_exit_load,
-};
-device_param_cb(pcpu_multi_exit_load, ¶m_ops_pcpu_multi_exit_load,
- NULL, 0644);
-static int set_perf_cl_peak_enter_load(const char *buf,
- const struct kernel_param *kp)
-{
- unsigned int val, i, ntokens = 0;
- const char *cp = buf;
- unsigned int bytes_left;
-
- if (!clusters_inited)
- return -EINVAL;
-
- while ((cp = strpbrk(cp + 1, ":")))
- ntokens++;
-
- if (ntokens != (num_clusters - 1))
- return -EINVAL;
-
- cp = buf;
- for (i = 0; i < num_clusters; i++) {
-
- if (sscanf(cp, "%u\n", &val) != 1)
- return -EINVAL;
-
- if (val < managed_clusters[i]->perf_cl_peak_exit_load)
- return -EINVAL;
-
- managed_clusters[i]->perf_cl_peak_enter_load = val;
-
- bytes_left = PAGE_SIZE - (cp - buf);
- cp = strnchr(cp, bytes_left, ':');
- cp++;
- }
-
- return 0;
-}
-
-static int get_perf_cl_peak_enter_load(char *buf,
- const struct kernel_param *kp)
-{
- int i, cnt = 0;
-
- if (!clusters_inited)
- return cnt;
-
- for (i = 0; i < num_clusters; i++)
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
- "%u:", managed_clusters[i]->perf_cl_peak_enter_load);
- cnt--;
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
- return cnt;
-}
-
-static const struct kernel_param_ops param_ops_perf_cl_peak_enter_load = {
- .set = set_perf_cl_peak_enter_load,
- .get = get_perf_cl_peak_enter_load,
-};
-device_param_cb(perf_cl_peak_enter_load, ¶m_ops_perf_cl_peak_enter_load,
- NULL, 0644);
-
-static int set_perf_cl_peak_exit_load(const char *buf,
- const struct kernel_param *kp)
-{
- unsigned int val, i, ntokens = 0;
- const char *cp = buf;
- unsigned int bytes_left;
-
- if (!clusters_inited)
- return -EINVAL;
-
- while ((cp = strpbrk(cp + 1, ":")))
- ntokens++;
-
- if (ntokens != (num_clusters - 1))
- return -EINVAL;
-
- cp = buf;
- for (i = 0; i < num_clusters; i++) {
-
- if (sscanf(cp, "%u\n", &val) != 1)
- return -EINVAL;
-
- if (val > managed_clusters[i]->perf_cl_peak_enter_load)
- return -EINVAL;
-
- managed_clusters[i]->perf_cl_peak_exit_load = val;
-
- bytes_left = PAGE_SIZE - (cp - buf);
- cp = strnchr(cp, bytes_left, ':');
- cp++;
- }
-
- return 0;
-}
-
-static int get_perf_cl_peak_exit_load(char *buf,
- const struct kernel_param *kp)
-{
- int i, cnt = 0;
-
- if (!clusters_inited)
- return cnt;
-
- for (i = 0; i < num_clusters; i++)
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
- "%u:", managed_clusters[i]->perf_cl_peak_exit_load);
- cnt--;
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
- return cnt;
-}
-
-static const struct kernel_param_ops param_ops_perf_cl_peak_exit_load = {
- .set = set_perf_cl_peak_exit_load,
- .get = get_perf_cl_peak_exit_load,
-};
-device_param_cb(perf_cl_peak_exit_load, ¶m_ops_perf_cl_peak_exit_load,
- NULL, 0644);
-
-static int set_perf_cl_peak_enter_cycles(const char *buf,
- const struct kernel_param *kp)
-{
- unsigned int val, i, ntokens = 0;
- const char *cp = buf;
- unsigned int bytes_left;
-
- if (!clusters_inited)
- return -EINVAL;
-
- while ((cp = strpbrk(cp + 1, ":")))
- ntokens++;
-
- if (ntokens != (num_clusters - 1))
- return -EINVAL;
-
- cp = buf;
- for (i = 0; i < num_clusters; i++) {
-
- if (sscanf(cp, "%u\n", &val) != 1)
- return -EINVAL;
-
- managed_clusters[i]->perf_cl_peak_enter_cycles = val;
-
- bytes_left = PAGE_SIZE - (cp - buf);
- cp = strnchr(cp, bytes_left, ':');
- cp++;
- }
-
- return 0;
-}
-
-static int get_perf_cl_peak_enter_cycles(char *buf,
- const struct kernel_param *kp)
-{
- int i, cnt = 0;
-
- if (!clusters_inited)
- return cnt;
-
- for (i = 0; i < num_clusters; i++)
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%u:",
- managed_clusters[i]->perf_cl_peak_enter_cycles);
- cnt--;
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
- return cnt;
-}
-
-static const struct kernel_param_ops param_ops_perf_cl_peak_enter_cycles = {
- .set = set_perf_cl_peak_enter_cycles,
- .get = get_perf_cl_peak_enter_cycles,
-};
-device_param_cb(perf_cl_peak_enter_cycles, ¶m_ops_perf_cl_peak_enter_cycles,
- NULL, 0644);
-
-
-static int set_perf_cl_peak_exit_cycles(const char *buf,
- const struct kernel_param *kp)
-{
- unsigned int val, i, ntokens = 0;
- const char *cp = buf;
- unsigned int bytes_left;
-
- if (!clusters_inited)
- return -EINVAL;
-
- while ((cp = strpbrk(cp + 1, ":")))
- ntokens++;
-
- if (ntokens != (num_clusters - 1))
- return -EINVAL;
-
- cp = buf;
- for (i = 0; i < num_clusters; i++) {
-
- if (sscanf(cp, "%u\n", &val) != 1)
- return -EINVAL;
-
- managed_clusters[i]->perf_cl_peak_exit_cycles = val;
-
- bytes_left = PAGE_SIZE - (cp - buf);
- cp = strnchr(cp, bytes_left, ':');
- cp++;
- }
-
- return 0;
-}
-
-static int get_perf_cl_peak_exit_cycles(char *buf,
- const struct kernel_param *kp)
-{
- int i, cnt = 0;
-
- if (!clusters_inited)
- return cnt;
-
- for (i = 0; i < num_clusters; i++)
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
- "%u:", managed_clusters[i]->perf_cl_peak_exit_cycles);
- cnt--;
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
- return cnt;
-}
-
-static const struct kernel_param_ops param_ops_perf_cl_peak_exit_cycles = {
- .set = set_perf_cl_peak_exit_cycles,
- .get = get_perf_cl_peak_exit_cycles,
-};
-device_param_cb(perf_cl_peak_exit_cycles, ¶m_ops_perf_cl_peak_exit_cycles,
- NULL, 0644);
-
-
-static int set_single_enter_cycles(const char *buf,
- const struct kernel_param *kp)
-{
- unsigned int val, i, ntokens = 0;
- const char *cp = buf;
- unsigned int bytes_left;
-
- if (!clusters_inited)
- return -EINVAL;
-
- while ((cp = strpbrk(cp + 1, ":")))
- ntokens++;
-
- if (ntokens != (num_clusters - 1))
- return -EINVAL;
-
- cp = buf;
- for (i = 0; i < num_clusters; i++) {
-
- if (sscanf(cp, "%u\n", &val) != 1)
- return -EINVAL;
-
- managed_clusters[i]->single_enter_cycles = val;
-
- bytes_left = PAGE_SIZE - (cp - buf);
- cp = strnchr(cp, bytes_left, ':');
- cp++;
- }
-
- return 0;
-}
-
-static int get_single_enter_cycles(char *buf, const struct kernel_param *kp)
-{
- int i, cnt = 0;
-
- if (!clusters_inited)
- return cnt;
-
- for (i = 0; i < num_clusters; i++)
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%u:",
- managed_clusters[i]->single_enter_cycles);
- cnt--;
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
- return cnt;
-}
-
-static const struct kernel_param_ops param_ops_single_enter_cycles = {
- .set = set_single_enter_cycles,
- .get = get_single_enter_cycles,
-};
-device_param_cb(single_enter_cycles, ¶m_ops_single_enter_cycles,
- NULL, 0644);
-
-
-static int set_single_exit_cycles(const char *buf,
- const struct kernel_param *kp)
-{
- unsigned int val, i, ntokens = 0;
- const char *cp = buf;
- unsigned int bytes_left;
-
- if (!clusters_inited)
- return -EINVAL;
-
- while ((cp = strpbrk(cp + 1, ":")))
- ntokens++;
-
- if (ntokens != (num_clusters - 1))
- return -EINVAL;
-
- cp = buf;
- for (i = 0; i < num_clusters; i++) {
-
- if (sscanf(cp, "%u\n", &val) != 1)
- return -EINVAL;
-
- managed_clusters[i]->single_exit_cycles = val;
-
- bytes_left = PAGE_SIZE - (cp - buf);
- cp = strnchr(cp, bytes_left, ':');
- cp++;
- }
-
- return 0;
-}
-
-static int get_single_exit_cycles(char *buf, const struct kernel_param *kp)
-{
- int i, cnt = 0;
-
- if (!clusters_inited)
- return cnt;
-
- for (i = 0; i < num_clusters; i++)
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
- "%u:", managed_clusters[i]->single_exit_cycles);
- cnt--;
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
- return cnt;
-}
-
-static const struct kernel_param_ops param_ops_single_exit_cycles = {
- .set = set_single_exit_cycles,
- .get = get_single_exit_cycles,
-};
-device_param_cb(single_exit_cycles, ¶m_ops_single_exit_cycles, NULL, 0644);
-
-static int set_multi_enter_cycles(const char *buf,
- const struct kernel_param *kp)
-{
- unsigned int val, i, ntokens = 0;
- const char *cp = buf;
- unsigned int bytes_left;
-
- if (!clusters_inited)
- return -EINVAL;
-
- while ((cp = strpbrk(cp + 1, ":")))
- ntokens++;
-
- if (ntokens != (num_clusters - 1))
- return -EINVAL;
-
- cp = buf;
- for (i = 0; i < num_clusters; i++) {
-
- if (sscanf(cp, "%u\n", &val) != 1)
- return -EINVAL;
-
- managed_clusters[i]->multi_enter_cycles = val;
-
- bytes_left = PAGE_SIZE - (cp - buf);
- cp = strnchr(cp, bytes_left, ':');
- cp++;
- }
-
- return 0;
-}
-
-static int get_multi_enter_cycles(char *buf, const struct kernel_param *kp)
-{
- int i, cnt = 0;
-
- if (!clusters_inited)
- return cnt;
-
- for (i = 0; i < num_clusters; i++)
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
- "%u:", managed_clusters[i]->multi_enter_cycles);
- cnt--;
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
- return cnt;
-}
-
-static const struct kernel_param_ops param_ops_multi_enter_cycles = {
- .set = set_multi_enter_cycles,
- .get = get_multi_enter_cycles,
-};
-device_param_cb(multi_enter_cycles, ¶m_ops_multi_enter_cycles, NULL, 0644);
-
-static int set_multi_exit_cycles(const char *buf, const struct kernel_param *kp)
-{
- unsigned int val, i, ntokens = 0;
- const char *cp = buf;
- unsigned int bytes_left;
-
- if (!clusters_inited)
- return -EINVAL;
-
- while ((cp = strpbrk(cp + 1, ":")))
- ntokens++;
-
- if (ntokens != (num_clusters - 1))
- return -EINVAL;
-
- cp = buf;
- for (i = 0; i < num_clusters; i++) {
-
- if (sscanf(cp, "%u\n", &val) != 1)
- return -EINVAL;
-
- managed_clusters[i]->multi_exit_cycles = val;
-
- bytes_left = PAGE_SIZE - (cp - buf);
- cp = strnchr(cp, bytes_left, ':');
- cp++;
- }
-
- return 0;
-}
-
-static int get_multi_exit_cycles(char *buf, const struct kernel_param *kp)
-{
- int i, cnt = 0;
-
- if (!clusters_inited)
- return cnt;
-
- for (i = 0; i < num_clusters; i++)
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
- "%u:", managed_clusters[i]->multi_exit_cycles);
- cnt--;
- cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
- return cnt;
-}
-
-static const struct kernel_param_ops param_ops_multi_exit_cycles = {
- .set = set_multi_exit_cycles,
- .get = get_multi_exit_cycles,
-};
-device_param_cb(multi_exit_cycles, ¶m_ops_multi_exit_cycles, NULL, 0644);
-
-static int set_io_enter_cycles(const char *buf, const struct kernel_param *kp)
-{
- unsigned int val;
-
- if (sscanf(buf, "%u\n", &val) != 1)
- return -EINVAL;
-
- io_enter_cycles = val;
-
- return 0;
-}
-
-static int get_io_enter_cycles(char *buf, const struct kernel_param *kp)
-{
- return snprintf(buf, PAGE_SIZE, "%u", io_enter_cycles);
-}
-
-static const struct kernel_param_ops param_ops_io_enter_cycles = {
- .set = set_io_enter_cycles,
- .get = get_io_enter_cycles,
-};
-device_param_cb(io_enter_cycles, ¶m_ops_io_enter_cycles, NULL, 0644);
-
-static int set_io_exit_cycles(const char *buf, const struct kernel_param *kp)
-{
- unsigned int val;
-
- if (sscanf(buf, "%u\n", &val) != 1)
- return -EINVAL;
-
- io_exit_cycles = val;
-
- return 0;
-}
-
-static int get_io_exit_cycles(char *buf, const struct kernel_param *kp)
-{
- return snprintf(buf, PAGE_SIZE, "%u", io_exit_cycles);
-}
-
-static const struct kernel_param_ops param_ops_io_exit_cycles = {
- .set = set_io_exit_cycles,
- .get = get_io_exit_cycles,
-};
-device_param_cb(io_exit_cycles, ¶m_ops_io_exit_cycles, NULL, 0644);
-
-static int set_iowait_floor_pct(const char *buf, const struct kernel_param *kp)
-{
- u64 val;
-
- if (sscanf(buf, "%llu\n", &val) != 1)
- return -EINVAL;
- if (val > iowait_ceiling_pct)
- return -EINVAL;
-
- iowait_floor_pct = val;
-
- return 0;
-}
-
-static int get_iowait_floor_pct(char *buf, const struct kernel_param *kp)
-{
- return snprintf(buf, PAGE_SIZE, "%llu", iowait_floor_pct);
-}
-
-static const struct kernel_param_ops param_ops_iowait_floor_pct = {
- .set = set_iowait_floor_pct,
- .get = get_iowait_floor_pct,
-};
-device_param_cb(iowait_floor_pct, ¶m_ops_iowait_floor_pct, NULL, 0644);
-
-static int set_iowait_ceiling_pct(const char *buf,
- const struct kernel_param *kp)
-{
- u64 val;
-
- if (sscanf(buf, "%llu\n", &val) != 1)
- return -EINVAL;
- if (val < iowait_floor_pct)
- return -EINVAL;
-
- iowait_ceiling_pct = val;
-
- return 0;
-}
-
-static int get_iowait_ceiling_pct(char *buf, const struct kernel_param *kp)
-{
- return snprintf(buf, PAGE_SIZE, "%llu", iowait_ceiling_pct);
-}
-
-static const struct kernel_param_ops param_ops_iowait_ceiling_pct = {
- .set = set_iowait_ceiling_pct,
- .get = get_iowait_ceiling_pct,
-};
-device_param_cb(iowait_ceiling_pct, ¶m_ops_iowait_ceiling_pct, NULL, 0644);
-
-static int set_workload_detect(const char *buf, const struct kernel_param *kp)
-{
- unsigned int val, i;
- struct cluster *i_cl;
- unsigned long flags;
-
- if (!clusters_inited)
- return -EINVAL;
-
- if (sscanf(buf, "%u\n", &val) != 1)
- return -EINVAL;
-
- if (val == workload_detect)
- return 0;
-
- workload_detect = val;
- if (!(workload_detect & IO_DETECT)) {
- for (i = 0; i < num_clusters; i++) {
- i_cl = managed_clusters[i];
- spin_lock_irqsave(&i_cl->iowait_lock, flags);
- i_cl->iowait_enter_cycle_cnt = 0;
- i_cl->iowait_exit_cycle_cnt = 0;
- i_cl->cur_io_busy = 0;
- i_cl->io_change = true;
- spin_unlock_irqrestore(&i_cl->iowait_lock, flags);
- }
- }
- if (!(workload_detect & MODE_DETECT)) {
- for (i = 0; i < num_clusters; i++) {
- i_cl = managed_clusters[i];
- spin_lock_irqsave(&i_cl->mode_lock, flags);
- i_cl->single_enter_cycle_cnt = 0;
- i_cl->single_exit_cycle_cnt = 0;
- i_cl->multi_enter_cycle_cnt = 0;
- i_cl->multi_exit_cycle_cnt = 0;
- i_cl->mode = 0;
- i_cl->mode_change = true;
- spin_unlock_irqrestore(&i_cl->mode_lock, flags);
- }
- }
-
- if (!(workload_detect & PERF_CL_PEAK_DETECT)) {
- for (i = 0; i < num_clusters; i++) {
- i_cl = managed_clusters[i];
- spin_lock_irqsave(&i_cl->perf_cl_peak_lock, flags);
- i_cl->perf_cl_peak_enter_cycle_cnt = 0;
- i_cl->perf_cl_peak_exit_cycle_cnt = 0;
- i_cl->perf_cl_peak = 0;
- spin_unlock_irqrestore(&i_cl->perf_cl_peak_lock, flags);
- }
- }
-
- wake_up_process(notify_thread);
- return 0;
-}
-
-static int get_workload_detect(char *buf, const struct kernel_param *kp)
-{
- return snprintf(buf, PAGE_SIZE, "%u", workload_detect);
-}
-
-static const struct kernel_param_ops param_ops_workload_detect = {
- .set = set_workload_detect,
- .get = get_workload_detect,
-};
-device_param_cb(workload_detect, ¶m_ops_workload_detect, NULL, 0644);
-
-
-static int set_input_evts_with_hi_slvt_detect(const char *buf,
- const struct kernel_param *kp)
-{
-
- unsigned int val;
-
- if (sscanf(buf, "%u\n", &val) != 1)
- return -EINVAL;
-
- if (val == use_input_evts_with_hi_slvt_detect)
- return 0;
-
- use_input_evts_with_hi_slvt_detect = val;
-
- if ((workload_detect & PERF_CL_PEAK_DETECT) &&
- !input_events_handler_registered &&
- use_input_evts_with_hi_slvt_detect) {
- if (register_input_handler() == -ENOMEM) {
- use_input_evts_with_hi_slvt_detect = 0;
- return -ENOMEM;
- }
- } else if ((workload_detect & PERF_CL_PEAK_DETECT) &&
- input_events_handler_registered &&
- !use_input_evts_with_hi_slvt_detect) {
- unregister_input_handler();
- }
- return 0;
-}
-
-static int get_input_evts_with_hi_slvt_detect(char *buf,
- const struct kernel_param *kp)
-{
- return snprintf(buf, PAGE_SIZE, "%u",
- use_input_evts_with_hi_slvt_detect);
-}
-
-static const struct kernel_param_ops param_ops_ip_evts_with_hi_slvt_detect = {
- .set = set_input_evts_with_hi_slvt_detect,
- .get = get_input_evts_with_hi_slvt_detect,
-};
-device_param_cb(input_evts_with_hi_slvt_detect,
- ¶m_ops_ip_evts_with_hi_slvt_detect, NULL, 0644);
-
-static struct kobject *mode_kobj;
-
-static ssize_t show_aggr_mode(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", aggr_mode);
-}
-static struct kobj_attribute aggr_mode_attr =
-__ATTR(aggr_mode, 0444, show_aggr_mode, NULL);
-
-static ssize_t show_aggr_iobusy(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", aggr_iobusy);
-}
-static struct kobj_attribute aggr_iobusy_attr =
-__ATTR(aggr_iobusy, 0444, show_aggr_iobusy, NULL);
-
-static struct attribute *attrs[] = {
- &aggr_mode_attr.attr,
- &aggr_iobusy_attr.attr,
- NULL,
-};
-
-static struct attribute_group attr_group = {
- .attrs = attrs,
-};
-
-static bool check_notify_status(void)
-{
- int i;
- struct cluster *cl;
- bool any_change = false;
- unsigned long flags;
-
-
- for (i = 0; i < num_clusters; i++) {
- cl = managed_clusters[i];
- spin_lock_irqsave(&cl->iowait_lock, flags);
- if (!any_change)
- any_change = cl->io_change;
- cl->io_change = false;
- spin_unlock_irqrestore(&cl->iowait_lock, flags);
-
- spin_lock_irqsave(&cl->mode_lock, flags);
- if (!any_change)
- any_change = cl->mode_change;
- cl->mode_change = false;
- spin_unlock_irqrestore(&cl->mode_lock, flags);
-
- spin_lock_irqsave(&cl->perf_cl_peak_lock, flags);
- if (!any_change)
- any_change = cl->perf_cl_detect_state_change;
- cl->perf_cl_detect_state_change = false;
- spin_unlock_irqrestore(&cl->perf_cl_peak_lock, flags);
- }
-
- return any_change;
-}
-
-static int notify_userspace(void *data)
-{
- unsigned int i, io, cpu_mode, perf_cl_peak_mode;
-
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (!check_notify_status()) {
- schedule();
-
- if (kthread_should_stop())
- break;
- }
- set_current_state(TASK_RUNNING);
-
- io = 0;
- cpu_mode = 0;
- perf_cl_peak_mode = 0;
- for (i = 0; i < num_clusters; i++) {
- io |= managed_clusters[i]->cur_io_busy;
- cpu_mode |= managed_clusters[i]->mode;
- perf_cl_peak_mode |= managed_clusters[i]->perf_cl_peak;
- }
- if (io != aggr_iobusy) {
- aggr_iobusy = io;
- sysfs_notify(mode_kobj, NULL, "aggr_iobusy");
- pr_debug("msm_perf: Notifying IO: %u\n", aggr_iobusy);
- }
- if ((aggr_mode & (SINGLE | MULTI)) != cpu_mode) {
- aggr_mode &= ~(SINGLE | MULTI);
- aggr_mode |= cpu_mode;
- sysfs_notify(mode_kobj, NULL, "aggr_mode");
- pr_debug("msm_perf: Notifying CPU mode:%u\n",
- aggr_mode);
- }
- if ((aggr_mode & PERF_CL_PEAK) != perf_cl_peak_mode) {
- aggr_mode &= ~(PERF_CL_PEAK);
- aggr_mode |= perf_cl_peak_mode;
- sysfs_notify(mode_kobj, NULL, "aggr_mode");
- pr_debug("msm_perf: Notifying Gaming mode:%u\n",
- aggr_mode);
- }
- }
-
- return 0;
-}
-
-static void check_cluster_iowait(struct cluster *cl, u64 now)
-{
- struct load_stats *pcpu_st;
- unsigned int i;
- unsigned long flags;
- unsigned int temp_iobusy;
- u64 max_iowait = 0;
-
- spin_lock_irqsave(&cl->iowait_lock, flags);
-
- if (((now - cl->last_io_check_ts)
- < (cl->timer_rate - LAST_IO_CHECK_TOL)) ||
- !(workload_detect & IO_DETECT)) {
- spin_unlock_irqrestore(&cl->iowait_lock, flags);
- return;
- }
-
- temp_iobusy = cl->cur_io_busy;
- for_each_cpu(i, cl->cpus) {
- pcpu_st = &per_cpu(cpu_load_stats, i);
- if ((now - pcpu_st->last_wallclock)
- > (cl->timer_rate + LAST_UPDATE_TOL))
- continue;
- if (max_iowait < pcpu_st->last_iopercent)
- max_iowait = pcpu_st->last_iopercent;
- }
-
- if (!cl->cur_io_busy) {
- if (max_iowait > iowait_ceiling_pct) {
- cl->iowait_enter_cycle_cnt++;
- if (cl->iowait_enter_cycle_cnt >= io_enter_cycles) {
- cl->cur_io_busy = 1;
- cl->iowait_enter_cycle_cnt = 0;
- }
- } else {
- cl->iowait_enter_cycle_cnt = 0;
- }
- } else {
- if (max_iowait < iowait_floor_pct) {
- cl->iowait_exit_cycle_cnt++;
- if (cl->iowait_exit_cycle_cnt >= io_exit_cycles) {
- cl->cur_io_busy = 0;
- cl->iowait_exit_cycle_cnt = 0;
- }
- } else {
- cl->iowait_exit_cycle_cnt = 0;
- }
- }
-
- cl->last_io_check_ts = now;
- trace_track_iowait(cpumask_first(cl->cpus), cl->iowait_enter_cycle_cnt,
- cl->iowait_exit_cycle_cnt, cl->cur_io_busy, max_iowait);
-
- if (temp_iobusy != cl->cur_io_busy) {
- cl->io_change = true;
- pr_debug("msm_perf: IO changed to %u\n", cl->cur_io_busy);
- }
-
- spin_unlock_irqrestore(&cl->iowait_lock, flags);
- if (cl->io_change)
- wake_up_process(notify_thread);
-}
-
-static void disable_timer(struct cluster *cl)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cl->timer_lock, flags);
-
- if (del_timer(&cl->mode_exit_timer)) {
- trace_single_cycle_exit_timer_stop(cpumask_first(cl->cpus),
- cl->single_enter_cycles, cl->single_enter_cycle_cnt,
- cl->single_exit_cycles, cl->single_exit_cycle_cnt,
- cl->multi_enter_cycles, cl->multi_enter_cycle_cnt,
- cl->multi_exit_cycles, cl->multi_exit_cycle_cnt,
- cl->timer_rate, cl->mode);
- }
-
- spin_unlock_irqrestore(&cl->timer_lock, flags);
-}
-
-static void start_timer(struct cluster *cl)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cl->timer_lock, flags);
- if ((cl->mode & SINGLE) && !timer_pending(&cl->mode_exit_timer)) {
- /* Set timer for the Cluster since there is none pending */
- cl->mode_exit_timer.expires = get_jiffies_64() +
- usecs_to_jiffies(cl->single_exit_cycles * cl->timer_rate);
- cl->mode_exit_timer.data = cpumask_first(cl->cpus);
- add_timer(&cl->mode_exit_timer);
- trace_single_cycle_exit_timer_start(cpumask_first(cl->cpus),
- cl->single_enter_cycles, cl->single_enter_cycle_cnt,
- cl->single_exit_cycles, cl->single_exit_cycle_cnt,
- cl->multi_enter_cycles, cl->multi_enter_cycle_cnt,
- cl->multi_exit_cycles, cl->multi_exit_cycle_cnt,
- cl->timer_rate, cl->mode);
- }
- spin_unlock_irqrestore(&cl->timer_lock, flags);
-}
-
-static void disable_perf_cl_peak_timer(struct cluster *cl)
-{
-
- if (del_timer(&cl->perf_cl_peak_mode_exit_timer)) {
- trace_perf_cl_peak_exit_timer_stop(cpumask_first(cl->cpus),
- cl->perf_cl_peak_enter_cycles,
- cl->perf_cl_peak_enter_cycle_cnt,
- cl->perf_cl_peak_exit_cycles,
- cl->perf_cl_peak_exit_cycle_cnt,
- cl->timer_rate, cl->mode);
- }
-
-}
-
-static void start_perf_cl_peak_timer(struct cluster *cl)
-{
- if ((cl->mode & PERF_CL_PEAK) &&
- !timer_pending(&cl->perf_cl_peak_mode_exit_timer)) {
- /* Set timer for the Cluster since there is none pending */
- cl->perf_cl_peak_mode_exit_timer.expires = get_jiffies_64() +
- usecs_to_jiffies(cl->perf_cl_peak_exit_cycles * cl->timer_rate);
- cl->perf_cl_peak_mode_exit_timer.data = cpumask_first(cl->cpus);
- add_timer(&cl->perf_cl_peak_mode_exit_timer);
- trace_perf_cl_peak_exit_timer_start(cpumask_first(cl->cpus),
- cl->perf_cl_peak_enter_cycles,
- cl->perf_cl_peak_enter_cycle_cnt,
- cl->perf_cl_peak_exit_cycles,
- cl->perf_cl_peak_exit_cycle_cnt,
- cl->timer_rate, cl->mode);
- }
-}
-
-static const struct input_device_id msm_perf_input_ids[] = {
-
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
- .evbit = {BIT_MASK(EV_ABS)},
- .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
- BIT_MASK(ABS_MT_POSITION_X) |
- BIT_MASK(ABS_MT_POSITION_Y)},
- },
-
- {},
-};
-
-static void msm_perf_input_event_handler(struct input_handle *handle,
- unsigned int type,
- unsigned int code,
- int value)
-{
- if (type != EV_ABS)
- return;
-
- switch (code) {
-
- case ABS_MT_POSITION_X:
- ip_evts->evt_x_cnt++;
- break;
- case ABS_MT_POSITION_Y:
- ip_evts->evt_y_cnt++;
- break;
-
- case ABS_MT_DISTANCE:
- break;
-
- case ABS_MT_PRESSURE:
- break;
-
- default:
- break;
-
- }
-}
-static int msm_perf_input_connect(struct input_handler *handler,
- struct input_dev *dev,
- const struct input_device_id *id)
-{
- int rc;
- struct input_handle *handle;
-
- handle = kzalloc(sizeof(*handle), GFP_KERNEL);
- if (!handle)
- return -ENOMEM;
-
- handle->dev = dev;
- handle->handler = handler;
- handle->name = handler->name;
-
- rc = input_register_handle(handle);
- if (rc) {
- pr_err("Failed to register handle\n");
- goto error;
- }
-
- rc = input_open_device(handle);
- if (rc) {
- pr_err("Failed to open device\n");
- goto error_unregister;
- }
- return 0;
-
-error_unregister:
- input_unregister_handle(handle);
-error:
- kfree(handle);
- return rc;
-}
-
-static void msm_perf_input_disconnect(struct input_handle *handle)
-{
- input_close_device(handle);
- input_unregister_handle(handle);
- kfree(handle);
-}
-
-static void unregister_input_handler(void)
-{
- if (handler != NULL) {
- input_unregister_handler(handler);
- input_events_handler_registered = false;
- }
-}
-
-static int register_input_handler(void)
-{
- int rc;
-
- if (handler == NULL) {
- handler = kzalloc(sizeof(*handler), GFP_KERNEL);
- if (!handler)
- return -ENOMEM;
- handler->event = msm_perf_input_event_handler;
- handler->connect = msm_perf_input_connect;
- handler->disconnect = msm_perf_input_disconnect;
- handler->name = "msm_perf";
- handler->id_table = msm_perf_input_ids;
- handler->private = NULL;
- }
- rc = input_register_handler(handler);
- if (rc) {
- pr_err("Unable to register the input handler for msm_perf\n");
- kfree(handler);
- } else {
- input_events_handler_registered = true;
- }
- return rc;
-}
-
-static void check_perf_cl_peak_load(struct cluster *cl, u64 now)
-{
- struct load_stats *pcpu_st;
- unsigned int i, ret_mode, max_load = 0;
- unsigned int total_load = 0, cpu_cnt = 0;
- unsigned long flags;
- bool cpu_of_cluster_zero = true;
-
- spin_lock_irqsave(&cl->perf_cl_peak_lock, flags);
-
- cpu_of_cluster_zero = cpumask_first(cl->cpus) ? false:true;
- /*
- * If delta of last load to now < than timer_rate - ld check tolerance
- * which is 18ms OR if perf_cl_peak detection not set
- * OR the first CPU of Cluster is CPU 0 (LVT)
- * then return do nothing. We are interested only in SLVT
- */
- if (((now - cl->last_perf_cl_check_ts)
- < (cl->timer_rate - LAST_LD_CHECK_TOL)) ||
- !(workload_detect & PERF_CL_PEAK_DETECT) ||
- cpu_of_cluster_zero) {
- spin_unlock_irqrestore(&cl->perf_cl_peak_lock, flags);
- return;
- }
- for_each_cpu(i, cl->cpus) {
- pcpu_st = &per_cpu(cpu_load_stats, i);
- if ((now - pcpu_st->last_wallclock)
- > (cl->timer_rate + LAST_UPDATE_TOL))
- continue;
- if (pcpu_st->cpu_load > max_load)
- max_load = pcpu_st->cpu_load;
- /*
- * Save the frequency for the cpu of the cluster
- * This frequency is the most recent/current
- * as obtained due to a transition
- * notifier callback.
- */
- cl->current_freq = pcpu_st->freq;
- }
- ret_mode = cl->perf_cl_peak;
-
- if (!(cl->perf_cl_peak & PERF_CL_PEAK)) {
- if (max_load >= cl->perf_cl_peak_enter_load &&
- freq_greater_than_threshold(cl,
- cpumask_first(cl->cpus))) {
- /*
- * Reset the event count for the first cycle
- * of perf_cl_peak we detect
- */
- if (!cl->perf_cl_peak_enter_cycle_cnt)
- ip_evts->evt_x_cnt = ip_evts->evt_y_cnt = 0;
- cl->perf_cl_peak_enter_cycle_cnt++;
- if (cl->perf_cl_peak_enter_cycle_cnt >=
- cl->perf_cl_peak_enter_cycles) {
- if (input_events_greater_than_threshold())
- ret_mode |= PERF_CL_PEAK;
- cl->perf_cl_peak_enter_cycle_cnt = 0;
- }
- } else {
- cl->perf_cl_peak_enter_cycle_cnt = 0;
- /* Reset the event count */
- ip_evts->evt_x_cnt = ip_evts->evt_y_cnt = 0;
- }
- } else {
- if (max_load >= cl->perf_cl_peak_exit_load &&
- freq_greater_than_threshold(cl,
- cpumask_first(cl->cpus))) {
- cl->perf_cl_peak_exit_cycle_cnt = 0;
- disable_perf_cl_peak_timer(cl);
- } else {
- start_perf_cl_peak_timer(cl);
- cl->perf_cl_peak_exit_cycle_cnt++;
- if (cl->perf_cl_peak_exit_cycle_cnt
- >= cl->perf_cl_peak_exit_cycles) {
- ret_mode &= ~PERF_CL_PEAK;
- cl->perf_cl_peak_exit_cycle_cnt = 0;
- disable_perf_cl_peak_timer(cl);
- }
- }
- }
-
- cl->last_perf_cl_check_ts = now;
- if (ret_mode != cl->perf_cl_peak) {
- pr_debug("msm_perf: Mode changed to %u\n", ret_mode);
- cl->perf_cl_peak = ret_mode;
- cl->perf_cl_detect_state_change = true;
- }
-
- trace_cpu_mode_detect(cpumask_first(cl->cpus), max_load,
- cl->single_enter_cycle_cnt, cl->single_exit_cycle_cnt,
- total_load, cl->multi_enter_cycle_cnt,
- cl->multi_exit_cycle_cnt, cl->perf_cl_peak_enter_cycle_cnt,
- cl->perf_cl_peak_exit_cycle_cnt, cl->mode, cpu_cnt);
-
- spin_unlock_irqrestore(&cl->perf_cl_peak_lock, flags);
-
- if (cl->perf_cl_detect_state_change)
- wake_up_process(notify_thread);
-
-}
-
-static void check_cpu_load(struct cluster *cl, u64 now)
-{
- struct load_stats *pcpu_st;
- unsigned int i, max_load = 0, total_load = 0, ret_mode, cpu_cnt = 0;
- unsigned int total_load_ceil, total_load_floor;
- unsigned long flags;
-
- spin_lock_irqsave(&cl->mode_lock, flags);
-
- if (((now - cl->last_mode_check_ts)
- < (cl->timer_rate - LAST_LD_CHECK_TOL)) ||
- !(workload_detect & MODE_DETECT)) {
- spin_unlock_irqrestore(&cl->mode_lock, flags);
- return;
- }
-
- for_each_cpu(i, cl->cpus) {
- pcpu_st = &per_cpu(cpu_load_stats, i);
- if ((now - pcpu_st->last_wallclock)
- > (cl->timer_rate + LAST_UPDATE_TOL))
- continue;
- if (pcpu_st->cpu_load > max_load)
- max_load = pcpu_st->cpu_load;
- total_load += pcpu_st->cpu_load;
- cpu_cnt++;
- }
-
- if (cpu_cnt > 1) {
- total_load_ceil = cl->pcpu_multi_enter_load * cpu_cnt;
- total_load_floor = cl->pcpu_multi_exit_load * cpu_cnt;
- } else {
- total_load_ceil = UINT_MAX;
- total_load_floor = UINT_MAX;
- }
-
- ret_mode = cl->mode;
- if (!(cl->mode & SINGLE)) {
- if (max_load >= cl->single_enter_load) {
- cl->single_enter_cycle_cnt++;
- if (cl->single_enter_cycle_cnt
- >= cl->single_enter_cycles) {
- ret_mode |= SINGLE;
- cl->single_enter_cycle_cnt = 0;
- }
- } else {
- cl->single_enter_cycle_cnt = 0;
- }
- } else {
- if (max_load < cl->single_exit_load) {
- start_timer(cl);
- cl->single_exit_cycle_cnt++;
- if (cl->single_exit_cycle_cnt
- >= cl->single_exit_cycles) {
- ret_mode &= ~SINGLE;
- cl->single_exit_cycle_cnt = 0;
- disable_timer(cl);
- }
- } else {
- cl->single_exit_cycle_cnt = 0;
- disable_timer(cl);
- }
- }
-
- if (!(cl->mode & MULTI)) {
- if (total_load >= total_load_ceil) {
- cl->multi_enter_cycle_cnt++;
- if (cl->multi_enter_cycle_cnt
- >= cl->multi_enter_cycles) {
- ret_mode |= MULTI;
- cl->multi_enter_cycle_cnt = 0;
- }
- } else {
- cl->multi_enter_cycle_cnt = 0;
- }
- } else {
- if (total_load < total_load_floor) {
- cl->multi_exit_cycle_cnt++;
- if (cl->multi_exit_cycle_cnt
- >= cl->multi_exit_cycles) {
- ret_mode &= ~MULTI;
- cl->multi_exit_cycle_cnt = 0;
- }
- } else {
- cl->multi_exit_cycle_cnt = 0;
- }
- }
-
- cl->last_mode_check_ts = now;
-
- if (ret_mode != cl->mode) {
- cl->mode = ret_mode;
- cl->mode_change = true;
- pr_debug("msm_perf: Mode changed to %u\n", ret_mode);
- }
-
- trace_cpu_mode_detect(cpumask_first(cl->cpus), max_load,
- cl->single_enter_cycle_cnt, cl->single_exit_cycle_cnt,
- total_load, cl->multi_enter_cycle_cnt,
- cl->multi_exit_cycle_cnt, cl->perf_cl_peak_enter_cycle_cnt,
- cl->perf_cl_peak_exit_cycle_cnt, cl->mode, cpu_cnt);
-
- spin_unlock_irqrestore(&cl->mode_lock, flags);
-
- if (cl->mode_change)
- wake_up_process(notify_thread);
-}
-
-static void check_workload_stats(unsigned int cpu, unsigned int rate, u64 now)
-{
- struct cluster *cl = NULL;
- unsigned int i;
-
- for (i = 0; i < num_clusters; i++) {
- if (cpumask_test_cpu(cpu, managed_clusters[i]->cpus)) {
- cl = managed_clusters[i];
- break;
- }
- }
- if (cl == NULL)
- return;
-
- cl->timer_rate = rate;
- check_cluster_iowait(cl, now);
- check_cpu_load(cl, now);
- check_perf_cl_peak_load(cl, now);
-}
-
-static int perf_govinfo_notify(struct notifier_block *nb, unsigned long val,
- void *data)
-{
- struct cpufreq_govinfo *gov_info = data;
- unsigned int cpu = gov_info->cpu;
- struct load_stats *cpu_st = &per_cpu(cpu_load_stats, cpu);
- u64 now, cur_iowait, time_diff, iowait_diff;
-
- if (!clusters_inited || !workload_detect)
- return NOTIFY_OK;
-
- cur_iowait = get_cpu_iowait_time_us(cpu, &now);
- if (cur_iowait >= cpu_st->last_iowait)
- iowait_diff = cur_iowait - cpu_st->last_iowait;
- else
- iowait_diff = 0;
-
- if (now > cpu_st->last_wallclock)
- time_diff = now - cpu_st->last_wallclock;
- else
- return NOTIFY_OK;
-
- if (iowait_diff <= time_diff) {
- iowait_diff *= 100;
- cpu_st->last_iopercent = div64_u64(iowait_diff, time_diff);
- } else {
- cpu_st->last_iopercent = 100;
- }
-
- cpu_st->last_wallclock = now;
- cpu_st->last_iowait = cur_iowait;
- cpu_st->cpu_load = gov_info->load;
-
- /*
- * Avoid deadlock in case governor notifier ran in the context
- * of notify_work thread
- */
- if (current == notify_thread)
- return NOTIFY_OK;
-
- check_workload_stats(cpu, gov_info->sampling_rate_us, now);
-
- return NOTIFY_OK;
-}
-
-static int perf_cputrans_notify(struct notifier_block *nb, unsigned long val,
- void *data)
-{
- struct cpufreq_freqs *freq = data;
- unsigned int cpu = freq->cpu;
- unsigned long flags;
- unsigned int i;
- struct cluster *cl = NULL;
- struct load_stats *cpu_st = &per_cpu(cpu_load_stats, cpu);
-
- if (!clusters_inited || !workload_detect)
- return NOTIFY_OK;
- for (i = 0; i < num_clusters; i++) {
- if (cpumask_test_cpu(cpu, managed_clusters[i]->cpus)) {
- cl = managed_clusters[i];
- break;
- }
- }
- if (cl == NULL)
- return NOTIFY_OK;
- if (val == CPUFREQ_POSTCHANGE) {
- spin_lock_irqsave(&cl->perf_cl_peak_lock, flags);
- cpu_st->freq = freq->new;
- spin_unlock_irqrestore(&cl->perf_cl_peak_lock, flags);
- }
-
- /*
- * Avoid deadlock in case governor notifier ran in the context
- * of notify_work thread
- */
- if (current == notify_thread)
- return NOTIFY_OK;
- return NOTIFY_OK;
-}
-
-static struct notifier_block perf_govinfo_nb = {
- .notifier_call = perf_govinfo_notify,
-};
-
-static struct notifier_block perf_cputransitions_nb = {
- .notifier_call = perf_cputrans_notify,
-};
-
-static void single_mod_exit_timer(unsigned long data)
-{
- int i;
- struct cluster *i_cl = NULL;
- unsigned long flags;
-
- if (!clusters_inited)
- return;
-
- for (i = 0; i < num_clusters; i++) {
- if (cpumask_test_cpu(data,
- managed_clusters[i]->cpus)) {
- i_cl = managed_clusters[i];
- break;
- }
- }
-
- if (i_cl == NULL)
- return;
-
- spin_lock_irqsave(&i_cl->mode_lock, flags);
- if (i_cl->mode & SINGLE) {
- /* Disable SINGLE mode and exit since the timer expired */
- i_cl->mode = i_cl->mode & ~SINGLE;
- i_cl->single_enter_cycle_cnt = 0;
- i_cl->single_exit_cycle_cnt = 0;
- trace_single_mode_timeout(cpumask_first(i_cl->cpus),
- i_cl->single_enter_cycles, i_cl->single_enter_cycle_cnt,
- i_cl->single_exit_cycles, i_cl->single_exit_cycle_cnt,
- i_cl->multi_enter_cycles, i_cl->multi_enter_cycle_cnt,
- i_cl->multi_exit_cycles, i_cl->multi_exit_cycle_cnt,
- i_cl->timer_rate, i_cl->mode);
- }
- spin_unlock_irqrestore(&i_cl->mode_lock, flags);
- wake_up_process(notify_thread);
-}
-
-static void perf_cl_peak_mod_exit_timer(unsigned long data)
-{
- int i;
- struct cluster *i_cl = NULL;
- unsigned long flags;
-
- if (!clusters_inited)
- return;
-
- for (i = 0; i < num_clusters; i++) {
- if (cpumask_test_cpu(data,
- managed_clusters[i]->cpus)) {
- i_cl = managed_clusters[i];
- break;
- }
- }
- if (i_cl == NULL)
- return;
- spin_lock_irqsave(&i_cl->perf_cl_peak_lock, flags);
- if (i_cl->perf_cl_peak & PERF_CL_PEAK) {
- /* Disable PERF_CL_PEAK mode and exit since the timer expired */
- i_cl->perf_cl_peak = i_cl->perf_cl_peak & ~PERF_CL_PEAK;
- i_cl->perf_cl_peak_enter_cycle_cnt = 0;
- i_cl->perf_cl_peak_exit_cycle_cnt = 0;
- }
- spin_unlock_irqrestore(&i_cl->perf_cl_peak_lock, flags);
- wake_up_process(notify_thread);
-}
/* CPU Hotplug */
static struct kobject *events_kobj;
@@ -2186,19 +254,18 @@
.notifier_call = perf_adjust_notify,
};
-static void hotplug_notify(int action)
+static int hotplug_notify(unsigned int cpu)
{
unsigned long flags;
- if (!events_group.init_success)
- return;
-
- if ((action == CPU_ONLINE) || (action == CPU_DEAD)) {
+ if (events_group.init_success) {
spin_lock_irqsave(&(events_group.cpu_hotplug_lock), flags);
events_group.cpu_hotplug = true;
spin_unlock_irqrestore(&(events_group.cpu_hotplug_lock), flags);
wake_up_process(events_notify_thread);
}
+
+ return 0;
}
static int events_notify_userspace(void *data)
@@ -2233,138 +300,7 @@
return 0;
}
-static int __ref msm_performance_cpu_callback(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
-{
- uint32_t cpu = (uintptr_t)hcpu;
- unsigned int i;
- struct cluster *i_cl = NULL;
- hotplug_notify(action);
-
- if (!clusters_inited)
- return NOTIFY_OK;
-
- for (i = 0; i < num_clusters; i++) {
- if (managed_clusters[i]->cpus == NULL)
- return NOTIFY_OK;
- if (cpumask_test_cpu(cpu, managed_clusters[i]->cpus)) {
- i_cl = managed_clusters[i];
- break;
- }
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block __refdata msm_performance_cpu_notifier = {
- .notifier_call = msm_performance_cpu_callback,
-};
-
-static int init_cluster_control(void)
-{
- unsigned int i;
- int ret = 0;
-
- struct kobject *module_kobj;
-
- managed_clusters = kcalloc(num_clusters, sizeof(struct cluster *),
- GFP_KERNEL);
- if (!managed_clusters)
- return -ENOMEM;
- for (i = 0; i < num_clusters; i++) {
- managed_clusters[i] = kcalloc(1, sizeof(struct cluster),
- GFP_KERNEL);
- if (!managed_clusters[i]) {
- ret = -ENOMEM;
- goto error;
- }
- if (!alloc_cpumask_var(&managed_clusters[i]->cpus,
- GFP_KERNEL)) {
- ret = -ENOMEM;
- goto error;
- }
-
- managed_clusters[i]->single_enter_load = DEF_SINGLE_ENT;
- managed_clusters[i]->single_exit_load = DEF_SINGLE_EX;
- managed_clusters[i]->single_enter_cycles
- = DEF_SINGLE_ENTER_CYCLE;
- managed_clusters[i]->single_exit_cycles
- = DEF_SINGLE_EXIT_CYCLE;
- managed_clusters[i]->pcpu_multi_enter_load
- = DEF_PCPU_MULTI_ENT;
- managed_clusters[i]->pcpu_multi_exit_load = DEF_PCPU_MULTI_EX;
- managed_clusters[i]->multi_enter_cycles = DEF_MULTI_ENTER_CYCLE;
- managed_clusters[i]->multi_exit_cycles = DEF_MULTI_EXIT_CYCLE;
- managed_clusters[i]->perf_cl_peak_enter_load =
- DEF_PERF_CL_PEAK_ENT;
- managed_clusters[i]->perf_cl_peak_exit_load =
- DEF_PERF_CL_PEAK_EX;
- managed_clusters[i]->perf_cl_peak_enter_cycles =
- DEF_PERF_CL_PEAK_ENTER_CYCLE;
- managed_clusters[i]->perf_cl_peak_exit_cycles =
- DEF_PERF_CL_PEAK_EXIT_CYCLE;
-
- /* Initialize trigger threshold */
- thr.perf_cl_trigger_threshold = CLUSTER_1_THRESHOLD_FREQ;
- thr.pwr_cl_trigger_threshold = CLUSTER_0_THRESHOLD_FREQ;
- thr.ip_evt_threshold = INPUT_EVENT_CNT_THRESHOLD;
- spin_lock_init(&(managed_clusters[i]->iowait_lock));
- spin_lock_init(&(managed_clusters[i]->mode_lock));
- spin_lock_init(&(managed_clusters[i]->timer_lock));
- spin_lock_init(&(managed_clusters[i]->perf_cl_peak_lock));
- init_timer(&managed_clusters[i]->mode_exit_timer);
- managed_clusters[i]->mode_exit_timer.function =
- single_mod_exit_timer;
- init_timer(&managed_clusters[i]->perf_cl_peak_mode_exit_timer);
- managed_clusters[i]->perf_cl_peak_mode_exit_timer.function =
- perf_cl_peak_mod_exit_timer;
- }
-
- mutex_init(&managed_cpus_lock);
-
- ip_evts = kcalloc(1, sizeof(struct input_events), GFP_KERNEL);
- if (!ip_evts) {
- ret = -ENOMEM;
- goto error;
- }
- module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
- if (!module_kobj) {
- pr_err("msm_perf: Couldn't find module kobject\n");
- ret = -ENOENT;
- goto error;
- }
- mode_kobj = kobject_create_and_add("workload_modes", module_kobj);
- if (!mode_kobj) {
- pr_err("msm_perf: Failed to add mode_kobj\n");
- ret = -ENOMEM;
- kobject_put(module_kobj);
- goto error;
- }
- ret = sysfs_create_group(mode_kobj, &attr_group);
- if (ret) {
- pr_err("msm_perf: Failed to create sysfs\n");
- kobject_put(module_kobj);
- kobject_put(mode_kobj);
- goto error;
- }
- notify_thread = kthread_run(notify_userspace, NULL, "wrkld_notify");
-
- clusters_inited = true;
-
- return 0;
-
-error:
- for (i = 0; i < num_clusters; i++) {
- if (!managed_clusters[i])
- break;
- if (managed_clusters[i]->cpus)
- free_cpumask_var(managed_clusters[i]->cpus);
- kfree(managed_clusters[i]);
- }
- kfree(managed_clusters);
- return ret;
-}
static int init_events_group(void)
{
@@ -2403,16 +339,17 @@
static int __init msm_performance_init(void)
{
unsigned int cpu;
+ int rc;
cpufreq_register_notifier(&perf_cpufreq_nb, CPUFREQ_POLICY_NOTIFIER);
- cpufreq_register_notifier(&perf_govinfo_nb, CPUFREQ_GOVINFO_NOTIFIER);
- cpufreq_register_notifier(&perf_cputransitions_nb,
- CPUFREQ_TRANSITION_NOTIFIER);
for_each_present_cpu(cpu)
per_cpu(cpu_stats, cpu).max = UINT_MAX;
- register_cpu_notifier(&msm_performance_cpu_notifier);
+ rc = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE,
+ "msm_performance_cpu_hotplug",
+ hotplug_notify,
+ NULL);
init_events_group();
diff --git a/drivers/soc/qcom/msm_smd.c b/drivers/soc/qcom/msm_smd.c
index 1631984..eb7aede 100644
--- a/drivers/soc/qcom/msm_smd.c
+++ b/drivers/soc/qcom/msm_smd.c
@@ -1,7 +1,7 @@
/* drivers/soc/qcom/msm_smd.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2017, 2018, The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -269,11 +269,12 @@
uint32_t *dest_local = (uint32_t *)dest;
uint32_t *src_local = (uint32_t *)src;
+ if (WARN_ON(!dest_local || !src_local))
+ return dest;
WARN_ON(num_bytes & SMD_FIFO_ADDR_ALIGN_BYTES);
- WARN_ON(!dest_local ||
- ((uintptr_t)dest_local & SMD_FIFO_ADDR_ALIGN_BYTES));
- WARN_ON(!src_local ||
- ((uintptr_t)src_local & SMD_FIFO_ADDR_ALIGN_BYTES));
+ WARN_ON(((uintptr_t)dest_local & SMD_FIFO_ADDR_ALIGN_BYTES));
+ WARN_ON(((uintptr_t)src_local & SMD_FIFO_ADDR_ALIGN_BYTES));
+
num_bytes /= sizeof(uint32_t);
while (num_bytes--)
@@ -301,11 +302,12 @@
uint32_t *dest_local = (uint32_t *)dest;
uint32_t *src_local = (uint32_t *)src;
+ if (WARN_ON(!dest_local || !src_local))
+ return dest;
WARN_ON(num_bytes & SMD_FIFO_ADDR_ALIGN_BYTES);
- WARN_ON(!dest_local ||
- ((uintptr_t)dest_local & SMD_FIFO_ADDR_ALIGN_BYTES));
- WARN_ON(!src_local ||
- ((uintptr_t)src_local & SMD_FIFO_ADDR_ALIGN_BYTES));
+ WARN_ON(((uintptr_t)dest_local & SMD_FIFO_ADDR_ALIGN_BYTES));
+ WARN_ON(((uintptr_t)src_local & SMD_FIFO_ADDR_ALIGN_BYTES));
+
num_bytes /= sizeof(uint32_t);
while (num_bytes--)
diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c
index 3fc7fbf..c29cfcb 100644
--- a/drivers/soc/qcom/rpm-smd.c
+++ b/drivers/soc/qcom/rpm-smd.c
@@ -31,7 +31,6 @@
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -126,8 +125,6 @@
return atomic_notifier_chain_unregister(&msm_rpm_sleep_notifier, nb);
}
-static struct workqueue_struct *msm_rpm_smd_wq;
-
enum {
MSM_RPM_MSG_REQUEST_TYPE = 0,
MSM_RPM_MSG_TYPE_NR,
@@ -2120,15 +2117,6 @@
smd_disable_read_intr(msm_rpm_data.ch_info);
- msm_rpm_smd_wq = alloc_workqueue("rpm-smd",
- WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
- if (!msm_rpm_smd_wq) {
- pr_err("%s: Unable to alloc rpm-smd workqueue\n", __func__);
- ret = -EINVAL;
- goto fail;
- }
- queue_work(msm_rpm_smd_wq, &msm_rpm_data.work);
-
probe_status = ret;
skip_init:
of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
diff --git a/drivers/soc/qcom/rq_stats.c b/drivers/soc/qcom/rq_stats.c
index 5850c46..1b4cf4f 100644
--- a/drivers/soc/qcom/rq_stats.c
+++ b/drivers/soc/qcom/rq_stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2015, 2018, 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
@@ -264,7 +264,7 @@
static ssize_t show_def_timer_ms(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
- int64_t diff;
+ uint64_t diff;
unsigned int udiff;
diff = ktime_to_ns(ktime_get()) - rq_info.def_start_time;
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 0e83971..d5de12b 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -571,6 +571,13 @@
/* sdxpoorwills ID */
[334] = {SDX_CPU_SDXPOORWILLS, "SDXPOORWILLS"},
+ /* 9650 IDs */
+ [279] = {MSM_CPU_9650, "MDM9650"},
+ [283] = {MSM_CPU_9650, "MDM9650"},
+ [284] = {MSM_CPU_9650, "MDM9650"},
+ [285] = {MSM_CPU_9650, "MDM9650"},
+ [286] = {MSM_CPU_9650, "MDM9650"},
+
/* SDM670 ID */
[336] = {MSM_CPU_SDM670, "SDM670"},
@@ -580,6 +587,9 @@
/* SDA670 ID */
[337] = {MSM_CPU_SDA670, "SDA670"},
+ /* SDM710 ID */
+ [360] = {MSM_CPU_SDM710, "SDM710"},
+
/* 8953 ID */
[293] = {MSM_CPU_8953, "MSM8953"},
[304] = {MSM_CPU_8953, "APQ8053"},
@@ -599,7 +609,6 @@
[353] = {MSM_CPU_SDM439, "SDM439"},
[354] = {MSM_CPU_SDM429, "SDM429"},
-
/* Uninitialized IDs are not known to run Linux.
* MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
* considered as unknown CPU.
@@ -1511,6 +1520,10 @@
dummy_socinfo.id = 336;
strlcpy(dummy_socinfo.build_id, "sdm670 - ",
sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_sdm710()) {
+ dummy_socinfo.id = 360;
+ strlcpy(dummy_socinfo.build_id, "sdm710 - ",
+ sizeof(dummy_socinfo.build_id));
} else if (early_machine_is_sda670()) {
dummy_socinfo.id = 337;
strlcpy(dummy_socinfo.build_id, "sda670 - ",
@@ -1519,6 +1532,10 @@
dummy_socinfo.id = 347;
strlcpy(dummy_socinfo.build_id, "qcs605 - ",
sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_mdm9650()) {
+ dummy_socinfo.id = 286;
+ strlcpy(dummy_socinfo.build_id, "mdm9650 - ",
+ sizeof(dummy_socinfo.build_id));
} else if (early_machine_is_sdxpoorwills()) {
dummy_socinfo.id = 334;
strlcpy(dummy_socinfo.build_id, "sdxpoorwills - ",
diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c
index 8040d6d..5630dc0 100644
--- a/drivers/soc/qcom/watchdog_v2.c
+++ b/drivers/soc/qcom/watchdog_v2.c
@@ -701,7 +701,7 @@
wdog_dd->user_pet_complete = true;
wdog_dd->user_pet_enabled = false;
wake_up_process(wdog_dd->watchdog_task);
- init_timer_deferrable(&wdog_dd->pet_timer);
+ init_timer(&wdog_dd->pet_timer);
wdog_dd->pet_timer.data = (unsigned long)wdog_dd;
wdog_dd->pet_timer.function = pet_task_wakeup;
wdog_dd->pet_timer.expires = jiffies + delay_time;
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index fc96f62..6ee1da0 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -156,6 +156,7 @@
config SPI_BCM_QSPI
tristate "Broadcom BSPI and MSPI controller support"
depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || COMPILE_TEST
+ depends on MTD_NORFLASH
default ARCH_BCM_IPROC
help
Enables support for the Broadcom SPI flash and MSPI controller.
diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index 4969dc1..d8995b6 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -466,7 +466,7 @@
static int sun4i_spi_remove(struct platform_device *pdev)
{
- pm_runtime_disable(&pdev->dev);
+ pm_runtime_force_suspend(&pdev->dev);
return 0;
}
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index eb41e84..35697e6 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -711,30 +711,32 @@
size_t pgstart, pgend;
int ret = -EINVAL;
- if (unlikely(!asma->file))
- return -EINVAL;
+ mutex_lock(&ashmem_mutex);
- if (unlikely(copy_from_user(&pin, p, sizeof(pin))))
- return -EFAULT;
+ if (unlikely(!asma->file))
+ goto out_unlock;
+
+ if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
/* per custom, you can pass zero for len to mean "everything onward" */
if (!pin.len)
pin.len = PAGE_ALIGN(asma->size) - pin.offset;
if (unlikely((pin.offset | pin.len) & ~PAGE_MASK))
- return -EINVAL;
+ goto out_unlock;
if (unlikely(((__u32)-1) - pin.offset < pin.len))
- return -EINVAL;
+ goto out_unlock;
if (unlikely(PAGE_ALIGN(asma->size) < pin.offset + pin.len))
- return -EINVAL;
+ goto out_unlock;
pgstart = pin.offset / PAGE_SIZE;
pgend = pgstart + (pin.len / PAGE_SIZE) - 1;
- mutex_lock(&ashmem_mutex);
-
switch (cmd) {
case ASHMEM_PIN:
ret = ashmem_pin(asma, pgstart, pgend);
@@ -747,6 +749,7 @@
break;
}
+out_unlock:
mutex_unlock(&ashmem_mutex);
return ret;
diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c
index c9028bb..800c167 100644
--- a/drivers/staging/android/ion/ion_system_heap.c
+++ b/drivers/staging/android/ion/ion_system_heap.c
@@ -884,7 +884,7 @@
if (align > (PAGE_SIZE << order))
return -EINVAL;
- page = alloc_pages(low_order_gfp_flags | __GFP_ZERO, order);
+ page = alloc_pages(low_order_gfp_flags | __GFP_ZERO | __GFP_NOWARN, order);
if (!page)
return -ENOMEM;
diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c
index 3771726..4b9e359 100644
--- a/drivers/staging/android/ion/msm/msm_ion.c
+++ b/drivers/staging/android/ion/msm/msm_ion.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -659,7 +659,8 @@
vmid == VMID_CP_CAMERA_PREVIEW ||
vmid == VMID_CP_SPSS_SP ||
vmid == VMID_CP_SPSS_SP_SHARED ||
- vmid == VMID_CP_SPSS_HLOS_SHARED);
+ vmid == VMID_CP_SPSS_HLOS_SHARED ||
+ vmid == VMID_CP_CDSP);
}
unsigned int count_set_bits(unsigned long val)
@@ -709,6 +710,8 @@
return VMID_CP_SPSS_SP_SHARED;
if (flags & ION_FLAG_CP_SPSS_HLOS_SHARED)
return VMID_CP_SPSS_HLOS_SHARED;
+ if (flags & ION_FLAG_CP_CDSP)
+ return VMID_CP_CDSP;
return -EINVAL;
}
@@ -910,6 +913,7 @@
memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
vunmap(ptr);
+ ptr = NULL;
}
return 0;
diff --git a/drivers/staging/android/uapi/msm_ion.h b/drivers/staging/android/uapi/msm_ion.h
index d510fda..eb60bad 100644
--- a/drivers/staging/android/uapi/msm_ion.h
+++ b/drivers/staging/android/uapi/msm_ion.h
@@ -90,6 +90,8 @@
#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)
+/* ION_FLAG_ALLOW_NON_CONTIG uses ION_BIT(28) */
+#define ION_FLAG_CP_CDSP ION_BIT(29)
#define ION_FLAG_CP_SPSS_HLOS_SHARED ION_BIT(30)
/**
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index eeacb0e..4dc9ca3 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -141,6 +141,8 @@
#define AD7192_GPOCON_P1DAT BIT(1) /* P1 state */
#define AD7192_GPOCON_P0DAT BIT(0) /* P0 state */
+#define AD7192_EXT_FREQ_MHZ_MIN 2457600
+#define AD7192_EXT_FREQ_MHZ_MAX 5120000
#define AD7192_INT_FREQ_MHZ 4915200
/* NOTE:
@@ -216,6 +218,12 @@
ARRAY_SIZE(ad7192_calib_arr));
}
+static inline bool ad7192_valid_external_frequency(u32 freq)
+{
+ return (freq >= AD7192_EXT_FREQ_MHZ_MIN &&
+ freq <= AD7192_EXT_FREQ_MHZ_MAX);
+}
+
static int ad7192_setup(struct ad7192_state *st,
const struct ad7192_platform_data *pdata)
{
@@ -241,17 +249,20 @@
id);
switch (pdata->clock_source_sel) {
- case AD7192_CLK_EXT_MCLK1_2:
- case AD7192_CLK_EXT_MCLK2:
- st->mclk = AD7192_INT_FREQ_MHZ;
- break;
case AD7192_CLK_INT:
case AD7192_CLK_INT_CO:
- if (pdata->ext_clk_hz)
- st->mclk = pdata->ext_clk_hz;
- else
- st->mclk = AD7192_INT_FREQ_MHZ;
+ st->mclk = AD7192_INT_FREQ_MHZ;
break;
+ case AD7192_CLK_EXT_MCLK1_2:
+ case AD7192_CLK_EXT_MCLK2:
+ if (ad7192_valid_external_frequency(pdata->ext_clk_hz)) {
+ st->mclk = pdata->ext_clk_hz;
+ break;
+ }
+ dev_err(&st->sd.spi->dev, "Invalid frequency setting %u\n",
+ pdata->ext_clk_hz);
+ ret = -EINVAL;
+ goto out;
default:
ret = -EINVAL;
goto out;
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index 3892a74..4c7465c 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -642,8 +642,6 @@
/* Ring buffer functions - here trigger setup related */
indio_dev->setup_ops = &ad5933_ring_setup_ops;
- indio_dev->modes |= INDIO_BUFFER_HARDWARE;
-
return 0;
}
@@ -754,7 +752,7 @@
indio_dev->dev.parent = &client->dev;
indio_dev->info = &ad5933_info;
indio_dev->name = id->name;
- indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
indio_dev->channels = ad5933_channels;
indio_dev->num_channels = ARRAY_SIZE(ad5933_channels);
diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto-adler.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto-adler.c
index db05727..ab30a0f 100644
--- a/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto-adler.c
+++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto-adler.c
@@ -119,6 +119,7 @@
.cra_name = "adler32",
.cra_driver_name = "adler32-zlib",
.cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
.cra_blocksize = CHKSUM_BLOCK_SIZE,
.cra_ctxsize = sizeof(u32),
.cra_module = THIS_MODULE,
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
index e116f0e..98f75e5 100644
--- a/drivers/target/iscsi/iscsi_target_auth.c
+++ b/drivers/target/iscsi/iscsi_target_auth.c
@@ -413,7 +413,8 @@
auth_ret = 0;
out:
kzfree(desc);
- crypto_free_shash(tfm);
+ if (tfm)
+ crypto_free_shash(tfm);
kfree(challenge);
kfree(challenge_binhex);
return auth_ret;
diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig
new file mode 100644
index 0000000..a6df12d
--- /dev/null
+++ b/drivers/tee/Kconfig
@@ -0,0 +1,19 @@
+# Generic Trusted Execution Environment Configuration
+config TEE
+ tristate "Trusted Execution Environment support"
+ depends on HAVE_ARM_SMCCC || COMPILE_TEST
+ select DMA_SHARED_BUFFER
+ select GENERIC_ALLOCATOR
+ help
+ This implements a generic interface towards a Trusted Execution
+ Environment (TEE).
+
+if TEE
+
+menu "TEE drivers"
+
+source "drivers/tee/optee/Kconfig"
+
+endmenu
+
+endif
diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile
new file mode 100644
index 0000000..7a4e4a1
--- /dev/null
+++ b/drivers/tee/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_TEE) += tee.o
+tee-objs += tee_core.o
+tee-objs += tee_shm.o
+tee-objs += tee_shm_pool.o
+obj-$(CONFIG_OPTEE) += optee/
diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig
new file mode 100644
index 0000000..0126de8
--- /dev/null
+++ b/drivers/tee/optee/Kconfig
@@ -0,0 +1,7 @@
+# OP-TEE Trusted Execution Environment Configuration
+config OPTEE
+ tristate "OP-TEE"
+ depends on HAVE_ARM_SMCCC
+ help
+ This implements the OP-TEE Trusted Execution Environment (TEE)
+ driver.
diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile
new file mode 100644
index 0000000..220cf42
--- /dev/null
+++ b/drivers/tee/optee/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_OPTEE) += optee.o
+optee-objs += core.o
+optee-objs += call.o
+optee-objs += rpc.o
+optee-objs += supp.o
+optee-objs += shm_pool.o
diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
new file mode 100644
index 0000000..a5afbe6
--- /dev/null
+++ b/drivers/tee/optee/call.c
@@ -0,0 +1,662 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/arm-smccc.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include "optee_private.h"
+#include "optee_smc.h"
+
+struct optee_call_waiter {
+ struct list_head list_node;
+ struct completion c;
+};
+
+static void optee_cq_wait_init(struct optee_call_queue *cq,
+ struct optee_call_waiter *w)
+{
+ /*
+ * We're preparing to make a call to secure world. In case we can't
+ * allocate a thread in secure world we'll end up waiting in
+ * optee_cq_wait_for_completion().
+ *
+ * Normally if there's no contention in secure world the call will
+ * complete and we can cleanup directly with optee_cq_wait_final().
+ */
+ mutex_lock(&cq->mutex);
+
+ /*
+ * We add ourselves to the queue, but we don't wait. This
+ * guarantees that we don't lose a completion if secure world
+ * returns busy and another thread just exited and try to complete
+ * someone.
+ */
+ init_completion(&w->c);
+ list_add_tail(&w->list_node, &cq->waiters);
+
+ mutex_unlock(&cq->mutex);
+}
+
+static void optee_cq_wait_for_completion(struct optee_call_queue *cq,
+ struct optee_call_waiter *w)
+{
+ wait_for_completion(&w->c);
+
+ mutex_lock(&cq->mutex);
+
+ /* Move to end of list to get out of the way for other waiters */
+ list_del(&w->list_node);
+ reinit_completion(&w->c);
+ list_add_tail(&w->list_node, &cq->waiters);
+
+ mutex_unlock(&cq->mutex);
+}
+
+static void optee_cq_complete_one(struct optee_call_queue *cq)
+{
+ struct optee_call_waiter *w;
+
+ list_for_each_entry(w, &cq->waiters, list_node) {
+ if (!completion_done(&w->c)) {
+ complete(&w->c);
+ break;
+ }
+ }
+}
+
+static void optee_cq_wait_final(struct optee_call_queue *cq,
+ struct optee_call_waiter *w)
+{
+ /*
+ * We're done with the call to secure world. The thread in secure
+ * world that was used for this call is now available for some
+ * other task to use.
+ */
+ mutex_lock(&cq->mutex);
+
+ /* Get out of the list */
+ list_del(&w->list_node);
+
+ /* Wake up one eventual waiting task */
+ optee_cq_complete_one(cq);
+
+ /*
+ * If we're completed we've got a completion from another task that
+ * was just done with its call to secure world. Since yet another
+ * thread now is available in secure world wake up another eventual
+ * waiting task.
+ */
+ if (completion_done(&w->c))
+ optee_cq_complete_one(cq);
+
+ mutex_unlock(&cq->mutex);
+}
+
+/* Requires the filpstate mutex to be held */
+static struct optee_session *find_session(struct optee_context_data *ctxdata,
+ u32 session_id)
+{
+ struct optee_session *sess;
+
+ list_for_each_entry(sess, &ctxdata->sess_list, list_node)
+ if (sess->session_id == session_id)
+ return sess;
+
+ return NULL;
+}
+
+/**
+ * optee_do_call_with_arg() - Do an SMC to OP-TEE in secure world
+ * @ctx: calling context
+ * @parg: physical address of message to pass to secure world
+ *
+ * Does and SMC to OP-TEE in secure world and handles eventual resulting
+ * Remote Procedure Calls (RPC) from OP-TEE.
+ *
+ * Returns return code from secure world, 0 is OK
+ */
+u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg)
+{
+ struct optee *optee = tee_get_drvdata(ctx->teedev);
+ struct optee_call_waiter w;
+ struct optee_rpc_param param = { };
+ struct optee_call_ctx call_ctx = { };
+ u32 ret;
+
+ param.a0 = OPTEE_SMC_CALL_WITH_ARG;
+ reg_pair_from_64(¶m.a1, ¶m.a2, parg);
+ /* Initialize waiter */
+ optee_cq_wait_init(&optee->call_queue, &w);
+ while (true) {
+ struct arm_smccc_res res;
+
+ optee->invoke_fn(param.a0, param.a1, param.a2, param.a3,
+ param.a4, param.a5, param.a6, param.a7,
+ &res);
+
+ if (res.a0 == OPTEE_SMC_RETURN_ETHREAD_LIMIT) {
+ /*
+ * Out of threads in secure world, wait for a thread
+ * become available.
+ */
+ optee_cq_wait_for_completion(&optee->call_queue, &w);
+ } else if (OPTEE_SMC_RETURN_IS_RPC(res.a0)) {
+ param.a0 = res.a0;
+ param.a1 = res.a1;
+ param.a2 = res.a2;
+ param.a3 = res.a3;
+ optee_handle_rpc(ctx, ¶m, &call_ctx);
+ } else {
+ ret = res.a0;
+ break;
+ }
+ }
+
+ optee_rpc_finalize_call(&call_ctx);
+ /*
+ * We're done with our thread in secure world, if there's any
+ * thread waiters wake up one.
+ */
+ optee_cq_wait_final(&optee->call_queue, &w);
+
+ return ret;
+}
+
+static struct tee_shm *get_msg_arg(struct tee_context *ctx, size_t num_params,
+ struct optee_msg_arg **msg_arg,
+ phys_addr_t *msg_parg)
+{
+ int rc;
+ struct tee_shm *shm;
+ struct optee_msg_arg *ma;
+
+ shm = tee_shm_alloc(ctx, OPTEE_MSG_GET_ARG_SIZE(num_params),
+ TEE_SHM_MAPPED);
+ if (IS_ERR(shm))
+ return shm;
+
+ ma = tee_shm_get_va(shm, 0);
+ if (IS_ERR(ma)) {
+ rc = PTR_ERR(ma);
+ goto out;
+ }
+
+ rc = tee_shm_get_pa(shm, 0, msg_parg);
+ if (rc)
+ goto out;
+
+ memset(ma, 0, OPTEE_MSG_GET_ARG_SIZE(num_params));
+ ma->num_params = num_params;
+ *msg_arg = ma;
+out:
+ if (rc) {
+ tee_shm_free(shm);
+ return ERR_PTR(rc);
+ }
+
+ return shm;
+}
+
+int optee_open_session(struct tee_context *ctx,
+ struct tee_ioctl_open_session_arg *arg,
+ struct tee_param *param)
+{
+ struct optee_context_data *ctxdata = ctx->data;
+ int rc;
+ struct tee_shm *shm;
+ struct optee_msg_arg *msg_arg;
+ phys_addr_t msg_parg;
+ struct optee_session *sess = NULL;
+
+ /* +2 for the meta parameters added below */
+ shm = get_msg_arg(ctx, arg->num_params + 2, &msg_arg, &msg_parg);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ msg_arg->cmd = OPTEE_MSG_CMD_OPEN_SESSION;
+ msg_arg->cancel_id = arg->cancel_id;
+
+ /*
+ * Initialize and add the meta parameters needed when opening a
+ * session.
+ */
+ msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT |
+ OPTEE_MSG_ATTR_META;
+ msg_arg->params[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT |
+ OPTEE_MSG_ATTR_META;
+ memcpy(&msg_arg->params[0].u.value, arg->uuid, sizeof(arg->uuid));
+ memcpy(&msg_arg->params[1].u.value, arg->uuid, sizeof(arg->clnt_uuid));
+ msg_arg->params[1].u.value.c = arg->clnt_login;
+
+ rc = optee_to_msg_param(msg_arg->params + 2, arg->num_params, param);
+ if (rc)
+ goto out;
+
+ sess = kzalloc(sizeof(*sess), GFP_KERNEL);
+ if (!sess) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ if (optee_do_call_with_arg(ctx, msg_parg)) {
+ msg_arg->ret = TEEC_ERROR_COMMUNICATION;
+ msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
+ }
+
+ if (msg_arg->ret == TEEC_SUCCESS) {
+ /* A new session has been created, add it to the list. */
+ sess->session_id = msg_arg->session;
+ mutex_lock(&ctxdata->mutex);
+ list_add(&sess->list_node, &ctxdata->sess_list);
+ mutex_unlock(&ctxdata->mutex);
+ } else {
+ kfree(sess);
+ }
+
+ if (optee_from_msg_param(param, arg->num_params, msg_arg->params + 2)) {
+ arg->ret = TEEC_ERROR_COMMUNICATION;
+ arg->ret_origin = TEEC_ORIGIN_COMMS;
+ /* Close session again to avoid leakage */
+ optee_close_session(ctx, msg_arg->session);
+ } else {
+ arg->session = msg_arg->session;
+ arg->ret = msg_arg->ret;
+ arg->ret_origin = msg_arg->ret_origin;
+ }
+out:
+ tee_shm_free(shm);
+
+ return rc;
+}
+
+int optee_close_session(struct tee_context *ctx, u32 session)
+{
+ struct optee_context_data *ctxdata = ctx->data;
+ struct tee_shm *shm;
+ struct optee_msg_arg *msg_arg;
+ phys_addr_t msg_parg;
+ struct optee_session *sess;
+
+ /* Check that the session is valid and remove it from the list */
+ mutex_lock(&ctxdata->mutex);
+ sess = find_session(ctxdata, session);
+ if (sess)
+ list_del(&sess->list_node);
+ mutex_unlock(&ctxdata->mutex);
+ if (!sess)
+ return -EINVAL;
+ kfree(sess);
+
+ shm = get_msg_arg(ctx, 0, &msg_arg, &msg_parg);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ msg_arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION;
+ msg_arg->session = session;
+ optee_do_call_with_arg(ctx, msg_parg);
+
+ tee_shm_free(shm);
+ return 0;
+}
+
+int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
+ struct tee_param *param)
+{
+ struct optee_context_data *ctxdata = ctx->data;
+ struct tee_shm *shm;
+ struct optee_msg_arg *msg_arg;
+ phys_addr_t msg_parg;
+ struct optee_session *sess;
+ int rc;
+
+ /* Check that the session is valid */
+ mutex_lock(&ctxdata->mutex);
+ sess = find_session(ctxdata, arg->session);
+ mutex_unlock(&ctxdata->mutex);
+ if (!sess)
+ return -EINVAL;
+
+ shm = get_msg_arg(ctx, arg->num_params, &msg_arg, &msg_parg);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+ msg_arg->cmd = OPTEE_MSG_CMD_INVOKE_COMMAND;
+ msg_arg->func = arg->func;
+ msg_arg->session = arg->session;
+ msg_arg->cancel_id = arg->cancel_id;
+
+ rc = optee_to_msg_param(msg_arg->params, arg->num_params, param);
+ if (rc)
+ goto out;
+
+ if (optee_do_call_with_arg(ctx, msg_parg)) {
+ msg_arg->ret = TEEC_ERROR_COMMUNICATION;
+ msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
+ }
+
+ if (optee_from_msg_param(param, arg->num_params, msg_arg->params)) {
+ msg_arg->ret = TEEC_ERROR_COMMUNICATION;
+ msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
+ }
+
+ arg->ret = msg_arg->ret;
+ arg->ret_origin = msg_arg->ret_origin;
+out:
+ tee_shm_free(shm);
+ return rc;
+}
+
+int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session)
+{
+ struct optee_context_data *ctxdata = ctx->data;
+ struct tee_shm *shm;
+ struct optee_msg_arg *msg_arg;
+ phys_addr_t msg_parg;
+ struct optee_session *sess;
+
+ /* Check that the session is valid */
+ mutex_lock(&ctxdata->mutex);
+ sess = find_session(ctxdata, session);
+ mutex_unlock(&ctxdata->mutex);
+ if (!sess)
+ return -EINVAL;
+
+ shm = get_msg_arg(ctx, 0, &msg_arg, &msg_parg);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ msg_arg->cmd = OPTEE_MSG_CMD_CANCEL;
+ msg_arg->session = session;
+ msg_arg->cancel_id = cancel_id;
+ optee_do_call_with_arg(ctx, msg_parg);
+
+ tee_shm_free(shm);
+ return 0;
+}
+
+/**
+ * optee_enable_shm_cache() - Enables caching of some shared memory allocation
+ * in OP-TEE
+ * @optee: main service struct
+ */
+void optee_enable_shm_cache(struct optee *optee)
+{
+ struct optee_call_waiter w;
+
+ /* We need to retry until secure world isn't busy. */
+ optee_cq_wait_init(&optee->call_queue, &w);
+ while (true) {
+ struct arm_smccc_res res;
+
+ optee->invoke_fn(OPTEE_SMC_ENABLE_SHM_CACHE, 0, 0, 0, 0, 0, 0,
+ 0, &res);
+ if (res.a0 == OPTEE_SMC_RETURN_OK)
+ break;
+ optee_cq_wait_for_completion(&optee->call_queue, &w);
+ }
+ optee_cq_wait_final(&optee->call_queue, &w);
+}
+
+/**
+ * optee_disable_shm_cache() - Disables caching of some shared memory allocation
+ * in OP-TEE
+ * @optee: main service struct
+ */
+void optee_disable_shm_cache(struct optee *optee)
+{
+ struct optee_call_waiter w;
+
+ /* We need to retry until secure world isn't busy. */
+ optee_cq_wait_init(&optee->call_queue, &w);
+ while (true) {
+ union {
+ struct arm_smccc_res smccc;
+ struct optee_smc_disable_shm_cache_result result;
+ } res;
+
+ optee->invoke_fn(OPTEE_SMC_DISABLE_SHM_CACHE, 0, 0, 0, 0, 0, 0,
+ 0, &res.smccc);
+ if (res.result.status == OPTEE_SMC_RETURN_ENOTAVAIL)
+ break; /* All shm's freed */
+ if (res.result.status == OPTEE_SMC_RETURN_OK) {
+ struct tee_shm *shm;
+
+ shm = reg_pair_to_ptr(res.result.shm_upper32,
+ res.result.shm_lower32);
+ tee_shm_free(shm);
+ } else {
+ optee_cq_wait_for_completion(&optee->call_queue, &w);
+ }
+ }
+ optee_cq_wait_final(&optee->call_queue, &w);
+}
+
+#define PAGELIST_ENTRIES_PER_PAGE \
+ ((OPTEE_MSG_NONCONTIG_PAGE_SIZE / sizeof(u64)) - 1)
+
+/**
+ * optee_fill_pages_list() - write list of user pages to given shared
+ * buffer.
+ *
+ * @dst: page-aligned buffer where list of pages will be stored
+ * @pages: array of pages that represents shared buffer
+ * @num_pages: number of entries in @pages
+ * @page_offset: offset of user buffer from page start
+ *
+ * @dst should be big enough to hold list of user page addresses and
+ * links to the next pages of buffer
+ */
+void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages,
+ size_t page_offset)
+{
+ int n = 0;
+ phys_addr_t optee_page;
+ /*
+ * Refer to OPTEE_MSG_ATTR_NONCONTIG description in optee_msg.h
+ * for details.
+ */
+ struct {
+ u64 pages_list[PAGELIST_ENTRIES_PER_PAGE];
+ u64 next_page_data;
+ } *pages_data;
+
+ /*
+ * Currently OP-TEE uses 4k page size and it does not looks
+ * like this will change in the future. On other hand, there are
+ * no know ARM architectures with page size < 4k.
+ * Thus the next built assert looks redundant. But the following
+ * code heavily relies on this assumption, so it is better be
+ * safe than sorry.
+ */
+ BUILD_BUG_ON(PAGE_SIZE < OPTEE_MSG_NONCONTIG_PAGE_SIZE);
+
+ pages_data = (void *)dst;
+ /*
+ * If linux page is bigger than 4k, and user buffer offset is
+ * larger than 4k/8k/12k/etc this will skip first 4k pages,
+ * because they bear no value data for OP-TEE.
+ */
+ optee_page = page_to_phys(*pages) +
+ round_down(page_offset, OPTEE_MSG_NONCONTIG_PAGE_SIZE);
+
+ while (true) {
+ pages_data->pages_list[n++] = optee_page;
+
+ if (n == PAGELIST_ENTRIES_PER_PAGE) {
+ pages_data->next_page_data =
+ virt_to_phys(pages_data + 1);
+ pages_data++;
+ n = 0;
+ }
+
+ optee_page += OPTEE_MSG_NONCONTIG_PAGE_SIZE;
+ if (!(optee_page & ~PAGE_MASK)) {
+ if (!--num_pages)
+ break;
+ pages++;
+ optee_page = page_to_phys(*pages);
+ }
+ }
+}
+
+/*
+ * The final entry in each pagelist page is a pointer to the next
+ * pagelist page.
+ */
+static size_t get_pages_list_size(size_t num_entries)
+{
+ int pages = DIV_ROUND_UP(num_entries, PAGELIST_ENTRIES_PER_PAGE);
+
+ return pages * OPTEE_MSG_NONCONTIG_PAGE_SIZE;
+}
+
+u64 *optee_allocate_pages_list(size_t num_entries)
+{
+ return alloc_pages_exact(get_pages_list_size(num_entries), GFP_KERNEL);
+}
+
+void optee_free_pages_list(void *list, size_t num_entries)
+{
+ free_pages_exact(list, get_pages_list_size(num_entries));
+}
+
+static bool is_normal_memory(pgprot_t p)
+{
+#if defined(CONFIG_ARM)
+ return (pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEALLOC;
+#elif defined(CONFIG_ARM64)
+ return (pgprot_val(p) & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL);
+#else
+#error "Unuspported architecture"
+#endif
+}
+
+static int __check_mem_type(struct vm_area_struct *vma, unsigned long end)
+{
+ while (vma && is_normal_memory(vma->vm_page_prot)) {
+ if (vma->vm_end >= end)
+ return 0;
+ vma = vma->vm_next;
+ }
+
+ return -EINVAL;
+}
+
+static int check_mem_type(unsigned long start, size_t num_pages)
+{
+ struct mm_struct *mm = current->mm;
+ int rc;
+
+ down_read(&mm->mmap_sem);
+ rc = __check_mem_type(find_vma(mm, start),
+ start + num_pages * PAGE_SIZE);
+ up_read(&mm->mmap_sem);
+
+ return rc;
+}
+
+int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
+ struct page **pages, size_t num_pages,
+ unsigned long start)
+{
+ struct tee_shm *shm_arg = NULL;
+ struct optee_msg_arg *msg_arg;
+ u64 *pages_list;
+ phys_addr_t msg_parg;
+ int rc;
+
+ if (!num_pages)
+ return -EINVAL;
+
+ rc = check_mem_type(start, num_pages);
+ if (rc)
+ return rc;
+
+ pages_list = optee_allocate_pages_list(num_pages);
+ if (!pages_list)
+ return -ENOMEM;
+
+ shm_arg = get_msg_arg(ctx, 1, &msg_arg, &msg_parg);
+ if (IS_ERR(shm_arg)) {
+ rc = PTR_ERR(shm_arg);
+ goto out;
+ }
+
+ optee_fill_pages_list(pages_list, pages, num_pages,
+ tee_shm_get_page_offset(shm));
+
+ msg_arg->cmd = OPTEE_MSG_CMD_REGISTER_SHM;
+ msg_arg->params->attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
+ OPTEE_MSG_ATTR_NONCONTIG;
+ msg_arg->params->u.tmem.shm_ref = (unsigned long)shm;
+ msg_arg->params->u.tmem.size = tee_shm_get_size(shm);
+ /*
+ * In the least bits of msg_arg->params->u.tmem.buf_ptr we
+ * store buffer offset from 4k page, as described in OP-TEE ABI.
+ */
+ msg_arg->params->u.tmem.buf_ptr = virt_to_phys(pages_list) |
+ (tee_shm_get_page_offset(shm) & (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1));
+
+ if (optee_do_call_with_arg(ctx, msg_parg) ||
+ msg_arg->ret != TEEC_SUCCESS)
+ rc = -EINVAL;
+
+ tee_shm_free(shm_arg);
+out:
+ optee_free_pages_list(pages_list, num_pages);
+ return rc;
+}
+
+int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm)
+{
+ struct tee_shm *shm_arg;
+ struct optee_msg_arg *msg_arg;
+ phys_addr_t msg_parg;
+ int rc = 0;
+
+ shm_arg = get_msg_arg(ctx, 1, &msg_arg, &msg_parg);
+ if (IS_ERR(shm_arg))
+ return PTR_ERR(shm_arg);
+
+ msg_arg->cmd = OPTEE_MSG_CMD_UNREGISTER_SHM;
+
+ msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
+ msg_arg->params[0].u.rmem.shm_ref = (unsigned long)shm;
+
+ if (optee_do_call_with_arg(ctx, msg_parg) ||
+ msg_arg->ret != TEEC_SUCCESS)
+ rc = -EINVAL;
+ tee_shm_free(shm_arg);
+ return rc;
+}
+
+int optee_shm_register_supp(struct tee_context *ctx, struct tee_shm *shm,
+ struct page **pages, size_t num_pages,
+ unsigned long start)
+{
+ /*
+ * We don't want to register supplicant memory in OP-TEE.
+ * Instead information about it will be passed in RPC code.
+ */
+ return check_mem_type(start, num_pages);
+}
+
+int optee_shm_unregister_supp(struct tee_context *ctx, struct tee_shm *shm)
+{
+ return 0;
+}
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
new file mode 100644
index 0000000..e9843c5
--- /dev/null
+++ b/drivers/tee/optee/core.c
@@ -0,0 +1,705 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/arm-smccc.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tee_drv.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include "optee_private.h"
+#include "optee_smc.h"
+#include "shm_pool.h"
+
+#define DRIVER_NAME "optee"
+
+#define OPTEE_SHM_NUM_PRIV_PAGES 1
+
+/**
+ * optee_from_msg_param() - convert from OPTEE_MSG parameters to
+ * struct tee_param
+ * @params: subsystem internal parameter representation
+ * @num_params: number of elements in the parameter arrays
+ * @msg_params: OPTEE_MSG parameters
+ * Returns 0 on success or <0 on failure
+ */
+int optee_from_msg_param(struct tee_param *params, size_t num_params,
+ const struct optee_msg_param *msg_params)
+{
+ int rc;
+ size_t n;
+ struct tee_shm *shm;
+ phys_addr_t pa;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_param *p = params + n;
+ const struct optee_msg_param *mp = msg_params + n;
+ u32 attr = mp->attr & OPTEE_MSG_ATTR_TYPE_MASK;
+
+ switch (attr) {
+ case OPTEE_MSG_ATTR_TYPE_NONE:
+ p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
+ memset(&p->u, 0, sizeof(p->u));
+ break;
+ case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
+ case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
+ case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
+ p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT +
+ attr - OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
+ p->u.value.a = mp->u.value.a;
+ p->u.value.b = mp->u.value.b;
+ p->u.value.c = mp->u.value.c;
+ break;
+ case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
+ case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
+ case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
+ p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
+ attr - OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
+ p->u.memref.size = mp->u.tmem.size;
+ shm = (struct tee_shm *)(unsigned long)
+ mp->u.tmem.shm_ref;
+ if (!shm) {
+ p->u.memref.shm_offs = 0;
+ p->u.memref.shm = NULL;
+ break;
+ }
+ rc = tee_shm_get_pa(shm, 0, &pa);
+ if (rc)
+ return rc;
+ p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa;
+ p->u.memref.shm = shm;
+
+ /* Check that the memref is covered by the shm object */
+ if (p->u.memref.size) {
+ size_t o = p->u.memref.shm_offs +
+ p->u.memref.size - 1;
+
+ rc = tee_shm_get_pa(shm, o, NULL);
+ if (rc)
+ return rc;
+ }
+ break;
+ case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
+ case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
+ case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
+ p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
+ attr - OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
+ p->u.memref.size = mp->u.rmem.size;
+ shm = (struct tee_shm *)(unsigned long)
+ mp->u.rmem.shm_ref;
+
+ if (!shm) {
+ p->u.memref.shm_offs = 0;
+ p->u.memref.shm = NULL;
+ break;
+ }
+ p->u.memref.shm_offs = mp->u.rmem.offs;
+ p->u.memref.shm = shm;
+
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int to_msg_param_tmp_mem(struct optee_msg_param *mp,
+ const struct tee_param *p)
+{
+ int rc;
+ phys_addr_t pa;
+
+ mp->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT + p->attr -
+ TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+
+ mp->u.tmem.shm_ref = (unsigned long)p->u.memref.shm;
+ mp->u.tmem.size = p->u.memref.size;
+
+ if (!p->u.memref.shm) {
+ mp->u.tmem.buf_ptr = 0;
+ return 0;
+ }
+
+ rc = tee_shm_get_pa(p->u.memref.shm, p->u.memref.shm_offs, &pa);
+ if (rc)
+ return rc;
+
+ mp->u.tmem.buf_ptr = pa;
+ mp->attr |= OPTEE_MSG_ATTR_CACHE_PREDEFINED <<
+ OPTEE_MSG_ATTR_CACHE_SHIFT;
+
+ return 0;
+}
+
+static int to_msg_param_reg_mem(struct optee_msg_param *mp,
+ const struct tee_param *p)
+{
+ mp->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT + p->attr -
+ TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+
+ mp->u.rmem.shm_ref = (unsigned long)p->u.memref.shm;
+ mp->u.rmem.size = p->u.memref.size;
+ mp->u.rmem.offs = p->u.memref.shm_offs;
+ return 0;
+}
+
+/**
+ * optee_to_msg_param() - convert from struct tee_params to OPTEE_MSG parameters
+ * @msg_params: OPTEE_MSG parameters
+ * @num_params: number of elements in the parameter arrays
+ * @params: subsystem itnernal parameter representation
+ * Returns 0 on success or <0 on failure
+ */
+int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
+ const struct tee_param *params)
+{
+ int rc;
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ const struct tee_param *p = params + n;
+ struct optee_msg_param *mp = msg_params + n;
+
+ switch (p->attr) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_NONE:
+ mp->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
+ memset(&mp->u, 0, sizeof(mp->u));
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ mp->attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT + p->attr -
+ TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+ mp->u.value.a = p->u.value.a;
+ mp->u.value.b = p->u.value.b;
+ mp->u.value.c = p->u.value.c;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ if (tee_shm_is_registered(p->u.memref.shm))
+ rc = to_msg_param_reg_mem(mp, p);
+ else
+ rc = to_msg_param_tmp_mem(mp, p);
+ if (rc)
+ return rc;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static void optee_get_version(struct tee_device *teedev,
+ struct tee_ioctl_version_data *vers)
+{
+ struct tee_ioctl_version_data v = {
+ .impl_id = TEE_IMPL_ID_OPTEE,
+ .impl_caps = TEE_OPTEE_CAP_TZ,
+ .gen_caps = TEE_GEN_CAP_GP,
+ };
+ struct optee *optee = tee_get_drvdata(teedev);
+
+ if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
+ v.gen_caps |= TEE_GEN_CAP_REG_MEM;
+ *vers = v;
+}
+
+static int optee_open(struct tee_context *ctx)
+{
+ struct optee_context_data *ctxdata;
+ struct tee_device *teedev = ctx->teedev;
+ struct optee *optee = tee_get_drvdata(teedev);
+
+ ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL);
+ if (!ctxdata)
+ return -ENOMEM;
+
+ if (teedev == optee->supp_teedev) {
+ bool busy = true;
+
+ mutex_lock(&optee->supp.mutex);
+ if (!optee->supp.ctx) {
+ busy = false;
+ optee->supp.ctx = ctx;
+ }
+ mutex_unlock(&optee->supp.mutex);
+ if (busy) {
+ kfree(ctxdata);
+ return -EBUSY;
+ }
+ }
+
+ mutex_init(&ctxdata->mutex);
+ INIT_LIST_HEAD(&ctxdata->sess_list);
+
+ ctx->data = ctxdata;
+ return 0;
+}
+
+static void optee_release(struct tee_context *ctx)
+{
+ struct optee_context_data *ctxdata = ctx->data;
+ struct tee_device *teedev = ctx->teedev;
+ struct optee *optee = tee_get_drvdata(teedev);
+ struct tee_shm *shm;
+ struct optee_msg_arg *arg = NULL;
+ phys_addr_t parg;
+ struct optee_session *sess;
+ struct optee_session *sess_tmp;
+
+ if (!ctxdata)
+ return;
+
+ shm = tee_shm_alloc(ctx, sizeof(struct optee_msg_arg), TEE_SHM_MAPPED);
+ if (!IS_ERR(shm)) {
+ arg = tee_shm_get_va(shm, 0);
+ /*
+ * If va2pa fails for some reason, we can't call into
+ * secure world, only free the memory. Secure OS will leak
+ * sessions and finally refuse more sessions, but we will
+ * at least let normal world reclaim its memory.
+ */
+ if (!IS_ERR(arg))
+ if (tee_shm_va2pa(shm, arg, &parg))
+ arg = NULL; /* prevent usage of parg below */
+ }
+
+ list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list,
+ list_node) {
+ list_del(&sess->list_node);
+ if (!IS_ERR_OR_NULL(arg)) {
+ memset(arg, 0, sizeof(*arg));
+ arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION;
+ arg->session = sess->session_id;
+ optee_do_call_with_arg(ctx, parg);
+ }
+ kfree(sess);
+ }
+ kfree(ctxdata);
+
+ if (!IS_ERR(shm))
+ tee_shm_free(shm);
+
+ ctx->data = NULL;
+
+ if (teedev == optee->supp_teedev)
+ optee_supp_release(&optee->supp);
+}
+
+static const struct tee_driver_ops optee_ops = {
+ .get_version = optee_get_version,
+ .open = optee_open,
+ .release = optee_release,
+ .open_session = optee_open_session,
+ .close_session = optee_close_session,
+ .invoke_func = optee_invoke_func,
+ .cancel_req = optee_cancel_req,
+ .shm_register = optee_shm_register,
+ .shm_unregister = optee_shm_unregister,
+};
+
+static const struct tee_desc optee_desc = {
+ .name = DRIVER_NAME "-clnt",
+ .ops = &optee_ops,
+ .owner = THIS_MODULE,
+};
+
+static const struct tee_driver_ops optee_supp_ops = {
+ .get_version = optee_get_version,
+ .open = optee_open,
+ .release = optee_release,
+ .supp_recv = optee_supp_recv,
+ .supp_send = optee_supp_send,
+ .shm_register = optee_shm_register_supp,
+ .shm_unregister = optee_shm_unregister_supp,
+};
+
+static const struct tee_desc optee_supp_desc = {
+ .name = DRIVER_NAME "-supp",
+ .ops = &optee_supp_ops,
+ .owner = THIS_MODULE,
+ .flags = TEE_DESC_PRIVILEGED,
+};
+
+static bool optee_msg_api_uid_is_optee_api(optee_invoke_fn *invoke_fn)
+{
+ struct arm_smccc_res res;
+
+ invoke_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res);
+
+ if (res.a0 == OPTEE_MSG_UID_0 && res.a1 == OPTEE_MSG_UID_1 &&
+ res.a2 == OPTEE_MSG_UID_2 && res.a3 == OPTEE_MSG_UID_3)
+ return true;
+ return false;
+}
+
+static bool optee_msg_api_revision_is_compatible(optee_invoke_fn *invoke_fn)
+{
+ union {
+ struct arm_smccc_res smccc;
+ struct optee_smc_calls_revision_result result;
+ } res;
+
+ invoke_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
+
+ if (res.result.major == OPTEE_MSG_REVISION_MAJOR &&
+ (int)res.result.minor >= OPTEE_MSG_REVISION_MINOR)
+ return true;
+ return false;
+}
+
+static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn,
+ u32 *sec_caps)
+{
+ union {
+ struct arm_smccc_res smccc;
+ struct optee_smc_exchange_capabilities_result result;
+ } res;
+ u32 a1 = 0;
+
+ /*
+ * TODO This isn't enough to tell if it's UP system (from kernel
+ * point of view) or not, is_smp() returns the the information
+ * needed, but can't be called directly from here.
+ */
+ if (!IS_ENABLED(CONFIG_SMP) || nr_cpu_ids == 1)
+ a1 |= OPTEE_SMC_NSEC_CAP_UNIPROCESSOR;
+
+ invoke_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, a1, 0, 0, 0, 0, 0, 0,
+ &res.smccc);
+
+ if (res.result.status != OPTEE_SMC_RETURN_OK)
+ return false;
+
+ *sec_caps = res.result.capabilities;
+ return true;
+}
+
+static struct tee_shm_pool *
+optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm,
+ u32 sec_caps)
+{
+ union {
+ struct arm_smccc_res smccc;
+ struct optee_smc_get_shm_config_result result;
+ } res;
+ unsigned long vaddr;
+ phys_addr_t paddr;
+ size_t size;
+ phys_addr_t begin;
+ phys_addr_t end;
+ void *va;
+ struct tee_shm_pool_mgr *priv_mgr;
+ struct tee_shm_pool_mgr *dmabuf_mgr;
+ void *rc;
+
+ invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
+ if (res.result.status != OPTEE_SMC_RETURN_OK) {
+ pr_info("shm service not available\n");
+ return ERR_PTR(-ENOENT);
+ }
+
+ if (res.result.settings != OPTEE_SMC_SHM_CACHED) {
+ pr_err("only normal cached shared memory supported\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ begin = roundup(res.result.start, PAGE_SIZE);
+ end = rounddown(res.result.start + res.result.size, PAGE_SIZE);
+ paddr = begin;
+ size = end - begin;
+
+ if (size < 2 * OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE) {
+ pr_err("too small shared memory area\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ va = memremap(paddr, size, MEMREMAP_WB);
+ if (!va) {
+ pr_err("shared memory ioremap failed\n");
+ return ERR_PTR(-EINVAL);
+ }
+ vaddr = (unsigned long)va;
+
+ /*
+ * If OP-TEE can work with unregistered SHM, we will use own pool
+ * for private shm
+ */
+ if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) {
+ rc = optee_shm_pool_alloc_pages();
+ if (IS_ERR(rc))
+ goto err_memunmap;
+ priv_mgr = rc;
+ } else {
+ const size_t sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
+
+ rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz,
+ 3 /* 8 bytes aligned */);
+ if (IS_ERR(rc))
+ goto err_memunmap;
+ priv_mgr = rc;
+
+ vaddr += sz;
+ paddr += sz;
+ size -= sz;
+ }
+
+ rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, size, PAGE_SHIFT);
+ if (IS_ERR(rc))
+ goto err_free_priv_mgr;
+ dmabuf_mgr = rc;
+
+ rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
+ if (IS_ERR(rc))
+ goto err_free_dmabuf_mgr;
+
+ *memremaped_shm = va;
+
+ return rc;
+
+err_free_dmabuf_mgr:
+ tee_shm_pool_mgr_destroy(dmabuf_mgr);
+err_free_priv_mgr:
+ tee_shm_pool_mgr_destroy(priv_mgr);
+err_memunmap:
+ memunmap(va);
+ return rc;
+}
+
+/* Simple wrapper functions to be able to use a function pointer */
+static void optee_smccc_smc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3,
+ unsigned long a4, unsigned long a5,
+ unsigned long a6, unsigned long a7,
+ struct arm_smccc_res *res)
+{
+ arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res);
+}
+
+static void optee_smccc_hvc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3,
+ unsigned long a4, unsigned long a5,
+ unsigned long a6, unsigned long a7,
+ struct arm_smccc_res *res)
+{
+ arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res);
+}
+
+static optee_invoke_fn *get_invoke_func(struct device_node *np)
+{
+ const char *method;
+
+ pr_info("probing for conduit method from DT.\n");
+
+ if (of_property_read_string(np, "method", &method)) {
+ pr_warn("missing \"method\" property\n");
+ return ERR_PTR(-ENXIO);
+ }
+
+ if (!strcmp("hvc", method))
+ return optee_smccc_hvc;
+ else if (!strcmp("smc", method))
+ return optee_smccc_smc;
+
+ pr_warn("invalid \"method\" property: %s\n", method);
+ return ERR_PTR(-EINVAL);
+}
+
+static struct optee *optee_probe(struct device_node *np)
+{
+ optee_invoke_fn *invoke_fn;
+ struct tee_shm_pool *pool;
+ struct optee *optee = NULL;
+ void *memremaped_shm = NULL;
+ struct tee_device *teedev;
+ u32 sec_caps;
+ int rc;
+
+ invoke_fn = get_invoke_func(np);
+ if (IS_ERR(invoke_fn))
+ return (void *)invoke_fn;
+
+ if (!optee_msg_api_uid_is_optee_api(invoke_fn)) {
+ pr_warn("api uid mismatch\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
+ pr_warn("api revision mismatch\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps)) {
+ pr_warn("capabilities mismatch\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ /*
+ * We have no other option for shared memory, if secure world
+ * doesn't have any reserved memory we can use we can't continue.
+ */
+ if (!(sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM))
+ return ERR_PTR(-EINVAL);
+
+ pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm, sec_caps);
+ if (IS_ERR(pool))
+ return (void *)pool;
+
+ optee = kzalloc(sizeof(*optee), GFP_KERNEL);
+ if (!optee) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ optee->invoke_fn = invoke_fn;
+ optee->sec_caps = sec_caps;
+
+ teedev = tee_device_alloc(&optee_desc, NULL, pool, optee);
+ if (IS_ERR(teedev)) {
+ rc = PTR_ERR(teedev);
+ goto err;
+ }
+ optee->teedev = teedev;
+
+ teedev = tee_device_alloc(&optee_supp_desc, NULL, pool, optee);
+ if (IS_ERR(teedev)) {
+ rc = PTR_ERR(teedev);
+ goto err;
+ }
+ optee->supp_teedev = teedev;
+
+ rc = tee_device_register(optee->teedev);
+ if (rc)
+ goto err;
+
+ rc = tee_device_register(optee->supp_teedev);
+ if (rc)
+ goto err;
+
+ mutex_init(&optee->call_queue.mutex);
+ INIT_LIST_HEAD(&optee->call_queue.waiters);
+ optee_wait_queue_init(&optee->wait_queue);
+ optee_supp_init(&optee->supp);
+ optee->memremaped_shm = memremaped_shm;
+ optee->pool = pool;
+
+ optee_enable_shm_cache(optee);
+
+ pr_info("initialized driver\n");
+ return optee;
+err:
+ if (optee) {
+ /*
+ * tee_device_unregister() is safe to call even if the
+ * devices hasn't been registered with
+ * tee_device_register() yet.
+ */
+ tee_device_unregister(optee->supp_teedev);
+ tee_device_unregister(optee->teedev);
+ kfree(optee);
+ }
+ if (pool)
+ tee_shm_pool_free(pool);
+ if (memremaped_shm)
+ memunmap(memremaped_shm);
+ return ERR_PTR(rc);
+}
+
+static void optee_remove(struct optee *optee)
+{
+ /*
+ * Ask OP-TEE to free all cached shared memory objects to decrease
+ * reference counters and also avoid wild pointers in secure world
+ * into the old shared memory range.
+ */
+ optee_disable_shm_cache(optee);
+
+ /*
+ * The two devices has to be unregistered before we can free the
+ * other resources.
+ */
+ tee_device_unregister(optee->supp_teedev);
+ tee_device_unregister(optee->teedev);
+
+ tee_shm_pool_free(optee->pool);
+ if (optee->memremaped_shm)
+ memunmap(optee->memremaped_shm);
+ optee_wait_queue_exit(&optee->wait_queue);
+ optee_supp_uninit(&optee->supp);
+ mutex_destroy(&optee->call_queue.mutex);
+
+ kfree(optee);
+}
+
+static const struct of_device_id optee_match[] = {
+ { .compatible = "linaro,optee-tz" },
+ {},
+};
+
+static struct optee *optee_svc;
+
+static int __init optee_driver_init(void)
+{
+ struct device_node *fw_np;
+ struct device_node *np;
+ struct optee *optee;
+
+ /* Node is supposed to be below /firmware */
+ fw_np = of_find_node_by_name(NULL, "firmware");
+ if (!fw_np)
+ return -ENODEV;
+
+ np = of_find_matching_node(fw_np, optee_match);
+ if (!np)
+ return -ENODEV;
+
+ optee = optee_probe(np);
+ of_node_put(np);
+
+ if (IS_ERR(optee))
+ return PTR_ERR(optee);
+
+ optee_svc = optee;
+
+ return 0;
+}
+module_init(optee_driver_init);
+
+static void __exit optee_driver_exit(void)
+{
+ struct optee *optee = optee_svc;
+
+ optee_svc = NULL;
+ if (optee)
+ optee_remove(optee);
+}
+module_exit(optee_driver_exit);
+
+MODULE_AUTHOR("Linaro");
+MODULE_DESCRIPTION("OP-TEE driver");
+MODULE_SUPPORTED_DEVICE("");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h
new file mode 100644
index 0000000..3050490
--- /dev/null
+++ b/drivers/tee/optee/optee_msg.h
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _OPTEE_MSG_H
+#define _OPTEE_MSG_H
+
+#include <linux/bitops.h>
+#include <linux/types.h>
+
+/*
+ * This file defines the OP-TEE message protocol used to communicate
+ * with an instance of OP-TEE running in secure world.
+ *
+ * This file is divided into three sections.
+ * 1. Formatting of messages.
+ * 2. Requests from normal world
+ * 3. Requests from secure world, Remote Procedure Call (RPC), handled by
+ * tee-supplicant.
+ */
+
+/*****************************************************************************
+ * Part 1 - formatting of messages
+ *****************************************************************************/
+
+#define OPTEE_MSG_ATTR_TYPE_NONE 0x0
+#define OPTEE_MSG_ATTR_TYPE_VALUE_INPUT 0x1
+#define OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT 0x2
+#define OPTEE_MSG_ATTR_TYPE_VALUE_INOUT 0x3
+#define OPTEE_MSG_ATTR_TYPE_RMEM_INPUT 0x5
+#define OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT 0x6
+#define OPTEE_MSG_ATTR_TYPE_RMEM_INOUT 0x7
+#define OPTEE_MSG_ATTR_TYPE_TMEM_INPUT 0x9
+#define OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT 0xa
+#define OPTEE_MSG_ATTR_TYPE_TMEM_INOUT 0xb
+
+#define OPTEE_MSG_ATTR_TYPE_MASK GENMASK(7, 0)
+
+/*
+ * Meta parameter to be absorbed by the Secure OS and not passed
+ * to the Trusted Application.
+ *
+ * Currently only used with OPTEE_MSG_CMD_OPEN_SESSION.
+ */
+#define OPTEE_MSG_ATTR_META BIT(8)
+
+/*
+ * Pointer to a list of pages used to register user-defined SHM buffer.
+ * Used with OPTEE_MSG_ATTR_TYPE_TMEM_*.
+ * buf_ptr should point to the beginning of the buffer. Buffer will contain
+ * list of page addresses. OP-TEE core can reconstruct contiguous buffer from
+ * that page addresses list. Page addresses are stored as 64 bit values.
+ * Last entry on a page should point to the next page of buffer.
+ * Every entry in buffer should point to a 4k page beginning (12 least
+ * significant bits must be equal to zero).
+ *
+ * 12 least significant bints of optee_msg_param.u.tmem.buf_ptr should hold page
+ * offset of the user buffer.
+ *
+ * So, entries should be placed like members of this structure:
+ *
+ * struct page_data {
+ * uint64_t pages_array[OPTEE_MSG_NONCONTIG_PAGE_SIZE/sizeof(uint64_t) - 1];
+ * uint64_t next_page_data;
+ * };
+ *
+ * Structure is designed to exactly fit into the page size
+ * OPTEE_MSG_NONCONTIG_PAGE_SIZE which is a standard 4KB page.
+ *
+ * The size of 4KB is chosen because this is the smallest page size for ARM
+ * architectures. If REE uses larger pages, it should divide them to 4KB ones.
+ */
+#define OPTEE_MSG_ATTR_NONCONTIG BIT(9)
+
+/*
+ * Memory attributes for caching passed with temp memrefs. The actual value
+ * used is defined outside the message protocol with the exception of
+ * OPTEE_MSG_ATTR_CACHE_PREDEFINED which means the attributes already
+ * defined for the memory range should be used. If optee_smc.h is used as
+ * bearer of this protocol OPTEE_SMC_SHM_* is used for values.
+ */
+#define OPTEE_MSG_ATTR_CACHE_SHIFT 16
+#define OPTEE_MSG_ATTR_CACHE_MASK GENMASK(2, 0)
+#define OPTEE_MSG_ATTR_CACHE_PREDEFINED 0
+
+/*
+ * Same values as TEE_LOGIN_* from TEE Internal API
+ */
+#define OPTEE_MSG_LOGIN_PUBLIC 0x00000000
+#define OPTEE_MSG_LOGIN_USER 0x00000001
+#define OPTEE_MSG_LOGIN_GROUP 0x00000002
+#define OPTEE_MSG_LOGIN_APPLICATION 0x00000004
+#define OPTEE_MSG_LOGIN_APPLICATION_USER 0x00000005
+#define OPTEE_MSG_LOGIN_APPLICATION_GROUP 0x00000006
+
+/*
+ * Page size used in non-contiguous buffer entries
+ */
+#define OPTEE_MSG_NONCONTIG_PAGE_SIZE 4096
+
+/**
+ * struct optee_msg_param_tmem - temporary memory reference parameter
+ * @buf_ptr: Address of the buffer
+ * @size: Size of the buffer
+ * @shm_ref: Temporary shared memory reference, pointer to a struct tee_shm
+ *
+ * Secure and normal world communicates pointers as physical address
+ * instead of the virtual address. This is because secure and normal world
+ * have completely independent memory mapping. Normal world can even have a
+ * hypervisor which need to translate the guest physical address (AKA IPA
+ * in ARM documentation) to a real physical address before passing the
+ * structure to secure world.
+ */
+struct optee_msg_param_tmem {
+ u64 buf_ptr;
+ u64 size;
+ u64 shm_ref;
+};
+
+/**
+ * struct optee_msg_param_rmem - registered memory reference parameter
+ * @offs: Offset into shared memory reference
+ * @size: Size of the buffer
+ * @shm_ref: Shared memory reference, pointer to a struct tee_shm
+ */
+struct optee_msg_param_rmem {
+ u64 offs;
+ u64 size;
+ u64 shm_ref;
+};
+
+/**
+ * struct optee_msg_param_value - opaque value parameter
+ *
+ * Value parameters are passed unchecked between normal and secure world.
+ */
+struct optee_msg_param_value {
+ u64 a;
+ u64 b;
+ u64 c;
+};
+
+/**
+ * struct optee_msg_param - parameter used together with struct optee_msg_arg
+ * @attr: attributes
+ * @tmem: parameter by temporary memory reference
+ * @rmem: parameter by registered memory reference
+ * @value: parameter by opaque value
+ *
+ * @attr & OPTEE_MSG_ATTR_TYPE_MASK indicates if tmem, rmem or value is used in
+ * the union. OPTEE_MSG_ATTR_TYPE_VALUE_* indicates value,
+ * OPTEE_MSG_ATTR_TYPE_TMEM_* indicates @tmem and
+ * OPTEE_MSG_ATTR_TYPE_RMEM_* indicates @rmem,
+ * OPTEE_MSG_ATTR_TYPE_NONE indicates that none of the members are used.
+ */
+struct optee_msg_param {
+ u64 attr;
+ union {
+ struct optee_msg_param_tmem tmem;
+ struct optee_msg_param_rmem rmem;
+ struct optee_msg_param_value value;
+ } u;
+};
+
+/**
+ * struct optee_msg_arg - call argument
+ * @cmd: Command, one of OPTEE_MSG_CMD_* or OPTEE_MSG_RPC_CMD_*
+ * @func: Trusted Application function, specific to the Trusted Application,
+ * used if cmd == OPTEE_MSG_CMD_INVOKE_COMMAND
+ * @session: In parameter for all OPTEE_MSG_CMD_* except
+ * OPTEE_MSG_CMD_OPEN_SESSION where it's an output parameter instead
+ * @cancel_id: Cancellation id, a unique value to identify this request
+ * @ret: return value
+ * @ret_origin: origin of the return value
+ * @num_params: number of parameters supplied to the OS Command
+ * @params: the parameters supplied to the OS Command
+ *
+ * All normal calls to Trusted OS uses this struct. If cmd requires further
+ * information than what these field holds it can be passed as a parameter
+ * tagged as meta (setting the OPTEE_MSG_ATTR_META bit in corresponding
+ * attrs field). All parameters tagged as meta has to come first.
+ *
+ * Temp memref parameters can be fragmented if supported by the Trusted OS
+ * (when optee_smc.h is bearer of this protocol this is indicated with
+ * OPTEE_SMC_SEC_CAP_UNREGISTERED_SHM). If a logical memref parameter is
+ * fragmented then has all but the last fragment the
+ * OPTEE_MSG_ATTR_FRAGMENT bit set in attrs. Even if a memref is fragmented
+ * it will still be presented as a single logical memref to the Trusted
+ * Application.
+ */
+struct optee_msg_arg {
+ u32 cmd;
+ u32 func;
+ u32 session;
+ u32 cancel_id;
+ u32 pad;
+ u32 ret;
+ u32 ret_origin;
+ u32 num_params;
+
+ /* num_params tells the actual number of element in params */
+ struct optee_msg_param params[0];
+};
+
+/**
+ * OPTEE_MSG_GET_ARG_SIZE - return size of struct optee_msg_arg
+ *
+ * @num_params: Number of parameters embedded in the struct optee_msg_arg
+ *
+ * Returns the size of the struct optee_msg_arg together with the number
+ * of embedded parameters.
+ */
+#define OPTEE_MSG_GET_ARG_SIZE(num_params) \
+ (sizeof(struct optee_msg_arg) + \
+ sizeof(struct optee_msg_param) * (num_params))
+
+/*****************************************************************************
+ * Part 2 - requests from normal world
+ *****************************************************************************/
+
+/*
+ * Return the following UID if using API specified in this file without
+ * further extensions:
+ * 384fb3e0-e7f8-11e3-af63-0002a5d5c51b.
+ * Represented in 4 32-bit words in OPTEE_MSG_UID_0, OPTEE_MSG_UID_1,
+ * OPTEE_MSG_UID_2, OPTEE_MSG_UID_3.
+ */
+#define OPTEE_MSG_UID_0 0x384fb3e0
+#define OPTEE_MSG_UID_1 0xe7f811e3
+#define OPTEE_MSG_UID_2 0xaf630002
+#define OPTEE_MSG_UID_3 0xa5d5c51b
+#define OPTEE_MSG_FUNCID_CALLS_UID 0xFF01
+
+/*
+ * Returns 2.0 if using API specified in this file without further
+ * extensions. Represented in 2 32-bit words in OPTEE_MSG_REVISION_MAJOR
+ * and OPTEE_MSG_REVISION_MINOR
+ */
+#define OPTEE_MSG_REVISION_MAJOR 2
+#define OPTEE_MSG_REVISION_MINOR 0
+#define OPTEE_MSG_FUNCID_CALLS_REVISION 0xFF03
+
+/*
+ * Get UUID of Trusted OS.
+ *
+ * Used by non-secure world to figure out which Trusted OS is installed.
+ * Note that returned UUID is the UUID of the Trusted OS, not of the API.
+ *
+ * Returns UUID in 4 32-bit words in the same way as
+ * OPTEE_MSG_FUNCID_CALLS_UID described above.
+ */
+#define OPTEE_MSG_OS_OPTEE_UUID_0 0x486178e0
+#define OPTEE_MSG_OS_OPTEE_UUID_1 0xe7f811e3
+#define OPTEE_MSG_OS_OPTEE_UUID_2 0xbc5e0002
+#define OPTEE_MSG_OS_OPTEE_UUID_3 0xa5d5c51b
+#define OPTEE_MSG_FUNCID_GET_OS_UUID 0x0000
+
+/*
+ * Get revision of Trusted OS.
+ *
+ * Used by non-secure world to figure out which version of the Trusted OS
+ * is installed. Note that the returned revision is the revision of the
+ * Trusted OS, not of the API.
+ *
+ * Returns revision in 2 32-bit words in the same way as
+ * OPTEE_MSG_CALLS_REVISION described above.
+ */
+#define OPTEE_MSG_FUNCID_GET_OS_REVISION 0x0001
+
+/*
+ * Do a secure call with struct optee_msg_arg as argument
+ * The OPTEE_MSG_CMD_* below defines what goes in struct optee_msg_arg::cmd
+ *
+ * OPTEE_MSG_CMD_OPEN_SESSION opens a session to a Trusted Application.
+ * The first two parameters are tagged as meta, holding two value
+ * parameters to pass the following information:
+ * param[0].u.value.a-b uuid of Trusted Application
+ * param[1].u.value.a-b uuid of Client
+ * param[1].u.value.c Login class of client OPTEE_MSG_LOGIN_*
+ *
+ * OPTEE_MSG_CMD_INVOKE_COMMAND invokes a command a previously opened
+ * session to a Trusted Application. struct optee_msg_arg::func is Trusted
+ * Application function, specific to the Trusted Application.
+ *
+ * OPTEE_MSG_CMD_CLOSE_SESSION closes a previously opened session to
+ * Trusted Application.
+ *
+ * OPTEE_MSG_CMD_CANCEL cancels a currently invoked command.
+ *
+ * OPTEE_MSG_CMD_REGISTER_SHM registers a shared memory reference. The
+ * information is passed as:
+ * [in] param[0].attr OPTEE_MSG_ATTR_TYPE_TMEM_INPUT
+ * [| OPTEE_MSG_ATTR_FRAGMENT]
+ * [in] param[0].u.tmem.buf_ptr physical address (of first fragment)
+ * [in] param[0].u.tmem.size size (of first fragment)
+ * [in] param[0].u.tmem.shm_ref holds shared memory reference
+ * ...
+ * The shared memory can optionally be fragmented, temp memrefs can follow
+ * each other with all but the last with the OPTEE_MSG_ATTR_FRAGMENT bit set.
+ *
+ * OPTEE_MSG_CMD_UNREGISTER_SHM unregisteres a previously registered shared
+ * memory reference. The information is passed as:
+ * [in] param[0].attr OPTEE_MSG_ATTR_TYPE_RMEM_INPUT
+ * [in] param[0].u.rmem.shm_ref holds shared memory reference
+ * [in] param[0].u.rmem.offs 0
+ * [in] param[0].u.rmem.size 0
+ */
+#define OPTEE_MSG_CMD_OPEN_SESSION 0
+#define OPTEE_MSG_CMD_INVOKE_COMMAND 1
+#define OPTEE_MSG_CMD_CLOSE_SESSION 2
+#define OPTEE_MSG_CMD_CANCEL 3
+#define OPTEE_MSG_CMD_REGISTER_SHM 4
+#define OPTEE_MSG_CMD_UNREGISTER_SHM 5
+#define OPTEE_MSG_FUNCID_CALL_WITH_ARG 0x0004
+
+/*****************************************************************************
+ * Part 3 - Requests from secure world, RPC
+ *****************************************************************************/
+
+/*
+ * All RPC is done with a struct optee_msg_arg as bearer of information,
+ * struct optee_msg_arg::arg holds values defined by OPTEE_MSG_RPC_CMD_* below
+ *
+ * RPC communication with tee-supplicant is reversed compared to normal
+ * client communication desribed above. The supplicant receives requests
+ * and sends responses.
+ */
+
+/*
+ * Load a TA into memory, defined in tee-supplicant
+ */
+#define OPTEE_MSG_RPC_CMD_LOAD_TA 0
+
+/*
+ * Reserved
+ */
+#define OPTEE_MSG_RPC_CMD_RPMB 1
+
+/*
+ * File system access, defined in tee-supplicant
+ */
+#define OPTEE_MSG_RPC_CMD_FS 2
+
+/*
+ * Get time
+ *
+ * Returns number of seconds and nano seconds since the Epoch,
+ * 1970-01-01 00:00:00 +0000 (UTC).
+ *
+ * [out] param[0].u.value.a Number of seconds
+ * [out] param[0].u.value.b Number of nano seconds.
+ */
+#define OPTEE_MSG_RPC_CMD_GET_TIME 3
+
+/*
+ * Wait queue primitive, helper for secure world to implement a wait queue.
+ *
+ * If secure world need to wait for a secure world mutex it issues a sleep
+ * request instead of spinning in secure world. Conversely is a wakeup
+ * request issued when a secure world mutex with a thread waiting thread is
+ * unlocked.
+ *
+ * Waiting on a key
+ * [in] param[0].u.value.a OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP
+ * [in] param[0].u.value.b wait key
+ *
+ * Waking up a key
+ * [in] param[0].u.value.a OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP
+ * [in] param[0].u.value.b wakeup key
+ */
+#define OPTEE_MSG_RPC_CMD_WAIT_QUEUE 4
+#define OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP 0
+#define OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP 1
+
+/*
+ * Suspend execution
+ *
+ * [in] param[0].value .a number of milliseconds to suspend
+ */
+#define OPTEE_MSG_RPC_CMD_SUSPEND 5
+
+/*
+ * Allocate a piece of shared memory
+ *
+ * Shared memory can optionally be fragmented, to support that additional
+ * spare param entries are allocated to make room for eventual fragments.
+ * The spare param entries has .attr = OPTEE_MSG_ATTR_TYPE_NONE when
+ * unused. All returned temp memrefs except the last should have the
+ * OPTEE_MSG_ATTR_FRAGMENT bit set in the attr field.
+ *
+ * [in] param[0].u.value.a type of memory one of
+ * OPTEE_MSG_RPC_SHM_TYPE_* below
+ * [in] param[0].u.value.b requested size
+ * [in] param[0].u.value.c required alignment
+ *
+ * [out] param[0].u.tmem.buf_ptr physical address (of first fragment)
+ * [out] param[0].u.tmem.size size (of first fragment)
+ * [out] param[0].u.tmem.shm_ref shared memory reference
+ * ...
+ * [out] param[n].u.tmem.buf_ptr physical address
+ * [out] param[n].u.tmem.size size
+ * [out] param[n].u.tmem.shm_ref shared memory reference (same value
+ * as in param[n-1].u.tmem.shm_ref)
+ */
+#define OPTEE_MSG_RPC_CMD_SHM_ALLOC 6
+/* Memory that can be shared with a non-secure user space application */
+#define OPTEE_MSG_RPC_SHM_TYPE_APPL 0
+/* Memory only shared with non-secure kernel */
+#define OPTEE_MSG_RPC_SHM_TYPE_KERNEL 1
+
+/*
+ * Free shared memory previously allocated with OPTEE_MSG_RPC_CMD_SHM_ALLOC
+ *
+ * [in] param[0].u.value.a type of memory one of
+ * OPTEE_MSG_RPC_SHM_TYPE_* above
+ * [in] param[0].u.value.b value of shared memory reference
+ * returned in param[0].u.tmem.shm_ref
+ * above
+ */
+#define OPTEE_MSG_RPC_CMD_SHM_FREE 7
+
+#endif /* _OPTEE_MSG_H */
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
new file mode 100644
index 0000000..35e7938
--- /dev/null
+++ b/drivers/tee/optee/optee_private.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * 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 OPTEE_PRIVATE_H
+#define OPTEE_PRIVATE_H
+
+#include <linux/arm-smccc.h>
+#include <linux/semaphore.h>
+#include <linux/tee_drv.h>
+#include <linux/types.h>
+#include "optee_msg.h"
+
+#define OPTEE_MAX_ARG_SIZE 1024
+
+/* Some Global Platform error codes used in this driver */
+#define TEEC_SUCCESS 0x00000000
+#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
+#define TEEC_ERROR_COMMUNICATION 0xFFFF000E
+#define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C
+
+#define TEEC_ORIGIN_COMMS 0x00000002
+
+typedef void (optee_invoke_fn)(unsigned long, unsigned long, unsigned long,
+ unsigned long, unsigned long, unsigned long,
+ unsigned long, unsigned long,
+ struct arm_smccc_res *);
+
+struct optee_call_queue {
+ /* Serializes access to this struct */
+ struct mutex mutex;
+ struct list_head waiters;
+};
+
+struct optee_wait_queue {
+ /* Serializes access to this struct */
+ struct mutex mu;
+ struct list_head db;
+};
+
+/**
+ * struct optee_supp - supplicant synchronization struct
+ * @ctx the context of current connected supplicant.
+ * if !NULL the supplicant device is available for use,
+ * else busy
+ * @mutex: held while accessing content of this struct
+ * @req_id: current request id if supplicant is doing synchronous
+ * communication, else -1
+ * @reqs: queued request not yet retrieved by supplicant
+ * @idr: IDR holding all requests currently being processed
+ * by supplicant
+ * @reqs_c: completion used by supplicant when waiting for a
+ * request to be queued.
+ */
+struct optee_supp {
+ /* Serializes access to this struct */
+ struct mutex mutex;
+ struct tee_context *ctx;
+
+ int req_id;
+ struct list_head reqs;
+ struct idr idr;
+ struct completion reqs_c;
+};
+
+/**
+ * struct optee - main service struct
+ * @supp_teedev: supplicant device
+ * @teedev: client device
+ * @invoke_fn: function to issue smc or hvc
+ * @call_queue: queue of threads waiting to call @invoke_fn
+ * @wait_queue: queue of threads from secure world waiting for a
+ * secure world sync object
+ * @supp: supplicant synchronization struct for RPC to supplicant
+ * @pool: shared memory pool
+ * @memremaped_shm virtual address of memory in shared memory pool
+ * @sec_caps: secure world capabilities defined by
+ * OPTEE_SMC_SEC_CAP_* in optee_smc.h
+ */
+struct optee {
+ struct tee_device *supp_teedev;
+ struct tee_device *teedev;
+ optee_invoke_fn *invoke_fn;
+ struct optee_call_queue call_queue;
+ struct optee_wait_queue wait_queue;
+ struct optee_supp supp;
+ struct tee_shm_pool *pool;
+ void *memremaped_shm;
+ u32 sec_caps;
+};
+
+struct optee_session {
+ struct list_head list_node;
+ u32 session_id;
+};
+
+struct optee_context_data {
+ /* Serializes access to this struct */
+ struct mutex mutex;
+ struct list_head sess_list;
+};
+
+struct optee_rpc_param {
+ u32 a0;
+ u32 a1;
+ u32 a2;
+ u32 a3;
+ u32 a4;
+ u32 a5;
+ u32 a6;
+ u32 a7;
+};
+
+/* Holds context that is preserved during one STD call */
+struct optee_call_ctx {
+ /* information about pages list used in last allocation */
+ void *pages_list;
+ size_t num_entries;
+};
+
+void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param,
+ struct optee_call_ctx *call_ctx);
+void optee_rpc_finalize_call(struct optee_call_ctx *call_ctx);
+
+void optee_wait_queue_init(struct optee_wait_queue *wq);
+void optee_wait_queue_exit(struct optee_wait_queue *wq);
+
+u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
+ struct tee_param *param);
+
+int optee_supp_read(struct tee_context *ctx, void __user *buf, size_t len);
+int optee_supp_write(struct tee_context *ctx, void __user *buf, size_t len);
+void optee_supp_init(struct optee_supp *supp);
+void optee_supp_uninit(struct optee_supp *supp);
+void optee_supp_release(struct optee_supp *supp);
+
+int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
+ struct tee_param *param);
+int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
+ struct tee_param *param);
+
+u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg);
+int optee_open_session(struct tee_context *ctx,
+ struct tee_ioctl_open_session_arg *arg,
+ struct tee_param *param);
+int optee_close_session(struct tee_context *ctx, u32 session);
+int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
+ struct tee_param *param);
+int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session);
+
+void optee_enable_shm_cache(struct optee *optee);
+void optee_disable_shm_cache(struct optee *optee);
+
+int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
+ struct page **pages, size_t num_pages,
+ unsigned long start);
+int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm);
+
+int optee_shm_register_supp(struct tee_context *ctx, struct tee_shm *shm,
+ struct page **pages, size_t num_pages,
+ unsigned long start);
+int optee_shm_unregister_supp(struct tee_context *ctx, struct tee_shm *shm);
+
+int optee_from_msg_param(struct tee_param *params, size_t num_params,
+ const struct optee_msg_param *msg_params);
+int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
+ const struct tee_param *params);
+
+u64 *optee_allocate_pages_list(size_t num_entries);
+void optee_free_pages_list(void *array, size_t num_entries);
+void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages,
+ size_t page_offset);
+
+/*
+ * Small helpers
+ */
+
+static inline void *reg_pair_to_ptr(u32 reg0, u32 reg1)
+{
+ return (void *)(unsigned long)(((u64)reg0 << 32) | reg1);
+}
+
+static inline void reg_pair_from_64(u32 *reg0, u32 *reg1, u64 val)
+{
+ *reg0 = val >> 32;
+ *reg1 = val;
+}
+
+#endif /*OPTEE_PRIVATE_H*/
diff --git a/drivers/tee/optee/optee_smc.h b/drivers/tee/optee/optee_smc.h
new file mode 100644
index 0000000..7cd3272
--- /dev/null
+++ b/drivers/tee/optee/optee_smc.h
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef OPTEE_SMC_H
+#define OPTEE_SMC_H
+
+#include <linux/arm-smccc.h>
+#include <linux/bitops.h>
+
+#define OPTEE_SMC_STD_CALL_VAL(func_num) \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_32, \
+ ARM_SMCCC_OWNER_TRUSTED_OS, (func_num))
+#define OPTEE_SMC_FAST_CALL_VAL(func_num) \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \
+ ARM_SMCCC_OWNER_TRUSTED_OS, (func_num))
+
+/*
+ * Function specified by SMC Calling convention.
+ */
+#define OPTEE_SMC_FUNCID_CALLS_COUNT 0xFF00
+#define OPTEE_SMC_CALLS_COUNT \
+ ARM_SMCCC_CALL_VAL(OPTEE_SMC_FAST_CALL, SMCCC_SMC_32, \
+ SMCCC_OWNER_TRUSTED_OS_END, \
+ OPTEE_SMC_FUNCID_CALLS_COUNT)
+
+/*
+ * Normal cached memory (write-back), shareable for SMP systems and not
+ * shareable for UP systems.
+ */
+#define OPTEE_SMC_SHM_CACHED 1
+
+/*
+ * a0..a7 is used as register names in the descriptions below, on arm32
+ * that translates to r0..r7 and on arm64 to w0..w7. In both cases it's
+ * 32-bit registers.
+ */
+
+/*
+ * Function specified by SMC Calling convention
+ *
+ * Return one of the following UIDs if using API specified in this file
+ * without further extentions:
+ * 65cb6b93-af0c-4617-8ed6-644a8d1140f8
+ * see also OPTEE_SMC_UID_* in optee_msg.h
+ */
+#define OPTEE_SMC_FUNCID_CALLS_UID OPTEE_MSG_FUNCID_CALLS_UID
+#define OPTEE_SMC_CALLS_UID \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \
+ ARM_SMCCC_OWNER_TRUSTED_OS_END, \
+ OPTEE_SMC_FUNCID_CALLS_UID)
+
+/*
+ * Function specified by SMC Calling convention
+ *
+ * Returns 2.0 if using API specified in this file without further extentions.
+ * see also OPTEE_MSG_REVISION_* in optee_msg.h
+ */
+#define OPTEE_SMC_FUNCID_CALLS_REVISION OPTEE_MSG_FUNCID_CALLS_REVISION
+#define OPTEE_SMC_CALLS_REVISION \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \
+ ARM_SMCCC_OWNER_TRUSTED_OS_END, \
+ OPTEE_SMC_FUNCID_CALLS_REVISION)
+
+struct optee_smc_calls_revision_result {
+ unsigned long major;
+ unsigned long minor;
+ unsigned long reserved0;
+ unsigned long reserved1;
+};
+
+/*
+ * Get UUID of Trusted OS.
+ *
+ * Used by non-secure world to figure out which Trusted OS is installed.
+ * Note that returned UUID is the UUID of the Trusted OS, not of the API.
+ *
+ * Returns UUID in a0-4 in the same way as OPTEE_SMC_CALLS_UID
+ * described above.
+ */
+#define OPTEE_SMC_FUNCID_GET_OS_UUID OPTEE_MSG_FUNCID_GET_OS_UUID
+#define OPTEE_SMC_CALL_GET_OS_UUID \
+ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_OS_UUID)
+
+/*
+ * Get revision of Trusted OS.
+ *
+ * Used by non-secure world to figure out which version of the Trusted OS
+ * is installed. Note that the returned revision is the revision of the
+ * Trusted OS, not of the API.
+ *
+ * Returns revision in a0-1 in the same way as OPTEE_SMC_CALLS_REVISION
+ * described above.
+ */
+#define OPTEE_SMC_FUNCID_GET_OS_REVISION OPTEE_MSG_FUNCID_GET_OS_REVISION
+#define OPTEE_SMC_CALL_GET_OS_REVISION \
+ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_OS_REVISION)
+
+/*
+ * Call with struct optee_msg_arg as argument
+ *
+ * Call register usage:
+ * a0 SMC Function ID, OPTEE_SMC*CALL_WITH_ARG
+ * a1 Upper 32bit of a 64bit physical pointer to a struct optee_msg_arg
+ * a2 Lower 32bit of a 64bit physical pointer to a struct optee_msg_arg
+ * a3 Cache settings, not used if physical pointer is in a predefined shared
+ * memory area else per OPTEE_SMC_SHM_*
+ * a4-6 Not used
+ * a7 Hypervisor Client ID register
+ *
+ * Normal return register usage:
+ * a0 Return value, OPTEE_SMC_RETURN_*
+ * a1-3 Not used
+ * a4-7 Preserved
+ *
+ * OPTEE_SMC_RETURN_ETHREAD_LIMIT return register usage:
+ * a0 Return value, OPTEE_SMC_RETURN_ETHREAD_LIMIT
+ * a1-3 Preserved
+ * a4-7 Preserved
+ *
+ * RPC return register usage:
+ * a0 Return value, OPTEE_SMC_RETURN_IS_RPC(val)
+ * a1-2 RPC parameters
+ * a3-7 Resume information, must be preserved
+ *
+ * Possible return values:
+ * OPTEE_SMC_RETURN_UNKNOWN_FUNCTION Trusted OS does not recognize this
+ * function.
+ * OPTEE_SMC_RETURN_OK Call completed, result updated in
+ * the previously supplied struct
+ * optee_msg_arg.
+ * OPTEE_SMC_RETURN_ETHREAD_LIMIT Number of Trusted OS threads exceeded,
+ * try again later.
+ * OPTEE_SMC_RETURN_EBADADDR Bad physcial pointer to struct
+ * optee_msg_arg.
+ * OPTEE_SMC_RETURN_EBADCMD Bad/unknown cmd in struct optee_msg_arg
+ * OPTEE_SMC_RETURN_IS_RPC() Call suspended by RPC call to normal
+ * world.
+ */
+#define OPTEE_SMC_FUNCID_CALL_WITH_ARG OPTEE_MSG_FUNCID_CALL_WITH_ARG
+#define OPTEE_SMC_CALL_WITH_ARG \
+ OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_WITH_ARG)
+
+/*
+ * Get Shared Memory Config
+ *
+ * Returns the Secure/Non-secure shared memory config.
+ *
+ * Call register usage:
+ * a0 SMC Function ID, OPTEE_SMC_GET_SHM_CONFIG
+ * a1-6 Not used
+ * a7 Hypervisor Client ID register
+ *
+ * Have config return register usage:
+ * a0 OPTEE_SMC_RETURN_OK
+ * a1 Physical address of start of SHM
+ * a2 Size of of SHM
+ * a3 Cache settings of memory, as defined by the
+ * OPTEE_SMC_SHM_* values above
+ * a4-7 Preserved
+ *
+ * Not available register usage:
+ * a0 OPTEE_SMC_RETURN_ENOTAVAIL
+ * a1-3 Not used
+ * a4-7 Preserved
+ */
+#define OPTEE_SMC_FUNCID_GET_SHM_CONFIG 7
+#define OPTEE_SMC_GET_SHM_CONFIG \
+ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_SHM_CONFIG)
+
+struct optee_smc_get_shm_config_result {
+ unsigned long status;
+ unsigned long start;
+ unsigned long size;
+ unsigned long settings;
+};
+
+/*
+ * Exchanges capabilities between normal world and secure world
+ *
+ * Call register usage:
+ * a0 SMC Function ID, OPTEE_SMC_EXCHANGE_CAPABILITIES
+ * a1 bitfield of normal world capabilities OPTEE_SMC_NSEC_CAP_*
+ * a2-6 Not used
+ * a7 Hypervisor Client ID register
+ *
+ * Normal return register usage:
+ * a0 OPTEE_SMC_RETURN_OK
+ * a1 bitfield of secure world capabilities OPTEE_SMC_SEC_CAP_*
+ * a2-7 Preserved
+ *
+ * Error return register usage:
+ * a0 OPTEE_SMC_RETURN_ENOTAVAIL, can't use the capabilities from normal world
+ * a1 bitfield of secure world capabilities OPTEE_SMC_SEC_CAP_*
+ * a2-7 Preserved
+ */
+/* Normal world works as a uniprocessor system */
+#define OPTEE_SMC_NSEC_CAP_UNIPROCESSOR BIT(0)
+/* Secure world has reserved shared memory for normal world to use */
+#define OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM BIT(0)
+/* Secure world can communicate via previously unregistered shared memory */
+#define OPTEE_SMC_SEC_CAP_UNREGISTERED_SHM BIT(1)
+
+/*
+ * Secure world supports commands "register/unregister shared memory",
+ * secure world accepts command buffers located in any parts of non-secure RAM
+ */
+#define OPTEE_SMC_SEC_CAP_DYNAMIC_SHM BIT(2)
+
+#define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9
+#define OPTEE_SMC_EXCHANGE_CAPABILITIES \
+ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES)
+
+struct optee_smc_exchange_capabilities_result {
+ unsigned long status;
+ unsigned long capabilities;
+ unsigned long reserved0;
+ unsigned long reserved1;
+};
+
+/*
+ * Disable and empties cache of shared memory objects
+ *
+ * Secure world can cache frequently used shared memory objects, for
+ * example objects used as RPC arguments. When secure world is idle this
+ * function returns one shared memory reference to free. To disable the
+ * cache and free all cached objects this function has to be called until
+ * it returns OPTEE_SMC_RETURN_ENOTAVAIL.
+ *
+ * Call register usage:
+ * a0 SMC Function ID, OPTEE_SMC_DISABLE_SHM_CACHE
+ * a1-6 Not used
+ * a7 Hypervisor Client ID register
+ *
+ * Normal return register usage:
+ * a0 OPTEE_SMC_RETURN_OK
+ * a1 Upper 32bit of a 64bit Shared memory cookie
+ * a2 Lower 32bit of a 64bit Shared memory cookie
+ * a3-7 Preserved
+ *
+ * Cache empty return register usage:
+ * a0 OPTEE_SMC_RETURN_ENOTAVAIL
+ * a1-7 Preserved
+ *
+ * Not idle return register usage:
+ * a0 OPTEE_SMC_RETURN_EBUSY
+ * a1-7 Preserved
+ */
+#define OPTEE_SMC_FUNCID_DISABLE_SHM_CACHE 10
+#define OPTEE_SMC_DISABLE_SHM_CACHE \
+ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_DISABLE_SHM_CACHE)
+
+struct optee_smc_disable_shm_cache_result {
+ unsigned long status;
+ unsigned long shm_upper32;
+ unsigned long shm_lower32;
+ unsigned long reserved0;
+};
+
+/*
+ * Enable cache of shared memory objects
+ *
+ * Secure world can cache frequently used shared memory objects, for
+ * example objects used as RPC arguments. When secure world is idle this
+ * function returns OPTEE_SMC_RETURN_OK and the cache is enabled. If
+ * secure world isn't idle OPTEE_SMC_RETURN_EBUSY is returned.
+ *
+ * Call register usage:
+ * a0 SMC Function ID, OPTEE_SMC_ENABLE_SHM_CACHE
+ * a1-6 Not used
+ * a7 Hypervisor Client ID register
+ *
+ * Normal return register usage:
+ * a0 OPTEE_SMC_RETURN_OK
+ * a1-7 Preserved
+ *
+ * Not idle return register usage:
+ * a0 OPTEE_SMC_RETURN_EBUSY
+ * a1-7 Preserved
+ */
+#define OPTEE_SMC_FUNCID_ENABLE_SHM_CACHE 11
+#define OPTEE_SMC_ENABLE_SHM_CACHE \
+ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_ENABLE_SHM_CACHE)
+
+/*
+ * Resume from RPC (for example after processing a foreign interrupt)
+ *
+ * Call register usage:
+ * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC
+ * a1-3 Value of a1-3 when OPTEE_SMC_CALL_WITH_ARG returned
+ * OPTEE_SMC_RETURN_RPC in a0
+ *
+ * Return register usage is the same as for OPTEE_SMC_*CALL_WITH_ARG above.
+ *
+ * Possible return values
+ * OPTEE_SMC_RETURN_UNKNOWN_FUNCTION Trusted OS does not recognize this
+ * function.
+ * OPTEE_SMC_RETURN_OK Original call completed, result
+ * updated in the previously supplied.
+ * struct optee_msg_arg
+ * OPTEE_SMC_RETURN_RPC Call suspended by RPC call to normal
+ * world.
+ * OPTEE_SMC_RETURN_ERESUME Resume failed, the opaque resume
+ * information was corrupt.
+ */
+#define OPTEE_SMC_FUNCID_RETURN_FROM_RPC 3
+#define OPTEE_SMC_CALL_RETURN_FROM_RPC \
+ OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_RETURN_FROM_RPC)
+
+#define OPTEE_SMC_RETURN_RPC_PREFIX_MASK 0xFFFF0000
+#define OPTEE_SMC_RETURN_RPC_PREFIX 0xFFFF0000
+#define OPTEE_SMC_RETURN_RPC_FUNC_MASK 0x0000FFFF
+
+#define OPTEE_SMC_RETURN_GET_RPC_FUNC(ret) \
+ ((ret) & OPTEE_SMC_RETURN_RPC_FUNC_MASK)
+
+#define OPTEE_SMC_RPC_VAL(func) ((func) | OPTEE_SMC_RETURN_RPC_PREFIX)
+
+/*
+ * Allocate memory for RPC parameter passing. The memory is used to hold a
+ * struct optee_msg_arg.
+ *
+ * "Call" register usage:
+ * a0 This value, OPTEE_SMC_RETURN_RPC_ALLOC
+ * a1 Size in bytes of required argument memory
+ * a2 Not used
+ * a3 Resume information, must be preserved
+ * a4-5 Not used
+ * a6-7 Resume information, must be preserved
+ *
+ * "Return" register usage:
+ * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
+ * a1 Upper 32bits of 64bit physical pointer to allocated
+ * memory, (a1 == 0 && a2 == 0) if size was 0 or if memory can't
+ * be allocated.
+ * a2 Lower 32bits of 64bit physical pointer to allocated
+ * memory, (a1 == 0 && a2 == 0) if size was 0 or if memory can't
+ * be allocated
+ * a3 Preserved
+ * a4 Upper 32bits of 64bit Shared memory cookie used when freeing
+ * the memory or doing an RPC
+ * a5 Lower 32bits of 64bit Shared memory cookie used when freeing
+ * the memory or doing an RPC
+ * a6-7 Preserved
+ */
+#define OPTEE_SMC_RPC_FUNC_ALLOC 0
+#define OPTEE_SMC_RETURN_RPC_ALLOC \
+ OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_ALLOC)
+
+/*
+ * Free memory previously allocated by OPTEE_SMC_RETURN_RPC_ALLOC
+ *
+ * "Call" register usage:
+ * a0 This value, OPTEE_SMC_RETURN_RPC_FREE
+ * a1 Upper 32bits of 64bit shared memory cookie belonging to this
+ * argument memory
+ * a2 Lower 32bits of 64bit shared memory cookie belonging to this
+ * argument memory
+ * a3-7 Resume information, must be preserved
+ *
+ * "Return" register usage:
+ * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
+ * a1-2 Not used
+ * a3-7 Preserved
+ */
+#define OPTEE_SMC_RPC_FUNC_FREE 2
+#define OPTEE_SMC_RETURN_RPC_FREE \
+ OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_FREE)
+
+/*
+ * Deliver foreign interrupt to normal world.
+ *
+ * "Call" register usage:
+ * a0 OPTEE_SMC_RETURN_RPC_FOREIGN_INTR
+ * a1-7 Resume information, must be preserved
+ *
+ * "Return" register usage:
+ * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
+ * a1-7 Preserved
+ */
+#define OPTEE_SMC_RPC_FUNC_FOREIGN_INTR 4
+#define OPTEE_SMC_RETURN_RPC_FOREIGN_INTR \
+ OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_FOREIGN_INTR)
+
+/*
+ * Do an RPC request. The supplied struct optee_msg_arg tells which
+ * request to do and the parameters for the request. The following fields
+ * are used (the rest are unused):
+ * - cmd the Request ID
+ * - ret return value of the request, filled in by normal world
+ * - num_params number of parameters for the request
+ * - params the parameters
+ * - param_attrs attributes of the parameters
+ *
+ * "Call" register usage:
+ * a0 OPTEE_SMC_RETURN_RPC_CMD
+ * a1 Upper 32bit of a 64bit Shared memory cookie holding a
+ * struct optee_msg_arg, must be preserved, only the data should
+ * be updated
+ * a2 Lower 32bit of a 64bit Shared memory cookie holding a
+ * struct optee_msg_arg, must be preserved, only the data should
+ * be updated
+ * a3-7 Resume information, must be preserved
+ *
+ * "Return" register usage:
+ * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
+ * a1-2 Not used
+ * a3-7 Preserved
+ */
+#define OPTEE_SMC_RPC_FUNC_CMD 5
+#define OPTEE_SMC_RETURN_RPC_CMD \
+ OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_CMD)
+
+/* Returned in a0 */
+#define OPTEE_SMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF
+
+/* Returned in a0 only from Trusted OS functions */
+#define OPTEE_SMC_RETURN_OK 0x0
+#define OPTEE_SMC_RETURN_ETHREAD_LIMIT 0x1
+#define OPTEE_SMC_RETURN_EBUSY 0x2
+#define OPTEE_SMC_RETURN_ERESUME 0x3
+#define OPTEE_SMC_RETURN_EBADADDR 0x4
+#define OPTEE_SMC_RETURN_EBADCMD 0x5
+#define OPTEE_SMC_RETURN_ENOMEM 0x6
+#define OPTEE_SMC_RETURN_ENOTAVAIL 0x7
+#define OPTEE_SMC_RETURN_IS_RPC(ret) __optee_smc_return_is_rpc((ret))
+
+static inline bool __optee_smc_return_is_rpc(u32 ret)
+{
+ return ret != OPTEE_SMC_RETURN_UNKNOWN_FUNCTION &&
+ (ret & OPTEE_SMC_RETURN_RPC_PREFIX_MASK) ==
+ OPTEE_SMC_RETURN_RPC_PREFIX;
+}
+
+#endif /* OPTEE_SMC_H */
diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c
new file mode 100644
index 0000000..41aea12
--- /dev/null
+++ b/drivers/tee/optee/rpc.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include "optee_private.h"
+#include "optee_smc.h"
+
+struct wq_entry {
+ struct list_head link;
+ struct completion c;
+ u32 key;
+};
+
+void optee_wait_queue_init(struct optee_wait_queue *priv)
+{
+ mutex_init(&priv->mu);
+ INIT_LIST_HEAD(&priv->db);
+}
+
+void optee_wait_queue_exit(struct optee_wait_queue *priv)
+{
+ mutex_destroy(&priv->mu);
+}
+
+static void handle_rpc_func_cmd_get_time(struct optee_msg_arg *arg)
+{
+ struct timespec64 ts;
+
+ if (arg->num_params != 1)
+ goto bad;
+ if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=
+ OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT)
+ goto bad;
+
+ getnstimeofday64(&ts);
+ arg->params[0].u.value.a = ts.tv_sec;
+ arg->params[0].u.value.b = ts.tv_nsec;
+
+ arg->ret = TEEC_SUCCESS;
+ return;
+bad:
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+}
+
+static struct wq_entry *wq_entry_get(struct optee_wait_queue *wq, u32 key)
+{
+ struct wq_entry *w;
+
+ mutex_lock(&wq->mu);
+
+ list_for_each_entry(w, &wq->db, link)
+ if (w->key == key)
+ goto out;
+
+ w = kmalloc(sizeof(*w), GFP_KERNEL);
+ if (w) {
+ init_completion(&w->c);
+ w->key = key;
+ list_add_tail(&w->link, &wq->db);
+ }
+out:
+ mutex_unlock(&wq->mu);
+ return w;
+}
+
+static void wq_sleep(struct optee_wait_queue *wq, u32 key)
+{
+ struct wq_entry *w = wq_entry_get(wq, key);
+
+ if (w) {
+ wait_for_completion(&w->c);
+ mutex_lock(&wq->mu);
+ list_del(&w->link);
+ mutex_unlock(&wq->mu);
+ kfree(w);
+ }
+}
+
+static void wq_wakeup(struct optee_wait_queue *wq, u32 key)
+{
+ struct wq_entry *w = wq_entry_get(wq, key);
+
+ if (w)
+ complete(&w->c);
+}
+
+static void handle_rpc_func_cmd_wq(struct optee *optee,
+ struct optee_msg_arg *arg)
+{
+ if (arg->num_params != 1)
+ goto bad;
+
+ if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=
+ OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)
+ goto bad;
+
+ switch (arg->params[0].u.value.a) {
+ case OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP:
+ wq_sleep(&optee->wait_queue, arg->params[0].u.value.b);
+ break;
+ case OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP:
+ wq_wakeup(&optee->wait_queue, arg->params[0].u.value.b);
+ break;
+ default:
+ goto bad;
+ }
+
+ arg->ret = TEEC_SUCCESS;
+ return;
+bad:
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+}
+
+static void handle_rpc_func_cmd_wait(struct optee_msg_arg *arg)
+{
+ u32 msec_to_wait;
+
+ if (arg->num_params != 1)
+ goto bad;
+
+ if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=
+ OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)
+ goto bad;
+
+ msec_to_wait = arg->params[0].u.value.a;
+
+ /* Go to interruptible sleep */
+ msleep_interruptible(msec_to_wait);
+
+ arg->ret = TEEC_SUCCESS;
+ return;
+bad:
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+}
+
+static void handle_rpc_supp_cmd(struct tee_context *ctx,
+ struct optee_msg_arg *arg)
+{
+ struct tee_param *params;
+
+ arg->ret_origin = TEEC_ORIGIN_COMMS;
+
+ params = kmalloc_array(arg->num_params, sizeof(struct tee_param),
+ GFP_KERNEL);
+ if (!params) {
+ arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+ return;
+ }
+
+ if (optee_from_msg_param(params, arg->num_params, arg->params)) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ goto out;
+ }
+
+ arg->ret = optee_supp_thrd_req(ctx, arg->cmd, arg->num_params, params);
+
+ if (optee_to_msg_param(arg->params, arg->num_params, params))
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+out:
+ kfree(params);
+}
+
+static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz)
+{
+ u32 ret;
+ struct tee_param param;
+ struct optee *optee = tee_get_drvdata(ctx->teedev);
+ struct tee_shm *shm;
+
+ param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
+ param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL;
+ param.u.value.b = sz;
+ param.u.value.c = 0;
+
+ ret = optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_ALLOC, 1, ¶m);
+ if (ret)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_lock(&optee->supp.mutex);
+ /* Increases count as secure world doesn't have a reference */
+ shm = tee_shm_get_from_id(optee->supp.ctx, param.u.value.c);
+ mutex_unlock(&optee->supp.mutex);
+ return shm;
+}
+
+static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
+ struct optee_msg_arg *arg,
+ struct optee_call_ctx *call_ctx)
+{
+ phys_addr_t pa;
+ struct tee_shm *shm;
+ size_t sz;
+ size_t n;
+
+ arg->ret_origin = TEEC_ORIGIN_COMMS;
+
+ if (!arg->num_params ||
+ arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ for (n = 1; n < arg->num_params; n++) {
+ if (arg->params[n].attr != OPTEE_MSG_ATTR_TYPE_NONE) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
+ }
+
+ sz = arg->params[0].u.value.b;
+ switch (arg->params[0].u.value.a) {
+ case OPTEE_MSG_RPC_SHM_TYPE_APPL:
+ shm = cmd_alloc_suppl(ctx, sz);
+ break;
+ case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
+ shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED);
+ break;
+ default:
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ if (IS_ERR(shm)) {
+ arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+ return;
+ }
+
+ if (tee_shm_get_pa(shm, 0, &pa)) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ goto bad;
+ }
+
+ sz = tee_shm_get_size(shm);
+
+ if (tee_shm_is_registered(shm)) {
+ struct page **pages;
+ u64 *pages_list;
+ size_t page_num;
+
+ pages = tee_shm_get_pages(shm, &page_num);
+ if (!pages || !page_num) {
+ arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+ goto bad;
+ }
+
+ pages_list = optee_allocate_pages_list(page_num);
+ if (!pages_list) {
+ arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+ goto bad;
+ }
+
+ call_ctx->pages_list = pages_list;
+ call_ctx->num_entries = page_num;
+
+ arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
+ OPTEE_MSG_ATTR_NONCONTIG;
+ /*
+ * In the least bits of u.tmem.buf_ptr we store buffer offset
+ * from 4k page, as described in OP-TEE ABI.
+ */
+ arg->params[0].u.tmem.buf_ptr = virt_to_phys(pages_list) |
+ (tee_shm_get_page_offset(shm) &
+ (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1));
+ arg->params[0].u.tmem.size = tee_shm_get_size(shm);
+ arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
+
+ optee_fill_pages_list(pages_list, pages, page_num,
+ tee_shm_get_page_offset(shm));
+ } else {
+ arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
+ arg->params[0].u.tmem.buf_ptr = pa;
+ arg->params[0].u.tmem.size = sz;
+ arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
+ }
+
+ arg->ret = TEEC_SUCCESS;
+ return;
+bad:
+ tee_shm_free(shm);
+}
+
+static void cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm)
+{
+ struct tee_param param;
+
+ param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
+ param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL;
+ param.u.value.b = tee_shm_get_id(shm);
+ param.u.value.c = 0;
+
+ /*
+ * Match the tee_shm_get_from_id() in cmd_alloc_suppl() as secure
+ * world has released its reference.
+ *
+ * It's better to do this before sending the request to supplicant
+ * as we'd like to let the process doing the initial allocation to
+ * do release the last reference too in order to avoid stacking
+ * many pending fput() on the client process. This could otherwise
+ * happen if secure world does many allocate and free in a single
+ * invoke.
+ */
+ tee_shm_put(shm);
+
+ optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_FREE, 1, ¶m);
+}
+
+static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx,
+ struct optee_msg_arg *arg)
+{
+ struct tee_shm *shm;
+
+ arg->ret_origin = TEEC_ORIGIN_COMMS;
+
+ if (arg->num_params != 1 ||
+ arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ shm = (struct tee_shm *)(unsigned long)arg->params[0].u.value.b;
+ switch (arg->params[0].u.value.a) {
+ case OPTEE_MSG_RPC_SHM_TYPE_APPL:
+ cmd_free_suppl(ctx, shm);
+ break;
+ case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
+ tee_shm_free(shm);
+ break;
+ default:
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ }
+ arg->ret = TEEC_SUCCESS;
+}
+
+static void free_pages_list(struct optee_call_ctx *call_ctx)
+{
+ if (call_ctx->pages_list) {
+ optee_free_pages_list(call_ctx->pages_list,
+ call_ctx->num_entries);
+ call_ctx->pages_list = NULL;
+ call_ctx->num_entries = 0;
+ }
+}
+
+void optee_rpc_finalize_call(struct optee_call_ctx *call_ctx)
+{
+ free_pages_list(call_ctx);
+}
+
+static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
+ struct tee_shm *shm,
+ struct optee_call_ctx *call_ctx)
+{
+ struct optee_msg_arg *arg;
+
+ arg = tee_shm_get_va(shm, 0);
+ if (IS_ERR(arg)) {
+ pr_err("%s: tee_shm_get_va %p failed\n", __func__, shm);
+ return;
+ }
+
+ switch (arg->cmd) {
+ case OPTEE_MSG_RPC_CMD_GET_TIME:
+ handle_rpc_func_cmd_get_time(arg);
+ break;
+ case OPTEE_MSG_RPC_CMD_WAIT_QUEUE:
+ handle_rpc_func_cmd_wq(optee, arg);
+ break;
+ case OPTEE_MSG_RPC_CMD_SUSPEND:
+ handle_rpc_func_cmd_wait(arg);
+ break;
+ case OPTEE_MSG_RPC_CMD_SHM_ALLOC:
+ free_pages_list(call_ctx);
+ handle_rpc_func_cmd_shm_alloc(ctx, arg, call_ctx);
+ break;
+ case OPTEE_MSG_RPC_CMD_SHM_FREE:
+ handle_rpc_func_cmd_shm_free(ctx, arg);
+ break;
+ default:
+ handle_rpc_supp_cmd(ctx, arg);
+ }
+}
+
+/**
+ * optee_handle_rpc() - handle RPC from secure world
+ * @ctx: context doing the RPC
+ * @param: value of registers for the RPC
+ * @call_ctx: call context. Preserved during one OP-TEE invocation
+ *
+ * Result of RPC is written back into @param.
+ */
+void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param,
+ struct optee_call_ctx *call_ctx)
+{
+ struct tee_device *teedev = ctx->teedev;
+ struct optee *optee = tee_get_drvdata(teedev);
+ struct tee_shm *shm;
+ phys_addr_t pa;
+
+ switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) {
+ case OPTEE_SMC_RPC_FUNC_ALLOC:
+ shm = tee_shm_alloc(ctx, param->a1, TEE_SHM_MAPPED);
+ if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) {
+ reg_pair_from_64(¶m->a1, ¶m->a2, pa);
+ reg_pair_from_64(¶m->a4, ¶m->a5,
+ (unsigned long)shm);
+ } else {
+ param->a1 = 0;
+ param->a2 = 0;
+ param->a4 = 0;
+ param->a5 = 0;
+ }
+ break;
+ case OPTEE_SMC_RPC_FUNC_FREE:
+ shm = reg_pair_to_ptr(param->a1, param->a2);
+ tee_shm_free(shm);
+ break;
+ case OPTEE_SMC_RPC_FUNC_FOREIGN_INTR:
+ /*
+ * A foreign interrupt was raised while secure world was
+ * executing, since they are handled in Linux a dummy RPC is
+ * performed to let Linux take the interrupt through the normal
+ * vector.
+ */
+ break;
+ case OPTEE_SMC_RPC_FUNC_CMD:
+ shm = reg_pair_to_ptr(param->a1, param->a2);
+ handle_rpc_func_cmd(ctx, optee, shm, call_ctx);
+ break;
+ default:
+ pr_warn("Unknown RPC func 0x%x\n",
+ (u32)OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0));
+ break;
+ }
+
+ param->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC;
+}
diff --git a/drivers/tee/optee/shm_pool.c b/drivers/tee/optee/shm_pool.c
new file mode 100644
index 0000000..4939781
--- /dev/null
+++ b/drivers/tee/optee/shm_pool.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ * Copyright (c) 2017, EPAM Systems
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/device.h>
+#include <linux/dma-buf.h>
+#include <linux/genalloc.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include "optee_private.h"
+#include "optee_smc.h"
+#include "shm_pool.h"
+
+static int pool_op_alloc(struct tee_shm_pool_mgr *poolm,
+ struct tee_shm *shm, size_t size)
+{
+ unsigned int order = get_order(size);
+ struct page *page;
+
+ page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
+ if (!page)
+ return -ENOMEM;
+
+ shm->kaddr = page_address(page);
+ shm->paddr = page_to_phys(page);
+ shm->size = PAGE_SIZE << order;
+
+ return 0;
+}
+
+static void pool_op_free(struct tee_shm_pool_mgr *poolm,
+ struct tee_shm *shm)
+{
+ free_pages((unsigned long)shm->kaddr, get_order(shm->size));
+ shm->kaddr = NULL;
+}
+
+static void pool_op_destroy_poolmgr(struct tee_shm_pool_mgr *poolm)
+{
+ kfree(poolm);
+}
+
+static const struct tee_shm_pool_mgr_ops pool_ops = {
+ .alloc = pool_op_alloc,
+ .free = pool_op_free,
+ .destroy_poolmgr = pool_op_destroy_poolmgr,
+};
+
+/**
+ * optee_shm_pool_alloc_pages() - create page-based allocator pool
+ *
+ * This pool is used when OP-TEE supports dymanic SHM. In this case
+ * command buffers and such are allocated from kernel's own memory.
+ */
+struct tee_shm_pool_mgr *optee_shm_pool_alloc_pages(void)
+{
+ struct tee_shm_pool_mgr *mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
+
+ if (!mgr)
+ return ERR_PTR(-ENOMEM);
+
+ mgr->ops = &pool_ops;
+
+ return mgr;
+}
diff --git a/drivers/tee/optee/shm_pool.h b/drivers/tee/optee/shm_pool.h
new file mode 100644
index 0000000..4e753c3
--- /dev/null
+++ b/drivers/tee/optee/shm_pool.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ * Copyright (c) 2016, EPAM Systems
+ *
+ * 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 SHM_POOL_H
+#define SHM_POOL_H
+
+#include <linux/tee_drv.h>
+
+struct tee_shm_pool_mgr *optee_shm_pool_alloc_pages(void);
+
+#endif
diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c
new file mode 100644
index 0000000..df35fc0
--- /dev/null
+++ b/drivers/tee/optee/supp.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include "optee_private.h"
+
+struct optee_supp_req {
+ struct list_head link;
+
+ bool busy;
+ u32 func;
+ u32 ret;
+ size_t num_params;
+ struct tee_param *param;
+
+ struct completion c;
+};
+
+void optee_supp_init(struct optee_supp *supp)
+{
+ memset(supp, 0, sizeof(*supp));
+ mutex_init(&supp->mutex);
+ init_completion(&supp->reqs_c);
+ idr_init(&supp->idr);
+ INIT_LIST_HEAD(&supp->reqs);
+ supp->req_id = -1;
+}
+
+void optee_supp_uninit(struct optee_supp *supp)
+{
+ mutex_destroy(&supp->mutex);
+ idr_destroy(&supp->idr);
+}
+
+void optee_supp_release(struct optee_supp *supp)
+{
+ int id;
+ struct optee_supp_req *req;
+ struct optee_supp_req *req_tmp;
+
+ mutex_lock(&supp->mutex);
+
+ /* Abort all request retrieved by supplicant */
+ idr_for_each_entry(&supp->idr, req, id) {
+ req->busy = false;
+ idr_remove(&supp->idr, id);
+ req->ret = TEEC_ERROR_COMMUNICATION;
+ complete(&req->c);
+ }
+
+ /* Abort all queued requests */
+ list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) {
+ list_del(&req->link);
+ req->ret = TEEC_ERROR_COMMUNICATION;
+ complete(&req->c);
+ }
+
+ supp->ctx = NULL;
+ supp->req_id = -1;
+
+ mutex_unlock(&supp->mutex);
+}
+
+/**
+ * optee_supp_thrd_req() - request service from supplicant
+ * @ctx: context doing the request
+ * @func: function requested
+ * @num_params: number of elements in @param array
+ * @param: parameters for function
+ *
+ * Returns result of operation to be passed to secure world
+ */
+u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
+ struct tee_param *param)
+
+{
+ struct optee *optee = tee_get_drvdata(ctx->teedev);
+ struct optee_supp *supp = &optee->supp;
+ struct optee_supp_req *req = kzalloc(sizeof(*req), GFP_KERNEL);
+ bool interruptable;
+ u32 ret;
+
+ if (!req)
+ return TEEC_ERROR_OUT_OF_MEMORY;
+
+ init_completion(&req->c);
+ req->func = func;
+ req->num_params = num_params;
+ req->param = param;
+
+ /* Insert the request in the request list */
+ mutex_lock(&supp->mutex);
+ list_add_tail(&req->link, &supp->reqs);
+ mutex_unlock(&supp->mutex);
+
+ /* Tell an eventual waiter there's a new request */
+ complete(&supp->reqs_c);
+
+ /*
+ * Wait for supplicant to process and return result, once we've
+ * returned from wait_for_completion(&req->c) successfully we have
+ * exclusive access again.
+ */
+ while (wait_for_completion_interruptible(&req->c)) {
+ mutex_lock(&supp->mutex);
+ interruptable = !supp->ctx;
+ if (interruptable) {
+ /*
+ * There's no supplicant available and since the
+ * supp->mutex currently is held none can
+ * become available until the mutex released
+ * again.
+ *
+ * Interrupting an RPC to supplicant is only
+ * allowed as a way of slightly improving the user
+ * experience in case the supplicant hasn't been
+ * started yet. During normal operation the supplicant
+ * will serve all requests in a timely manner and
+ * interrupting then wouldn't make sense.
+ */
+ interruptable = !req->busy;
+ if (!req->busy)
+ list_del(&req->link);
+ }
+ mutex_unlock(&supp->mutex);
+
+ if (interruptable) {
+ req->ret = TEEC_ERROR_COMMUNICATION;
+ break;
+ }
+ }
+
+ ret = req->ret;
+ kfree(req);
+
+ return ret;
+}
+
+static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp,
+ int num_params, int *id)
+{
+ struct optee_supp_req *req;
+
+ if (supp->req_id != -1) {
+ /*
+ * Supplicant should not mix synchronous and asnynchronous
+ * requests.
+ */
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (list_empty(&supp->reqs))
+ return NULL;
+
+ req = list_first_entry(&supp->reqs, struct optee_supp_req, link);
+
+ if (num_params < req->num_params) {
+ /* Not enough room for parameters */
+ return ERR_PTR(-EINVAL);
+ }
+
+ *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL);
+ if (*id < 0)
+ return ERR_PTR(-ENOMEM);
+
+ list_del(&req->link);
+ req->busy = true;
+
+ return req;
+}
+
+static int supp_check_recv_params(size_t num_params, struct tee_param *params,
+ size_t *num_meta)
+{
+ size_t n;
+
+ if (!num_params)
+ return -EINVAL;
+
+ /*
+ * If there's memrefs we need to decrease those as they where
+ * increased earlier and we'll even refuse to accept any below.
+ */
+ for (n = 0; n < num_params; n++)
+ if (tee_param_is_memref(params + n) && params[n].u.memref.shm)
+ tee_shm_put(params[n].u.memref.shm);
+
+ /*
+ * We only expect parameters as TEE_IOCTL_PARAM_ATTR_TYPE_NONE with
+ * or without the TEE_IOCTL_PARAM_ATTR_META bit set.
+ */
+ for (n = 0; n < num_params; n++)
+ if (params[n].attr &&
+ params[n].attr != TEE_IOCTL_PARAM_ATTR_META)
+ return -EINVAL;
+
+ /* At most we'll need one meta parameter so no need to check for more */
+ if (params->attr == TEE_IOCTL_PARAM_ATTR_META)
+ *num_meta = 1;
+ else
+ *num_meta = 0;
+
+ return 0;
+}
+
+/**
+ * optee_supp_recv() - receive request for supplicant
+ * @ctx: context receiving the request
+ * @func: requested function in supplicant
+ * @num_params: number of elements allocated in @param, updated with number
+ * used elements
+ * @param: space for parameters for @func
+ *
+ * Returns 0 on success or <0 on failure
+ */
+int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
+ struct tee_param *param)
+{
+ struct tee_device *teedev = ctx->teedev;
+ struct optee *optee = tee_get_drvdata(teedev);
+ struct optee_supp *supp = &optee->supp;
+ struct optee_supp_req *req = NULL;
+ int id;
+ size_t num_meta;
+ int rc;
+
+ rc = supp_check_recv_params(*num_params, param, &num_meta);
+ if (rc)
+ return rc;
+
+ while (true) {
+ mutex_lock(&supp->mutex);
+ req = supp_pop_entry(supp, *num_params - num_meta, &id);
+ mutex_unlock(&supp->mutex);
+
+ if (req) {
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+ break;
+ }
+
+ /*
+ * If we didn't get a request we'll block in
+ * wait_for_completion() to avoid needless spinning.
+ *
+ * This is where supplicant will be hanging most of
+ * the time, let's make this interruptable so we
+ * can easily restart supplicant if needed.
+ */
+ if (wait_for_completion_interruptible(&supp->reqs_c))
+ return -ERESTARTSYS;
+ }
+
+ if (num_meta) {
+ /*
+ * tee-supplicant support meta parameters -> requsts can be
+ * processed asynchronously.
+ */
+ param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
+ TEE_IOCTL_PARAM_ATTR_META;
+ param->u.value.a = id;
+ param->u.value.b = 0;
+ param->u.value.c = 0;
+ } else {
+ mutex_lock(&supp->mutex);
+ supp->req_id = id;
+ mutex_unlock(&supp->mutex);
+ }
+
+ *func = req->func;
+ *num_params = req->num_params + num_meta;
+ memcpy(param + num_meta, req->param,
+ sizeof(struct tee_param) * req->num_params);
+
+ return 0;
+}
+
+static struct optee_supp_req *supp_pop_req(struct optee_supp *supp,
+ size_t num_params,
+ struct tee_param *param,
+ size_t *num_meta)
+{
+ struct optee_supp_req *req;
+ int id;
+ size_t nm;
+ const u32 attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
+ TEE_IOCTL_PARAM_ATTR_META;
+
+ if (!num_params)
+ return ERR_PTR(-EINVAL);
+
+ if (supp->req_id == -1) {
+ if (param->attr != attr)
+ return ERR_PTR(-EINVAL);
+ id = param->u.value.a;
+ nm = 1;
+ } else {
+ id = supp->req_id;
+ nm = 0;
+ }
+
+ req = idr_find(&supp->idr, id);
+ if (!req)
+ return ERR_PTR(-ENOENT);
+
+ if ((num_params - nm) != req->num_params)
+ return ERR_PTR(-EINVAL);
+
+ req->busy = false;
+ idr_remove(&supp->idr, id);
+ supp->req_id = -1;
+ *num_meta = nm;
+
+ return req;
+}
+
+/**
+ * optee_supp_send() - send result of request from supplicant
+ * @ctx: context sending result
+ * @ret: return value of request
+ * @num_params: number of parameters returned
+ * @param: returned parameters
+ *
+ * Returns 0 on success or <0 on failure.
+ */
+int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
+ struct tee_param *param)
+{
+ struct tee_device *teedev = ctx->teedev;
+ struct optee *optee = tee_get_drvdata(teedev);
+ struct optee_supp *supp = &optee->supp;
+ struct optee_supp_req *req;
+ size_t n;
+ size_t num_meta;
+
+ mutex_lock(&supp->mutex);
+ req = supp_pop_req(supp, num_params, param, &num_meta);
+ mutex_unlock(&supp->mutex);
+
+ if (IS_ERR(req)) {
+ /* Something is wrong, let supplicant restart. */
+ return PTR_ERR(req);
+ }
+
+ /* Update out and in/out parameters */
+ for (n = 0; n < req->num_params; n++) {
+ struct tee_param *p = req->param + n;
+
+ switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ p->u.value.a = param[n + num_meta].u.value.a;
+ p->u.value.b = param[n + num_meta].u.value.b;
+ p->u.value.c = param[n + num_meta].u.value.c;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ p->u.memref.size = param[n + num_meta].u.memref.size;
+ break;
+ default:
+ break;
+ }
+ }
+ req->ret = ret;
+
+ /* Let the requesting thread continue */
+ complete(&req->c);
+
+ return 0;
+}
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
new file mode 100644
index 0000000..6c4b200
--- /dev/null
+++ b/drivers/tee/tee_core.c
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ *
+ * 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) "%s: " fmt, __func__
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include <linux/uaccess.h>
+#include "tee_private.h"
+
+#define TEE_NUM_DEVICES 32
+
+#define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x))
+
+/*
+ * Unprivileged devices in the lower half range and privileged devices in
+ * the upper half range.
+ */
+static DECLARE_BITMAP(dev_mask, TEE_NUM_DEVICES);
+static DEFINE_SPINLOCK(driver_lock);
+
+static struct class *tee_class;
+static dev_t tee_devt;
+
+static int tee_open(struct inode *inode, struct file *filp)
+{
+ int rc;
+ struct tee_device *teedev;
+ struct tee_context *ctx;
+
+ teedev = container_of(inode->i_cdev, struct tee_device, cdev);
+ if (!tee_device_get(teedev))
+ return -EINVAL;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ kref_init(&ctx->refcount);
+ ctx->teedev = teedev;
+ INIT_LIST_HEAD(&ctx->list_shm);
+ filp->private_data = ctx;
+ rc = teedev->desc->ops->open(ctx);
+ if (rc)
+ goto err;
+
+ return 0;
+err:
+ kfree(ctx);
+ tee_device_put(teedev);
+ return rc;
+}
+
+void teedev_ctx_get(struct tee_context *ctx)
+{
+ if (ctx->releasing)
+ return;
+
+ kref_get(&ctx->refcount);
+}
+
+static void teedev_ctx_release(struct kref *ref)
+{
+ struct tee_context *ctx = container_of(ref, struct tee_context,
+ refcount);
+ ctx->releasing = true;
+ ctx->teedev->desc->ops->release(ctx);
+ kfree(ctx);
+}
+
+void teedev_ctx_put(struct tee_context *ctx)
+{
+ if (ctx->releasing)
+ return;
+
+ kref_put(&ctx->refcount, teedev_ctx_release);
+}
+
+static void teedev_close_context(struct tee_context *ctx)
+{
+ tee_device_put(ctx->teedev);
+ teedev_ctx_put(ctx);
+}
+
+static int tee_release(struct inode *inode, struct file *filp)
+{
+ teedev_close_context(filp->private_data);
+ return 0;
+}
+
+static int tee_ioctl_version(struct tee_context *ctx,
+ struct tee_ioctl_version_data __user *uvers)
+{
+ struct tee_ioctl_version_data vers;
+
+ ctx->teedev->desc->ops->get_version(ctx->teedev, &vers);
+
+ if (ctx->teedev->desc->flags & TEE_DESC_PRIVILEGED)
+ vers.gen_caps |= TEE_GEN_CAP_PRIVILEGED;
+
+ if (copy_to_user(uvers, &vers, sizeof(vers)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int tee_ioctl_shm_alloc(struct tee_context *ctx,
+ struct tee_ioctl_shm_alloc_data __user *udata)
+{
+ long ret;
+ struct tee_ioctl_shm_alloc_data data;
+ struct tee_shm *shm;
+
+ if (copy_from_user(&data, udata, sizeof(data)))
+ return -EFAULT;
+
+ /* Currently no input flags are supported */
+ if (data.flags)
+ return -EINVAL;
+
+ shm = tee_shm_alloc(ctx, data.size, TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ data.id = shm->id;
+ data.flags = shm->flags;
+ data.size = shm->size;
+
+ if (copy_to_user(udata, &data, sizeof(data)))
+ ret = -EFAULT;
+ else
+ ret = tee_shm_get_fd(shm);
+
+ /*
+ * When user space closes the file descriptor the shared memory
+ * should be freed or if tee_shm_get_fd() failed then it will
+ * be freed immediately.
+ */
+ tee_shm_put(shm);
+ return ret;
+}
+
+static int
+tee_ioctl_shm_register(struct tee_context *ctx,
+ struct tee_ioctl_shm_register_data __user *udata)
+{
+ long ret;
+ struct tee_ioctl_shm_register_data data;
+ struct tee_shm *shm;
+
+ if (copy_from_user(&data, udata, sizeof(data)))
+ return -EFAULT;
+
+ /* Currently no input flags are supported */
+ if (data.flags)
+ return -EINVAL;
+
+ shm = tee_shm_register(ctx, data.addr, data.length,
+ TEE_SHM_DMA_BUF | TEE_SHM_USER_MAPPED);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ data.id = shm->id;
+ data.flags = shm->flags;
+ data.length = shm->size;
+
+ if (copy_to_user(udata, &data, sizeof(data)))
+ ret = -EFAULT;
+ else
+ ret = tee_shm_get_fd(shm);
+ /*
+ * When user space closes the file descriptor the shared memory
+ * should be freed or if tee_shm_get_fd() failed then it will
+ * be freed immediately.
+ */
+ tee_shm_put(shm);
+ return ret;
+}
+
+static int params_from_user(struct tee_context *ctx, struct tee_param *params,
+ size_t num_params,
+ struct tee_ioctl_param __user *uparams)
+{
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_shm *shm;
+ struct tee_ioctl_param ip;
+
+ if (copy_from_user(&ip, uparams + n, sizeof(ip)))
+ return -EFAULT;
+
+ /* All unused attribute bits has to be zero */
+ if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_MASK)
+ return -EINVAL;
+
+ params[n].attr = ip.attr;
+ switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_NONE:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ params[n].u.value.a = ip.a;
+ params[n].u.value.b = ip.b;
+ params[n].u.value.c = ip.c;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ /*
+ * If we fail to get a pointer to a shared memory
+ * object (and increase the ref count) from an
+ * identifier we return an error. All pointers that
+ * has been added in params have an increased ref
+ * count. It's the callers responibility to do
+ * tee_shm_put() on all resolved pointers.
+ */
+ shm = tee_shm_get_from_id(ctx, ip.c);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ params[n].u.memref.shm_offs = ip.a;
+ params[n].u.memref.size = ip.b;
+ params[n].u.memref.shm = shm;
+ break;
+ default:
+ /* Unknown attribute */
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int params_to_user(struct tee_ioctl_param __user *uparams,
+ size_t num_params, struct tee_param *params)
+{
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_ioctl_param __user *up = uparams + n;
+ struct tee_param *p = params + n;
+
+ switch (p->attr) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ if (put_user(p->u.value.a, &up->a) ||
+ put_user(p->u.value.b, &up->b) ||
+ put_user(p->u.value.c, &up->c))
+ return -EFAULT;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ if (put_user((u64)p->u.memref.size, &up->b))
+ return -EFAULT;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+static int tee_ioctl_open_session(struct tee_context *ctx,
+ struct tee_ioctl_buf_data __user *ubuf)
+{
+ int rc;
+ size_t n;
+ struct tee_ioctl_buf_data buf;
+ struct tee_ioctl_open_session_arg __user *uarg;
+ struct tee_ioctl_open_session_arg arg;
+ struct tee_ioctl_param __user *uparams = NULL;
+ struct tee_param *params = NULL;
+ bool have_session = false;
+
+ if (!ctx->teedev->desc->ops->open_session)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, sizeof(buf)))
+ return -EFAULT;
+
+ if (buf.buf_len > TEE_MAX_ARG_SIZE ||
+ buf.buf_len < sizeof(struct tee_ioctl_open_session_arg))
+ return -EINVAL;
+
+ uarg = u64_to_user_ptr(buf.buf_ptr);
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+ return -EFAULT;
+
+ if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len)
+ return -EINVAL;
+
+ if (arg.num_params) {
+ params = kcalloc(arg.num_params, sizeof(struct tee_param),
+ GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+ uparams = uarg->params;
+ rc = params_from_user(ctx, params, arg.num_params, uparams);
+ if (rc)
+ goto out;
+ }
+
+ rc = ctx->teedev->desc->ops->open_session(ctx, &arg, params);
+ if (rc)
+ goto out;
+ have_session = true;
+
+ if (put_user(arg.session, &uarg->session) ||
+ put_user(arg.ret, &uarg->ret) ||
+ put_user(arg.ret_origin, &uarg->ret_origin)) {
+ rc = -EFAULT;
+ goto out;
+ }
+ rc = params_to_user(uparams, arg.num_params, params);
+out:
+ /*
+ * If we've succeeded to open the session but failed to communicate
+ * it back to user space, close the session again to avoid leakage.
+ */
+ if (rc && have_session && ctx->teedev->desc->ops->close_session)
+ ctx->teedev->desc->ops->close_session(ctx, arg.session);
+
+ if (params) {
+ /* Decrease ref count for all valid shared memory pointers */
+ for (n = 0; n < arg.num_params; n++)
+ if (tee_param_is_memref(params + n) &&
+ params[n].u.memref.shm)
+ tee_shm_put(params[n].u.memref.shm);
+ kfree(params);
+ }
+
+ return rc;
+}
+
+static int tee_ioctl_invoke(struct tee_context *ctx,
+ struct tee_ioctl_buf_data __user *ubuf)
+{
+ int rc;
+ size_t n;
+ struct tee_ioctl_buf_data buf;
+ struct tee_ioctl_invoke_arg __user *uarg;
+ struct tee_ioctl_invoke_arg arg;
+ struct tee_ioctl_param __user *uparams = NULL;
+ struct tee_param *params = NULL;
+
+ if (!ctx->teedev->desc->ops->invoke_func)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, sizeof(buf)))
+ return -EFAULT;
+
+ if (buf.buf_len > TEE_MAX_ARG_SIZE ||
+ buf.buf_len < sizeof(struct tee_ioctl_invoke_arg))
+ return -EINVAL;
+
+ uarg = u64_to_user_ptr(buf.buf_ptr);
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+ return -EFAULT;
+
+ if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len)
+ return -EINVAL;
+
+ if (arg.num_params) {
+ params = kcalloc(arg.num_params, sizeof(struct tee_param),
+ GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+ uparams = uarg->params;
+ rc = params_from_user(ctx, params, arg.num_params, uparams);
+ if (rc)
+ goto out;
+ }
+
+ rc = ctx->teedev->desc->ops->invoke_func(ctx, &arg, params);
+ if (rc)
+ goto out;
+
+ if (put_user(arg.ret, &uarg->ret) ||
+ put_user(arg.ret_origin, &uarg->ret_origin)) {
+ rc = -EFAULT;
+ goto out;
+ }
+ rc = params_to_user(uparams, arg.num_params, params);
+out:
+ if (params) {
+ /* Decrease ref count for all valid shared memory pointers */
+ for (n = 0; n < arg.num_params; n++)
+ if (tee_param_is_memref(params + n) &&
+ params[n].u.memref.shm)
+ tee_shm_put(params[n].u.memref.shm);
+ kfree(params);
+ }
+ return rc;
+}
+
+static int tee_ioctl_cancel(struct tee_context *ctx,
+ struct tee_ioctl_cancel_arg __user *uarg)
+{
+ struct tee_ioctl_cancel_arg arg;
+
+ if (!ctx->teedev->desc->ops->cancel_req)
+ return -EINVAL;
+
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+ return -EFAULT;
+
+ return ctx->teedev->desc->ops->cancel_req(ctx, arg.cancel_id,
+ arg.session);
+}
+
+static int
+tee_ioctl_close_session(struct tee_context *ctx,
+ struct tee_ioctl_close_session_arg __user *uarg)
+{
+ struct tee_ioctl_close_session_arg arg;
+
+ if (!ctx->teedev->desc->ops->close_session)
+ return -EINVAL;
+
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+ return -EFAULT;
+
+ return ctx->teedev->desc->ops->close_session(ctx, arg.session);
+}
+
+static int params_to_supp(struct tee_context *ctx,
+ struct tee_ioctl_param __user *uparams,
+ size_t num_params, struct tee_param *params)
+{
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_ioctl_param ip;
+ struct tee_param *p = params + n;
+
+ ip.attr = p->attr;
+ switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ ip.a = p->u.value.a;
+ ip.b = p->u.value.b;
+ ip.c = p->u.value.c;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ ip.b = p->u.memref.size;
+ if (!p->u.memref.shm) {
+ ip.a = 0;
+ ip.c = (u64)-1; /* invalid shm id */
+ break;
+ }
+ ip.a = p->u.memref.shm_offs;
+ ip.c = p->u.memref.shm->id;
+ break;
+ default:
+ ip.a = 0;
+ ip.b = 0;
+ ip.c = 0;
+ break;
+ }
+
+ if (copy_to_user(uparams + n, &ip, sizeof(ip)))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int tee_ioctl_supp_recv(struct tee_context *ctx,
+ struct tee_ioctl_buf_data __user *ubuf)
+{
+ int rc;
+ struct tee_ioctl_buf_data buf;
+ struct tee_iocl_supp_recv_arg __user *uarg;
+ struct tee_param *params;
+ u32 num_params;
+ u32 func;
+
+ if (!ctx->teedev->desc->ops->supp_recv)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, sizeof(buf)))
+ return -EFAULT;
+
+ if (buf.buf_len > TEE_MAX_ARG_SIZE ||
+ buf.buf_len < sizeof(struct tee_iocl_supp_recv_arg))
+ return -EINVAL;
+
+ uarg = u64_to_user_ptr(buf.buf_ptr);
+ if (get_user(num_params, &uarg->num_params))
+ return -EFAULT;
+
+ if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) != buf.buf_len)
+ return -EINVAL;
+
+ params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ rc = params_from_user(ctx, params, num_params, uarg->params);
+ if (rc)
+ goto out;
+
+ rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params);
+ if (rc)
+ goto out;
+
+ if (put_user(func, &uarg->func) ||
+ put_user(num_params, &uarg->num_params)) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ rc = params_to_supp(ctx, uarg->params, num_params, params);
+out:
+ kfree(params);
+ return rc;
+}
+
+static int params_from_supp(struct tee_param *params, size_t num_params,
+ struct tee_ioctl_param __user *uparams)
+{
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_param *p = params + n;
+ struct tee_ioctl_param ip;
+
+ if (copy_from_user(&ip, uparams + n, sizeof(ip)))
+ return -EFAULT;
+
+ /* All unused attribute bits has to be zero */
+ if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_MASK)
+ return -EINVAL;
+
+ p->attr = ip.attr;
+ switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ /* Only out and in/out values can be updated */
+ p->u.value.a = ip.a;
+ p->u.value.b = ip.b;
+ p->u.value.c = ip.c;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ /*
+ * Only the size of the memref can be updated.
+ * Since we don't have access to the original
+ * parameters here, only store the supplied size.
+ * The driver will copy the updated size into the
+ * original parameters.
+ */
+ p->u.memref.shm = NULL;
+ p->u.memref.shm_offs = 0;
+ p->u.memref.size = ip.b;
+ break;
+ default:
+ memset(&p->u, 0, sizeof(p->u));
+ break;
+ }
+ }
+ return 0;
+}
+
+static int tee_ioctl_supp_send(struct tee_context *ctx,
+ struct tee_ioctl_buf_data __user *ubuf)
+{
+ long rc;
+ struct tee_ioctl_buf_data buf;
+ struct tee_iocl_supp_send_arg __user *uarg;
+ struct tee_param *params;
+ u32 num_params;
+ u32 ret;
+
+ /* Not valid for this driver */
+ if (!ctx->teedev->desc->ops->supp_send)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, sizeof(buf)))
+ return -EFAULT;
+
+ if (buf.buf_len > TEE_MAX_ARG_SIZE ||
+ buf.buf_len < sizeof(struct tee_iocl_supp_send_arg))
+ return -EINVAL;
+
+ uarg = u64_to_user_ptr(buf.buf_ptr);
+ if (get_user(ret, &uarg->ret) ||
+ get_user(num_params, &uarg->num_params))
+ return -EFAULT;
+
+ if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) > buf.buf_len)
+ return -EINVAL;
+
+ params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ rc = params_from_supp(params, num_params, uarg->params);
+ if (rc)
+ goto out;
+
+ rc = ctx->teedev->desc->ops->supp_send(ctx, ret, num_params, params);
+out:
+ kfree(params);
+ return rc;
+}
+
+static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct tee_context *ctx = filp->private_data;
+ void __user *uarg = (void __user *)arg;
+
+ switch (cmd) {
+ case TEE_IOC_VERSION:
+ return tee_ioctl_version(ctx, uarg);
+ case TEE_IOC_SHM_ALLOC:
+ return tee_ioctl_shm_alloc(ctx, uarg);
+ case TEE_IOC_SHM_REGISTER:
+ return tee_ioctl_shm_register(ctx, uarg);
+ case TEE_IOC_OPEN_SESSION:
+ return tee_ioctl_open_session(ctx, uarg);
+ case TEE_IOC_INVOKE:
+ return tee_ioctl_invoke(ctx, uarg);
+ case TEE_IOC_CANCEL:
+ return tee_ioctl_cancel(ctx, uarg);
+ case TEE_IOC_CLOSE_SESSION:
+ return tee_ioctl_close_session(ctx, uarg);
+ case TEE_IOC_SUPPL_RECV:
+ return tee_ioctl_supp_recv(ctx, uarg);
+ case TEE_IOC_SUPPL_SEND:
+ return tee_ioctl_supp_send(ctx, uarg);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct file_operations tee_fops = {
+ .owner = THIS_MODULE,
+ .open = tee_open,
+ .release = tee_release,
+ .unlocked_ioctl = tee_ioctl,
+ .compat_ioctl = tee_ioctl,
+};
+
+static void tee_release_device(struct device *dev)
+{
+ struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+
+ spin_lock(&driver_lock);
+ clear_bit(teedev->id, dev_mask);
+ spin_unlock(&driver_lock);
+ mutex_destroy(&teedev->mutex);
+ idr_destroy(&teedev->idr);
+ kfree(teedev);
+}
+
+/**
+ * tee_device_alloc() - Allocate a new struct tee_device instance
+ * @teedesc: Descriptor for this driver
+ * @dev: Parent device for this device
+ * @pool: Shared memory pool, NULL if not used
+ * @driver_data: Private driver data for this device
+ *
+ * Allocates a new struct tee_device instance. The device is
+ * removed by tee_device_unregister().
+ *
+ * @returns a pointer to a 'struct tee_device' or an ERR_PTR on failure
+ */
+struct tee_device *tee_device_alloc(const struct tee_desc *teedesc,
+ struct device *dev,
+ struct tee_shm_pool *pool,
+ void *driver_data)
+{
+ struct tee_device *teedev;
+ void *ret;
+ int rc;
+ int offs = 0;
+
+ if (!teedesc || !teedesc->name || !teedesc->ops ||
+ !teedesc->ops->get_version || !teedesc->ops->open ||
+ !teedesc->ops->release || !pool)
+ return ERR_PTR(-EINVAL);
+
+ teedev = kzalloc(sizeof(*teedev), GFP_KERNEL);
+ if (!teedev) {
+ ret = ERR_PTR(-ENOMEM);
+ goto err;
+ }
+
+ if (teedesc->flags & TEE_DESC_PRIVILEGED)
+ offs = TEE_NUM_DEVICES / 2;
+
+ spin_lock(&driver_lock);
+ teedev->id = find_next_zero_bit(dev_mask, TEE_NUM_DEVICES, offs);
+ if (teedev->id < TEE_NUM_DEVICES)
+ set_bit(teedev->id, dev_mask);
+ spin_unlock(&driver_lock);
+
+ if (teedev->id >= TEE_NUM_DEVICES) {
+ ret = ERR_PTR(-ENOMEM);
+ goto err;
+ }
+
+ snprintf(teedev->name, sizeof(teedev->name), "tee%s%d",
+ teedesc->flags & TEE_DESC_PRIVILEGED ? "priv" : "",
+ teedev->id - offs);
+
+ teedev->dev.class = tee_class;
+ teedev->dev.release = tee_release_device;
+ teedev->dev.parent = dev;
+
+ teedev->dev.devt = MKDEV(MAJOR(tee_devt), teedev->id);
+
+ rc = dev_set_name(&teedev->dev, "%s", teedev->name);
+ if (rc) {
+ ret = ERR_PTR(rc);
+ goto err_devt;
+ }
+
+ cdev_init(&teedev->cdev, &tee_fops);
+ teedev->cdev.owner = teedesc->owner;
+ teedev->cdev.kobj.parent = &teedev->dev.kobj;
+
+ dev_set_drvdata(&teedev->dev, driver_data);
+ device_initialize(&teedev->dev);
+
+ /* 1 as tee_device_unregister() does one final tee_device_put() */
+ teedev->num_users = 1;
+ init_completion(&teedev->c_no_users);
+ mutex_init(&teedev->mutex);
+ idr_init(&teedev->idr);
+
+ teedev->desc = teedesc;
+ teedev->pool = pool;
+
+ return teedev;
+err_devt:
+ unregister_chrdev_region(teedev->dev.devt, 1);
+err:
+ pr_err("could not register %s driver\n",
+ teedesc->flags & TEE_DESC_PRIVILEGED ? "privileged" : "client");
+ if (teedev && teedev->id < TEE_NUM_DEVICES) {
+ spin_lock(&driver_lock);
+ clear_bit(teedev->id, dev_mask);
+ spin_unlock(&driver_lock);
+ }
+ kfree(teedev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tee_device_alloc);
+
+static ssize_t implementation_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+ struct tee_ioctl_version_data vers;
+
+ teedev->desc->ops->get_version(teedev, &vers);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", vers.impl_id);
+}
+static DEVICE_ATTR_RO(implementation_id);
+
+static struct attribute *tee_dev_attrs[] = {
+ &dev_attr_implementation_id.attr,
+ NULL
+};
+
+static const struct attribute_group tee_dev_group = {
+ .attrs = tee_dev_attrs,
+};
+
+/**
+ * tee_device_register() - Registers a TEE device
+ * @teedev: Device to register
+ *
+ * tee_device_unregister() need to be called to remove the @teedev if
+ * this function fails.
+ *
+ * @returns < 0 on failure
+ */
+int tee_device_register(struct tee_device *teedev)
+{
+ int rc;
+
+ if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) {
+ dev_err(&teedev->dev, "attempt to register twice\n");
+ return -EINVAL;
+ }
+
+ rc = cdev_add(&teedev->cdev, teedev->dev.devt, 1);
+ if (rc) {
+ dev_err(&teedev->dev,
+ "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
+ teedev->name, MAJOR(teedev->dev.devt),
+ MINOR(teedev->dev.devt), rc);
+ return rc;
+ }
+
+ rc = device_add(&teedev->dev);
+ if (rc) {
+ dev_err(&teedev->dev,
+ "unable to device_add() %s, major %d, minor %d, err=%d\n",
+ teedev->name, MAJOR(teedev->dev.devt),
+ MINOR(teedev->dev.devt), rc);
+ goto err_device_add;
+ }
+
+ rc = sysfs_create_group(&teedev->dev.kobj, &tee_dev_group);
+ if (rc) {
+ dev_err(&teedev->dev,
+ "failed to create sysfs attributes, err=%d\n", rc);
+ goto err_sysfs_create_group;
+ }
+
+ teedev->flags |= TEE_DEVICE_FLAG_REGISTERED;
+ return 0;
+
+err_sysfs_create_group:
+ device_del(&teedev->dev);
+err_device_add:
+ cdev_del(&teedev->cdev);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(tee_device_register);
+
+void tee_device_put(struct tee_device *teedev)
+{
+ mutex_lock(&teedev->mutex);
+ /* Shouldn't put in this state */
+ if (!WARN_ON(!teedev->desc)) {
+ teedev->num_users--;
+ if (!teedev->num_users) {
+ teedev->desc = NULL;
+ complete(&teedev->c_no_users);
+ }
+ }
+ mutex_unlock(&teedev->mutex);
+}
+
+bool tee_device_get(struct tee_device *teedev)
+{
+ mutex_lock(&teedev->mutex);
+ if (!teedev->desc) {
+ mutex_unlock(&teedev->mutex);
+ return false;
+ }
+ teedev->num_users++;
+ mutex_unlock(&teedev->mutex);
+ return true;
+}
+
+/**
+ * tee_device_unregister() - Removes a TEE device
+ * @teedev: Device to unregister
+ *
+ * This function should be called to remove the @teedev even if
+ * tee_device_register() hasn't been called yet. Does nothing if
+ * @teedev is NULL.
+ */
+void tee_device_unregister(struct tee_device *teedev)
+{
+ if (!teedev)
+ return;
+
+ if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) {
+ sysfs_remove_group(&teedev->dev.kobj, &tee_dev_group);
+ cdev_del(&teedev->cdev);
+ device_del(&teedev->dev);
+ }
+
+ tee_device_put(teedev);
+ wait_for_completion(&teedev->c_no_users);
+
+ /*
+ * No need to take a mutex any longer now since teedev->desc was
+ * set to NULL before teedev->c_no_users was completed.
+ */
+
+ teedev->pool = NULL;
+
+ put_device(&teedev->dev);
+}
+EXPORT_SYMBOL_GPL(tee_device_unregister);
+
+/**
+ * tee_get_drvdata() - Return driver_data pointer
+ * @teedev: Device containing the driver_data pointer
+ * @returns the driver_data pointer supplied to tee_register().
+ */
+void *tee_get_drvdata(struct tee_device *teedev)
+{
+ return dev_get_drvdata(&teedev->dev);
+}
+EXPORT_SYMBOL_GPL(tee_get_drvdata);
+
+static int __init tee_init(void)
+{
+ int rc;
+
+ tee_class = class_create(THIS_MODULE, "tee");
+ if (IS_ERR(tee_class)) {
+ pr_err("couldn't create class\n");
+ return PTR_ERR(tee_class);
+ }
+
+ rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee");
+ if (rc) {
+ pr_err("failed to allocate char dev region\n");
+ class_destroy(tee_class);
+ tee_class = NULL;
+ }
+
+ return rc;
+}
+
+static void __exit tee_exit(void)
+{
+ class_destroy(tee_class);
+ tee_class = NULL;
+ unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES);
+}
+
+subsys_initcall(tee_init);
+module_exit(tee_exit);
+
+MODULE_AUTHOR("Linaro");
+MODULE_DESCRIPTION("TEE Driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tee/tee_private.h b/drivers/tee/tee_private.h
new file mode 100644
index 0000000..85d99d6
--- /dev/null
+++ b/drivers/tee/tee_private.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ *
+ * 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 TEE_PRIVATE_H
+#define TEE_PRIVATE_H
+
+#include <linux/cdev.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/kref.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+/**
+ * struct tee_shm_pool - shared memory pool
+ * @private_mgr: pool manager for shared memory only between kernel
+ * and secure world
+ * @dma_buf_mgr: pool manager for shared memory exported to user space
+ */
+struct tee_shm_pool {
+ struct tee_shm_pool_mgr *private_mgr;
+ struct tee_shm_pool_mgr *dma_buf_mgr;
+};
+
+#define TEE_DEVICE_FLAG_REGISTERED 0x1
+#define TEE_MAX_DEV_NAME_LEN 32
+
+/**
+ * struct tee_device - TEE Device representation
+ * @name: name of device
+ * @desc: description of device
+ * @id: unique id of device
+ * @flags: represented by TEE_DEVICE_FLAG_REGISTERED above
+ * @dev: embedded basic device structure
+ * @cdev: embedded cdev
+ * @num_users: number of active users of this device
+ * @c_no_user: completion used when unregistering the device
+ * @mutex: mutex protecting @num_users and @idr
+ * @idr: register of shared memory object allocated on this device
+ * @pool: shared memory pool
+ */
+struct tee_device {
+ char name[TEE_MAX_DEV_NAME_LEN];
+ const struct tee_desc *desc;
+ int id;
+ unsigned int flags;
+
+ struct device dev;
+ struct cdev cdev;
+
+ size_t num_users;
+ struct completion c_no_users;
+ struct mutex mutex; /* protects num_users and idr */
+
+ struct idr idr;
+ struct tee_shm_pool *pool;
+};
+
+int tee_shm_init(void);
+
+int tee_shm_get_fd(struct tee_shm *shm);
+
+bool tee_device_get(struct tee_device *teedev);
+void tee_device_put(struct tee_device *teedev);
+
+void teedev_ctx_get(struct tee_context *ctx);
+void teedev_ctx_put(struct tee_context *ctx);
+
+#endif /*TEE_PRIVATE_H*/
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
new file mode 100644
index 0000000..ed2d71c
--- /dev/null
+++ b/drivers/tee/tee_shm.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/device.h>
+#include <linux/dma-buf.h>
+#include <linux/fdtable.h>
+#include <linux/idr.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include "tee_private.h"
+
+static void tee_shm_release(struct tee_shm *shm)
+{
+ struct tee_device *teedev = shm->teedev;
+
+ mutex_lock(&teedev->mutex);
+ idr_remove(&teedev->idr, shm->id);
+ if (shm->ctx)
+ list_del(&shm->link);
+ mutex_unlock(&teedev->mutex);
+
+ if (shm->flags & TEE_SHM_POOL) {
+ struct tee_shm_pool_mgr *poolm;
+
+ if (shm->flags & TEE_SHM_DMA_BUF)
+ poolm = teedev->pool->dma_buf_mgr;
+ else
+ poolm = teedev->pool->private_mgr;
+
+ poolm->ops->free(poolm, shm);
+ } else if (shm->flags & TEE_SHM_REGISTER) {
+ size_t n;
+ int rc = teedev->desc->ops->shm_unregister(shm->ctx, shm);
+
+ if (rc)
+ dev_err(teedev->dev.parent,
+ "unregister shm %p failed: %d", shm, rc);
+
+ for (n = 0; n < shm->num_pages; n++)
+ put_page(shm->pages[n]);
+
+ kfree(shm->pages);
+ }
+
+ if (shm->ctx)
+ teedev_ctx_put(shm->ctx);
+
+ kfree(shm);
+
+ tee_device_put(teedev);
+}
+
+static struct sg_table *tee_shm_op_map_dma_buf(struct dma_buf_attachment
+ *attach, enum dma_data_direction dir)
+{
+ return NULL;
+}
+
+static void tee_shm_op_unmap_dma_buf(struct dma_buf_attachment *attach,
+ struct sg_table *table,
+ enum dma_data_direction dir)
+{
+}
+
+static void tee_shm_op_release(struct dma_buf *dmabuf)
+{
+ struct tee_shm *shm = dmabuf->priv;
+
+ tee_shm_release(shm);
+}
+
+static void *tee_shm_op_kmap_atomic(struct dma_buf *dmabuf, unsigned long pgnum)
+{
+ return NULL;
+}
+
+static void *tee_shm_op_kmap(struct dma_buf *dmabuf, unsigned long pgnum)
+{
+ return NULL;
+}
+
+static int tee_shm_op_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
+{
+ struct tee_shm *shm = dmabuf->priv;
+ size_t size = vma->vm_end - vma->vm_start;
+
+ /* Refuse sharing shared memory provided by application */
+ if (shm->flags & TEE_SHM_REGISTER)
+ return -EINVAL;
+
+ return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT,
+ size, vma->vm_page_prot);
+}
+
+static const struct dma_buf_ops tee_shm_dma_buf_ops = {
+ .map_dma_buf = tee_shm_op_map_dma_buf,
+ .unmap_dma_buf = tee_shm_op_unmap_dma_buf,
+ .release = tee_shm_op_release,
+ .kmap_atomic = tee_shm_op_kmap_atomic,
+ .kmap = tee_shm_op_kmap,
+ .mmap = tee_shm_op_mmap,
+};
+
+static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx,
+ struct tee_device *teedev,
+ size_t size, u32 flags)
+{
+ struct tee_shm_pool_mgr *poolm = NULL;
+ struct tee_shm *shm;
+ void *ret;
+ int rc;
+
+ if (ctx && ctx->teedev != teedev) {
+ dev_err(teedev->dev.parent, "ctx and teedev mismatch\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!(flags & TEE_SHM_MAPPED)) {
+ dev_err(teedev->dev.parent,
+ "only mapped allocations supported\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if ((flags & ~(TEE_SHM_MAPPED | TEE_SHM_DMA_BUF))) {
+ dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!tee_device_get(teedev))
+ return ERR_PTR(-EINVAL);
+
+ if (!teedev->pool) {
+ /* teedev has been detached from driver */
+ ret = ERR_PTR(-EINVAL);
+ goto err_dev_put;
+ }
+
+ shm = kzalloc(sizeof(*shm), GFP_KERNEL);
+ if (!shm) {
+ ret = ERR_PTR(-ENOMEM);
+ goto err_dev_put;
+ }
+
+ shm->flags = flags | TEE_SHM_POOL;
+ shm->teedev = teedev;
+ shm->ctx = ctx;
+ if (flags & TEE_SHM_DMA_BUF)
+ poolm = teedev->pool->dma_buf_mgr;
+ else
+ poolm = teedev->pool->private_mgr;
+
+ rc = poolm->ops->alloc(poolm, shm, size);
+ if (rc) {
+ ret = ERR_PTR(rc);
+ goto err_kfree;
+ }
+
+ mutex_lock(&teedev->mutex);
+ shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
+ mutex_unlock(&teedev->mutex);
+ if (shm->id < 0) {
+ ret = ERR_PTR(shm->id);
+ goto err_pool_free;
+ }
+
+ if (flags & TEE_SHM_DMA_BUF) {
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+
+ exp_info.ops = &tee_shm_dma_buf_ops;
+ exp_info.size = shm->size;
+ exp_info.flags = O_RDWR;
+ exp_info.priv = shm;
+
+ shm->dmabuf = dma_buf_export(&exp_info);
+ if (IS_ERR(shm->dmabuf)) {
+ ret = ERR_CAST(shm->dmabuf);
+ goto err_rem;
+ }
+ }
+
+ if (ctx) {
+ teedev_ctx_get(ctx);
+ mutex_lock(&teedev->mutex);
+ list_add_tail(&shm->link, &ctx->list_shm);
+ mutex_unlock(&teedev->mutex);
+ }
+
+ return shm;
+err_rem:
+ mutex_lock(&teedev->mutex);
+ idr_remove(&teedev->idr, shm->id);
+ mutex_unlock(&teedev->mutex);
+err_pool_free:
+ poolm->ops->free(poolm, shm);
+err_kfree:
+ kfree(shm);
+err_dev_put:
+ tee_device_put(teedev);
+ return ret;
+}
+
+/**
+ * tee_shm_alloc() - Allocate shared memory
+ * @ctx: Context that allocates the shared memory
+ * @size: Requested size of shared memory
+ * @flags: Flags setting properties for the requested shared memory.
+ *
+ * Memory allocated as global shared memory is automatically freed when the
+ * TEE file pointer is closed. The @flags field uses the bits defined by
+ * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be
+ * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and
+ * associated with a dma-buf handle, else driver private memory.
+ */
+struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
+{
+ return __tee_shm_alloc(ctx, ctx->teedev, size, flags);
+}
+EXPORT_SYMBOL_GPL(tee_shm_alloc);
+
+struct tee_shm *tee_shm_priv_alloc(struct tee_device *teedev, size_t size)
+{
+ return __tee_shm_alloc(NULL, teedev, size, TEE_SHM_MAPPED);
+}
+EXPORT_SYMBOL_GPL(tee_shm_priv_alloc);
+
+struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
+ size_t length, u32 flags)
+{
+ struct tee_device *teedev = ctx->teedev;
+ const u32 req_flags = TEE_SHM_DMA_BUF | TEE_SHM_USER_MAPPED;
+ struct tee_shm *shm;
+ void *ret;
+ int rc;
+ int num_pages;
+ unsigned long start;
+
+ if (flags != req_flags)
+ return ERR_PTR(-ENOTSUPP);
+
+ if (!tee_device_get(teedev))
+ return ERR_PTR(-EINVAL);
+
+ if (!teedev->desc->ops->shm_register ||
+ !teedev->desc->ops->shm_unregister) {
+ tee_device_put(teedev);
+ return ERR_PTR(-ENOTSUPP);
+ }
+
+ teedev_ctx_get(ctx);
+
+ shm = kzalloc(sizeof(*shm), GFP_KERNEL);
+ if (!shm) {
+ ret = ERR_PTR(-ENOMEM);
+ goto err;
+ }
+
+ shm->flags = flags | TEE_SHM_REGISTER;
+ shm->teedev = teedev;
+ shm->ctx = ctx;
+ shm->id = -1;
+ start = rounddown(addr, PAGE_SIZE);
+ shm->offset = addr - start;
+ shm->size = length;
+ num_pages = (roundup(addr + length, PAGE_SIZE) - start) / PAGE_SIZE;
+ shm->pages = kcalloc(num_pages, sizeof(*shm->pages), GFP_KERNEL);
+ if (!shm->pages) {
+ ret = ERR_PTR(-ENOMEM);
+ goto err;
+ }
+
+ rc = get_user_pages_fast(start, num_pages, 1, shm->pages);
+ if (rc > 0)
+ shm->num_pages = rc;
+ if (rc != num_pages) {
+ if (rc >= 0)
+ rc = -ENOMEM;
+ ret = ERR_PTR(rc);
+ goto err;
+ }
+
+ mutex_lock(&teedev->mutex);
+ shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
+ mutex_unlock(&teedev->mutex);
+
+ if (shm->id < 0) {
+ ret = ERR_PTR(shm->id);
+ goto err;
+ }
+
+ rc = teedev->desc->ops->shm_register(ctx, shm, shm->pages,
+ shm->num_pages, start);
+ if (rc) {
+ ret = ERR_PTR(rc);
+ goto err;
+ }
+
+ if (flags & TEE_SHM_DMA_BUF) {
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+
+ exp_info.ops = &tee_shm_dma_buf_ops;
+ exp_info.size = shm->size;
+ exp_info.flags = O_RDWR;
+ exp_info.priv = shm;
+
+ shm->dmabuf = dma_buf_export(&exp_info);
+ if (IS_ERR(shm->dmabuf)) {
+ ret = ERR_CAST(shm->dmabuf);
+ teedev->desc->ops->shm_unregister(ctx, shm);
+ goto err;
+ }
+ }
+
+ mutex_lock(&teedev->mutex);
+ list_add_tail(&shm->link, &ctx->list_shm);
+ mutex_unlock(&teedev->mutex);
+
+ return shm;
+err:
+ if (shm) {
+ size_t n;
+
+ if (shm->id >= 0) {
+ mutex_lock(&teedev->mutex);
+ idr_remove(&teedev->idr, shm->id);
+ mutex_unlock(&teedev->mutex);
+ }
+ if (shm->pages) {
+ for (n = 0; n < shm->num_pages; n++)
+ put_page(shm->pages[n]);
+ kfree(shm->pages);
+ }
+ }
+ kfree(shm);
+ teedev_ctx_put(ctx);
+ tee_device_put(teedev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tee_shm_register);
+
+/**
+ * tee_shm_get_fd() - Increase reference count and return file descriptor
+ * @shm: Shared memory handle
+ * @returns user space file descriptor to shared memory
+ */
+int tee_shm_get_fd(struct tee_shm *shm)
+{
+ int fd;
+
+ if (!(shm->flags & TEE_SHM_DMA_BUF))
+ return -EINVAL;
+
+ fd = dma_buf_fd(shm->dmabuf, O_CLOEXEC);
+ if (fd >= 0)
+ get_dma_buf(shm->dmabuf);
+ return fd;
+}
+
+/**
+ * tee_shm_free() - Free shared memory
+ * @shm: Handle to shared memory to free
+ */
+void tee_shm_free(struct tee_shm *shm)
+{
+ /*
+ * dma_buf_put() decreases the dmabuf reference counter and will
+ * call tee_shm_release() when the last reference is gone.
+ *
+ * In the case of driver private memory we call tee_shm_release
+ * directly instead as it doesn't have a reference counter.
+ */
+ if (shm->flags & TEE_SHM_DMA_BUF)
+ dma_buf_put(shm->dmabuf);
+ else
+ tee_shm_release(shm);
+}
+EXPORT_SYMBOL_GPL(tee_shm_free);
+
+/**
+ * tee_shm_va2pa() - Get physical address of a virtual address
+ * @shm: Shared memory handle
+ * @va: Virtual address to tranlsate
+ * @pa: Returned physical address
+ * @returns 0 on success and < 0 on failure
+ */
+int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa)
+{
+ if (!(shm->flags & TEE_SHM_MAPPED))
+ return -EINVAL;
+ /* Check that we're in the range of the shm */
+ if ((char *)va < (char *)shm->kaddr)
+ return -EINVAL;
+ if ((char *)va >= ((char *)shm->kaddr + shm->size))
+ return -EINVAL;
+
+ return tee_shm_get_pa(
+ shm, (unsigned long)va - (unsigned long)shm->kaddr, pa);
+}
+EXPORT_SYMBOL_GPL(tee_shm_va2pa);
+
+/**
+ * tee_shm_pa2va() - Get virtual address of a physical address
+ * @shm: Shared memory handle
+ * @pa: Physical address to tranlsate
+ * @va: Returned virtual address
+ * @returns 0 on success and < 0 on failure
+ */
+int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va)
+{
+ if (!(shm->flags & TEE_SHM_MAPPED))
+ return -EINVAL;
+ /* Check that we're in the range of the shm */
+ if (pa < shm->paddr)
+ return -EINVAL;
+ if (pa >= (shm->paddr + shm->size))
+ return -EINVAL;
+
+ if (va) {
+ void *v = tee_shm_get_va(shm, pa - shm->paddr);
+
+ if (IS_ERR(v))
+ return PTR_ERR(v);
+ *va = v;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tee_shm_pa2va);
+
+/**
+ * tee_shm_get_va() - Get virtual address of a shared memory plus an offset
+ * @shm: Shared memory handle
+ * @offs: Offset from start of this shared memory
+ * @returns virtual address of the shared memory + offs if offs is within
+ * the bounds of this shared memory, else an ERR_PTR
+ */
+void *tee_shm_get_va(struct tee_shm *shm, size_t offs)
+{
+ if (!(shm->flags & TEE_SHM_MAPPED))
+ return ERR_PTR(-EINVAL);
+ if (offs >= shm->size)
+ return ERR_PTR(-EINVAL);
+ return (char *)shm->kaddr + offs;
+}
+EXPORT_SYMBOL_GPL(tee_shm_get_va);
+
+/**
+ * tee_shm_get_pa() - Get physical address of a shared memory plus an offset
+ * @shm: Shared memory handle
+ * @offs: Offset from start of this shared memory
+ * @pa: Physical address to return
+ * @returns 0 if offs is within the bounds of this shared memory, else an
+ * error code.
+ */
+int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa)
+{
+ if (offs >= shm->size)
+ return -EINVAL;
+ if (pa)
+ *pa = shm->paddr + offs;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tee_shm_get_pa);
+
+/**
+ * tee_shm_get_from_id() - Find shared memory object and increase reference
+ * count
+ * @ctx: Context owning the shared memory
+ * @id: Id of shared memory object
+ * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure
+ */
+struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id)
+{
+ struct tee_device *teedev;
+ struct tee_shm *shm;
+
+ if (!ctx)
+ return ERR_PTR(-EINVAL);
+
+ teedev = ctx->teedev;
+ mutex_lock(&teedev->mutex);
+ shm = idr_find(&teedev->idr, id);
+ if (!shm || shm->ctx != ctx)
+ shm = ERR_PTR(-EINVAL);
+ else if (shm->flags & TEE_SHM_DMA_BUF)
+ get_dma_buf(shm->dmabuf);
+ mutex_unlock(&teedev->mutex);
+ return shm;
+}
+EXPORT_SYMBOL_GPL(tee_shm_get_from_id);
+
+/**
+ * tee_shm_put() - Decrease reference count on a shared memory handle
+ * @shm: Shared memory handle
+ */
+void tee_shm_put(struct tee_shm *shm)
+{
+ if (shm->flags & TEE_SHM_DMA_BUF)
+ dma_buf_put(shm->dmabuf);
+}
+EXPORT_SYMBOL_GPL(tee_shm_put);
diff --git a/drivers/tee/tee_shm_pool.c b/drivers/tee/tee_shm_pool.c
new file mode 100644
index 0000000..e6d4b9e
--- /dev/null
+++ b/drivers/tee/tee_shm_pool.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/device.h>
+#include <linux/dma-buf.h>
+#include <linux/genalloc.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include "tee_private.h"
+
+static int pool_op_gen_alloc(struct tee_shm_pool_mgr *poolm,
+ struct tee_shm *shm, size_t size)
+{
+ unsigned long va;
+ struct gen_pool *genpool = poolm->private_data;
+ size_t s = roundup(size, 1 << genpool->min_alloc_order);
+
+ va = gen_pool_alloc(genpool, s);
+ if (!va)
+ return -ENOMEM;
+
+ memset((void *)va, 0, s);
+ shm->kaddr = (void *)va;
+ shm->paddr = gen_pool_virt_to_phys(genpool, va);
+ shm->size = s;
+ return 0;
+}
+
+static void pool_op_gen_free(struct tee_shm_pool_mgr *poolm,
+ struct tee_shm *shm)
+{
+ gen_pool_free(poolm->private_data, (unsigned long)shm->kaddr,
+ shm->size);
+ shm->kaddr = NULL;
+}
+
+static void pool_op_gen_destroy_poolmgr(struct tee_shm_pool_mgr *poolm)
+{
+ gen_pool_destroy(poolm->private_data);
+ kfree(poolm);
+}
+
+static const struct tee_shm_pool_mgr_ops pool_ops_generic = {
+ .alloc = pool_op_gen_alloc,
+ .free = pool_op_gen_free,
+ .destroy_poolmgr = pool_op_gen_destroy_poolmgr,
+};
+
+/**
+ * tee_shm_pool_alloc_res_mem() - Create a shared memory pool from reserved
+ * memory range
+ * @priv_info: Information for driver private shared memory pool
+ * @dmabuf_info: Information for dma-buf shared memory pool
+ *
+ * Start and end of pools will must be page aligned.
+ *
+ * Allocation with the flag TEE_SHM_DMA_BUF set will use the range supplied
+ * in @dmabuf, others will use the range provided by @priv.
+ *
+ * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure.
+ */
+struct tee_shm_pool *
+tee_shm_pool_alloc_res_mem(struct tee_shm_pool_mem_info *priv_info,
+ struct tee_shm_pool_mem_info *dmabuf_info)
+{
+ struct tee_shm_pool_mgr *priv_mgr;
+ struct tee_shm_pool_mgr *dmabuf_mgr;
+ void *rc;
+
+ /*
+ * Create the pool for driver private shared memory
+ */
+ rc = tee_shm_pool_mgr_alloc_res_mem(priv_info->vaddr, priv_info->paddr,
+ priv_info->size,
+ 3 /* 8 byte aligned */);
+ if (IS_ERR(rc))
+ return rc;
+ priv_mgr = rc;
+
+ /*
+ * Create the pool for dma_buf shared memory
+ */
+ rc = tee_shm_pool_mgr_alloc_res_mem(dmabuf_info->vaddr,
+ dmabuf_info->paddr,
+ dmabuf_info->size, PAGE_SHIFT);
+ if (IS_ERR(rc))
+ goto err_free_priv_mgr;
+ dmabuf_mgr = rc;
+
+ rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
+ if (IS_ERR(rc))
+ goto err_free_dmabuf_mgr;
+
+ return rc;
+
+err_free_dmabuf_mgr:
+ tee_shm_pool_mgr_destroy(dmabuf_mgr);
+err_free_priv_mgr:
+ tee_shm_pool_mgr_destroy(priv_mgr);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem);
+
+struct tee_shm_pool_mgr *tee_shm_pool_mgr_alloc_res_mem(unsigned long vaddr,
+ phys_addr_t paddr,
+ size_t size,
+ int min_alloc_order)
+{
+ const size_t page_mask = PAGE_SIZE - 1;
+ struct tee_shm_pool_mgr *mgr;
+ int rc;
+
+ /* Start and end must be page aligned */
+ if (vaddr & page_mask || paddr & page_mask || size & page_mask)
+ return ERR_PTR(-EINVAL);
+
+ mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
+ if (!mgr)
+ return ERR_PTR(-ENOMEM);
+
+ mgr->private_data = gen_pool_create(min_alloc_order, -1);
+ if (!mgr->private_data) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ gen_pool_set_algo(mgr->private_data, gen_pool_best_fit, NULL);
+ rc = gen_pool_add_virt(mgr->private_data, vaddr, paddr, size, -1);
+ if (rc) {
+ gen_pool_destroy(mgr->private_data);
+ goto err;
+ }
+
+ mgr->ops = &pool_ops_generic;
+
+ return mgr;
+err:
+ kfree(mgr);
+
+ return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(tee_shm_pool_mgr_alloc_res_mem);
+
+static bool check_mgr_ops(struct tee_shm_pool_mgr *mgr)
+{
+ return mgr && mgr->ops && mgr->ops->alloc && mgr->ops->free &&
+ mgr->ops->destroy_poolmgr;
+}
+
+struct tee_shm_pool *tee_shm_pool_alloc(struct tee_shm_pool_mgr *priv_mgr,
+ struct tee_shm_pool_mgr *dmabuf_mgr)
+{
+ struct tee_shm_pool *pool;
+
+ if (!check_mgr_ops(priv_mgr) || !check_mgr_ops(dmabuf_mgr))
+ return ERR_PTR(-EINVAL);
+
+ pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+ if (!pool)
+ return ERR_PTR(-ENOMEM);
+
+ pool->private_mgr = priv_mgr;
+ pool->dma_buf_mgr = dmabuf_mgr;
+
+ return pool;
+}
+EXPORT_SYMBOL_GPL(tee_shm_pool_alloc);
+
+/**
+ * tee_shm_pool_free() - Free a shared memory pool
+ * @pool: The shared memory pool to free
+ *
+ * There must be no remaining shared memory allocated from this pool when
+ * this function is called.
+ */
+void tee_shm_pool_free(struct tee_shm_pool *pool)
+{
+ if (pool->private_mgr)
+ tee_shm_pool_mgr_destroy(pool->private_mgr);
+ if (pool->dma_buf_mgr)
+ tee_shm_pool_mgr_destroy(pool->dma_buf_mgr);
+ kfree(pool);
+}
+EXPORT_SYMBOL_GPL(tee_shm_pool_free);
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 2db473a..51c9d0a 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -326,7 +326,7 @@
config INTEL_SOC_DTS_IOSF_CORE
tristate
- depends on X86
+ depends on X86 && PCI
select IOSF_MBI
help
This is becoming a common feature for Intel SoCs to expose the additional
@@ -336,7 +336,7 @@
config INTEL_SOC_DTS_THERMAL
tristate "Intel SoCs DTS thermal driver"
- depends on X86
+ depends on X86 && PCI
select INTEL_SOC_DTS_IOSF_CORE
select THERMAL_WRITABLE_TRIPS
help
diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c
index c5285ed..2d855a9 100644
--- a/drivers/thermal/hisi_thermal.c
+++ b/drivers/thermal/hisi_thermal.c
@@ -23,243 +23,450 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/of_device.h>
#include "thermal_core.h"
-#define TEMP0_TH (0x4)
-#define TEMP0_RST_TH (0x8)
-#define TEMP0_CFG (0xC)
-#define TEMP0_EN (0x10)
-#define TEMP0_INT_EN (0x14)
-#define TEMP0_INT_CLR (0x18)
-#define TEMP0_RST_MSK (0x1C)
-#define TEMP0_VALUE (0x28)
+#define HI6220_TEMP0_LAG (0x0)
+#define HI6220_TEMP0_TH (0x4)
+#define HI6220_TEMP0_RST_TH (0x8)
+#define HI6220_TEMP0_CFG (0xC)
+#define HI6220_TEMP0_CFG_SS_MSK (0xF000)
+#define HI6220_TEMP0_CFG_HDAK_MSK (0x30)
+#define HI6220_TEMP0_EN (0x10)
+#define HI6220_TEMP0_INT_EN (0x14)
+#define HI6220_TEMP0_INT_CLR (0x18)
+#define HI6220_TEMP0_RST_MSK (0x1C)
+#define HI6220_TEMP0_VALUE (0x28)
-#define HISI_TEMP_BASE (-60000)
-#define HISI_TEMP_RESET (100000)
-#define HISI_TEMP_STEP (784)
+#define HI3660_OFFSET(chan) ((chan) * 0x40)
+#define HI3660_TEMP(chan) (HI3660_OFFSET(chan) + 0x1C)
+#define HI3660_TH(chan) (HI3660_OFFSET(chan) + 0x20)
+#define HI3660_LAG(chan) (HI3660_OFFSET(chan) + 0x28)
+#define HI3660_INT_EN(chan) (HI3660_OFFSET(chan) + 0x2C)
+#define HI3660_INT_CLR(chan) (HI3660_OFFSET(chan) + 0x30)
-#define HISI_MAX_SENSORS 4
+#define HI6220_TEMP_BASE (-60000)
+#define HI6220_TEMP_RESET (100000)
+#define HI6220_TEMP_STEP (785)
+#define HI6220_TEMP_LAG (3500)
+
+#define HI3660_TEMP_BASE (-63780)
+#define HI3660_TEMP_STEP (205)
+#define HI3660_TEMP_LAG (4000)
+
+#define HI6220_DEFAULT_SENSOR 2
+#define HI3660_DEFAULT_SENSOR 1
struct hisi_thermal_sensor {
- struct hisi_thermal_data *thermal;
struct thermal_zone_device *tzd;
-
- long sensor_temp;
uint32_t id;
uint32_t thres_temp;
};
struct hisi_thermal_data {
- struct mutex thermal_lock; /* protects register data */
+ int (*get_temp)(struct hisi_thermal_data *data);
+ int (*enable_sensor)(struct hisi_thermal_data *data);
+ int (*disable_sensor)(struct hisi_thermal_data *data);
+ int (*irq_handler)(struct hisi_thermal_data *data);
struct platform_device *pdev;
struct clk *clk;
- struct hisi_thermal_sensor sensors[HISI_MAX_SENSORS];
-
- int irq, irq_bind_sensor;
- bool irq_enabled;
-
+ struct hisi_thermal_sensor sensor;
void __iomem *regs;
+ int irq;
};
/*
* The temperature computation on the tsensor is as follow:
* Unit: millidegree Celsius
- * Step: 255/200 (0.7843)
+ * Step: 200/255 (0.7843)
* Temperature base: -60°C
*
- * The register is programmed in temperature steps, every step is 784
+ * The register is programmed in temperature steps, every step is 785
* millidegree and begins at -60 000 m°C
*
* The temperature from the steps:
*
- * Temp = TempBase + (steps x 784)
+ * Temp = TempBase + (steps x 785)
*
* and the steps from the temperature:
*
- * steps = (Temp - TempBase) / 784
+ * steps = (Temp - TempBase) / 785
*
*/
-static inline int hisi_thermal_step_to_temp(int step)
+static inline int hi6220_thermal_step_to_temp(int step)
{
- return HISI_TEMP_BASE + (step * HISI_TEMP_STEP);
+ return HI6220_TEMP_BASE + (step * HI6220_TEMP_STEP);
}
-static inline long hisi_thermal_temp_to_step(long temp)
+static inline int hi6220_thermal_temp_to_step(int temp)
{
- return (temp - HISI_TEMP_BASE) / HISI_TEMP_STEP;
+ return DIV_ROUND_UP(temp - HI6220_TEMP_BASE, HI6220_TEMP_STEP);
}
-static inline long hisi_thermal_round_temp(int temp)
+/*
+ * for Hi3660,
+ * Step: 189/922 (0.205)
+ * Temperature base: -63.780°C
+ *
+ * The register is programmed in temperature steps, every step is 205
+ * millidegree and begins at -63 780 m°C
+ */
+static inline int hi3660_thermal_step_to_temp(int step)
{
- return hisi_thermal_step_to_temp(
- hisi_thermal_temp_to_step(temp));
+ return HI3660_TEMP_BASE + step * HI3660_TEMP_STEP;
}
-static long hisi_thermal_get_sensor_temp(struct hisi_thermal_data *data,
- struct hisi_thermal_sensor *sensor)
+static inline int hi3660_thermal_temp_to_step(int temp)
{
- long val;
-
- mutex_lock(&data->thermal_lock);
-
- /* disable interrupt */
- writel(0x0, data->regs + TEMP0_INT_EN);
- writel(0x1, data->regs + TEMP0_INT_CLR);
-
- /* disable module firstly */
- writel(0x0, data->regs + TEMP0_EN);
-
- /* select sensor id */
- writel((sensor->id << 12), data->regs + TEMP0_CFG);
-
- /* enable module */
- writel(0x1, data->regs + TEMP0_EN);
-
- usleep_range(3000, 5000);
-
- val = readl(data->regs + TEMP0_VALUE);
- val = hisi_thermal_step_to_temp(val);
-
- mutex_unlock(&data->thermal_lock);
-
- return val;
+ return DIV_ROUND_UP(temp - HI3660_TEMP_BASE, HI3660_TEMP_STEP);
}
-static void hisi_thermal_enable_bind_irq_sensor
- (struct hisi_thermal_data *data)
+/*
+ * The lag register contains 5 bits encoding the temperature in steps.
+ *
+ * Each time the temperature crosses the threshold boundary, an
+ * interrupt is raised. It could be when the temperature is going
+ * above the threshold or below. However, if the temperature is
+ * fluctuating around this value due to the load, we can receive
+ * several interrupts which may not desired.
+ *
+ * We can setup a temperature representing the delta between the
+ * threshold and the current temperature when the temperature is
+ * decreasing.
+ *
+ * For instance: the lag register is 5°C, the threshold is 65°C, when
+ * the temperature reaches 65°C an interrupt is raised and when the
+ * temperature decrease to 65°C - 5°C another interrupt is raised.
+ *
+ * A very short lag can lead to an interrupt storm, a long lag
+ * increase the latency to react to the temperature changes. In our
+ * case, that is not really a problem as we are polling the
+ * temperature.
+ *
+ * [0:4] : lag register
+ *
+ * The temperature is coded in steps, cf. HI6220_TEMP_STEP.
+ *
+ * Min : 0x00 : 0.0 °C
+ * Max : 0x1F : 24.3 °C
+ *
+ * The 'value' parameter is in milliCelsius.
+ */
+static inline void hi6220_thermal_set_lag(void __iomem *addr, int value)
{
- struct hisi_thermal_sensor *sensor;
-
- mutex_lock(&data->thermal_lock);
-
- sensor = &data->sensors[data->irq_bind_sensor];
-
- /* setting the hdak time */
- writel(0x0, data->regs + TEMP0_CFG);
-
- /* disable module firstly */
- writel(0x0, data->regs + TEMP0_RST_MSK);
- writel(0x0, data->regs + TEMP0_EN);
-
- /* select sensor id */
- writel((sensor->id << 12), data->regs + TEMP0_CFG);
-
- /* enable for interrupt */
- writel(hisi_thermal_temp_to_step(sensor->thres_temp) | 0x0FFFFFF00,
- data->regs + TEMP0_TH);
-
- writel(hisi_thermal_temp_to_step(HISI_TEMP_RESET),
- data->regs + TEMP0_RST_TH);
-
- /* enable module */
- writel(0x1, data->regs + TEMP0_RST_MSK);
- writel(0x1, data->regs + TEMP0_EN);
-
- writel(0x0, data->regs + TEMP0_INT_CLR);
- writel(0x1, data->regs + TEMP0_INT_EN);
-
- usleep_range(3000, 5000);
-
- mutex_unlock(&data->thermal_lock);
+ writel(DIV_ROUND_UP(value, HI6220_TEMP_STEP) & 0x1F,
+ addr + HI6220_TEMP0_LAG);
}
-static void hisi_thermal_disable_sensor(struct hisi_thermal_data *data)
+static inline void hi6220_thermal_alarm_clear(void __iomem *addr, int value)
{
- mutex_lock(&data->thermal_lock);
+ writel(value, addr + HI6220_TEMP0_INT_CLR);
+}
+static inline void hi6220_thermal_alarm_enable(void __iomem *addr, int value)
+{
+ writel(value, addr + HI6220_TEMP0_INT_EN);
+}
+
+static inline void hi6220_thermal_alarm_set(void __iomem *addr, int temp)
+{
+ writel(hi6220_thermal_temp_to_step(temp) | 0x0FFFFFF00,
+ addr + HI6220_TEMP0_TH);
+}
+
+static inline void hi6220_thermal_reset_set(void __iomem *addr, int temp)
+{
+ writel(hi6220_thermal_temp_to_step(temp), addr + HI6220_TEMP0_RST_TH);
+}
+
+static inline void hi6220_thermal_reset_enable(void __iomem *addr, int value)
+{
+ writel(value, addr + HI6220_TEMP0_RST_MSK);
+}
+
+static inline void hi6220_thermal_enable(void __iomem *addr, int value)
+{
+ writel(value, addr + HI6220_TEMP0_EN);
+}
+
+static inline int hi6220_thermal_get_temperature(void __iomem *addr)
+{
+ return hi6220_thermal_step_to_temp(readl(addr + HI6220_TEMP0_VALUE));
+}
+
+/*
+ * [0:6] lag register
+ *
+ * The temperature is coded in steps, cf. HI3660_TEMP_STEP.
+ *
+ * Min : 0x00 : 0.0 °C
+ * Max : 0x7F : 26.0 °C
+ *
+ */
+static inline void hi3660_thermal_set_lag(void __iomem *addr,
+ int id, int value)
+{
+ writel(DIV_ROUND_UP(value, HI3660_TEMP_STEP) & 0x7F,
+ addr + HI3660_LAG(id));
+}
+
+static inline void hi3660_thermal_alarm_clear(void __iomem *addr,
+ int id, int value)
+{
+ writel(value, addr + HI3660_INT_CLR(id));
+}
+
+static inline void hi3660_thermal_alarm_enable(void __iomem *addr,
+ int id, int value)
+{
+ writel(value, addr + HI3660_INT_EN(id));
+}
+
+static inline void hi3660_thermal_alarm_set(void __iomem *addr,
+ int id, int value)
+{
+ writel(value, addr + HI3660_TH(id));
+}
+
+static inline int hi3660_thermal_get_temperature(void __iomem *addr, int id)
+{
+ return hi3660_thermal_step_to_temp(readl(addr + HI3660_TEMP(id)));
+}
+
+/*
+ * Temperature configuration register - Sensor selection
+ *
+ * Bits [19:12]
+ *
+ * 0x0: local sensor (default)
+ * 0x1: remote sensor 1 (ACPU cluster 1)
+ * 0x2: remote sensor 2 (ACPU cluster 0)
+ * 0x3: remote sensor 3 (G3D)
+ */
+static inline void hi6220_thermal_sensor_select(void __iomem *addr, int sensor)
+{
+ writel((readl(addr + HI6220_TEMP0_CFG) & ~HI6220_TEMP0_CFG_SS_MSK) |
+ (sensor << 12), addr + HI6220_TEMP0_CFG);
+}
+
+/*
+ * Temperature configuration register - Hdak conversion polling interval
+ *
+ * Bits [5:4]
+ *
+ * 0x0 : 0.768 ms
+ * 0x1 : 6.144 ms
+ * 0x2 : 49.152 ms
+ * 0x3 : 393.216 ms
+ */
+static inline void hi6220_thermal_hdak_set(void __iomem *addr, int value)
+{
+ writel((readl(addr + HI6220_TEMP0_CFG) & ~HI6220_TEMP0_CFG_HDAK_MSK) |
+ (value << 4), addr + HI6220_TEMP0_CFG);
+}
+
+static int hi6220_thermal_irq_handler(struct hisi_thermal_data *data)
+{
+ hi6220_thermal_alarm_clear(data->regs, 1);
+ return 0;
+}
+
+static int hi3660_thermal_irq_handler(struct hisi_thermal_data *data)
+{
+ hi3660_thermal_alarm_clear(data->regs, data->sensor.id, 1);
+ return 0;
+}
+
+static int hi6220_thermal_get_temp(struct hisi_thermal_data *data)
+{
+ return hi6220_thermal_get_temperature(data->regs);
+}
+
+static int hi3660_thermal_get_temp(struct hisi_thermal_data *data)
+{
+ return hi3660_thermal_get_temperature(data->regs, data->sensor.id);
+}
+
+static int hi6220_thermal_disable_sensor(struct hisi_thermal_data *data)
+{
/* disable sensor module */
- writel(0x0, data->regs + TEMP0_INT_EN);
- writel(0x0, data->regs + TEMP0_RST_MSK);
- writel(0x0, data->regs + TEMP0_EN);
+ hi6220_thermal_enable(data->regs, 0);
+ hi6220_thermal_alarm_enable(data->regs, 0);
+ hi6220_thermal_reset_enable(data->regs, 0);
- mutex_unlock(&data->thermal_lock);
-}
-
-static int hisi_thermal_get_temp(void *_sensor, int *temp)
-{
- struct hisi_thermal_sensor *sensor = _sensor;
- struct hisi_thermal_data *data = sensor->thermal;
-
- int sensor_id = -1, i;
- long max_temp = 0;
-
- *temp = hisi_thermal_get_sensor_temp(data, sensor);
-
- sensor->sensor_temp = *temp;
-
- for (i = 0; i < HISI_MAX_SENSORS; i++) {
- if (!data->sensors[i].tzd)
- continue;
-
- if (data->sensors[i].sensor_temp >= max_temp) {
- max_temp = data->sensors[i].sensor_temp;
- sensor_id = i;
- }
- }
-
- /* If no sensor has been enabled, then skip to enable irq */
- if (sensor_id == -1)
- return 0;
-
- mutex_lock(&data->thermal_lock);
- data->irq_bind_sensor = sensor_id;
- mutex_unlock(&data->thermal_lock);
-
- dev_dbg(&data->pdev->dev, "id=%d, irq=%d, temp=%d, thres=%d\n",
- sensor->id, data->irq_enabled, *temp, sensor->thres_temp);
- /*
- * Bind irq to sensor for two cases:
- * Reenable alarm IRQ if temperature below threshold;
- * if irq has been enabled, always set it;
- */
- if (data->irq_enabled) {
- hisi_thermal_enable_bind_irq_sensor(data);
- return 0;
- }
-
- if (max_temp < sensor->thres_temp) {
- data->irq_enabled = true;
- hisi_thermal_enable_bind_irq_sensor(data);
- enable_irq(data->irq);
- }
+ clk_disable_unprepare(data->clk);
return 0;
}
-static struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
+static int hi3660_thermal_disable_sensor(struct hisi_thermal_data *data)
+{
+ /* disable sensor module */
+ hi3660_thermal_alarm_enable(data->regs, data->sensor.id, 0);
+ return 0;
+}
+
+static int hi6220_thermal_enable_sensor(struct hisi_thermal_data *data)
+{
+ struct hisi_thermal_sensor *sensor = &data->sensor;
+ int ret;
+
+ /* enable clock for tsensor */
+ ret = clk_prepare_enable(data->clk);
+ if (ret)
+ return ret;
+
+ /* disable module firstly */
+ hi6220_thermal_reset_enable(data->regs, 0);
+ hi6220_thermal_enable(data->regs, 0);
+
+ /* select sensor id */
+ hi6220_thermal_sensor_select(data->regs, sensor->id);
+
+ /* setting the hdak time */
+ hi6220_thermal_hdak_set(data->regs, 0);
+
+ /* setting lag value between current temp and the threshold */
+ hi6220_thermal_set_lag(data->regs, HI6220_TEMP_LAG);
+
+ /* enable for interrupt */
+ hi6220_thermal_alarm_set(data->regs, sensor->thres_temp);
+
+ hi6220_thermal_reset_set(data->regs, HI6220_TEMP_RESET);
+
+ /* enable module */
+ hi6220_thermal_reset_enable(data->regs, 1);
+ hi6220_thermal_enable(data->regs, 1);
+
+ hi6220_thermal_alarm_clear(data->regs, 0);
+ hi6220_thermal_alarm_enable(data->regs, 1);
+
+ return 0;
+}
+
+static int hi3660_thermal_enable_sensor(struct hisi_thermal_data *data)
+{
+ unsigned int value;
+ struct hisi_thermal_sensor *sensor = &data->sensor;
+
+ /* disable interrupt */
+ hi3660_thermal_alarm_enable(data->regs, sensor->id, 0);
+
+ /* setting lag value between current temp and the threshold */
+ hi3660_thermal_set_lag(data->regs, sensor->id, HI3660_TEMP_LAG);
+
+ /* set interrupt threshold */
+ value = hi3660_thermal_temp_to_step(sensor->thres_temp);
+ hi3660_thermal_alarm_set(data->regs, sensor->id, value);
+
+ /* enable interrupt */
+ hi3660_thermal_alarm_clear(data->regs, sensor->id, 1);
+ hi3660_thermal_alarm_enable(data->regs, sensor->id, 1);
+
+ return 0;
+}
+
+static int hi6220_thermal_probe(struct hisi_thermal_data *data)
+{
+ struct platform_device *pdev = data->pdev;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int ret;
+
+ data->get_temp = hi6220_thermal_get_temp;
+ data->enable_sensor = hi6220_thermal_enable_sensor;
+ data->disable_sensor = hi6220_thermal_disable_sensor;
+ data->irq_handler = hi6220_thermal_irq_handler;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(data->regs)) {
+ dev_err(dev, "failed to get io address\n");
+ return PTR_ERR(data->regs);
+ }
+
+ data->clk = devm_clk_get(dev, "thermal_clk");
+ if (IS_ERR(data->clk)) {
+ ret = PTR_ERR(data->clk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get thermal clk: %d\n", ret);
+ return ret;
+ }
+
+ data->irq = platform_get_irq(pdev, 0);
+ if (data->irq < 0)
+ return data->irq;
+
+ data->sensor.id = HI6220_DEFAULT_SENSOR;
+
+ return 0;
+}
+
+static int hi3660_thermal_probe(struct hisi_thermal_data *data)
+{
+ struct platform_device *pdev = data->pdev;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+
+ data->get_temp = hi3660_thermal_get_temp;
+ data->enable_sensor = hi3660_thermal_enable_sensor;
+ data->disable_sensor = hi3660_thermal_disable_sensor;
+ data->irq_handler = hi3660_thermal_irq_handler;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(data->regs)) {
+ dev_err(dev, "failed to get io address\n");
+ return PTR_ERR(data->regs);
+ }
+
+ data->irq = platform_get_irq(pdev, 0);
+ if (data->irq < 0)
+ return data->irq;
+
+ data->sensor.id = HI3660_DEFAULT_SENSOR;
+
+ return 0;
+}
+
+static int hisi_thermal_get_temp(void *__data, int *temp)
+{
+ struct hisi_thermal_data *data = __data;
+ struct hisi_thermal_sensor *sensor = &data->sensor;
+
+ *temp = data->get_temp(data);
+
+ dev_dbg(&data->pdev->dev, "id=%d, temp=%d, thres=%d\n",
+ sensor->id, *temp, sensor->thres_temp);
+
+ return 0;
+}
+
+static const struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
.get_temp = hisi_thermal_get_temp,
};
-static irqreturn_t hisi_thermal_alarm_irq(int irq, void *dev)
-{
- struct hisi_thermal_data *data = dev;
-
- disable_irq_nosync(irq);
- data->irq_enabled = false;
-
- return IRQ_WAKE_THREAD;
-}
-
static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
{
struct hisi_thermal_data *data = dev;
- struct hisi_thermal_sensor *sensor;
- int i;
+ struct hisi_thermal_sensor *sensor = &data->sensor;
+ int temp = 0;
- mutex_lock(&data->thermal_lock);
- sensor = &data->sensors[data->irq_bind_sensor];
+ data->irq_handler(data);
- dev_crit(&data->pdev->dev, "THERMAL ALARM: T > %d\n",
- sensor->thres_temp);
- mutex_unlock(&data->thermal_lock);
+ hisi_thermal_get_temp(data, &temp);
- for (i = 0; i < HISI_MAX_SENSORS; i++) {
- if (!data->sensors[i].tzd)
- continue;
+ if (temp >= sensor->thres_temp) {
+ dev_crit(&data->pdev->dev, "THERMAL ALARM: %d > %d\n",
+ temp, sensor->thres_temp);
- thermal_zone_device_update(data->sensors[i].tzd,
+ thermal_zone_device_update(data->sensor.tzd,
THERMAL_EVENT_UNSPECIFIED);
+
+ } else {
+ dev_crit(&data->pdev->dev, "THERMAL ALARM stopped: %d < %d\n",
+ temp, sensor->thres_temp);
}
return IRQ_HANDLED;
@@ -267,17 +474,14 @@
static int hisi_thermal_register_sensor(struct platform_device *pdev,
struct hisi_thermal_data *data,
- struct hisi_thermal_sensor *sensor,
- int index)
+ struct hisi_thermal_sensor *sensor)
{
int ret, i;
const struct thermal_trip *trip;
- sensor->id = index;
- sensor->thermal = data;
-
sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
- sensor->id, sensor, &hisi_of_thermal_ops);
+ sensor->id, data,
+ &hisi_of_thermal_ops);
if (IS_ERR(sensor->tzd)) {
ret = PTR_ERR(sensor->tzd);
sensor->tzd = NULL;
@@ -290,7 +494,7 @@
for (i = 0; i < of_thermal_get_ntrips(sensor->tzd); i++) {
if (trip[i].type == THERMAL_TRIP_PASSIVE) {
- sensor->thres_temp = hisi_thermal_round_temp(trip[i].temperature);
+ sensor->thres_temp = trip[i].temperature;
break;
}
}
@@ -299,7 +503,14 @@
}
static const struct of_device_id of_hisi_thermal_match[] = {
- { .compatible = "hisilicon,tsensor" },
+ {
+ .compatible = "hisilicon,tsensor",
+ .data = hi6220_thermal_probe
+ },
+ {
+ .compatible = "hisilicon,hi3660-tsensor",
+ .data = hi3660_thermal_probe
+ },
{ /* end */ }
};
MODULE_DEVICE_TABLE(of, of_hisi_thermal_match);
@@ -316,69 +527,51 @@
static int hisi_thermal_probe(struct platform_device *pdev)
{
struct hisi_thermal_data *data;
- struct resource *res;
- int i;
+ int const (*platform_probe)(struct hisi_thermal_data *);
+ struct device *dev = &pdev->dev;
int ret;
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- mutex_init(&data->thermal_lock);
data->pdev = pdev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- data->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(data->regs)) {
- dev_err(&pdev->dev, "failed to get io address\n");
- return PTR_ERR(data->regs);
- }
-
- data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0)
- return data->irq;
-
platform_set_drvdata(pdev, data);
- data->clk = devm_clk_get(&pdev->dev, "thermal_clk");
- if (IS_ERR(data->clk)) {
- ret = PTR_ERR(data->clk);
- if (ret != -EPROBE_DEFER)
- dev_err(&pdev->dev,
- "failed to get thermal clk: %d\n", ret);
- return ret;
+ platform_probe = of_device_get_match_data(dev);
+ if (!platform_probe) {
+ dev_err(dev, "failed to get probe func\n");
+ return -EINVAL;
}
- /* enable clock for thermal */
- ret = clk_prepare_enable(data->clk);
+ ret = platform_probe(data);
+ if (ret)
+ return ret;
+
+ ret = hisi_thermal_register_sensor(pdev, data,
+ &data->sensor);
if (ret) {
- dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
+ dev_err(dev, "failed to register thermal sensor: %d\n", ret);
return ret;
}
- hisi_thermal_enable_bind_irq_sensor(data);
- data->irq_enabled = true;
-
- for (i = 0; i < HISI_MAX_SENSORS; ++i) {
- ret = hisi_thermal_register_sensor(pdev, data,
- &data->sensors[i], i);
- if (ret)
- dev_err(&pdev->dev,
- "failed to register thermal sensor: %d\n", ret);
- else
- hisi_thermal_toggle_sensor(&data->sensors[i], true);
- }
-
- ret = devm_request_threaded_irq(&pdev->dev, data->irq,
- hisi_thermal_alarm_irq,
- hisi_thermal_alarm_irq_thread,
- 0, "hisi_thermal", data);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
+ ret = data->enable_sensor(data);
+ if (ret) {
+ dev_err(dev, "Failed to setup the sensor: %d\n", ret);
return ret;
}
- enable_irq(data->irq);
+ if (data->irq) {
+ ret = devm_request_threaded_irq(dev, data->irq, NULL,
+ hisi_thermal_alarm_irq_thread,
+ IRQF_ONESHOT, "hisi_thermal", data);
+ if (ret < 0) {
+ dev_err(dev, "failed to request alarm irq: %d\n", ret);
+ return ret;
+ }
+ }
+
+ hisi_thermal_toggle_sensor(&data->sensor, true);
return 0;
}
@@ -386,19 +579,11 @@
static int hisi_thermal_remove(struct platform_device *pdev)
{
struct hisi_thermal_data *data = platform_get_drvdata(pdev);
- int i;
+ struct hisi_thermal_sensor *sensor = &data->sensor;
- for (i = 0; i < HISI_MAX_SENSORS; i++) {
- struct hisi_thermal_sensor *sensor = &data->sensors[i];
+ hisi_thermal_toggle_sensor(sensor, false);
- if (!sensor->tzd)
- continue;
-
- hisi_thermal_toggle_sensor(sensor, false);
- }
-
- hisi_thermal_disable_sensor(data);
- clk_disable_unprepare(data->clk);
+ data->disable_sensor(data);
return 0;
}
@@ -408,10 +593,7 @@
{
struct hisi_thermal_data *data = dev_get_drvdata(dev);
- hisi_thermal_disable_sensor(data);
- data->irq_enabled = false;
-
- clk_disable_unprepare(data->clk);
+ data->disable_sensor(data);
return 0;
}
@@ -419,16 +601,8 @@
static int hisi_thermal_resume(struct device *dev)
{
struct hisi_thermal_data *data = dev_get_drvdata(dev);
- int ret;
- ret = clk_prepare_enable(data->clk);
- if (ret)
- return ret;
-
- data->irq_enabled = true;
- hisi_thermal_enable_bind_irq_sensor(data);
-
- return 0;
+ return data->enable_sensor(data);
}
#endif
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index bb5f706..c662cd7 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -430,7 +430,16 @@
if (trip >= data->ntrips || trip < 0)
return -EDOM;
- *temp = data->trips[trip].temperature;
+ if (data->senps && data->senps->ops->get_trip_temp) {
+ int ret;
+
+ ret = data->senps->ops->get_trip_temp(data->senps->sensor_data,
+ trip, temp);
+ if (ret)
+ return ret;
+ } else {
+ *temp = data->trips[trip].temperature;
+ }
return 0;
}
diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
index e7d6241..8085606 100644
--- a/drivers/thermal/qcom/Kconfig
+++ b/drivers/thermal/qcom/Kconfig
@@ -71,3 +71,24 @@
voltage.
If you want this support, you should say Y here.
+
+config QTI_BCL_PMIC5
+ bool "BCL driver for BCL peripherals in PMIC5"
+ depends on SPMI && THERMAL_OF
+ help
+ Say Y here to enable this BCL driver for PMIC5. This driver
+ provides routines to configure and monitor the BCL
+ PMIC peripheral. This driver registers the battery current and
+ voltage sensors with the thermal core framework and can take
+ threshold input and notify the thermal core when the threshold is
+ reached.
+
+config QTI_BCL_SOC_DRIVER
+ bool "QTI Battery state of charge sensor driver"
+ depends on THERMAL_OF
+ help
+ This driver registers battery state of charge as a sensor with
+ thermal zone. This sensor can monitor for state of charge
+ threshold and notify the thermal framework.
+
+ If you want this support, you should say Y here.
diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
index 257b714..8387285 100644
--- a/drivers/thermal/qcom/Makefile
+++ b/drivers/thermal/qcom/Makefile
@@ -6,3 +6,5 @@
obj-$(CONFIG_QTI_AOP_REG_COOLING_DEVICE) += regulator_aop_cdev.o
obj-$(CONFIG_REGULATOR_COOLING_DEVICE) += regulator_cdev.o
obj-$(CONFIG_QTI_QMI_COOLING_DEVICE) += thermal_mitigation_device_service_v01.o qmi_cooling.o
+obj-$(CONFIG_QTI_BCL_PMIC5) += bcl_pmic5.o
+obj-$(CONFIG_QTI_BCL_SOC_DRIVER) += bcl_soc.o
diff --git a/drivers/thermal/qcom/bcl_pmic5.c b/drivers/thermal/qcom/bcl_pmic5.c
new file mode 100644
index 0000000..146d09d
--- /dev/null
+++ b/drivers/thermal/qcom/bcl_pmic5.c
@@ -0,0 +1,609 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+#define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/kernel.h>
+#include <linux/regmap.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spmi.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/thermal.h>
+
+#include "../thermal_core.h"
+
+#define BCL_DRIVER_NAME "bcl_pmic5"
+#define BCL_MONITOR_EN 0x46
+#define BCL_IRQ_STATUS 0x09
+
+#define BCL_IBAT_HIGH 0x4B
+#define BCL_IBAT_TOO_HIGH 0x4C
+#define BCL_IBAT_READ 0x86
+#define BCL_IBAT_SCALING_UA 78127
+
+#define BCL_VBAT_READ 0x76
+#define BCL_VBAT_ADC_LOW 0x48
+#define BCL_VBAT_COMP_LOW 0x49
+#define BCL_VBAT_COMP_TLOW 0x4A
+
+#define BCL_IRQ_VCMP_L0 0x1
+#define BCL_IRQ_VCMP_L1 0x2
+#define BCL_IRQ_VCMP_L2 0x4
+#define BCL_IRQ_IBAT_L0 0x10
+#define BCL_IRQ_IBAT_L1 0x20
+#define BCL_IRQ_IBAT_L2 0x40
+
+#define BCL_VBAT_SCALING_UV 49827
+#define BCL_VBAT_NO_READING 127
+#define BCL_VBAT_BASE_MV 2000
+#define BCL_VBAT_INC_MV 25
+#define BCL_VBAT_MAX_MV 3600
+
+enum bcl_dev_type {
+ BCL_IBAT_LVL0,
+ BCL_IBAT_LVL1,
+ BCL_VBAT_LVL0,
+ BCL_VBAT_LVL1,
+ BCL_VBAT_LVL2,
+ BCL_TYPE_MAX,
+};
+
+static char bcl_int_names[BCL_TYPE_MAX][25] = {
+ "bcl-ibat-lvl0",
+ "bcl-ibat-lvl1",
+ "bcl-vbat-lvl0",
+ "bcl-vbat-lvl1",
+ "bcl-vbat-lvl2",
+};
+
+struct bcl_peripheral_data {
+ int irq_num;
+ long int trip_thresh;
+ int last_val;
+ struct mutex state_trans_lock;
+ bool irq_enabled;
+ enum bcl_dev_type type;
+ struct thermal_zone_of_device_ops ops;
+ struct thermal_zone_device *tz_dev;
+};
+
+struct bcl_device {
+ struct regmap *regmap;
+ uint16_t fg_bcl_addr;
+ struct bcl_peripheral_data param[BCL_TYPE_MAX];
+};
+
+static struct bcl_device *bcl_perph;
+
+static int bcl_read_register(int16_t reg_offset, unsigned int *data)
+{
+ int ret = 0;
+
+ if (!bcl_perph) {
+ pr_err("BCL device not initialized\n");
+ return -EINVAL;
+ }
+ ret = regmap_read(bcl_perph->regmap,
+ (bcl_perph->fg_bcl_addr + reg_offset),
+ data);
+ if (ret < 0)
+ pr_err("Error reading register %d. err:%d\n",
+ reg_offset, ret);
+
+ return ret;
+}
+
+static int bcl_write_general_register(int16_t reg_offset,
+ uint16_t base, uint8_t data)
+{
+ int ret = 0;
+ uint8_t *write_buf = &data;
+
+ if (!bcl_perph) {
+ pr_err("BCL device not initialized\n");
+ return -EINVAL;
+ }
+ ret = regmap_write(bcl_perph->regmap, (base + reg_offset), *write_buf);
+ if (ret < 0) {
+ pr_err("Error reading register %d. err:%d\n",
+ reg_offset, ret);
+ return ret;
+ }
+ pr_debug("wrote 0x%02x to 0x%04x\n", data, base + reg_offset);
+
+ return ret;
+}
+
+static int bcl_write_register(int16_t reg_offset, uint8_t data)
+{
+ return bcl_write_general_register(reg_offset,
+ bcl_perph->fg_bcl_addr, data);
+}
+
+static void convert_adc_to_vbat_thresh_val(int *val)
+{
+ /*
+ * Threshold register is bit shifted from ADC MSB.
+ * So the scaling factor is half.
+ */
+ *val = (*val * BCL_VBAT_SCALING_UV) / 2000;
+}
+
+static void convert_adc_to_vbat_val(int *val)
+{
+ *val = (*val * BCL_VBAT_SCALING_UV) / 1000;
+}
+
+static void convert_ibat_to_adc_val(int *val)
+{
+ /*
+ * Threshold register is bit shifted from ADC MSB.
+ * So the scaling factor is half.
+ */
+ *val = (*val * 2000) / BCL_IBAT_SCALING_UA;
+}
+
+static void convert_adc_to_ibat_val(int *val)
+{
+ *val = (*val * BCL_IBAT_SCALING_UA) / 1000;
+}
+
+static int bcl_set_ibat(void *data, int low, int high)
+{
+ int ret = 0, ibat_ua, thresh_value;
+ int8_t val = 0;
+ int16_t addr;
+ struct bcl_peripheral_data *bat_data =
+ (struct bcl_peripheral_data *)data;
+
+ mutex_lock(&bat_data->state_trans_lock);
+ thresh_value = high;
+ if (bat_data->trip_thresh == thresh_value)
+ goto set_trip_exit;
+
+ if (bat_data->irq_num && bat_data->irq_enabled) {
+ disable_irq_nosync(bat_data->irq_num);
+ bat_data->irq_enabled = false;
+ }
+ if (thresh_value == INT_MAX) {
+ bat_data->trip_thresh = thresh_value;
+ goto set_trip_exit;
+ }
+
+ ibat_ua = thresh_value;
+ convert_ibat_to_adc_val(&thresh_value);
+ val = (int8_t)thresh_value;
+ if (&bcl_perph->param[BCL_IBAT_LVL0] == bat_data) {
+ addr = BCL_IBAT_HIGH;
+ pr_debug("ibat high threshold:%d mA ADC:0x%02x\n",
+ ibat_ua, val);
+ } else if (&bcl_perph->param[BCL_IBAT_LVL1] == bat_data) {
+ addr = BCL_IBAT_TOO_HIGH;
+ pr_debug("ibat too high threshold:%d mA ADC:0x%02x\n",
+ ibat_ua, val);
+ } else {
+ goto set_trip_exit;
+ }
+ ret = bcl_write_register(addr, val);
+ if (ret)
+ goto set_trip_exit;
+ bat_data->trip_thresh = ibat_ua;
+
+ if (bat_data->irq_num && !bat_data->irq_enabled) {
+ enable_irq(bat_data->irq_num);
+ bat_data->irq_enabled = true;
+ }
+
+set_trip_exit:
+ mutex_unlock(&bat_data->state_trans_lock);
+
+ return ret;
+}
+
+static int bcl_read_ibat(void *data, int *adc_value)
+{
+ int ret = 0;
+ unsigned int val = 0;
+ struct bcl_peripheral_data *bat_data =
+ (struct bcl_peripheral_data *)data;
+
+ *adc_value = val;
+ ret = bcl_read_register(BCL_IBAT_READ, &val);
+ if (ret)
+ goto bcl_read_exit;
+ /* IBat ADC reading is in 2's compliment form */
+ *adc_value = sign_extend32(val, 7);
+ if (val == 0) {
+ /*
+ * The sensor sometime can read a value 0 if there is
+ * consequtive reads
+ */
+ *adc_value = bat_data->last_val;
+ } else {
+ convert_adc_to_ibat_val(adc_value);
+ bat_data->last_val = *adc_value;
+ }
+ pr_debug("ibat:%d mA ADC:0x%02x\n", bat_data->last_val, val);
+
+bcl_read_exit:
+ return ret;
+}
+
+static int bcl_get_vbat_trip(void *data, int type, int *trip)
+{
+ int ret = 0;
+ unsigned int val = 0;
+ struct bcl_peripheral_data *bat_data =
+ (struct bcl_peripheral_data *)data;
+ int16_t addr;
+
+ *trip = 0;
+ if (&bcl_perph->param[BCL_VBAT_LVL0] == bat_data)
+ addr = BCL_VBAT_ADC_LOW;
+ else if (&bcl_perph->param[BCL_VBAT_LVL1] == bat_data)
+ addr = BCL_VBAT_COMP_LOW;
+ else if (&bcl_perph->param[BCL_VBAT_LVL2] == bat_data)
+ addr = BCL_VBAT_COMP_TLOW;
+ else
+ return -ENODEV;
+
+ ret = bcl_read_register(addr, &val);
+ if (ret)
+ return ret;
+
+ if (addr == BCL_VBAT_ADC_LOW) {
+ *trip = val;
+ convert_adc_to_vbat_thresh_val(trip);
+ pr_debug("vbat trip: %d mV ADC:0x%02x\n", *trip, val);
+ } else {
+ *trip = 2250 + val * 25;
+ if (*trip > BCL_VBAT_MAX_MV)
+ *trip = BCL_VBAT_MAX_MV;
+ pr_debug("vbat-%s-low trip: %d mV ADC:0x%02x\n",
+ (addr == BCL_VBAT_COMP_LOW) ?
+ "too" : "critical",
+ *trip, val);
+ }
+
+ return 0;
+}
+
+static int bcl_set_vbat(void *data, int low, int high)
+{
+ struct bcl_peripheral_data *bat_data =
+ (struct bcl_peripheral_data *)data;
+
+ mutex_lock(&bat_data->state_trans_lock);
+
+ if (low == INT_MIN &&
+ bat_data->irq_num && bat_data->irq_enabled) {
+ disable_irq_nosync(bat_data->irq_num);
+ bat_data->irq_enabled = false;
+ pr_debug("vbat: disable irq:%d\n", bat_data->irq_num);
+ } else if (low != INT_MIN &&
+ bat_data->irq_num && !bat_data->irq_enabled) {
+ enable_irq(bat_data->irq_num);
+ bat_data->irq_enabled = true;
+ pr_debug("vbat: enable irq:%d\n", bat_data->irq_num);
+ }
+
+ /*
+ * Vbat threshold's are pre-configured and cant be
+ * programmed.
+ */
+ mutex_unlock(&bat_data->state_trans_lock);
+
+ return 0;
+}
+
+static int bcl_read_vbat(void *data, int *adc_value)
+{
+ int ret = 0;
+ unsigned int val = 0;
+ struct bcl_peripheral_data *bat_data =
+ (struct bcl_peripheral_data *)data;
+
+ *adc_value = val;
+ ret = bcl_read_register(BCL_VBAT_READ, &val);
+ if (ret)
+ goto bcl_read_exit;
+ *adc_value = val;
+ if (*adc_value == BCL_VBAT_NO_READING) {
+ *adc_value = bat_data->last_val;
+ } else {
+ convert_adc_to_vbat_val(adc_value);
+ bat_data->last_val = *adc_value;
+ }
+ pr_debug("vbat:%d mv\n", bat_data->last_val);
+
+bcl_read_exit:
+ return ret;
+}
+
+static irqreturn_t bcl_handle_irq(int irq, void *data)
+{
+ struct bcl_peripheral_data *perph_data =
+ (struct bcl_peripheral_data *)data;
+ unsigned int irq_status = 0;
+ int ret;
+ bool notify = false;
+
+ mutex_lock(&perph_data->state_trans_lock);
+ if (!perph_data->irq_enabled) {
+ pr_err("irq:%d not in expected state\n", irq);
+ disable_irq_nosync(irq);
+ perph_data->irq_enabled = false;
+ goto exit_intr;
+ }
+ mutex_unlock(&perph_data->state_trans_lock);
+
+ ret = bcl_read_register(BCL_IRQ_STATUS, &irq_status);
+ if (ret) {
+ disable_irq_nosync(irq);
+ perph_data->irq_enabled = false;
+ return IRQ_HANDLED;
+ }
+ pr_debug("Irq:%d triggered for bcl type:%d. status:%u\n",
+ irq, perph_data->type, irq_status);
+ switch (perph_data->type) {
+ case BCL_VBAT_LVL0: /* BCL L0 interrupt */
+ if ((irq_status & BCL_IRQ_VCMP_L0) &&
+ (bcl_perph->param[BCL_VBAT_LVL0].tz_dev)) {
+ of_thermal_handle_trip(
+ bcl_perph->param[BCL_VBAT_LVL0].tz_dev);
+ notify = true;
+ }
+ if ((irq_status & BCL_IRQ_IBAT_L0) &&
+ (bcl_perph->param[BCL_IBAT_LVL0].tz_dev)) {
+ of_thermal_handle_trip(
+ bcl_perph->param[BCL_IBAT_LVL0].tz_dev);
+ notify = true;
+ }
+ break;
+ case BCL_VBAT_LVL1: /* BCL L1 interrupt */
+ if ((irq_status & BCL_IRQ_VCMP_L1) &&
+ (bcl_perph->param[BCL_VBAT_LVL1].tz_dev)) {
+ of_thermal_handle_trip(
+ bcl_perph->param[BCL_VBAT_LVL1].tz_dev);
+ notify = true;
+ }
+ if ((irq_status & BCL_IRQ_IBAT_L1) &&
+ (bcl_perph->param[BCL_IBAT_LVL1].tz_dev)) {
+ of_thermal_handle_trip(
+ bcl_perph->param[BCL_IBAT_LVL1].tz_dev);
+ notify = true;
+ }
+ break;
+ case BCL_VBAT_LVL2: /* BCL L2 interrupt */
+ if ((irq_status & BCL_IRQ_VCMP_L2) &&
+ (bcl_perph->param[BCL_VBAT_LVL2].tz_dev)) {
+ of_thermal_handle_trip(
+ bcl_perph->param[BCL_VBAT_LVL2].tz_dev);
+ notify = true;
+ }
+ break;
+ default:
+ pr_err("Invalid type%d for interrupt:%d\n",
+ perph_data->type, irq);
+ break;
+ }
+ if (!notify)
+ pr_err_ratelimited("Irq:%d triggered. status:%u\n",
+ irq, irq_status);
+
+ return IRQ_HANDLED;
+
+exit_intr:
+ mutex_unlock(&perph_data->state_trans_lock);
+ return IRQ_HANDLED;
+}
+
+static int bcl_get_devicetree_data(struct platform_device *pdev)
+{
+ int ret = 0;
+ const __be32 *prop = NULL;
+ struct device_node *dev_node = pdev->dev.of_node;
+
+ prop = of_get_address(dev_node, 0, NULL, NULL);
+ if (prop) {
+ bcl_perph->fg_bcl_addr = be32_to_cpu(*prop);
+ pr_debug("fg_bcl@%04x\n", bcl_perph->fg_bcl_addr);
+ } else {
+ dev_err(&pdev->dev, "No fg_bcl registers found\n");
+ return -ENODEV;
+ }
+
+ return ret;
+}
+
+static void bcl_fetch_trip(struct platform_device *pdev, enum bcl_dev_type type,
+ struct bcl_peripheral_data *data,
+ irqreturn_t (*handle)(int, void *))
+{
+ int ret = 0, irq_num = 0;
+ char *int_name = bcl_int_names[type];
+
+ mutex_lock(&data->state_trans_lock);
+ data->irq_num = 0;
+ data->irq_enabled = false;
+ irq_num = platform_get_irq_byname(pdev, int_name);
+ if (irq_num && handle) {
+ ret = devm_request_threaded_irq(&pdev->dev,
+ irq_num, NULL, handle,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ int_name, data);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Error requesting trip irq. err:%d\n",
+ ret);
+ mutex_unlock(&data->state_trans_lock);
+ return;
+ }
+ disable_irq_nosync(irq_num);
+ data->irq_num = irq_num;
+ } else if (irq_num && !handle) {
+ disable_irq_nosync(irq_num);
+ data->irq_num = irq_num;
+ }
+ mutex_unlock(&data->state_trans_lock);
+}
+
+static void bcl_vbat_init(struct platform_device *pdev,
+ enum bcl_dev_type type)
+{
+ struct bcl_peripheral_data *vbat = &bcl_perph->param[type];
+ irqreturn_t (*handle)(int, void *) = bcl_handle_irq;
+
+ mutex_init(&vbat->state_trans_lock);
+ vbat->type = type;
+ bcl_fetch_trip(pdev, type, vbat, handle);
+ vbat->ops.get_temp = bcl_read_vbat;
+ vbat->ops.set_trips = bcl_set_vbat;
+ vbat->ops.get_trip_temp = bcl_get_vbat_trip;
+ vbat->tz_dev = thermal_zone_of_sensor_register(&pdev->dev,
+ type, vbat, &vbat->ops);
+ if (IS_ERR(vbat->tz_dev)) {
+ pr_debug("vbat[%s] register failed. err:%ld\n",
+ bcl_int_names[type],
+ PTR_ERR(vbat->tz_dev));
+ vbat->tz_dev = NULL;
+ return;
+ }
+ thermal_zone_device_update(vbat->tz_dev, THERMAL_DEVICE_UP);
+}
+
+static void bcl_probe_vbat(struct platform_device *pdev)
+{
+ bcl_vbat_init(pdev, BCL_VBAT_LVL0);
+ bcl_vbat_init(pdev, BCL_VBAT_LVL1);
+ bcl_vbat_init(pdev, BCL_VBAT_LVL2);
+}
+
+static void bcl_ibat_init(struct platform_device *pdev,
+ enum bcl_dev_type type)
+{
+ struct bcl_peripheral_data *ibat = &bcl_perph->param[type];
+
+ mutex_init(&ibat->state_trans_lock);
+ ibat->type = type;
+ bcl_fetch_trip(pdev, type, ibat, NULL);
+ ibat->ops.get_temp = bcl_read_ibat;
+ ibat->ops.set_trips = bcl_set_ibat;
+
+ switch (type) {
+ case BCL_IBAT_LVL0:
+ if (!bcl_perph->param[BCL_VBAT_LVL0].irq_num ||
+ ibat->irq_num !=
+ bcl_perph->param[BCL_VBAT_LVL0].irq_num) {
+ pr_err("ibat[%d]: irq %d mismatch\n",
+ type, ibat->irq_num);
+ return;
+ }
+ break;
+ case BCL_IBAT_LVL1:
+ if (!bcl_perph->param[BCL_VBAT_LVL1].irq_num ||
+ ibat->irq_num !=
+ bcl_perph->param[BCL_VBAT_LVL1].irq_num) {
+ pr_err("ibat[%d]: irq %d mismatch\n",
+ type, ibat->irq_num);
+ return;
+ }
+ break;
+ default:
+ return;
+ }
+ ibat->tz_dev = thermal_zone_of_sensor_register(&pdev->dev,
+ type, ibat, &ibat->ops);
+ if (IS_ERR(ibat->tz_dev)) {
+ pr_debug("ibat:[%s] register failed. err:%ld\n",
+ bcl_int_names[type],
+ PTR_ERR(ibat->tz_dev));
+ ibat->tz_dev = NULL;
+ return;
+ }
+ thermal_zone_device_update(ibat->tz_dev, THERMAL_DEVICE_UP);
+}
+
+static void bcl_probe_ibat(struct platform_device *pdev)
+{
+ bcl_ibat_init(pdev, BCL_IBAT_LVL0);
+ bcl_ibat_init(pdev, BCL_IBAT_LVL1);
+}
+
+static void bcl_configure_bcl_peripheral(void)
+{
+ bcl_write_register(BCL_MONITOR_EN, BIT(7));
+}
+
+static int bcl_remove(struct platform_device *pdev)
+{
+ int i = 0;
+
+ for (; i < BCL_TYPE_MAX; i++) {
+ if (!bcl_perph->param[i].tz_dev)
+ continue;
+ thermal_zone_of_sensor_unregister(&pdev->dev,
+ bcl_perph->param[i].tz_dev);
+ }
+ bcl_perph = NULL;
+
+ return 0;
+}
+
+static int bcl_probe(struct platform_device *pdev)
+{
+ bcl_perph = devm_kzalloc(&pdev->dev, sizeof(*bcl_perph), GFP_KERNEL);
+ if (!bcl_perph)
+ return -ENOMEM;
+
+ bcl_perph->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!bcl_perph->regmap) {
+ dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
+ return -EINVAL;
+ }
+
+ bcl_get_devicetree_data(pdev);
+ bcl_probe_vbat(pdev);
+ bcl_probe_ibat(pdev);
+ bcl_configure_bcl_peripheral();
+
+ dev_set_drvdata(&pdev->dev, bcl_perph);
+
+ return 0;
+}
+
+static const struct of_device_id bcl_match[] = {
+ {
+ .compatible = "qcom,bcl-v5",
+ },
+ {},
+};
+
+static struct platform_driver bcl_driver = {
+ .probe = bcl_probe,
+ .remove = bcl_remove,
+ .driver = {
+ .name = BCL_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = bcl_match,
+ },
+};
+
+builtin_platform_driver(bcl_driver);
diff --git a/drivers/thermal/qcom/bcl_soc.c b/drivers/thermal/qcom/bcl_soc.c
new file mode 100644
index 0000000..e4d5157
--- /dev/null
+++ b/drivers/thermal/qcom/bcl_soc.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+#define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__
+
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/power_supply.h>
+#include <linux/thermal.h>
+
+#include "../thermal_core.h"
+
+#define BCL_DRIVER_NAME "bcl_soc_peripheral"
+
+struct bcl_device {
+ struct notifier_block psy_nb;
+ struct work_struct soc_eval_work;
+ long int trip_temp;
+ int trip_val;
+ struct mutex state_trans_lock;
+ bool irq_enabled;
+ struct thermal_zone_device *tz_dev;
+ struct thermal_zone_of_device_ops ops;
+};
+
+static struct bcl_device *bcl_perph;
+
+static int bcl_set_soc(void *data, int low, int high)
+{
+ if (low == bcl_perph->trip_temp)
+ return 0;
+
+ mutex_lock(&bcl_perph->state_trans_lock);
+ pr_debug("low soc threshold:%d\n", low);
+ bcl_perph->trip_temp = low;
+ if (low == INT_MIN) {
+ bcl_perph->irq_enabled = false;
+ goto unlock_and_exit;
+ }
+ bcl_perph->irq_enabled = true;
+ schedule_work(&bcl_perph->soc_eval_work);
+
+unlock_and_exit:
+ mutex_unlock(&bcl_perph->state_trans_lock);
+ return 0;
+}
+
+static int bcl_read_soc(void *data, int *val)
+{
+ static struct power_supply *batt_psy;
+ union power_supply_propval ret = {0,};
+ int err = 0;
+
+ *val = 100;
+ if (!batt_psy)
+ batt_psy = power_supply_get_by_name("battery");
+ if (batt_psy) {
+ err = power_supply_get_property(batt_psy,
+ POWER_SUPPLY_PROP_CAPACITY, &ret);
+ if (err) {
+ pr_err("battery percentage read error:%d\n",
+ err);
+ return err;
+ }
+ *val = ret.intval;
+ }
+ pr_debug("soc:%d\n", *val);
+
+ return err;
+}
+
+static void bcl_evaluate_soc(struct work_struct *work)
+{
+ int battery_percentage;
+
+ if (bcl_read_soc(NULL, &battery_percentage))
+ return;
+
+ mutex_lock(&bcl_perph->state_trans_lock);
+ if (!bcl_perph->irq_enabled)
+ goto eval_exit;
+ if (battery_percentage > bcl_perph->trip_temp)
+ goto eval_exit;
+
+ bcl_perph->trip_val = battery_percentage;
+ mutex_unlock(&bcl_perph->state_trans_lock);
+ of_thermal_handle_trip(bcl_perph->tz_dev);
+
+ return;
+eval_exit:
+ mutex_unlock(&bcl_perph->state_trans_lock);
+}
+
+static int battery_supply_callback(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct power_supply *psy = data;
+
+ if (strcmp(psy->desc->name, "battery"))
+ return NOTIFY_OK;
+ schedule_work(&bcl_perph->soc_eval_work);
+
+ return NOTIFY_OK;
+}
+
+static int bcl_soc_remove(struct platform_device *pdev)
+{
+ power_supply_unreg_notifier(&bcl_perph->psy_nb);
+ flush_work(&bcl_perph->soc_eval_work);
+ if (bcl_perph->tz_dev)
+ thermal_zone_of_sensor_unregister(&pdev->dev,
+ bcl_perph->tz_dev);
+
+ return 0;
+}
+
+static int bcl_soc_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ bcl_perph = devm_kzalloc(&pdev->dev, sizeof(*bcl_perph), GFP_KERNEL);
+ if (!bcl_perph)
+ return -ENOMEM;
+
+ mutex_init(&bcl_perph->state_trans_lock);
+ bcl_perph->ops.get_temp = bcl_read_soc;
+ bcl_perph->ops.set_trips = bcl_set_soc;
+ INIT_WORK(&bcl_perph->soc_eval_work, bcl_evaluate_soc);
+ bcl_perph->psy_nb.notifier_call = battery_supply_callback;
+
+ ret = power_supply_reg_notifier(&bcl_perph->psy_nb);
+ if (ret < 0) {
+ pr_err("soc notifier registration error. defer. err:%d\n",
+ ret);
+ ret = -EPROBE_DEFER;
+ goto bcl_soc_probe_exit;
+ }
+ bcl_perph->tz_dev = thermal_zone_of_sensor_register(&pdev->dev,
+ 0, bcl_perph, &bcl_perph->ops);
+ if (IS_ERR(bcl_perph->tz_dev)) {
+ pr_err("soc TZ register failed. err:%ld\n",
+ PTR_ERR(bcl_perph->tz_dev));
+ ret = PTR_ERR(bcl_perph->tz_dev);
+ bcl_perph->tz_dev = NULL;
+ goto bcl_soc_probe_exit;
+ }
+ thermal_zone_device_update(bcl_perph->tz_dev, THERMAL_DEVICE_UP);
+ schedule_work(&bcl_perph->soc_eval_work);
+
+ dev_set_drvdata(&pdev->dev, bcl_perph);
+
+ return 0;
+
+bcl_soc_probe_exit:
+ bcl_soc_remove(pdev);
+ return ret;
+}
+
+static const struct of_device_id bcl_match[] = {
+ {
+ .compatible = "qcom,msm-bcl-soc",
+ },
+ {},
+};
+
+static struct platform_driver bcl_driver = {
+ .probe = bcl_soc_probe,
+ .remove = bcl_soc_remove,
+ .driver = {
+ .name = BCL_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = bcl_match,
+ },
+};
+
+builtin_platform_driver(bcl_driver);
diff --git a/drivers/thermal/qcom/qti_virtual_sensor.c b/drivers/thermal/qcom/qti_virtual_sensor.c
index 9b4fae8..8d988eb 100644
--- a/drivers/thermal/qcom/qti_virtual_sensor.c
+++ b/drivers/thermal/qcom/qti_virtual_sensor.c
@@ -79,6 +79,29 @@
"apc1-l2-usr"},
.logic = VIRT_MAXIMUM,
},
+ {
+ .virt_zone_name = "hepta-cpu-max-step",
+ .num_sensors = 7,
+ .sensor_names = {"apc1-cpu0-usr",
+ "apc1-cpu1-usr",
+ "apc1-cpu2-usr",
+ "apc1-cpu3-usr",
+ "cpuss0-usr",
+ "cpuss1-usr",
+ "cpuss3-usr"},
+ .logic = VIRT_MAXIMUM,
+ },
+ {
+ .virt_zone_name = "hexa-cpu-max-step",
+ .num_sensors = 6,
+ .sensor_names = {"apc1-cpu0-usr",
+ "apc1-cpu1-usr",
+ "apc1-cpu2-usr",
+ "apc1-cpu3-usr",
+ "cpuss0-usr",
+ "cpuss1-usr"},
+ .logic = VIRT_MAXIMUM,
+ },
};
int qti_virtual_sensor_register(struct device *dev)
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index bec3dea..6a3c06f 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -42,15 +42,128 @@
#define QPNP_PERPH_TYPE2 0x2
#define QPNP_REVISION_EIGHT_CHANNEL_SUPPORT 2
#define QPNP_PERPH_SUBTYPE_TWO_CHANNEL_SUPPORT 0x22
+#define QPNP_STATUS1 0x8
+#define QPNP_STATUS1_OP_MODE 4
+#define QPNP_STATUS1_MEAS_INTERVAL_EN_STS BIT(2)
+#define QPNP_STATUS1_REQ_STS BIT(1)
+#define QPNP_STATUS1_EOC BIT(0)
+#define QPNP_STATUS2 0x9
+#define QPNP_STATUS2_CONV_SEQ_STATE 6
+#define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG BIT(1)
+#define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS BIT(0)
+#define QPNP_CONV_TIMEOUT_ERR 2
+
+#define QPNP_MODE_CTL 0x40
+#define QPNP_OP_MODE_SHIFT 3
+#define QPNP_VREF_XO_THM_FORCE BIT(2)
+#define QPNP_AMUX_TRIM_EN BIT(1)
+#define QPNP_ADC_TRIM_EN BIT(0)
#define QPNP_EN_CTL1 0x46
#define QPNP_ADC_TM_EN BIT(7)
#define QPNP_BTM_CONV_REQ 0x47
#define QPNP_ADC_CONV_REQ_EN BIT(7)
+#define QPNP_ADC_DIG_PARAM 0x50
+#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT 3
+#define QPNP_HW_SETTLE_DELAY 0x51
+#define QPNP_CONV_SEQ_CTL 0x54
+#define QPNP_CONV_SEQ_HOLDOFF_SHIFT 4
+#define QPNP_CONV_SEQ_TRIG_CTL 0x55
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL 0x57
+#define QPNP_ADC_TM_MEAS_INTERVAL_TIME_SHIFT 0x3
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2 0x58
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT 0x4
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK 0xf0
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK 0xf
+
+#define QPNP_ADC_MEAS_INTERVAL_OP_CTL 0x59
+#define QPNP_ADC_MEAS_INTERVAL_OP BIT(7)
+
#define QPNP_OP_MODE_SHIFT 3
#define QPNP_CONV_REQ 0x52
#define QPNP_CONV_REQ_SET BIT(7)
+#define QPNP_FAST_AVG_CTL 0x5a
+#define QPNP_FAST_AVG_EN 0x5b
+#define QPNP_FAST_AVG_ENABLED BIT(7)
+
+#define QPNP_M0_LOW_THR_LSB 0x5c
+#define QPNP_M0_LOW_THR_MSB 0x5d
+#define QPNP_M0_HIGH_THR_LSB 0x5e
+#define QPNP_M0_HIGH_THR_MSB 0x5f
+#define QPNP_M1_ADC_CH_SEL_CTL 0x68
+#define QPNP_M1_LOW_THR_LSB 0x69
+#define QPNP_M1_LOW_THR_MSB 0x6a
+#define QPNP_M1_HIGH_THR_LSB 0x6b
+#define QPNP_M1_HIGH_THR_MSB 0x6c
+#define QPNP_M2_ADC_CH_SEL_CTL 0x70
+#define QPNP_M2_LOW_THR_LSB 0x71
+#define QPNP_M2_LOW_THR_MSB 0x72
+#define QPNP_M2_HIGH_THR_LSB 0x73
+#define QPNP_M2_HIGH_THR_MSB 0x74
+#define QPNP_M3_ADC_CH_SEL_CTL 0x78
+#define QPNP_M3_LOW_THR_LSB 0x79
+#define QPNP_M3_LOW_THR_MSB 0x7a
+#define QPNP_M3_HIGH_THR_LSB 0x7b
+#define QPNP_M3_HIGH_THR_MSB 0x7c
+#define QPNP_M4_ADC_CH_SEL_CTL 0x80
+#define QPNP_M4_LOW_THR_LSB 0x81
+#define QPNP_M4_LOW_THR_MSB 0x82
+#define QPNP_M4_HIGH_THR_LSB 0x83
+#define QPNP_M4_HIGH_THR_MSB 0x84
+#define QPNP_M5_ADC_CH_SEL_CTL 0x88
+#define QPNP_M5_LOW_THR_LSB 0x89
+#define QPNP_M5_LOW_THR_MSB 0x8a
+#define QPNP_M5_HIGH_THR_LSB 0x8b
+#define QPNP_M5_HIGH_THR_MSB 0x8c
+#define QPNP_M6_ADC_CH_SEL_CTL 0x90
+#define QPNP_M6_LOW_THR_LSB 0x91
+#define QPNP_M6_LOW_THR_MSB 0x92
+#define QPNP_M6_HIGH_THR_LSB 0x93
+#define QPNP_M6_HIGH_THR_MSB 0x94
+#define QPNP_M7_ADC_CH_SEL_CTL 0x98
+#define QPNP_M7_LOW_THR_LSB 0x99
+#define QPNP_M7_LOW_THR_MSB 0x9a
+#define QPNP_M7_HIGH_THR_LSB 0x9b
+#define QPNP_M7_HIGH_THR_MSB 0x9c
+
+#define QPNP_ADC_TM_MULTI_MEAS_EN 0x41
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M0 BIT(0)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M1 BIT(1)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M2 BIT(2)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M3 BIT(3)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M4 BIT(4)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M5 BIT(5)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M6 BIT(6)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M7 BIT(7)
+#define QPNP_ADC_TM_LOW_THR_INT_EN 0x42
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M0 BIT(0)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M1 BIT(1)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M2 BIT(2)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M3 BIT(3)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M4 BIT(4)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M5 BIT(5)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M6 BIT(6)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M7 BIT(7)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN 0x43
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M0 BIT(0)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M1 BIT(1)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M2 BIT(2)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M3 BIT(3)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M4 BIT(4)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M5 BIT(5)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M6 BIT(6)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M7 BIT(7)
+
+#define QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL 0x59
+#define QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL 0x6d
+#define QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL 0x75
+#define QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL 0x7d
+#define QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL 0x85
+#define QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL 0x8d
+#define QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL 0x95
+#define QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL 0x9d
+
#define QPNP_ADC_TM_STATUS1 0x8
#define QPNP_ADC_TM_STATUS_LOW 0xa
#define QPNP_ADC_TM_STATUS_HIGH 0xb
@@ -62,6 +175,10 @@
#define QPNP_ADC_TM_THR_LSB_MASK(val) (val & 0xff)
#define QPNP_ADC_TM_THR_MSB_MASK(val) ((val & 0xff00) >> 8)
+#define QPNP_MIN_TIME 2000
+#define QPNP_MAX_TIME 2100
+#define QPNP_RETRY 1000
+
/* QPNP ADC TM HC start */
#define QPNP_BTM_HC_STATUS1 0x08
#define QPNP_BTM_HC_STATUS_LOW 0x0a
@@ -110,6 +227,8 @@
u8 adc_tm_high_enable;
u8 adc_tm_low_thr_set;
u8 adc_tm_high_thr_set;
+ spinlock_t adc_tm_low_lock;
+ spinlock_t adc_tm_high_lock;
};
struct qpnp_adc_thr_client_info {
@@ -168,6 +287,69 @@
LIST_HEAD(qpnp_adc_tm_device_list);
+struct qpnp_adc_tm_trip_reg_type {
+ enum qpnp_adc_tm_channel_select btm_amux_chan;
+ uint16_t low_thr_lsb_addr;
+ uint16_t low_thr_msb_addr;
+ uint16_t high_thr_lsb_addr;
+ uint16_t high_thr_msb_addr;
+ u8 multi_meas_en;
+ u8 low_thr_int_chan_en;
+ u8 high_thr_int_chan_en;
+ u8 meas_interval_ctl;
+};
+
+static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
+ [QPNP_ADC_TM_CHAN0] = {QPNP_ADC_TM_M0_ADC_CH_SEL_CTL,
+ QPNP_M0_LOW_THR_LSB,
+ QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
+ QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
+ QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0,
+ QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL},
+ [QPNP_ADC_TM_CHAN1] = {QPNP_ADC_TM_M1_ADC_CH_SEL_CTL,
+ QPNP_M1_LOW_THR_LSB,
+ QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
+ QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
+ QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1,
+ QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL},
+ [QPNP_ADC_TM_CHAN2] = {QPNP_ADC_TM_M2_ADC_CH_SEL_CTL,
+ QPNP_M2_LOW_THR_LSB,
+ QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
+ QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
+ QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2,
+ QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL},
+ [QPNP_ADC_TM_CHAN3] = {QPNP_ADC_TM_M3_ADC_CH_SEL_CTL,
+ QPNP_M3_LOW_THR_LSB,
+ QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
+ QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
+ QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3,
+ QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL},
+ [QPNP_ADC_TM_CHAN4] = {QPNP_ADC_TM_M4_ADC_CH_SEL_CTL,
+ QPNP_M4_LOW_THR_LSB,
+ QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
+ QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
+ QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4,
+ QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL},
+ [QPNP_ADC_TM_CHAN5] = {QPNP_ADC_TM_M5_ADC_CH_SEL_CTL,
+ QPNP_M5_LOW_THR_LSB,
+ QPNP_M5_LOW_THR_MSB, QPNP_M5_HIGH_THR_LSB,
+ QPNP_M5_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M5,
+ QPNP_ADC_TM_LOW_THR_INT_EN_M5, QPNP_ADC_TM_HIGH_THR_INT_EN_M5,
+ QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL},
+ [QPNP_ADC_TM_CHAN6] = {QPNP_ADC_TM_M6_ADC_CH_SEL_CTL,
+ QPNP_M6_LOW_THR_LSB,
+ QPNP_M6_LOW_THR_MSB, QPNP_M6_HIGH_THR_LSB,
+ QPNP_M6_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M6,
+ QPNP_ADC_TM_LOW_THR_INT_EN_M6, QPNP_ADC_TM_HIGH_THR_INT_EN_M6,
+ QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL},
+ [QPNP_ADC_TM_CHAN7] = {QPNP_ADC_TM_M7_ADC_CH_SEL_CTL,
+ QPNP_M7_LOW_THR_LSB,
+ QPNP_M7_LOW_THR_MSB, QPNP_M7_HIGH_THR_LSB,
+ QPNP_M7_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M7,
+ QPNP_ADC_TM_LOW_THR_INT_EN_M7, QPNP_ADC_TM_HIGH_THR_INT_EN_M7,
+ QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL},
+};
+
static struct qpnp_adc_tm_reverse_scale_fn adc_tm_rscale_fn[] = {
[SCALE_R_VBATT] = {qpnp_adc_vbatt_rscaler},
[SCALE_RBATT_THERM] = {qpnp_adc_btm_scaler},
@@ -208,6 +390,33 @@
return rc;
}
+static int32_t qpnp_adc_tm_fast_avg_en(struct qpnp_adc_tm_chip *chip,
+ uint32_t *fast_avg_sample)
+{
+ int rc = 0, version = 0;
+ u8 fast_avg_en = 0;
+
+ version = qpnp_adc_get_revid_version(chip->dev);
+ if (!((version == QPNP_REV_ID_8916_1_0) ||
+ (version == QPNP_REV_ID_8916_1_1) ||
+ (version == QPNP_REV_ID_8916_2_0))) {
+ pr_debug("fast-avg-en not required for this version\n");
+ return rc;
+ }
+
+ fast_avg_en = QPNP_FAST_AVG_ENABLED;
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_FAST_AVG_EN, fast_avg_en, 1);
+ if (rc < 0) {
+ pr_err("adc-tm fast-avg enable err\n");
+ return rc;
+ }
+
+ if (*fast_avg_sample >= 3)
+ *fast_avg_sample = 2;
+
+ return rc;
+}
+
static int qpnp_adc_tm_check_vreg_vote(struct qpnp_adc_tm_chip *chip)
{
int rc = 0;
@@ -244,19 +453,31 @@
return rc;
}
- data = QPNP_ADC_CONV_REQ_EN;
- rc = qpnp_adc_tm_write_reg(chip, QPNP_BTM_CONV_REQ, data, 1);
- if (rc < 0) {
- pr_err("adc-tm enable failed\n");
- return rc;
+ if (chip->adc_tm_hc) {
+ data = QPNP_ADC_CONV_REQ_EN;
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_BTM_CONV_REQ, data, 1);
+ if (rc < 0) {
+ pr_err("adc-tm enable failed\n");
+ return rc;
+ }
}
-
return rc;
}
static int32_t qpnp_adc_tm_disable(struct qpnp_adc_tm_chip *chip)
{
- return 0;
+ u8 data = 0;
+ int rc = 0;
+
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data, 1);
+ if (rc < 0) {
+ pr_err("adc-tm disable failed\n");
+ return rc;
+ }
+ }
+
+ return rc;
}
static int qpnp_adc_tm_is_valid(struct qpnp_adc_tm_chip *chip)
@@ -320,11 +541,129 @@
static int32_t qpnp_adc_tm_enable_if_channel_meas(
struct qpnp_adc_tm_chip *chip)
{
+ u8 adc_tm_meas_en = 0, status_low = 0, status_high = 0;
int rc = 0;
- rc = qpnp_adc_tm_rc_check_channel_en(chip);
+ if (chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_rc_check_channel_en(chip);
+ if (rc) {
+ pr_err("adc_tm channel check failed\n");
+ return rc;
+ }
+ } else {
+ /* Check if a measurement request is still required */
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+ &adc_tm_meas_en, 1);
+ if (rc) {
+ pr_err("read status high failed with %d\n", rc);
+ return rc;
+ }
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+ &status_low, 1);
+ if (rc) {
+ pr_err("read status low failed with %d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+ &status_high, 1);
+ if (rc) {
+ pr_err("read status high failed with %d\n", rc);
+ return rc;
+ }
+
+ /* Enable only if there are pending measurement requests */
+ if ((adc_tm_meas_en && status_high) ||
+ (adc_tm_meas_en && status_low)) {
+ qpnp_adc_tm_enable(chip);
+ /* Request conversion */
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ,
+ QPNP_CONV_REQ_SET, 1);
+ if (rc < 0) {
+ pr_err("adc-tm request conversion failed\n");
+ return rc;
+ }
+ } else {
+ /* disable the vote if applicable */
+ if (chip->adc_vote_enable && chip->adc->hkadc_ldo &&
+ chip->adc->hkadc_ldo_ok) {
+ qpnp_adc_disable_voltage(chip->adc);
+ chip->adc_vote_enable = false;
+ }
+ }
+ }
+ return rc;
+}
+
+static int32_t qpnp_adc_tm_mode_select(struct qpnp_adc_tm_chip *chip,
+ u8 mode_ctl)
+{
+ int rc;
+
+ mode_ctl |= (QPNP_ADC_TRIM_EN | QPNP_AMUX_TRIM_EN);
+
+ /* VADC_BTM current sets mode to recurring measurements */
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_MODE_CTL, mode_ctl, 1);
+ if (rc < 0)
+ pr_err("adc-tm write mode selection err\n");
+
+ return rc;
+}
+
+static int32_t qpnp_adc_tm_req_sts_check(struct qpnp_adc_tm_chip *chip)
+{
+ u8 status1 = 0, mode_ctl = 0;
+ int rc, count = 0;
+
+ /* Re-enable the peripheral */
+ rc = qpnp_adc_tm_enable(chip);
if (rc) {
- pr_err("adc_tm channel check failed\n");
+ pr_err("adc-tm re-enable peripheral failed\n");
+ return rc;
+ }
+
+ /* The VADC_TM bank needs to be disabled for new conversion request */
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1, 1);
+ if (rc) {
+ pr_err("adc-tm read status1 failed\n");
+ return rc;
+ }
+
+ /* Disable the bank if a conversion is occurring */
+ while (status1 & QPNP_STATUS1_REQ_STS) {
+ if (count > QPNP_RETRY) {
+ pr_err("retry error=%d with 0x%x\n", count, status1);
+ break;
+ }
+ /*
+ * Wait time is based on the optimum sampling rate
+ * and adding enough time buffer to account for ADC conversions
+ * occurring on different peripheral banks
+ */
+ usleep_range(QPNP_MIN_TIME, QPNP_MAX_TIME);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1,
+ &status1, 1);
+ if (rc < 0) {
+ pr_err("adc-tm disable failed\n");
+ return rc;
+ }
+ count++;
+ }
+
+ if (!chip->adc_tm_hc) {
+ /* Change the mode back to recurring measurement mode */
+ mode_ctl = ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
+ rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
+ if (rc < 0) {
+ pr_err("adc-tm mode change to recurring failed\n");
+ return rc;
+ }
+ }
+
+ /* Disable the peripheral */
+ rc = qpnp_adc_tm_disable(chip);
+ if (rc < 0) {
+ pr_err("adc-tm peripheral disable failed\n");
return rc;
}
@@ -337,17 +676,25 @@
int rc = 0, i;
bool chan_found = false;
- for (i = 0; i < chip->max_channels_available; i++) {
- if (chip->sensor[i].btm_channel_num == btm_chan) {
- *btm_chan_idx = i;
- chan_found = true;
- break;
+ if (!chip->adc_tm_hc) {
+ for (i = 0; i < QPNP_ADC_TM_CHAN_NONE; i++) {
+ if (adc_tm_data[i].btm_amux_chan == btm_chan) {
+ *btm_chan_idx = i;
+ chan_found = true;
+ }
+ }
+ } else {
+ for (i = 0; i < chip->max_channels_available; i++) {
+ if (chip->sensor[i].btm_channel_num == btm_chan) {
+ *btm_chan_idx = i;
+ chan_found = true;
+ break;
+ }
}
}
if (!chan_found)
return -EINVAL;
-
return rc;
}
@@ -412,19 +759,29 @@
switch (chip->sensor[chan_idx].timer_select) {
case ADC_MEAS_TIMER_SELECT1:
- rc = qpnp_adc_tm_write_reg(chip,
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_ADC_TM_MEAS_INTERVAL_CTL,
+ chip->sensor[chan_idx].meas_interval, 1);
+ else
+ rc = qpnp_adc_tm_write_reg(chip,
QPNP_BTM_MEAS_INTERVAL_CTL,
chip->sensor[chan_idx].meas_interval, 1);
if (rc < 0) {
pr_err("timer1 configure failed\n");
return rc;
}
- break;
+ break;
case ADC_MEAS_TIMER_SELECT2:
/* Thermal channels uses timer2, default to 1 second */
- rc = qpnp_adc_tm_read_reg(chip,
- QPNP_BTM_MEAS_INTERVAL_CTL2,
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_read_reg(chip,
+ QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
&meas_interval_timer2, 1);
+ else
+ rc = qpnp_adc_tm_read_reg(chip,
+ QPNP_BTM_MEAS_INTERVAL_CTL2,
+ &meas_interval_timer2, 1);
if (rc < 0) {
pr_err("timer2 configure read failed\n");
return rc;
@@ -433,7 +790,12 @@
timer_interval_store <<= QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT;
timer_interval_store &= QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK;
meas_interval_timer2 |= timer_interval_store;
- rc = qpnp_adc_tm_write_reg(chip,
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+ meas_interval_timer2, 1);
+ else
+ rc = qpnp_adc_tm_write_reg(chip,
QPNP_BTM_MEAS_INTERVAL_CTL2,
meas_interval_timer2, 1);
if (rc < 0) {
@@ -442,7 +804,12 @@
}
break;
case ADC_MEAS_TIMER_SELECT3:
- rc = qpnp_adc_tm_read_reg(chip,
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_read_reg(chip,
+ QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+ &meas_interval_timer2, 1);
+ else
+ rc = qpnp_adc_tm_read_reg(chip,
QPNP_BTM_MEAS_INTERVAL_CTL2,
&meas_interval_timer2, 1);
if (rc < 0) {
@@ -452,6 +819,11 @@
timer_interval_store = chip->sensor[chan_idx].meas_interval;
timer_interval_store &= QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK;
meas_interval_timer2 |= timer_interval_store;
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+ meas_interval_timer2, 1);
+ else
rc = qpnp_adc_tm_write_reg(chip,
QPNP_BTM_MEAS_INTERVAL_CTL2,
meas_interval_timer2, 1);
@@ -471,7 +843,12 @@
pr_err("Invalid btm channel idx\n");
return rc;
}
- rc = qpnp_adc_tm_write_reg(chip,
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_write_reg(chip,
+ adc_tm_data[btm_chan_idx].meas_interval_ctl,
+ chip->sensor[chan_idx].timer_select, 1);
+ else
+ rc = qpnp_adc_tm_write_reg(chip,
QPNP_BTM_Mn_MEAS_INTERVAL_CTL(btm_chan_idx),
chip->sensor[chan_idx].timer_select, 1);
if (rc < 0) {
@@ -556,6 +933,69 @@
return rc;
}
+static int32_t qpnp_adc_tm_read_thr_value(struct qpnp_adc_tm_chip *chip,
+ uint32_t btm_chan)
+{
+ int rc = 0;
+ u8 data_lsb = 0, data_msb = 0;
+ uint32_t btm_chan_idx = 0;
+ int32_t low_thr = 0, high_thr = 0;
+
+ if (!chip->adc_tm_hc) {
+ pr_err("Not applicable for VADC HC peripheral\n");
+ return -EINVAL;
+ }
+
+ rc = qpnp_adc_tm_get_btm_idx(chip, btm_chan, &btm_chan_idx);
+ if (rc < 0) {
+ pr_err("Invalid btm channel idx\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip,
+ adc_tm_data[btm_chan_idx].low_thr_lsb_addr,
+ &data_lsb, 1);
+ if (rc < 0) {
+ pr_err("low threshold lsb setting failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip,
+ adc_tm_data[btm_chan_idx].low_thr_msb_addr,
+ &data_msb, 1);
+ if (rc < 0) {
+ pr_err("low threshold msb setting failed\n");
+ return rc;
+ }
+
+ low_thr = (data_msb << 8) | data_lsb;
+
+ rc = qpnp_adc_tm_read_reg(chip,
+ adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
+ &data_lsb, 1);
+ if (rc < 0) {
+ pr_err("high threshold lsb setting failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip,
+ adc_tm_data[btm_chan_idx].high_thr_msb_addr,
+ &data_msb, 1);
+ if (rc < 0) {
+ pr_err("high threshold msb setting failed\n");
+ return rc;
+ }
+
+ high_thr = (data_msb << 8) | data_lsb;
+
+ pr_debug("configured thresholds high:0x%x and low:0x%x\n",
+ high_thr, low_thr);
+
+ return rc;
+}
+
+
+
static int32_t qpnp_adc_tm_thr_update(struct qpnp_adc_tm_chip *chip,
uint32_t btm_chan, int32_t high_thr, int32_t low_thr)
{
@@ -568,38 +1008,71 @@
return rc;
}
- rc = qpnp_adc_tm_write_reg(chip,
- QPNP_BTM_Mn_LOW_THR0(btm_chan_idx),
- QPNP_ADC_TM_THR_LSB_MASK(low_thr), 1);
- if (rc < 0) {
- pr_err("low threshold lsb setting failed\n");
- return rc;
- }
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_write_reg(chip,
+ adc_tm_data[btm_chan_idx].low_thr_lsb_addr,
+ QPNP_ADC_TM_THR_LSB_MASK(low_thr), 1);
+ if (rc < 0) {
+ pr_err("low threshold lsb setting failed\n");
+ return rc;
+ }
- rc = qpnp_adc_tm_write_reg(chip,
- QPNP_BTM_Mn_LOW_THR1(btm_chan_idx),
- QPNP_ADC_TM_THR_MSB_MASK(low_thr), 1);
- if (rc < 0) {
- pr_err("low threshold msb setting failed\n");
- return rc;
- }
+ rc = qpnp_adc_tm_write_reg(chip,
+ adc_tm_data[btm_chan_idx].low_thr_msb_addr,
+ QPNP_ADC_TM_THR_MSB_MASK(low_thr), 1);
+ if (rc < 0) {
+ pr_err("low threshold msb setting failed\n");
+ return rc;
+ }
- rc = qpnp_adc_tm_write_reg(chip,
- QPNP_BTM_Mn_HIGH_THR0(btm_chan_idx),
- QPNP_ADC_TM_THR_LSB_MASK(high_thr), 1);
- if (rc < 0) {
- pr_err("high threshold lsb setting failed\n");
- return rc;
- }
+ rc = qpnp_adc_tm_write_reg(chip,
+ adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
+ QPNP_ADC_TM_THR_LSB_MASK(high_thr), 1);
+ if (rc < 0) {
+ pr_err("high threshold lsb setting failed\n");
+ return rc;
+ }
- rc = qpnp_adc_tm_write_reg(chip,
- QPNP_BTM_Mn_HIGH_THR1(btm_chan_idx),
- QPNP_ADC_TM_THR_MSB_MASK(high_thr), 1);
- if (rc < 0)
- pr_err("high threshold msb setting failed\n");
+ rc = qpnp_adc_tm_write_reg(chip,
+ adc_tm_data[btm_chan_idx].high_thr_msb_addr,
+ QPNP_ADC_TM_THR_MSB_MASK(high_thr), 1);
+ if (rc < 0)
+ pr_err("high threshold msb setting failed\n");
+ } else {
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_BTM_Mn_LOW_THR0(btm_chan_idx),
+ QPNP_ADC_TM_THR_LSB_MASK(low_thr), 1);
+ if (rc < 0) {
+ pr_err("low threshold lsb setting failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_BTM_Mn_LOW_THR1(btm_chan_idx),
+ QPNP_ADC_TM_THR_MSB_MASK(low_thr), 1);
+ if (rc < 0) {
+ pr_err("low threshold msb setting failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_BTM_Mn_HIGH_THR0(btm_chan_idx),
+ QPNP_ADC_TM_THR_LSB_MASK(high_thr), 1);
+ if (rc < 0) {
+ pr_err("high threshold lsb setting failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_BTM_Mn_HIGH_THR1(btm_chan_idx),
+ QPNP_ADC_TM_THR_MSB_MASK(high_thr), 1);
+ if (rc < 0)
+ pr_err("high threshold msb setting failed\n");
+
+ }
pr_debug("client requested high:%d and low:%d\n",
- high_thr, low_thr);
+ high_thr, low_thr);
return rc;
}
@@ -734,9 +1207,14 @@
pr_debug("low sensor mask:%x with state:%d\n",
sensor_mask, chan_prop->state_request);
/* Enable low threshold's interrupt */
- rc = qpnp_adc_tm_reg_update(chip,
- QPNP_BTM_Mn_EN(btm_chan_idx),
- QPNP_BTM_Mn_LOW_THR_INT_EN, true);
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_LOW_THR_INT_EN,
+ sensor_mask, true);
+ else
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(btm_chan_idx),
+ QPNP_BTM_Mn_LOW_THR_INT_EN, true);
if (rc < 0) {
pr_err("low thr enable err:%d\n", btm_chan);
return rc;
@@ -746,9 +1224,14 @@
if (high_thr_set) {
/* Enable high threshold's interrupt */
pr_debug("high sensor mask:%x\n", sensor_mask);
- rc = qpnp_adc_tm_reg_update(chip,
- QPNP_BTM_Mn_EN(btm_chan_idx),
- QPNP_BTM_Mn_HIGH_THR_INT_EN, true);
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_HIGH_THR_INT_EN,
+ sensor_mask, true);
+ else
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(btm_chan_idx),
+ QPNP_BTM_Mn_HIGH_THR_INT_EN, true);
if (rc < 0) {
pr_err("high thr enable err:%d\n", btm_chan);
return rc;
@@ -757,13 +1240,16 @@
}
/* Enable corresponding BTM channel measurement */
- rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_idx),
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
+ else
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_idx),
QPNP_BTM_Mn_MEAS_EN, true);
if (rc < 0) {
pr_err("multi measurement en failed\n");
return rc;
}
-
return rc;
}
@@ -872,12 +1358,120 @@
return 0;
}
+static int32_t qpnp_adc_tm_configure(struct qpnp_adc_tm_chip *chip,
+ struct qpnp_adc_amux_properties *chan_prop)
+{
+ u8 decimation = 0, op_cntrl = 0, mode_ctl = 0;
+ int rc = 0;
+ uint32_t btm_chan = 0;
+
+ /* Set measurement in single measurement mode */
+ mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
+ rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
+ if (rc < 0) {
+ pr_err("adc-tm single mode select failed\n");
+ return rc;
+ }
+
+ /* Disable bank */
+ rc = qpnp_adc_tm_disable(chip);
+ if (rc)
+ return rc;
+
+ /* Check if a conversion is in progress */
+ rc = qpnp_adc_tm_req_sts_check(chip);
+ if (rc < 0) {
+ pr_err("adc-tm req_sts check failed\n");
+ return rc;
+ }
+
+ /* Configure AMUX channel select for the corresponding BTM channel*/
+ btm_chan = chan_prop->chan_prop->tm_channel_select;
+ rc = qpnp_adc_tm_write_reg(chip, btm_chan, chan_prop->amux_channel, 1);
+ if (rc < 0) {
+ pr_err("adc-tm channel selection err\n");
+ return rc;
+ }
+
+ /* Digital parameter setup */
+ decimation |= chan_prop->decimation <<
+ QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT;
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_DIG_PARAM, decimation, 1);
+ if (rc < 0) {
+ pr_err("adc-tm digital parameter setup err\n");
+ return rc;
+ }
+
+ /* Hardware setting time */
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_HW_SETTLE_DELAY,
+ chan_prop->hw_settle_time, 1);
+ if (rc < 0) {
+ pr_err("adc-tm hw settling time setup err\n");
+ return rc;
+ }
+
+ /* Fast averaging setup/enable */
+ rc = qpnp_adc_tm_fast_avg_en(chip, &chan_prop->fast_avg_setup);
+ if (rc < 0) {
+ pr_err("adc-tm fast-avg enable err\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_FAST_AVG_CTL,
+ chan_prop->fast_avg_setup, 1);
+ if (rc < 0) {
+ pr_err("adc-tm fast-avg setup err\n");
+ return rc;
+ }
+
+ /* Measurement interval setup */
+ rc = qpnp_adc_tm_timer_interval_select(chip, btm_chan,
+ chan_prop->chan_prop);
+ if (rc < 0) {
+ pr_err("adc-tm timer select failed\n");
+ return rc;
+ }
+
+ /* Channel configuration setup */
+ rc = qpnp_adc_tm_channel_configure(chip, btm_chan,
+ chan_prop->chan_prop, chan_prop->amux_channel);
+ if (rc < 0) {
+ pr_err("adc-tm channel configure failed\n");
+ return rc;
+ }
+
+ /* Recurring interval measurement enable */
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
+ &op_cntrl, 1);
+ op_cntrl |= QPNP_ADC_MEAS_INTERVAL_OP;
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
+ op_cntrl, true);
+ if (rc < 0) {
+ pr_err("adc-tm meas interval op configure failed\n");
+ return rc;
+ }
+
+ /* Enable bank */
+ rc = qpnp_adc_tm_enable(chip);
+ if (rc)
+ return rc;
+
+ /* Request conversion */
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ, QPNP_CONV_REQ_SET, 1);
+ if (rc < 0) {
+ pr_err("adc-tm request conversion failed\n");
+ return rc;
+ }
+
+ return 0;
+}
+
static int qpnp_adc_tm_set_mode(struct qpnp_adc_tm_sensor *adc_tm,
enum thermal_device_mode mode)
{
struct qpnp_adc_tm_chip *chip = adc_tm->chip;
int rc = 0, channel;
- u8 sensor_mask = 0;
+ u8 sensor_mask = 0, mode_ctl = 0;
uint32_t btm_chan_idx = 0, btm_chan = 0;
if (qpnp_adc_tm_is_valid(chip)) {
@@ -916,13 +1510,30 @@
chip->adc->amux_prop->calib_type =
chip->adc->adc_channels[channel].calib_type;
- rc = qpnp_adc_tm_hc_configure(chip, chip->adc->amux_prop);
- if (rc) {
- pr_err("hc configure failed with %d\n", rc);
- goto fail;
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
+ if (rc) {
+ pr_err("adc-tm configure failed with %d\n", rc);
+ goto fail;
+ }
+ } else {
+ rc = qpnp_adc_tm_hc_configure(chip,
+ chip->adc->amux_prop);
+ if (rc) {
+ pr_err("hc configure failed with %d\n", rc);
+ goto fail;
+ }
}
} else if (mode == THERMAL_DEVICE_DISABLED) {
sensor_mask = 1 << adc_tm->sensor_num;
+ if (!chip->adc_tm_hc) {
+ mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
+ rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
+ if (rc < 0) {
+ pr_err("adc-tm single mode select failed\n");
+ goto fail;
+ }
+ }
/* Disable bank */
rc = qpnp_adc_tm_disable(chip);
@@ -931,12 +1542,28 @@
goto fail;
}
- rc = qpnp_adc_tm_reg_update(chip,
- QPNP_BTM_Mn_EN(btm_chan_idx),
- QPNP_BTM_Mn_MEAS_EN, false);
- if (rc < 0) {
- pr_err("multi measurement disable failed\n");
- goto fail;
+ if (!chip->adc_tm_hc) {
+ /* Check if a conversion is in progress */
+ rc = qpnp_adc_tm_req_sts_check(chip);
+ if (rc < 0) {
+ pr_err("adc-tm req_sts check failed\n");
+ goto fail;
+ }
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_MULTI_MEAS_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("multi measurement update failed\n");
+ goto fail;
+ }
+ } else {
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(btm_chan_idx),
+ QPNP_BTM_Mn_MEAS_EN, false);
+ if (rc < 0) {
+ pr_err("multi measurement disable failed\n");
+ goto fail;
+ }
}
rc = qpnp_adc_tm_enable_if_channel_meas(chip);
@@ -959,6 +1586,7 @@
{
struct qpnp_adc_tm_chip *chip = adc_tm->chip;
int rc = 0, sensor_mask = 0;
+ u8 thr_int_en = 0;
bool state = false;
uint32_t btm_chan_idx = 0, btm_chan = 0;
@@ -986,17 +1614,29 @@
switch (trip) {
case ADC_TM_TRIP_HIGH_WARM:
/* low_thr (lower voltage) for higher temp */
- rc = qpnp_adc_tm_reg_update(chip,
- QPNP_BTM_Mn_EN(btm_chan_idx),
- QPNP_BTM_Mn_LOW_THR_INT_EN, state);
+ thr_int_en = adc_tm_data[btm_chan_idx].low_thr_int_chan_en;
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_LOW_THR_INT_EN,
+ sensor_mask, state);
+ else
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(btm_chan_idx),
+ QPNP_BTM_Mn_LOW_THR_INT_EN, state);
if (rc)
pr_err("channel:%x failed\n", btm_chan);
break;
case ADC_TM_TRIP_LOW_COOL:
/* high_thr (higher voltage) for cooler temp */
- rc = qpnp_adc_tm_reg_update(chip,
- QPNP_BTM_Mn_EN(btm_chan_idx),
- QPNP_BTM_Mn_HIGH_THR_INT_EN, state);
+ thr_int_en = adc_tm_data[btm_chan_idx].high_thr_int_chan_en;
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_HIGH_THR_INT_EN,
+ sensor_mask, state);
+ else
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(btm_chan_idx),
+ QPNP_BTM_Mn_HIGH_THR_INT_EN, state);
if (rc)
pr_err("channel:%x failed\n", btm_chan);
break;
@@ -1060,10 +1700,17 @@
return rc;
}
- reg_low_thr_lsb = QPNP_BTM_Mn_LOW_THR0(btm_chan_idx);
- reg_low_thr_msb = QPNP_BTM_Mn_LOW_THR1(btm_chan_idx);
- reg_high_thr_lsb = QPNP_BTM_Mn_HIGH_THR0(btm_chan_idx);
- reg_high_thr_msb = QPNP_BTM_Mn_HIGH_THR1(btm_chan_idx);
+ if (!chip->adc_tm_hc) {
+ reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
+ reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
+ reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
+ reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
+ } else {
+ reg_low_thr_lsb = QPNP_BTM_Mn_LOW_THR0(btm_chan_idx);
+ reg_low_thr_msb = QPNP_BTM_Mn_LOW_THR1(btm_chan_idx);
+ reg_high_thr_lsb = QPNP_BTM_Mn_HIGH_THR0(btm_chan_idx);
+ reg_high_thr_msb = QPNP_BTM_Mn_HIGH_THR1(btm_chan_idx);
+ }
if (high_temp != INT_MAX) {
rc = qpnp_adc_tm_write_reg(chip, reg_low_thr_lsb,
@@ -1222,6 +1869,144 @@
atomic_dec(&chip->wq_cnt);
}
+static int qpnp_adc_tm_recalib_request_check(struct qpnp_adc_tm_chip *chip,
+ int sensor_num, u8 status_high, u8 *notify_check)
+{
+ int rc = 0;
+ u8 sensor_mask = 0, mode_ctl = 0;
+ int32_t old_thr = 0, new_thr = 0;
+ uint32_t channel, btm_chan_num, scale_type;
+ struct qpnp_vadc_result result;
+ struct qpnp_adc_thr_client_info *client_info = NULL;
+ struct list_head *thr_list;
+ bool status = false;
+
+ if (!chip->adc_tm_recalib_check) {
+ *notify_check = 1;
+ return rc;
+ }
+
+ list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
+ client_info = list_entry(thr_list,
+ struct qpnp_adc_thr_client_info, list);
+ channel = client_info->btm_param->channel;
+ btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
+ sensor_mask = 1 << sensor_num;
+
+ rc = qpnp_vadc_read(chip->vadc_dev, channel, &result);
+ if (rc < 0) {
+ pr_err("failure to read vadc channel=%d\n",
+ client_info->btm_param->channel);
+ goto fail;
+ }
+ new_thr = result.physical;
+
+ if (status_high)
+ old_thr = client_info->btm_param->high_thr;
+ else
+ old_thr = client_info->btm_param->low_thr;
+
+ if (new_thr > old_thr)
+ status = (status_high) ? true : false;
+ else
+ status = (status_high) ? false : true;
+
+ pr_debug(
+ "recalib:sen=%d, new_thr=%d, new_thr_adc_code=0x%x, old_thr=%d status=%d valid_status=%d\n",
+ sensor_num, new_thr, result.adc_code,
+ old_thr, status_high, status);
+
+ rc = qpnp_adc_tm_read_thr_value(chip, btm_chan_num);
+ if (rc < 0) {
+ pr_err("adc-tm thresholds read failed\n");
+ goto fail;
+ }
+
+ if (status) {
+ *notify_check = 1;
+ pr_debug("Client can be notify\n");
+ return rc;
+ }
+
+ pr_debug("Client can not be notify, restart measurement\n");
+ /* Set measurement in single measurement mode */
+ mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
+ rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
+ if (rc < 0) {
+ pr_err("adc-tm single mode select failed\n");
+ goto fail;
+ }
+
+ /* Disable bank */
+ rc = qpnp_adc_tm_disable(chip);
+ if (rc < 0) {
+ pr_err("adc-tm disable failed\n");
+ goto fail;
+ }
+
+ /* Check if a conversion is in progress */
+ rc = qpnp_adc_tm_req_sts_check(chip);
+ if (rc < 0) {
+ pr_err("adc-tm req_sts check failed\n");
+ goto fail;
+ }
+
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("low threshold int write failed\n");
+ goto fail;
+ }
+
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("high threshold int enable failed\n");
+ goto fail;
+ }
+
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("multi measurement en failed\n");
+ goto fail;
+ }
+
+ /* restart measurement */
+ scale_type = chip->sensor[sensor_num].scale_type;
+ chip->adc->amux_prop->amux_channel = channel;
+ chip->adc->amux_prop->decimation =
+ chip->adc->adc_channels[sensor_num].adc_decimation;
+ chip->adc->amux_prop->hw_settle_time =
+ chip->adc->adc_channels[sensor_num].hw_settle_time;
+ chip->adc->amux_prop->fast_avg_setup =
+ chip->adc->adc_channels[sensor_num].fast_avg_setup;
+ chip->adc->amux_prop->mode_sel =
+ ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
+ adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev,
+ client_info->btm_param,
+ &chip->adc->amux_prop->chan_prop->low_thr,
+ &chip->adc->amux_prop->chan_prop->high_thr);
+ qpnp_adc_tm_add_to_list(chip, sensor_num,
+ client_info->btm_param,
+ chip->adc->amux_prop->chan_prop);
+ chip->adc->amux_prop->chan_prop->tm_channel_select =
+ chip->sensor[sensor_num].btm_channel_num;
+ chip->adc->amux_prop->chan_prop->state_request =
+ client_info->btm_param->state_request;
+
+ rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
+ if (rc) {
+ pr_err("adc-tm configure failed with %d\n", rc);
+ goto fail;
+ }
+ *notify_check = 0;
+ pr_debug("BTM channel reconfigured for measuremnt\n");
+ }
+fail:
+ return rc;
+}
+
static int qpnp_adc_tm_disable_rearm_high_thresholds(
struct qpnp_adc_tm_chip *chip, int sensor_num)
{
@@ -1229,7 +2014,7 @@
struct qpnp_adc_thr_client_info *client_info = NULL;
struct list_head *thr_list;
uint32_t btm_chan_num = 0, btm_chan_idx = 0;
- u8 sensor_mask = 0;
+ u8 sensor_mask = 0, notify_check = 0;
int rc = 0;
btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
@@ -1250,14 +2035,24 @@
*/
sensor_mask = 1 << sensor_num;
pr_debug("non thermal node - mask:%x\n", sensor_mask);
- rc = qpnp_adc_tm_reg_update(chip,
- QPNP_BTM_Mn_EN(btm_chan_idx),
- QPNP_BTM_Mn_HIGH_THR_INT_EN, false);
- if (rc < 0) {
- pr_err("high threshold int update failed\n");
- return rc;
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_recalib_request_check(chip,
+ sensor_num, true, ¬ify_check);
+ if (rc < 0 || !notify_check) {
+ pr_debug("Calib recheck re-armed rc=%d\n", rc);
+ chip->th_info.adc_tm_high_enable = 0;
+ return rc;
+ }
+ } else {
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(btm_chan_idx),
+ QPNP_BTM_Mn_HIGH_THR_INT_EN, false);
+ if (rc < 0) {
+ pr_err("high threshold int update failed\n");
+ return rc;
+ }
}
- } else {
+ } else {
/*
* Uses the thermal sysfs registered device to disable
* the corresponding high voltage threshold which
@@ -1291,12 +2086,22 @@
}
qpnp_adc_tm_manage_thresholds(chip, sensor_num, btm_chan_num);
- rc = qpnp_adc_tm_reg_update(chip,
- QPNP_BTM_Mn_EN(sensor_num),
- QPNP_BTM_Mn_MEAS_EN, false);
- if (rc < 0) {
- pr_err("multi meas disable failed\n");
- return rc;
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_MULTI_MEAS_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("multi meas disable failed\n");
+ return rc;
+ }
+ } else {
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(sensor_num),
+ QPNP_BTM_Mn_MEAS_EN, false);
+ if (rc < 0) {
+ pr_err("multi meas disable failed\n");
+ return rc;
+ }
}
rc = qpnp_adc_tm_enable_if_channel_meas(chip);
@@ -1320,7 +2125,7 @@
struct qpnp_adc_thr_client_info *client_info = NULL;
struct list_head *thr_list;
uint32_t btm_chan_num = 0, btm_chan_idx = 0;
- u8 sensor_mask = 0;
+ u8 sensor_mask = 0, notify_check = 0;
int rc = 0;
btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
@@ -1341,12 +2146,22 @@
*/
sensor_mask = 1 << sensor_num;
pr_debug("non thermal node - mask:%x\n", sensor_mask);
- rc = qpnp_adc_tm_reg_update(chip,
- QPNP_BTM_Mn_EN(btm_chan_idx),
- QPNP_BTM_Mn_LOW_THR_INT_EN, false);
- if (rc < 0) {
- pr_err("low threshold int update failed\n");
- return rc;
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_recalib_request_check(chip,
+ sensor_num, false, ¬ify_check);
+ if (rc < 0 || !notify_check) {
+ pr_debug("Calib recheck re-armed rc=%d\n", rc);
+ chip->th_info.adc_tm_low_enable = 0;
+ return rc;
+ }
+ } else {
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(btm_chan_idx),
+ QPNP_BTM_Mn_LOW_THR_INT_EN, false);
+ if (rc < 0) {
+ pr_err("low threshold int update failed\n");
+ return rc;
+ }
}
} else {
/*
@@ -1382,12 +2197,22 @@
}
qpnp_adc_tm_manage_thresholds(chip, sensor_num, btm_chan_num);
- rc = qpnp_adc_tm_reg_update(chip,
- QPNP_BTM_Mn_EN(sensor_num),
- QPNP_BTM_Mn_MEAS_EN, false);
- if (rc < 0) {
- pr_err("multi meas disable failed\n");
- return rc;
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_MULTI_MEAS_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("multi meas disable failed\n");
+ return rc;
+ }
+ } else {
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(sensor_num),
+ QPNP_BTM_Mn_MEAS_EN, false);
+ if (rc < 0) {
+ pr_err("multi meas disable failed\n");
+ return rc;
+ }
}
rc = qpnp_adc_tm_enable_if_channel_meas(chip);
@@ -1416,6 +2241,13 @@
mutex_lock(&chip->adc->adc_lock);
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_req_sts_check(chip);
+ if (rc) {
+ pr_err("adc-tm-tm req sts check failed with %d\n", rc);
+ goto fail;
+ }
+ }
while (sensor_num < chip->max_channels_available) {
if (chip->sensor[sensor_num].high_thr_triggered) {
rc = qpnp_adc_tm_disable_rearm_high_thresholds(
@@ -1473,6 +2305,92 @@
pr_err("adc-tm high thr work failed\n");
}
+static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
+{
+ struct qpnp_adc_tm_chip *chip = data;
+ u8 mode_ctl = 0, status1 = 0, sensor_mask = 0;
+ int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
+
+ mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
+ /* Set measurement in single measurement mode */
+ qpnp_adc_tm_mode_select(chip, mode_ctl);
+
+ qpnp_adc_tm_disable(chip);
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1, 1);
+ if (rc) {
+ pr_err("adc-tm read status1 failed\n");
+ return IRQ_HANDLED;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_HIGH,
+ &chip->th_info.status_high, 1);
+ if (rc) {
+ pr_err("adc-tm-tm read status high failed with %d\n", rc);
+ return IRQ_HANDLED;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+ &chip->th_info.adc_tm_high_thr_set, 1);
+ if (rc) {
+ pr_err("adc-tm-tm read high thr failed with %d\n", rc);
+ return IRQ_HANDLED;
+ }
+
+ /* Check which interrupt threshold is lower and measure against the
+ * enabled channel
+ */
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+ &chip->th_info.qpnp_adc_tm_meas_en, 1);
+ if (rc) {
+ pr_err("adc-tm-tm read status high failed with %d\n", rc);
+ return IRQ_HANDLED;
+ }
+
+ chip->th_info.adc_tm_high_enable = chip->th_info.qpnp_adc_tm_meas_en &
+ chip->th_info.status_high;
+ chip->th_info.adc_tm_high_enable &= chip->th_info.adc_tm_high_thr_set;
+
+ sensor_notify_num = chip->th_info.adc_tm_high_enable;
+ while (i < chip->max_channels_available) {
+ if ((sensor_notify_num & 0x1) == 1)
+ sensor_num = i;
+ sensor_notify_num >>= 1;
+ i++;
+ }
+
+ if (!chip->sensor[sensor_num].thermal_node) {
+ sensor_mask = 1 << sensor_num;
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_HIGH_THR_INT_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("high threshold int read failed\n");
+ return IRQ_HANDLED;
+ }
+ } else {
+ /*
+ * Uses the thermal sysfs registered device to disable
+ * the corresponding high voltage threshold which
+ * is triggered by low temp
+ */
+ pr_debug("thermal node with mask:%x\n", sensor_mask);
+ rc = qpnp_adc_tm_activate_trip_type(
+ &chip->sensor[sensor_num],
+ ADC_TM_TRIP_LOW_COOL,
+ THERMAL_TRIP_ACTIVATION_DISABLED);
+ if (rc < 0) {
+ pr_err("notify error:%d\n", sensor_num);
+ return IRQ_HANDLED;
+ }
+ }
+
+ atomic_inc(&chip->wq_cnt);
+ queue_work(chip->high_thr_wq, &chip->trigger_high_thr_work);
+
+ return IRQ_HANDLED;
+}
+
static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
{
struct qpnp_adc_tm_chip *chip = container_of(work,
@@ -1493,6 +2411,89 @@
pr_err("adc-tm low thr work failed\n");
}
+static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
+{
+ struct qpnp_adc_tm_chip *chip = data;
+ u8 mode_ctl = 0, status1 = 0, sensor_mask = 0;
+ int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
+
+ mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
+ /* Set measurement in single measurement mode */
+ qpnp_adc_tm_mode_select(chip, mode_ctl);
+
+ qpnp_adc_tm_disable(chip);
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1, 1);
+ if (rc) {
+ pr_err("adc-tm read status1 failed\n");
+ return IRQ_HANDLED;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_LOW,
+ &chip->th_info.status_low, 1);
+ if (rc) {
+ pr_err("adc-tm-tm read status low failed with %d\n", rc);
+ return IRQ_HANDLED;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+ &chip->th_info.adc_tm_low_thr_set, 1);
+ if (rc) {
+ pr_err("adc-tm-tm read low thr failed with %d\n", rc);
+ return IRQ_HANDLED;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+ &chip->th_info.qpnp_adc_tm_meas_en, 1);
+ if (rc) {
+ pr_err("adc-tm-tm read status high failed with %d\n", rc);
+ return IRQ_HANDLED;
+ }
+
+ chip->th_info.adc_tm_low_enable = chip->th_info.qpnp_adc_tm_meas_en &
+ chip->th_info.status_low;
+ chip->th_info.adc_tm_low_enable &= chip->th_info.adc_tm_low_thr_set;
+
+ sensor_notify_num = chip->th_info.adc_tm_low_enable;
+ while (i < chip->max_channels_available) {
+ if ((sensor_notify_num & 0x1) == 1)
+ sensor_num = i;
+ sensor_notify_num >>= 1;
+ i++;
+ }
+
+ if (!chip->sensor[sensor_num].thermal_node) {
+ sensor_mask = 1 << sensor_num;
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_LOW_THR_INT_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("low threshold int read failed\n");
+ return IRQ_HANDLED;
+ }
+ } else {
+ /*
+ * Uses the thermal sysfs registered device to disable
+ * the corresponding low voltage threshold which
+ * is triggered by high temp
+ */
+ pr_debug("thermal node with mask:%x\n", sensor_mask);
+ rc = qpnp_adc_tm_activate_trip_type(
+ &chip->sensor[sensor_num],
+ ADC_TM_TRIP_HIGH_WARM,
+ THERMAL_TRIP_ACTIVATION_DISABLED);
+ if (rc < 0) {
+ pr_err("notify error:%d\n", sensor_num);
+ return IRQ_HANDLED;
+ }
+ }
+
+ atomic_inc(&chip->wq_cnt);
+ queue_work(chip->low_thr_wq, &chip->trigger_low_thr_work);
+
+ return IRQ_HANDLED;
+}
+
static int qpnp_adc_tm_rc_check_sensor_trip(struct qpnp_adc_tm_chip *chip,
u8 status_low, u8 status_high, int i,
int *sensor_low_notify_num, int *sensor_high_notify_num)
@@ -1743,11 +2744,18 @@
param->state_request;
chip->adc->amux_prop->calib_type =
chip->adc->adc_channels[dt_index].calib_type;
-
- rc = qpnp_adc_tm_hc_configure(chip, chip->adc->amux_prop);
- if (rc) {
- pr_err("adc-tm hc configure failed with %d\n", rc);
- goto fail_unlock;
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
+ if (rc) {
+ pr_err("adc-tm configure failed with %d\n", rc);
+ goto fail_unlock;
+ }
+ } else {
+ rc = qpnp_adc_tm_hc_configure(chip, chip->adc->amux_prop);
+ if (rc) {
+ pr_err("adc-tm hc configure failed with %d\n", rc);
+ goto fail_unlock;
+ }
}
chip->sensor[dt_index].scale_type = scale_type;
@@ -1763,6 +2771,7 @@
struct qpnp_adc_tm_btm_param *param)
{
uint32_t channel, dt_index = 0, btm_chan_num;
+ u8 sensor_mask = 0, mode_ctl = 0;
int rc = 0;
if (qpnp_adc_tm_is_valid(chip))
@@ -1770,6 +2779,16 @@
mutex_lock(&chip->adc->adc_lock);
+ if (!chip->adc_tm_hc) {
+ /* Set measurement in single measurement mode */
+ mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
+ rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
+ if (rc < 0) {
+ pr_err("adc-tm single mode select failed\n");
+ goto fail;
+ }
+ }
+
/* Disable bank */
rc = qpnp_adc_tm_disable(chip);
if (rc < 0) {
@@ -1777,6 +2796,15 @@
goto fail;
}
+ if (!chip->adc_tm_hc) {
+ /* Check if a conversion is in progress */
+ rc = qpnp_adc_tm_req_sts_check(chip);
+ if (rc < 0) {
+ pr_err("adc-tm req_sts check failed\n");
+ goto fail;
+ }
+ }
+
channel = param->channel;
while ((chip->adc->adc_channels[dt_index].channel_num
!= channel) && (dt_index < chip->max_channels_available))
@@ -1790,25 +2818,43 @@
btm_chan_num = chip->sensor[dt_index].btm_channel_num;
- rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
- QPNP_BTM_Mn_HIGH_THR_INT_EN, false);
- if (rc < 0) {
- pr_err("high thr disable err:%d\n", btm_chan_num);
- return rc;
- }
+ if (!chip->adc_tm_hc) {
+ sensor_mask = 1 << chip->sensor[dt_index].sensor_num;
- rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("high threshold int enable failed\n");
+ goto fail;
+ }
+
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("multi measurement en failed\n");
+ goto fail;
+ }
+ } else {
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
+ QPNP_BTM_Mn_HIGH_THR_INT_EN, false);
+ if (rc < 0) {
+ pr_err("high thr disable err:%d\n", btm_chan_num);
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
QPNP_BTM_Mn_LOW_THR_INT_EN, false);
- if (rc < 0) {
- pr_err("low thr disable err:%d\n", btm_chan_num);
- return rc;
- }
+ if (rc < 0) {
+ pr_err("low thr disable err:%d\n", btm_chan_num);
+ return rc;
+ }
- rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
QPNP_BTM_Mn_MEAS_EN, false);
- if (rc < 0) {
- pr_err("multi measurement disable failed\n");
- return rc;
+ if (rc < 0) {
+ pr_err("multi measurement disable failed\n");
+ return rc;
+ }
}
rc = qpnp_adc_tm_enable_if_channel_meas(chip);
@@ -1842,6 +2888,35 @@
}
EXPORT_SYMBOL(qpnp_get_adc_tm);
+static int qpnp_adc_tm_initial_setup(struct qpnp_adc_tm_chip *chip)
+{
+ u8 thr_init = 0;
+ int rc = 0;
+
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+ thr_init, 1);
+ if (rc < 0) {
+ pr_err("high thr init failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+ thr_init, 1);
+ if (rc < 0) {
+ pr_err("low thr init failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+ thr_init, 1);
+ if (rc < 0) {
+ pr_err("multi meas en failed\n");
+ return rc;
+ }
+
+ return rc;
+}
+
static const struct of_device_id qpnp_adc_tm_match_table[] = {
{ .compatible = "qcom,qpnp-adc-tm" },
{ .compatible = "qcom,qpnp-adc-tm-hc" },
@@ -1878,6 +2953,9 @@
if (!chip)
return -ENOMEM;
+ list_add(&chip->list, &qpnp_adc_tm_device_list);
+ chip->max_channels_available = count_adc_channel_list;
+
adc_qpnp = devm_kzalloc(&pdev->dev, sizeof(struct qpnp_adc_drv),
GFP_KERNEL);
if (!adc_qpnp) {
@@ -1894,8 +2972,10 @@
goto fail;
}
- chip->adc_tm_hc = true;
- chip->adc->adc_hc = true;
+ if (of_device_is_compatible(node, "qcom,qpnp-adc-tm-hc")) {
+ chip->adc_tm_hc = true;
+ chip->adc->adc_hc = true;
+ }
rc = qpnp_adc_get_devicetree_data(pdev, chip->adc);
if (rc) {
@@ -1904,6 +2984,24 @@
}
mutex_init(&chip->adc->adc_lock);
+ /* Register the ADC peripheral interrupt */
+ if (!chip->adc_tm_hc) {
+ chip->adc->adc_high_thr_irq = platform_get_irq_byname(pdev,
+ "high-thr-en-set");
+ if (chip->adc->adc_high_thr_irq < 0) {
+ pr_err("Invalid irq\n");
+ rc = -ENXIO;
+ goto fail;
+ }
+
+ chip->adc->adc_low_thr_irq = platform_get_irq_byname(pdev,
+ "low-thr-en-set");
+ if (chip->adc->adc_low_thr_irq < 0) {
+ pr_err("Invalid irq\n");
+ rc = -ENXIO;
+ goto fail;
+ }
+ }
chip->vadc_dev = qpnp_get_vadc(&pdev->dev, "adc_tm");
if (IS_ERR(chip->vadc_dev)) {
rc = PTR_ERR(chip->vadc_dev);
@@ -1989,7 +3087,6 @@
INIT_LIST_HEAD(&chip->sensor[sen_idx].thr_list);
sen_idx++;
}
- chip->max_channels_available = count_adc_channel_list;
chip->high_thr_wq = alloc_workqueue("qpnp_adc_tm_high_thr_wq",
WQ_HIGHPRI, 0);
@@ -2016,17 +3113,44 @@
INIT_WORK(&chip->trigger_low_thr_work, qpnp_adc_tm_low_thr_work);
atomic_set(&chip->wq_cnt, 0);
- rc = devm_request_irq(&pdev->dev, chip->adc->adc_irq_eoc,
- qpnp_adc_tm_rc_thr_isr,
- IRQF_TRIGGER_HIGH, "qpnp_adc_tm_interrupt", chip);
- if (rc)
- dev_err(&pdev->dev, "failed to request adc irq\n");
- else
- enable_irq_wake(chip->adc->adc_irq_eoc);
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_initial_setup(chip);
+ if (rc)
+ goto fail;
+ rc = devm_request_irq(&pdev->dev, chip->adc->adc_high_thr_irq,
+ qpnp_adc_tm_high_thr_isr,
+ IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", chip);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to request adc irq\n");
+ goto fail;
+ } else {
+ enable_irq_wake(chip->adc->adc_high_thr_irq);
+ }
+
+ rc = devm_request_irq(&pdev->dev, chip->adc->adc_low_thr_irq,
+ qpnp_adc_tm_low_thr_isr,
+ IRQF_TRIGGER_RISING,
+ "qpnp_adc_tm_low_interrupt", chip);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to request adc irq\n");
+ goto fail;
+ } else {
+ enable_irq_wake(chip->adc->adc_low_thr_irq);
+ }
+ } else {
+ rc = devm_request_irq(&pdev->dev, chip->adc->adc_irq_eoc,
+ qpnp_adc_tm_rc_thr_isr,
+ IRQF_TRIGGER_HIGH, "qpnp_adc_tm_interrupt", chip);
+ if (rc)
+ dev_err(&pdev->dev, "failed to request adc irq\n");
+ else
+ enable_irq_wake(chip->adc->adc_irq_eoc);
+ }
chip->adc_vote_enable = false;
dev_set_drvdata(&pdev->dev, chip);
- list_add(&chip->list, &qpnp_adc_tm_device_list);
+ spin_lock_init(&chip->th_info.adc_tm_low_lock);
+ spin_lock_init(&chip->th_info.adc_tm_high_lock);
pr_debug("OK\n");
return 0;
@@ -2044,6 +3168,7 @@
destroy_workqueue(chip->high_thr_wq);
if (chip->low_thr_wq)
destroy_workqueue(chip->low_thr_wq);
+ list_del(&chip->list);
dev_set_drvdata(&pdev->dev, NULL);
return rc;
}
diff --git a/drivers/thermal/tsens-mtc.c b/drivers/thermal/tsens-mtc.c
index 529503f..451c6c7 100644
--- a/drivers/thermal/tsens-mtc.c
+++ b/drivers/thermal/tsens-mtc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -30,7 +30,7 @@
}
EXPORT_SYMBOL(tsens_controller_is_present);
-static int tsens_mtc_reset_history_counter(unsigned int zone)
+int tsens_mtc_reset_history_counter(unsigned int zone)
{
unsigned int reg_cntl, is_valid;
void __iomem *sensor_addr;
diff --git a/drivers/thermal/tsens-mtc.h b/drivers/thermal/tsens-mtc.h
index 979513f..8782728 100644
--- a/drivers/thermal/tsens-mtc.h
+++ b/drivers/thermal/tsens-mtc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -57,3 +57,4 @@
extern int tsens_set_mtc_zone_sw_mask(unsigned int zone,
unsigned int th1_enable, unsigned int th2_enable);
extern int tsens_get_mtc_zone_log(unsigned int zone, void *zone_log);
+extern int tsens_mtc_reset_history_counter(unsigned int zone);
diff --git a/drivers/thermal/tsens1xxx.c b/drivers/thermal/tsens1xxx.c
index e2fad32..0ea4a46 100644
--- a/drivers/thermal/tsens1xxx.c
+++ b/drivers/thermal/tsens1xxx.c
@@ -53,6 +53,7 @@
#define TSENS_TRDY_RDY_MAX_TIME 2100
#define TSENS_THRESHOLD_MAX_CODE 0x3ff
#define TSENS_THRESHOLD_MIN_CODE 0x0
+#define TSENS_SCALE_MILLIDEG 1000
/* eeprom layout data for 8937 */
#define BASE0_MASK 0x000000ff
@@ -303,6 +304,7 @@
}
*temp = code_to_degc(last_temp, sensor);
+ *temp = *temp * TSENS_SCALE_MILLIDEG;
return 0;
}
@@ -386,6 +388,7 @@
spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
if (high_temp != INT_MAX) {
+ high_temp /= TSENS_SCALE_MILLIDEG;
high_code = degc_to_code(high_temp, tm_sensor);
tmdev->sensor[tm_sensor->hw_id].thr_state.high_adc_code =
high_code;
@@ -407,6 +410,7 @@
}
if (low_temp != INT_MIN) {
+ low_temp /= TSENS_SCALE_MILLIDEG;
low_code = degc_to_code(low_temp, tm_sensor);
tmdev->sensor[tm_sensor->hw_id].thr_state.low_adc_code =
low_code;
diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c
index af60a4b..0dc375f 100644
--- a/drivers/thermal/tsens2xxx.c
+++ b/drivers/thermal/tsens2xxx.c
@@ -31,6 +31,7 @@
#define TSENS_TM_CRITICAL_INT_EN BIT(2)
#define TSENS_TM_UPPER_INT_EN BIT(1)
#define TSENS_TM_LOWER_INT_EN BIT(0)
+#define TSENS_TM_UPPER_LOWER_INT_DISABLE 0xffffffff
#define TSENS_TM_SN_UPPER_LOWER_THRESHOLD(n) ((n) + 0x20)
#define TSENS_TM_SN_ADDR_OFFSET 0x4
#define TSENS_TM_UPPER_THRESHOLD_SET(n) ((n) << 12)
@@ -531,6 +532,7 @@
void __iomem *srot_addr;
void __iomem *sensor_int_mask_addr;
unsigned int srot_val, crit_mask, crit_val;
+ void __iomem *int_mask_addr;
srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
srot_val = readl_relaxed(srot_addr);
@@ -573,6 +575,9 @@
mb();
}
+ int_mask_addr = TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_tm_addr);
+ writel_relaxed(TSENS_TM_UPPER_LOWER_INT_DISABLE, int_mask_addr);
+
writel_relaxed(TSENS_TM_CRITICAL_INT_EN |
TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN,
TSENS_TM_INT_EN(tmdev->tsens_tm_addr));
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 2e2b88a..dce39de 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -968,6 +968,8 @@
}
} else {
retval = uart_startup(tty, state, 1);
+ if (retval == 0)
+ tty_port_set_initialized(port, true);
if (retval > 0)
retval = 0;
}
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 001c807..e0ed5d8 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -19,6 +19,14 @@
config USB_EHCI_BIG_ENDIAN_DESC
bool
+config USB_UHCI_BIG_ENDIAN_MMIO
+ bool
+ default y if SPARC_LEON
+
+config USB_UHCI_BIG_ENDIAN_DESC
+ bool
+ default y if SPARC_LEON
+
menuconfig USB_SUPPORT
bool "USB support"
depends on HAS_IOMEM
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index e0321a1..d1a63da 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -256,9 +256,9 @@
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
- dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT, 0);
- dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT, 0);
return 0;
}
@@ -366,7 +366,7 @@
dwc3_free_one_event_buffer(dwc, evt);
/* free GSI related event buffers */
- dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_FREE);
+ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_FREE, 0);
}
/**
@@ -389,7 +389,7 @@
dwc->ev_buf = evt;
/* alloc GSI related event buffers */
- dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_ALLOC);
+ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_ALLOC, 0);
return 0;
}
@@ -420,7 +420,7 @@
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
/* setup GSI related event buffers */
- dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_SETUP);
+ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_SETUP, 0);
return 0;
}
@@ -442,7 +442,7 @@
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
/* cleanup GSI related event buffers */
- dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEANUP);
+ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEANUP, 0);
}
static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
@@ -1026,19 +1026,20 @@
dwc3_gadget_restart(dwc);
}
-static void (*notify_event)(struct dwc3 *, unsigned int);
-void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned int))
+static void (*notify_event)(struct dwc3 *, unsigned int, unsigned int);
+void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned int,
+ unsigned int))
{
notify_event = notify;
}
EXPORT_SYMBOL(dwc3_set_notifier);
-int dwc3_notify_event(struct dwc3 *dwc, unsigned int event)
+int dwc3_notify_event(struct dwc3 *dwc, unsigned int event, unsigned int value)
{
int ret = 0;
if (dwc->notify_event)
- dwc->notify_event(dwc, event);
+ dwc->notify_event(dwc, event, value);
else
ret = -ENODEV;
@@ -1247,6 +1248,10 @@
"snps,disable-clk-gating");
dwc->enable_bus_suspend = device_property_read_bool(dev,
"snps,bus-suspend-enable");
+ dwc->usb3_u1u2_disable = device_property_read_bool(dev,
+ "snps,usb3-u1u2-disable");
+ dwc->usb2_l1_disable = device_property_read_bool(dev,
+ "snps,usb2-l1-disable");
if (dwc->enable_bus_suspend) {
pm_runtime_set_autosuspend_delay(dev, 500);
pm_runtime_use_autosuspend(dev);
@@ -1459,7 +1464,7 @@
int ret;
/* Check if platform glue driver handling PM, if not then handle here */
- if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT))
+ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0))
return 0;
ret = dwc3_suspend_common(dwc);
@@ -1477,7 +1482,7 @@
int ret;
/* Check if platform glue driver handling PM, if not then handle here */
- if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT))
+ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0))
return 0;
device_init_wakeup(dev, false);
@@ -1533,7 +1538,7 @@
int ret;
/* Check if platform glue driver handling PM, if not then handle here */
- if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT))
+ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT, 0))
return 0;
ret = dwc3_suspend_common(dwc);
@@ -1551,7 +1556,7 @@
int ret;
/* Check if platform glue driver handling PM, if not then handle here */
- if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT))
+ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0))
return 0;
pinctrl_pm_select_default_state(dev);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index b91642a..4407a83 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -821,21 +821,22 @@
__le64 dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
};
-#define DWC3_CONTROLLER_ERROR_EVENT 0
-#define DWC3_CONTROLLER_RESET_EVENT 1
-#define DWC3_CONTROLLER_POST_RESET_EVENT 2
-#define DWC3_CORE_PM_SUSPEND_EVENT 3
-#define DWC3_CORE_PM_RESUME_EVENT 4
-#define DWC3_CONTROLLER_CONNDONE_EVENT 5
-#define DWC3_CONTROLLER_NOTIFY_OTG_EVENT 6
-#define DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT 7
-#define DWC3_CONTROLLER_RESTART_USB_SESSION 8
+#define DWC3_CONTROLLER_ERROR_EVENT 0
+#define DWC3_CONTROLLER_RESET_EVENT 1
+#define DWC3_CONTROLLER_POST_RESET_EVENT 2
+#define DWC3_CORE_PM_SUSPEND_EVENT 3
+#define DWC3_CORE_PM_RESUME_EVENT 4
+#define DWC3_CONTROLLER_CONNDONE_EVENT 5
+#define DWC3_CONTROLLER_NOTIFY_OTG_EVENT 6
+#define DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT 7
+#define DWC3_CONTROLLER_RESTART_USB_SESSION 8
+#define DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER 9
/* USB GSI event buffer related notification */
-#define DWC3_GSI_EVT_BUF_ALLOC 9
-#define DWC3_GSI_EVT_BUF_SETUP 10
-#define DWC3_GSI_EVT_BUF_CLEANUP 11
-#define DWC3_GSI_EVT_BUF_FREE 12
+#define DWC3_GSI_EVT_BUF_ALLOC 10
+#define DWC3_GSI_EVT_BUF_SETUP 11
+#define DWC3_GSI_EVT_BUF_CLEANUP 12
+#define DWC3_GSI_EVT_BUF_FREE 13
#define MAX_INTR_STATS 10
@@ -942,6 +943,8 @@
* 3 - Reserved
* @is_drd: device supports dual-role or not
* @err_evt_seen: previous event in queue was erratic error
+ * @usb3_u1u2_disable: if true, disable U1U2 low power modes in Superspeed mode
+ * @usb1_l1_disable: if true, disable L1 low power modes in Highspeed mode
* @in_lpm: indicates if controller is in low power mode (no clocks)
* @tx_fifo_size: Available RAM size for TX fifo allocation
* @irq: irq number
@@ -1081,7 +1084,7 @@
const char *hsphy_interface;
unsigned connected:1;
- void (*notify_event)(struct dwc3 *, unsigned int);
+ void (*notify_event)(struct dwc3 *, unsigned int, unsigned int);
struct work_struct wakeup_work;
unsigned delayed_status:1;
@@ -1125,6 +1128,8 @@
/* Indicate if need to disable controller internal clkgating */
unsigned disable_clk_gating:1;
unsigned enable_bus_suspend:1;
+ unsigned usb3_u1u2_disable:1;
+ unsigned usb2_l1_disable:1;
atomic_t in_lpm;
int tx_fifo_size;
@@ -1416,6 +1421,9 @@
void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend);
extern void dwc3_set_notifier(
- void (*notify)(struct dwc3 *dwc3, unsigned int event));
-extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned int event);
+ void (*notify)(struct dwc3 *dwc3, unsigned int event,
+ unsigned int value));
+extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned int event,
+ unsigned int value);
+
#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/dbm.c b/drivers/usb/dwc3/dbm.c
index 44c082a..48b3894 100644
--- a/drivers/usb/dwc3/dbm.c
+++ b/drivers/usb/dwc3/dbm.c
@@ -37,6 +37,7 @@
DBM_HW_TRB2_EP,
DBM_HW_TRB3_EP,
DBM_PIPE_CFG,
+ DBM_DISABLE_UPDXFER,
DBM_SOFT_RESET,
DBM_GEN_CFG,
DBM_GEVNTADR_LSB,
@@ -103,6 +104,7 @@
[DBM_HW_TRB2_EP] = { 0x0240, 0x4 },
[DBM_HW_TRB3_EP] = { 0x0250, 0x4 },
[DBM_PIPE_CFG] = { 0x0274, 0x0 },
+ [DBM_DISABLE_UPDXFER] = { 0x0298, 0x0 },
[DBM_SOFT_RESET] = { 0x020C, 0x0 },
[DBM_GEN_CFG] = { 0x0210, 0x0 },
[DBM_GEVNTADR_LSB] = { 0x0260, 0x0 },
@@ -192,7 +194,7 @@
if (dbm->ep_num_mapping[i] == usb_ep)
return i;
- pr_err("%s: No DBM EP matches USB EP %d", __func__, usb_ep);
+ pr_debug("%s: No DBM EP matches USB EP %d", __func__, usb_ep);
return -ENODEV; /* Not found */
}
@@ -291,6 +293,7 @@
{
int dbm_ep;
u32 ep_cfg;
+ u32 data;
if (!dbm) {
pr_err("%s: dbm pointer is NULL!\n", __func__);
@@ -312,9 +315,6 @@
return -ENODEV;
}
- /* First, reset the dbm endpoint */
- ep_soft_reset(dbm, dbm_ep, 0);
-
/* Set ioc bit for dbm_ep if needed */
msm_dbm_write_reg_field(dbm, DBM_DBG_CNFG,
DBM_ENABLE_IOC_MASK & 1 << dbm_ep, ioc ? 1 : 0);
@@ -337,6 +337,10 @@
msm_dbm_write_ep_reg_field(dbm, DBM_EP_CFG, dbm_ep, DBM_EN_EP, 1);
+ data = msm_dbm_read_reg(dbm, DBM_DISABLE_UPDXFER);
+ data &= ~(0x1 << dbm_ep);
+ msm_dbm_write_reg(dbm, DBM_DISABLE_UPDXFER, data);
+
return dbm_ep;
}
@@ -381,7 +385,7 @@
dbm_ep = find_matching_dbm_ep(dbm, usb_ep);
if (dbm_ep < 0) {
- pr_err("usb ep index %d has no corresponding dbm ep\n", usb_ep);
+ pr_debug("usb ep index %d has no corespondng dbm ep\n", usb_ep);
return -ENODEV;
}
@@ -391,23 +395,10 @@
data &= (~0x1);
msm_dbm_write_ep_reg(dbm, DBM_EP_CFG, dbm_ep, data);
- /* Reset the dbm endpoint */
- ep_soft_reset(dbm, dbm_ep, true);
/*
- * The necessary delay between asserting and deasserting the dbm ep
- * reset is based on the number of active endpoints. If there is more
- * than one endpoint, a 1 msec delay is required. Otherwise, a shorter
- * delay will suffice.
- *
- * As this function can be called in atomic context, sleeping variants
- * for delay are not possible - albeit a 1ms delay.
+ * ep_soft_reset is not required during disconnect as pipe reset on
+ * next connect will take care of the same.
*/
- if (dbm_get_num_of_eps_configured(dbm) > 1)
- udelay(1000);
- else
- udelay(10);
- ep_soft_reset(dbm, dbm_ep, false);
-
return 0;
}
@@ -449,6 +440,35 @@
return 0;
}
+/**
+ * Disable update xfer before queueing stop xfer command to USB3 core.
+ *
+ * @usb_ep - USB physical EP number.
+ *
+ */
+int dwc3_dbm_disable_update_xfer(struct dbm *dbm, u8 usb_ep)
+{
+ u32 data;
+ int dbm_ep;
+
+ if (!dbm) {
+ pr_err("%s: dbm pointer is NULL!\n", __func__);
+ return -EPERM;
+ }
+
+ dbm_ep = find_matching_dbm_ep(dbm, usb_ep);
+
+ if (dbm_ep < 0) {
+ pr_err("usb ep index %d has no corresponding dbm ep\n", usb_ep);
+ return -ENODEV;
+ }
+
+ data = msm_dbm_read_reg(dbm, DBM_DISABLE_UPDXFER);
+ data |= (0x1 << dbm_ep);
+ msm_dbm_write_reg(dbm, DBM_DISABLE_UPDXFER, data);
+
+ return 0;
+}
int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, unsigned long addr,
u32 size, u8 dst_pipe_idx)
diff --git a/drivers/usb/dwc3/dbm.h b/drivers/usb/dwc3/dbm.h
index d8e1ce9..259900d 100644
--- a/drivers/usb/dwc3/dbm.h
+++ b/drivers/usb/dwc3/dbm.h
@@ -65,6 +65,7 @@
int size);
int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, unsigned long addr,
u32 size, u8 dst_pipe_idx);
+int dwc3_dbm_disable_update_xfer(struct dbm *dbm, u8 usb_ep);
void dbm_set_speed(struct dbm *dbm, bool speed);
void dbm_enable(struct dbm *dbm);
int dbm_ep_soft_reset(struct dbm *dbm, u8 usb_ep, bool enter_reset);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index a91dceb0..ded62f1 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -289,7 +289,8 @@
static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc);
static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA);
-static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event);
+static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
+ unsigned int value);
static int dwc3_restart_usb_host_mode(struct notifier_block *nb,
unsigned long event, void *ptr);
@@ -441,6 +442,16 @@
return dwc3_msm_is_dev_superspeed(mdwc);
}
+static int dwc3_msm_dbm_disable_updxfer(struct dwc3 *dwc, u8 usb_ep)
+{
+ struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
+
+ dev_dbg(mdwc->dev, "%s\n", __func__);
+ dwc3_dbm_disable_update_xfer(mdwc->dbm, usb_ep);
+
+ return 0;
+}
+
#if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
/**
* Configure the DBM with the BAM's data fifo.
@@ -697,67 +708,8 @@
struct dwc3_msm_req_complete *req_complete;
unsigned long flags;
int ret = 0, size;
- u8 bam_pipe;
- bool producer;
- bool disable_wb;
- bool internal_mem;
- bool ioc;
bool superspeed;
- if (!(request->udc_priv & MSM_SPS_MODE)) {
- /* Not SPS mode, call original queue */
- dev_vdbg(mdwc->dev, "%s: not sps mode, use regular queue\n",
- __func__);
-
- return (mdwc->original_ep_ops[dep->number])->queue(ep,
- request,
- gfp_flags);
- }
-
- /* HW restriction regarding TRB size (8KB) */
- if (req->request.length < 0x2000) {
- dev_err(mdwc->dev, "%s: Min TRB size is 8KB\n", __func__);
- return -EINVAL;
- }
-
- /*
- * Override req->complete function, but before doing that,
- * store it's original pointer in the req_complete_list.
- */
- req_complete = kzalloc(sizeof(*req_complete), gfp_flags);
- if (!req_complete)
- return -ENOMEM;
-
- req_complete->req = request;
- req_complete->orig_complete = request->complete;
- list_add_tail(&req_complete->list_item, &mdwc->req_complete_list);
- request->complete = dwc3_msm_req_complete_func;
-
- /*
- * Configure the DBM endpoint
- */
- bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK;
- producer = ((request->udc_priv & MSM_PRODUCER) ? true : false);
- disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false);
- internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false);
- ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false);
-
- ret = dbm_ep_config(mdwc->dbm, dep->number, bam_pipe, producer,
- disable_wb, internal_mem, ioc);
- if (ret < 0) {
- dev_err(mdwc->dev,
- "error %d after calling dbm_ep_config\n", ret);
- return ret;
- }
-
- dev_vdbg(dwc->dev, "%s: queing request %p to ep %s length %d\n",
- __func__, request, ep->name, request->length);
- size = dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTSIZ(0));
- dbm_event_buffer_config(mdwc->dbm,
- dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRLO(0)),
- dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRHI(0)),
- DWC3_GEVNTSIZ_SIZE(size));
-
/*
* We must obtain the lock of the dwc3 core driver,
* including disabling interrupts, so we will be sure
@@ -770,31 +722,83 @@
dev_err(mdwc->dev,
"%s: trying to queue request %p to disabled ep %s\n",
__func__, request, ep->name);
- ret = -EPERM;
- goto err;
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EPERM;
+ }
+
+ if (!mdwc->original_ep_ops[dep->number]) {
+ dev_err(mdwc->dev,
+ "ep [%s,%d] was unconfigured as msm endpoint\n",
+ ep->name, dep->number);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EINVAL;
+ }
+
+ if (!request) {
+ dev_err(mdwc->dev, "%s: request is NULL\n", __func__);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EINVAL;
+ }
+
+ if (!(request->udc_priv & MSM_SPS_MODE)) {
+ dev_err(mdwc->dev, "%s: sps mode is not set\n",
+ __func__);
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EINVAL;
+ }
+
+ /* HW restriction regarding TRB size (8KB) */
+ if (req->request.length < 0x2000) {
+ dev_err(mdwc->dev, "%s: Min TRB size is 8KB\n", __func__);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EINVAL;
}
if (dep->number == 0 || dep->number == 1) {
dev_err(mdwc->dev,
"%s: trying to queue dbm request %p to control ep %s\n",
__func__, request, ep->name);
- ret = -EPERM;
- goto err;
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EPERM;
}
-
- if (dep->trb_dequeue != dep->trb_enqueue ||
- !list_empty(&dep->pending_list)
- || !list_empty(&dep->started_list)) {
+ if (dep->trb_dequeue != dep->trb_enqueue
+ || !list_empty(&dep->pending_list)
+ || !list_empty(&dep->started_list)) {
dev_err(mdwc->dev,
"%s: trying to queue dbm request %p tp ep %s\n",
__func__, request, ep->name);
- ret = -EPERM;
- goto err;
- } else {
- dep->trb_dequeue = 0;
- dep->trb_enqueue = 0;
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EPERM;
}
+ dep->trb_dequeue = 0;
+ dep->trb_enqueue = 0;
+
+ /*
+ * Override req->complete function, but before doing that,
+ * store it's original pointer in the req_complete_list.
+ */
+ req_complete = kzalloc(sizeof(*req_complete), gfp_flags);
+
+ if (!req_complete) {
+ dev_err(mdwc->dev, "%s: not enough memory\n", __func__);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -ENOMEM;
+ }
+
+ req_complete->req = request;
+ req_complete->orig_complete = request->complete;
+ list_add_tail(&req_complete->list_item, &mdwc->req_complete_list);
+ request->complete = dwc3_msm_req_complete_func;
+
+ dev_vdbg(dwc->dev, "%s: queing request %p to ep %s length %d\n",
+ __func__, request, ep->name, request->length);
+ size = dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTSIZ(0));
+ dbm_event_buffer_config(mdwc->dbm,
+ dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRLO(0)),
+ dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRHI(0)),
+ DWC3_GEVNTSIZ_SIZE(size));
ret = __dwc3_msm_ep_queue(dep, req);
if (ret < 0) {
@@ -1471,37 +1475,68 @@
*
* @return int - 0 on success, negetive on error.
*/
-int msm_ep_config(struct usb_ep *ep)
+int msm_ep_config(struct usb_ep *ep, struct usb_request *request)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
struct usb_ep_ops *new_ep_ops;
+ int ret = 0;
+ u8 bam_pipe;
+ bool producer;
+ bool disable_wb;
+ bool internal_mem;
+ bool ioc;
+ unsigned long flags;
+ spin_lock_irqsave(&dwc->lock, flags);
/* Save original ep ops for future restore*/
if (mdwc->original_ep_ops[dep->number]) {
dev_err(mdwc->dev,
"ep [%s,%d] already configured as msm endpoint\n",
ep->name, dep->number);
+ spin_unlock_irqrestore(&dwc->lock, flags);
return -EPERM;
}
mdwc->original_ep_ops[dep->number] = ep->ops;
/* Set new usb ops as we like */
new_ep_ops = kzalloc(sizeof(struct usb_ep_ops), GFP_ATOMIC);
- if (!new_ep_ops)
+ if (!new_ep_ops) {
+ spin_unlock_irqrestore(&dwc->lock, flags);
return -ENOMEM;
+ }
(*new_ep_ops) = (*ep->ops);
new_ep_ops->queue = dwc3_msm_ep_queue;
new_ep_ops->gsi_ep_op = dwc3_msm_gsi_ep_op;
ep->ops = new_ep_ops;
+ if (!mdwc->dbm || !request || (dep->endpoint.ep_type == EP_TYPE_GSI)) {
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return 0;
+ }
+
/*
- * Do HERE more usb endpoint configurations
- * which are specific to MSM.
+ * Configure the DBM endpoint if required.
*/
+ bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK;
+ producer = ((request->udc_priv & MSM_PRODUCER) ? true : false);
+ disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false);
+ internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false);
+ ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false);
+
+ ret = dbm_ep_config(mdwc->dbm, dep->number, bam_pipe, producer,
+ disable_wb, internal_mem, ioc);
+ if (ret < 0) {
+ dev_err(mdwc->dev,
+ "error %d after calling dbm_ep_config\n", ret);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return ret;
+ }
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
@@ -1522,12 +1557,15 @@
struct dwc3 *dwc = dep->dwc;
struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
struct usb_ep_ops *old_ep_ops;
+ unsigned long flags;
+ spin_lock_irqsave(&dwc->lock, flags);
/* Restore original ep ops */
if (!mdwc->original_ep_ops[dep->number]) {
dev_err(mdwc->dev,
"ep [%s,%d] was not configured as msm endpoint\n",
ep->name, dep->number);
+ spin_unlock_irqrestore(&dwc->lock, flags);
return -EINVAL;
}
old_ep_ops = (struct usb_ep_ops *)ep->ops;
@@ -1539,6 +1577,32 @@
* Do HERE more usb endpoint un-configurations
* which are specific to MSM.
*/
+ if (!mdwc->dbm || (dep->endpoint.ep_type == EP_TYPE_GSI)) {
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return 0;
+ }
+
+ if (dep->trb_dequeue == dep->trb_enqueue
+ && list_empty(&dep->pending_list)
+ && list_empty(&dep->started_list)) {
+ dev_dbg(mdwc->dev,
+ "%s: request is not queued, disable DBM ep for ep %s\n",
+ __func__, ep->name);
+ /* Unconfigure dbm ep */
+ dbm_ep_unconfig(mdwc->dbm, dep->number);
+
+ /*
+ * If this is the last endpoint we unconfigured, than reset also
+ * the event buffers; unless unconfiguring the ep due to lpm,
+ * in which case the event buffer only gets reset during the
+ * block reset.
+ */
+ if (dbm_get_num_of_eps_configured(mdwc->dbm) == 0 &&
+ !dbm_reset_ep_after_lpm(mdwc->dbm))
+ dbm_event_buffer_config(mdwc->dbm, 0, 0, 0);
+ }
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
@@ -1764,7 +1828,8 @@
dwc3_msm_gadget_vbus_draw(mdwc, dwc->vbus_draw);
}
-static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event)
+static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
+ unsigned int value)
{
struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
struct dwc3_event_buffer *evt;
@@ -1951,6 +2016,9 @@
evt->buf, evt->dma);
}
break;
+ case DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER:
+ dwc3_msm_dbm_disable_updxfer(dwc, value);
+ break;
default:
dev_dbg(mdwc->dev, "unknown dwc3 event\n");
break;
@@ -3819,6 +3887,9 @@
if (on) {
dev_dbg(mdwc->dev, "%s: turn on host\n", __func__);
+ pm_runtime_get_sync(mdwc->dev);
+ dbg_event(0xFF, "StrtHost gync",
+ atomic_read(&mdwc->dev->power.usage_count));
mdwc->hs_phy->flags |= PHY_HOST_MODE;
if (dwc->maximum_speed == USB_SPEED_SUPER) {
mdwc->ss_phy->flags |= PHY_HOST_MODE;
@@ -3827,9 +3898,6 @@
}
usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH);
- pm_runtime_get_sync(mdwc->dev);
- dbg_event(0xFF, "StrtHost gync",
- atomic_read(&mdwc->dev->power.usage_count));
if (!IS_ERR_OR_NULL(mdwc->vbus_reg))
ret = regulator_enable(mdwc->vbus_reg);
if (ret) {
diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c
index fe414e7..a3e2200 100644
--- a/drivers/usb/dwc3/dwc3-of-simple.c
+++ b/drivers/usb/dwc3/dwc3-of-simple.c
@@ -58,8 +58,10 @@
clk = of_clk_get(np, i);
if (IS_ERR(clk)) {
- while (--i >= 0)
+ while (--i >= 0) {
+ clk_disable_unprepare(simple->clks[i]);
clk_put(simple->clks[i]);
+ }
return PTR_ERR(clk);
}
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 986c97c..8cf49fa 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -16,6 +16,7 @@
* GNU General Public License for more details.
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -35,6 +36,10 @@
#include "gadget.h"
#include "io.h"
+static bool enable_dwc3_u1u2;
+module_param(enable_dwc3_u1u2, bool, 0644);
+MODULE_PARM_DESC(enable_dwc3_u1u2, "Enable support for U1U2 low power modes");
+
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
struct dwc3_ep *dep, struct dwc3_request *req);
@@ -454,6 +459,9 @@
(dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
return -EINVAL;
+ if (dwc->usb3_u1u2_disable && !enable_dwc3_u1u2)
+ return -EINVAL;
+
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (set)
reg |= DWC3_DCTL_INITU1ENA;
@@ -469,6 +477,9 @@
(dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
return -EINVAL;
+ if (dwc->usb3_u1u2_disable && !enable_dwc3_u1u2)
+ return -EINVAL;
+
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (set)
reg |= DWC3_DCTL_INITU2ENA;
@@ -639,13 +650,16 @@
usb_gadget_set_state(&dwc->gadget,
USB_STATE_CONFIGURED);
- /*
- * Enable transition to U1/U2 state when
- * nothing is pending from application.
- */
- reg = dwc3_readl(dwc->regs, DWC3_DCTL);
- reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
- dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+ if (!dwc->usb3_u1u2_disable || enable_dwc3_u1u2) {
+ /*
+ * Enable transition to U1/U2 state when
+ * nothing is pending from application.
+ */
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg |= (DWC3_DCTL_ACCEPTU1ENA |
+ DWC3_DCTL_ACCEPTU2ENA);
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+ }
}
break;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 8f0ca3f..f90d0c9 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -39,6 +39,7 @@
static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc, bool remote_wakeup);
static int dwc3_gadget_wakeup_int(struct dwc3 *dwc);
+static void dwc3_stop_active_transfers(struct dwc3 *dwc);
/**
* dwc3_gadget_set_test_mode - Enables USB2 Test Modes
* @dwc: pointer to our context structure
@@ -416,7 +417,7 @@
if (cmd != DWC3_DEPCMD_ENDTRANSFER) {
dwc->ep_cmd_timeout_cnt++;
dwc3_notify_event(dwc,
- DWC3_CONTROLLER_RESTART_USB_SESSION);
+ DWC3_CONTROLLER_RESTART_USB_SESSION, 0);
}
cmd_status = -ETIMEDOUT;
}
@@ -1081,7 +1082,7 @@
*/
if (dep->trb_enqueue == dep->trb_dequeue) {
tmp = dwc3_ep_prev_trb(dep, dep->trb_enqueue);
- if (tmp->ctrl & DWC3_TRB_CTRL_HWO)
+ if (!tmp || tmp->ctrl & DWC3_TRB_CTRL_HWO)
return 0;
return DWC3_TRB_NUM - 1;
@@ -2034,6 +2035,14 @@
__dwc3_gadget_ep_disable(dwc->eps[0]);
__dwc3_gadget_ep_disable(dwc->eps[1]);
+ /*
+ * According to dwc3 databook, it is must to remove any active
+ * transfers before trying to stop USB device controller. Hence
+ * call dwc3_stop_active_transfers() API before stopping USB
+ * device controller.
+ */
+ dwc3_stop_active_transfers(dwc);
+
reg &= ~DWC3_DCTL_RUN_STOP;
if (dwc->has_hibernation && !suspend)
@@ -2074,7 +2083,7 @@
dwc->vbus_draw = mA;
dev_dbg(dwc->dev, "Notify controller from %s. mA = %u\n", __func__, mA);
dbg_event(0xFF, "currentDraw", mA);
- dwc3_notify_event(dwc, DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT, 0);
return 0;
}
@@ -2105,7 +2114,8 @@
* during enumeration.
*/
dwc->b_suspend = false;
- dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
+
ret = dwc3_gadget_run_stop(dwc, is_on, false);
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -2416,7 +2426,7 @@
struct dwc3 *dwc = gadget_to_dwc(g);
dbg_event(0xFF, "RestartUSBSession", 0);
- return dwc3_notify_event(dwc, DWC3_CONTROLLER_RESTART_USB_SESSION);
+ return dwc3_notify_event(dwc, DWC3_CONTROLLER_RESTART_USB_SESSION, 0);
}
static const struct usb_gadget_ops dwc3_gadget_ops = {
@@ -2969,6 +2979,10 @@
if (!dep->resource_index)
return;
+ if (dep->endpoint.endless)
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER,
+ dep->number);
+
/*
* NOTICE: We are violating what the Databook says about the
* EndTransfer command. Ideally we would _always_ wait for the
@@ -3062,7 +3076,7 @@
dbg_event(0xFF, "DISCONNECT INT", 0);
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
dwc->b_suspend = false;
- dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_INITU1ENA;
@@ -3122,7 +3136,7 @@
dbg_event(0xFF, "BUS RESET", 0);
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
dwc->b_suspend = false;
- dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
dwc3_usb3_phy_suspend(dwc, false);
usb_gadget_vbus_draw(&dwc->gadget, 100);
@@ -3297,7 +3311,8 @@
return;
}
- dwc3_notify_event(dwc, DWC3_CONTROLLER_CONNDONE_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_CONNDONE_EVENT, 0);
+
/*
* Configure PHY via GUSB3PIPECTLn if required.
*
@@ -3332,7 +3347,8 @@
*/
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
dwc->b_suspend = false;
- dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+ dwc3_notify_event(dwc,
+ DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
/*
* set state to U0 as function level resume is trying to queue
@@ -3476,7 +3492,7 @@
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
dwc->b_suspend = true;
- dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
}
dwc->link_state = next;
@@ -3640,7 +3656,8 @@
evt->lpos = (evt->lpos + left) %
DWC3_EVENT_BUFFERS_SIZE;
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), left);
- if (dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT))
+ if (dwc3_notify_event(dwc,
+ DWC3_CONTROLLER_ERROR_EVENT, 0))
dwc->err_evt_seen = 0;
break;
}
@@ -3863,6 +3880,7 @@
dwc->gadget.sg_supported = true;
dwc->gadget.name = "dwc3-gadget";
dwc->gadget.is_otg = dwc->dr_mode == USB_DR_MODE_OTG;
+ dwc->gadget.l1_supported = !dwc->usb2_l1_disable;
/*
* FIXME We might be setting max_speed to <SUPER, however versions
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index a5659f99..75205bf 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -3808,6 +3808,7 @@
udc->gadget.max_speed = USB_SPEED_HIGH;
udc->gadget.is_otg = 0;
udc->gadget.name = driver->name;
+ udc->gadget.is_chipidea = true;
/* alloc resources */
udc->qh_pool = dma_pool_create("ci13xxx_qh", dev,
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 0390c72..f6fc30a 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1733,10 +1733,12 @@
if (gadget->speed >= USB_SPEED_SUPER) {
cdev->desc.bcdUSB = cpu_to_le16(0x0310);
cdev->desc.bMaxPacketSize0 = 9;
- } else if (!disable_l1_for_hs) {
+ } else if (gadget->l1_supported
+ && !disable_l1_for_hs) {
cdev->desc.bcdUSB = cpu_to_le16(0x0210);
}
- } else if (!disable_l1_for_hs) {
+ } else if (gadget->l1_supported
+ && !disable_l1_for_hs) {
cdev->desc.bcdUSB = cpu_to_le16(0x0210);
DBG(cdev, "Config HS device with LPM(L1)\n");
}
@@ -1748,7 +1750,9 @@
if (!gadget_is_dualspeed(gadget) ||
gadget->speed >= USB_SPEED_SUPER)
break;
+ spin_lock(&cdev->lock);
device_qual(cdev);
+ spin_unlock(&cdev->lock);
value = min_t(int, w_length,
sizeof(struct usb_qualifier_descriptor));
break;
@@ -1758,7 +1762,9 @@
break;
/* FALLTHROUGH */
case USB_DT_CONFIG:
+ spin_lock(&cdev->lock);
value = config_desc(cdev, w_value);
+ spin_unlock(&cdev->lock);
if (value >= 0)
value = min(w_length, (u16) value);
break;
@@ -1769,8 +1775,10 @@
value = min(w_length, (u16) value);
break;
case USB_DT_BOS:
- if (gadget_is_superspeed(gadget) ||
- !disable_l1_for_hs) {
+ if ((gadget_is_superspeed(gadget) &&
+ (gadget->speed >= USB_SPEED_SUPER)) ||
+ (gadget->l1_supported
+ && !disable_l1_for_hs)) {
value = bos_desc(cdev);
value = min(w_length, (u16) value);
}
@@ -2262,7 +2270,8 @@
if (!cdev->req)
return -ENOMEM;
- cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
+ cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ +
+ (gadget->extra_buf_alloc), GFP_KERNEL);
if (!cdev->req->buf)
goto fail;
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile
index 0e96740..a9344a5 100644
--- a/drivers/usb/gadget/function/Makefile
+++ b/drivers/usb/gadget/function/Makefile
@@ -64,7 +64,7 @@
obj-$(CONFIG_USB_F_GSI) += usb_f_gsi.o
usb_f_qdss-y := f_qdss.o u_qdss.o
obj-$(CONFIG_USB_F_QDSS) += usb_f_qdss.o
-usb_f_qcrndis-y := f_qc_rndis.o rndis.o u_data_ipa.o
+usb_f_qcrndis-y := f_qc_rndis.o u_data_ipa.o
obj-$(CONFIG_USB_F_QCRNDIS) += usb_f_qcrndis.o
-usb_f_rmnet_bam-y := f_rmnet.o u_ctrl_qti.o
+usb_f_rmnet_bam-y := f_rmnet.o u_ctrl_qti.o u_bam_dmux.o
obj-$(CONFIG_USB_F_RMNET_BAM) += usb_f_rmnet_bam.o
diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c
index 899cbf1..45339c8 100644
--- a/drivers/usb/gadget/function/f_accessory.c
+++ b/drivers/usb/gadget/function/f_accessory.c
@@ -586,7 +586,8 @@
/* now allocate requests for our endpoints */
for (i = 0; i < TX_REQ_MAX; i++) {
- req = acc_request_new(dev->ep_in, BULK_BUFFER_SIZE);
+ req = acc_request_new(dev->ep_in,
+ BULK_BUFFER_SIZE + cdev->gadget->extra_buf_alloc);
if (!req)
goto fail;
req->complete = acc_complete_in;
diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c
index 4f2b847..e9d9918 100644
--- a/drivers/usb/gadget/function/f_acm.c
+++ b/drivers/usb/gadget/function/f_acm.c
@@ -667,7 +667,7 @@
/* allocate notification */
acm->notify_req = gs_alloc_req(ep,
sizeof(struct usb_cdc_notification) + 2,
- GFP_KERNEL);
+ cdev->gadget->extra_buf_alloc, GFP_KERNEL);
if (!acm->notify_req)
goto fail;
diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c
index 2373262..aaa15da 100644
--- a/drivers/usb/gadget/function/f_audio_source.c
+++ b/drivers/usb/gadget/function/f_audio_source.c
@@ -396,15 +396,22 @@
s64 msecs;
s64 frames;
ktime_t now;
+ unsigned long flags;
+ spin_lock_irqsave(&audio->lock, flags);
/* audio->substream will be null if we have been closed */
- if (!audio->substream)
+ if (!audio->substream) {
+ spin_unlock_irqrestore(&audio->lock, flags);
return;
+ }
/* audio->buffer_pos will be null if we have been stopped */
- if (!audio->buffer_pos)
+ if (!audio->buffer_pos) {
+ spin_unlock_irqrestore(&audio->lock, flags);
return;
+ }
runtime = audio->substream->runtime;
+ spin_unlock_irqrestore(&audio->lock, flags);
/* compute number of frames to send */
now = ktime_get();
@@ -427,8 +434,21 @@
while (frames > 0) {
req = audio_req_get(audio);
- if (!req)
+ spin_lock_irqsave(&audio->lock, flags);
+ /* audio->substream will be null if we have been closed */
+ if (!audio->substream) {
+ spin_unlock_irqrestore(&audio->lock, flags);
+ return;
+ }
+ /* audio->buffer_pos will be null if we have been stopped */
+ if (!audio->buffer_pos) {
+ spin_unlock_irqrestore(&audio->lock, flags);
+ return;
+ }
+ if (!req) {
+ spin_unlock_irqrestore(&audio->lock, flags);
break;
+ }
length = frames_to_bytes(runtime, frames);
if (length > IN_EP_MAX_PACKET_SIZE)
@@ -454,6 +474,7 @@
}
req->length = length;
+ spin_unlock_irqrestore(&audio->lock, flags);
ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC);
if (ret < 0) {
pr_err("usb_ep_queue failed ret: %d\n", ret);
diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c
index 0e86d28..4d4f039 100644
--- a/drivers/usb/gadget/function/f_cdev.c
+++ b/drivers/usb/gadget/function/f_cdev.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2013-2018, The Linux Foundation. All rights reserved.
* Linux Foundation chooses to take subject only to the GPLv2 license terms,
* and distributes only under these terms.
*
@@ -709,7 +709,8 @@
}
static struct usb_request *
-usb_cser_alloc_req(struct usb_ep *ep, unsigned int len, gfp_t flags)
+usb_cser_alloc_req(struct usb_ep *ep, unsigned int len, size_t extra_sz,
+ gfp_t flags)
{
struct usb_request *req;
@@ -720,7 +721,7 @@
}
req->length = len;
- req->buf = kmalloc(len, flags);
+ req->buf = kmalloc(len + extra_sz, flags);
if (!req->buf) {
pr_err("request buf allocation failed\n");
usb_ep_free_request(ep, req);
@@ -770,7 +771,8 @@
ep->driver_data = cdev;
/* allocate notification */
port->port_usb.notify_req = usb_cser_alloc_req(ep,
- sizeof(struct usb_cdc_notification) + 2, GFP_KERNEL);
+ sizeof(struct usb_cdc_notification) + 2,
+ cdev->gadget->extra_buf_alloc, GFP_KERNEL);
if (!port->port_usb.notify_req)
goto fail;
@@ -845,7 +847,7 @@
}
static int usb_cser_alloc_requests(struct usb_ep *ep, struct list_head *head,
- int num, int size,
+ int num, int size, size_t extra_sz,
void (*cb)(struct usb_ep *ep, struct usb_request *))
{
int i;
@@ -855,7 +857,7 @@
ep, head, num, size, cb);
for (i = 0; i < num; i++) {
- req = usb_cser_alloc_req(ep, size, GFP_ATOMIC);
+ req = usb_cser_alloc_req(ep, size, extra_sz, GFP_ATOMIC);
if (!req) {
pr_debug("req allocated:%d\n", i);
return list_empty(head) ? -ENOMEM : 0;
@@ -972,6 +974,8 @@
static void usb_cser_start_io(struct f_cdev *port)
{
+ struct usb_function *f = &port->port_usb.func;
+ struct usb_composite_dev *cdev = f->config->cdev;
int ret = -ENODEV;
unsigned long flags;
@@ -987,7 +991,7 @@
ret = usb_cser_alloc_requests(port->port_usb.out,
&port->read_pool,
- BRIDGE_RX_QUEUE_SIZE, BRIDGE_RX_BUF_SIZE,
+ BRIDGE_RX_QUEUE_SIZE, BRIDGE_RX_BUF_SIZE, 0,
usb_cser_read_complete);
if (ret) {
pr_err("unable to allocate out requests\n");
@@ -997,6 +1001,7 @@
ret = usb_cser_alloc_requests(port->port_usb.in,
&port->write_pool,
BRIDGE_TX_QUEUE_SIZE, BRIDGE_TX_BUF_SIZE,
+ cdev->gadget->extra_buf_alloc,
usb_cser_write_complete);
if (ret) {
usb_cser_free_requests(port->port_usb.out, &port->read_pool);
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 866c3ec..47f1a8e 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -67,18 +67,27 @@
static int __must_check
__ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len);
+static LIST_HEAD(inst_list);
+
/* ffs instance status */
-static DEFINE_MUTEX(ffs_ep_lock);
-static bool ffs_inst_exist;
-static struct f_fs_opts *g_opts;
+#define INST_NAME_SIZE 16
+
+struct ffs_inst_status {
+ char inst_name[INST_NAME_SIZE];
+ struct list_head list;
+ struct mutex ffs_lock;
+ bool inst_exist;
+ struct f_fs_opts *opts;
+ struct ffs_data *ffs_data;
+};
/* Free instance structures */
-static void ffs_inst_clean(struct f_fs_opts *opts);
-static void ffs_inst_clean_delay(void);
-static int ffs_inst_exist_check(void);
-
-/* Global ffs_data pointer */
-static struct ffs_data *g_ffs_data;
+static void ffs_inst_clean(struct f_fs_opts *opts,
+ const char *inst_name);
+static void ffs_inst_clean_delay(const char *inst_name);
+static int ffs_inst_exist_check(const char *inst_name);
+static struct ffs_inst_status *name_to_inst_status(
+ const char *inst_name, bool create_inst);
/* The function structure ***************************************************/
@@ -281,7 +290,8 @@
static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
__attribute__((warn_unused_result, nonnull));
-static char *ffs_prepare_buffer(const char __user *buf, size_t len)
+static char *ffs_prepare_buffer(const char __user *buf, size_t len,
+ size_t extra_buf_alloc)
__attribute__((warn_unused_result, nonnull));
@@ -357,6 +367,7 @@
size_t len, loff_t *ptr)
{
struct ffs_data *ffs = file->private_data;
+ struct usb_gadget *gadget = ffs->gadget;
ssize_t ret;
char *data;
@@ -365,7 +376,7 @@
ffs_log("enter:len %zu state %d setup_state %d flags %lu", len,
ffs->state, ffs->setup_state, ffs->flags);
- ret = ffs_inst_exist_check();
+ ret = ffs_inst_exist_check(ffs->dev_name);
if (ret < 0)
return ret;
@@ -388,7 +399,7 @@
break;
}
- data = ffs_prepare_buffer(buf, len);
+ data = ffs_prepare_buffer(buf, len, 0);
if (IS_ERR(data)) {
ret = PTR_ERR(data);
break;
@@ -460,7 +471,7 @@
spin_unlock_irq(&ffs->ev.waitq.lock);
- data = ffs_prepare_buffer(buf, len);
+ data = ffs_prepare_buffer(buf, len, gadget->extra_buf_alloc);
if (IS_ERR(data)) {
ret = PTR_ERR(data);
break;
@@ -555,7 +566,7 @@
ffs_log("enter:len %zu state %d setup_state %d flags %lu", len,
ffs->state, ffs->setup_state, ffs->flags);
- ret = ffs_inst_exist_check();
+ ret = ffs_inst_exist_check(ffs->dev_name);
if (ret < 0)
return ret;
@@ -666,7 +677,7 @@
ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state,
ffs->setup_state, ffs->flags, atomic_read(&ffs->opened));
- ret = ffs_inst_exist_check();
+ ret = ffs_inst_exist_check(ffs->dev_name);
if (ret < 0)
return ret;
@@ -709,7 +720,7 @@
ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state,
ffs->setup_state, ffs->flags, atomic_read(&ffs->opened));
- ret = ffs_inst_exist_check();
+ ret = ffs_inst_exist_check(ffs->dev_name);
if (ret < 0)
return ret;
@@ -734,7 +745,7 @@
ffs_log("enter:state %d setup_state %d flags %lu opened %d", ffs->state,
ffs->setup_state, ffs->flags, atomic_read(&ffs->opened));
- ret = ffs_inst_exist_check();
+ ret = ffs_inst_exist_check(ffs->dev_name);
if (ret < 0)
return ret;
@@ -860,9 +871,13 @@
ffs_log("enter: ret %d", ret);
if (io_data->read && ret > 0) {
+ mm_segment_t oldfs = get_fs();
+
+ set_fs(USER_DS);
use_mm(io_data->mm);
ret = ffs_copy_to_iter(io_data->buf, ret, &io_data->data);
unuse_mm(io_data->mm);
+ set_fs(oldfs);
}
io_data->kiocb->ki_complete(io_data->kiocb, ret, ret);
@@ -982,13 +997,19 @@
struct ffs_epfile *epfile = file->private_data;
struct usb_request *req;
struct ffs_ep *ep;
+ struct ffs_data *ffs = epfile->ffs;
char *data = NULL;
ssize_t ret, data_len = -EINVAL;
int halt;
+ size_t extra_buf_alloc = 0;
ffs_log("enter: epfile name %s epfile err %d (%s)", epfile->name,
atomic_read(&epfile->error), io_data->read ? "READ" : "WRITE");
+ ret = ffs_inst_exist_check(epfile->ffs->dev_name);
+ if (ret < 0)
+ return ret;
+
/* to get updated error atomic variable value */
smp_mb__before_atomic();
if (atomic_read(&epfile->error))
@@ -1075,7 +1096,12 @@
data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
spin_unlock_irq(&epfile->ffs->eps_lock);
- data = kmalloc(data_len, GFP_KERNEL);
+ extra_buf_alloc = ffs->gadget->extra_buf_alloc;
+ if (io_data->read)
+ data = kmalloc(data_len + extra_buf_alloc,
+ GFP_KERNEL);
+ else
+ data = kmalloc(data_len, GFP_KERNEL);
if (unlikely(!data)) {
ret = -ENOMEM;
goto error_mutex;
@@ -1238,7 +1264,7 @@
ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state,
epfile->ffs->setup_state, epfile->ffs->flags);
- ret = ffs_inst_exist_check();
+ ret = ffs_inst_exist_check(epfile->ffs->dev_name);
if (ret < 0)
return ret;
@@ -1293,16 +1319,11 @@
{
struct ffs_io_data io_data, *p = &io_data;
ssize_t res;
- int ret;
ENTER();
ffs_log("enter");
- ret = ffs_inst_exist_check();
- if (ret < 0)
- return ret;
-
if (!is_sync_kiocb(kiocb)) {
p = kmalloc(sizeof(io_data), GFP_KERNEL);
if (unlikely(!p))
@@ -1339,16 +1360,11 @@
{
struct ffs_io_data io_data, *p = &io_data;
ssize_t res;
- int ret;
ENTER();
ffs_log("enter");
- ret = ffs_inst_exist_check();
- if (ret < 0)
- return ret;
-
if (!is_sync_kiocb(kiocb)) {
p = kmalloc(sizeof(io_data), GFP_KERNEL);
if (unlikely(!p))
@@ -1424,7 +1440,7 @@
ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state,
epfile->ffs->setup_state, epfile->ffs->flags);
- ret = ffs_inst_exist_check();
+ ret = ffs_inst_exist_check(epfile->ffs->dev_name);
if (ret < 0)
return ret;
@@ -1732,6 +1748,7 @@
int ret;
void *ffs_dev;
struct ffs_data *ffs;
+ struct ffs_inst_status *inst_status;
ENTER();
@@ -1761,6 +1778,18 @@
ffs->private_data = ffs_dev;
data.ffs_data = ffs;
+ inst_status = name_to_inst_status(ffs->dev_name, false);
+ if (IS_ERR(inst_status)) {
+ ffs_log("failed to find instance (%s)\n",
+ ffs->dev_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* Store ffs to global status structure */
+ ffs_dev_lock();
+ inst_status->ffs_data = ffs;
+ ffs_dev_unlock();
+
rv = mount_nodev(t, flags, &data, ffs_sb_fill);
if (IS_ERR(rv) && data.ffs_data) {
ffs_release_dev(data.ffs_data);
@@ -1872,6 +1901,9 @@
static void ffs_data_put(struct ffs_data *ffs)
{
+ struct ffs_inst_status *inst_status;
+ const char *dev_name;
+
ENTER();
ffs_log("enter");
@@ -1880,16 +1912,20 @@
smp_mb__before_atomic();
if (unlikely(atomic_dec_and_test(&ffs->ref))) {
pr_info("%s(): freeing\n", __func__);
- /* Clear g_ffs_data */
- ffs_dev_lock();
- g_ffs_data = NULL;
- ffs_dev_unlock();
+ /* Clear ffs from global structure */
+ inst_status = name_to_inst_status(ffs->dev_name, false);
+ if (!IS_ERR(inst_status)) {
+ ffs_dev_lock();
+ inst_status->ffs_data = NULL;
+ ffs_dev_unlock();
+ }
ffs_data_clear(ffs);
BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
waitqueue_active(&ffs->ep0req_completion.wait));
- kfree(ffs->dev_name);
+ dev_name = ffs->dev_name;
kfree(ffs);
- ffs_inst_clean_delay();
+ ffs_inst_clean_delay(dev_name);
+ kfree(dev_name);
}
ffs_log("exit");
@@ -1956,11 +1992,6 @@
/* XXX REVISIT need to update it in some places, or do we? */
ffs->ev.can_stall = 1;
- /* Store ffs to g_ffs_data */
- ffs_dev_lock();
- g_ffs_data = ffs;
- ffs_dev_unlock();
-
ffs_log("exit");
return ffs;
@@ -3873,79 +3904,146 @@
/* Function registration interface ******************************************/
-static int ffs_inst_exist_check(void)
+static struct ffs_inst_status *name_to_inst_status(
+ const char *inst_name, bool create_inst)
{
- mutex_lock(&ffs_ep_lock);
+ struct ffs_inst_status *inst_status;
- if (unlikely(ffs_inst_exist == false)) {
- mutex_unlock(&ffs_ep_lock);
+ list_for_each_entry(inst_status, &inst_list, list) {
+ if (!strncasecmp(inst_status->inst_name,
+ inst_name, strlen(inst_name)))
+ return inst_status;
+ }
+
+ if (!create_inst)
+ return ERR_PTR(-ENODEV);
+
+ inst_status = kzalloc(sizeof(struct ffs_inst_status),
+ GFP_KERNEL);
+ if (!inst_status)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&inst_status->ffs_lock);
+ snprintf(inst_status->inst_name, INST_NAME_SIZE, inst_name);
+ list_add_tail(&inst_status->list, &inst_list);
+
+ return inst_status;
+}
+
+static int ffs_inst_exist_check(const char *inst_name)
+{
+ struct ffs_inst_status *inst_status;
+
+ inst_status = name_to_inst_status(inst_name, false);
+ if (IS_ERR(inst_status)) {
pr_err_ratelimited(
- "%s: f_fs instance freed already.\n",
- __func__);
+ "%s: failed to find instance (%s)\n",
+ __func__, inst_name);
return -ENODEV;
}
- mutex_unlock(&ffs_ep_lock);
+ mutex_lock(&inst_status->ffs_lock);
+
+ if (unlikely(inst_status->inst_exist == false)) {
+ mutex_unlock(&inst_status->ffs_lock);
+ pr_err_ratelimited(
+ "%s: f_fs instance (%s) has been freed already.\n",
+ __func__, inst_name);
+ return -ENODEV;
+ }
+
+ mutex_unlock(&inst_status->ffs_lock);
return 0;
}
-static void ffs_inst_clean(struct f_fs_opts *opts)
+static void ffs_inst_clean(struct f_fs_opts *opts,
+ const char *inst_name)
{
- g_opts = NULL;
+ struct ffs_inst_status *inst_status;
+
+ inst_status = name_to_inst_status(inst_name, false);
+ if (IS_ERR(inst_status)) {
+ pr_err_ratelimited(
+ "%s: failed to find instance (%s)\n",
+ __func__, inst_name);
+ return;
+ }
+
+ inst_status->opts = NULL;
+
ffs_dev_lock();
_ffs_free_dev(opts->dev);
ffs_dev_unlock();
kfree(opts);
}
-static void ffs_inst_clean_delay(void)
+static void ffs_inst_clean_delay(const char *inst_name)
{
- mutex_lock(&ffs_ep_lock);
+ struct ffs_inst_status *inst_status;
- if (unlikely(ffs_inst_exist == false)) {
- if (g_opts) {
- ffs_inst_clean(g_opts);
- pr_err_ratelimited("%s: Delayed free memory\n",
- __func__);
- }
- mutex_unlock(&ffs_ep_lock);
+ inst_status = name_to_inst_status(inst_name, false);
+ if (IS_ERR(inst_status)) {
+ pr_err_ratelimited(
+ "%s: failed to find (%s) instance\n",
+ __func__, inst_name);
return;
}
- mutex_unlock(&ffs_ep_lock);
+ mutex_lock(&inst_status->ffs_lock);
+
+ if (unlikely(inst_status->inst_exist == false)) {
+ if (inst_status->opts) {
+ ffs_inst_clean(inst_status->opts, inst_name);
+ pr_err_ratelimited("%s: Delayed free memory\n",
+ __func__);
+ }
+ mutex_unlock(&inst_status->ffs_lock);
+ return;
+ }
+
+ mutex_unlock(&inst_status->ffs_lock);
}
static void ffs_free_inst(struct usb_function_instance *f)
{
struct f_fs_opts *opts;
+ struct ffs_inst_status *inst_status;
opts = to_f_fs_opts(f);
- mutex_lock(&ffs_ep_lock);
- if (opts->dev->ffs_data
- && atomic_read(&opts->dev->ffs_data->opened)) {
- ffs_inst_exist = false;
- mutex_unlock(&ffs_ep_lock);
- ffs_log("%s: Dev is open, free mem when dev close\n",
- __func__);
+ inst_status = name_to_inst_status(opts->dev->name, false);
+ if (IS_ERR(inst_status)) {
+ ffs_log("failed to find (%s) instance\n",
+ opts->dev->name);
return;
}
- ffs_inst_clean(opts);
- ffs_inst_exist = false;
- g_opts = NULL;
- mutex_unlock(&ffs_ep_lock);
+ mutex_lock(&inst_status->ffs_lock);
+ if (opts->dev->ffs_data
+ && atomic_read(&opts->dev->ffs_data->opened)) {
+ inst_status->inst_exist = false;
+ mutex_unlock(&inst_status->ffs_lock);
+ ffs_log("Dev is open, free mem when dev (%s) close\n",
+ opts->dev->name);
+ return;
+ }
+
+ ffs_inst_clean(opts, opts->dev->name);
+ inst_status->inst_exist = false;
+ mutex_unlock(&inst_status->ffs_lock);
}
#define MAX_INST_NAME_LEN 40
static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name)
{
- struct f_fs_opts *opts;
+ struct f_fs_opts *opts, *opts_prev;
+ struct ffs_data *ffs_data_tmp;
char *ptr;
const char *tmp;
int name_len, ret;
+ struct ffs_inst_status *inst_status;
name_len = strlen(name) + 1;
if (name_len > MAX_INST_NAME_LEN)
@@ -3955,13 +4053,22 @@
if (!ptr)
return -ENOMEM;
- mutex_lock(&ffs_ep_lock);
- if (g_opts) {
- mutex_unlock(&ffs_ep_lock);
- ffs_log("%s: prev inst do not freed yet\n", __func__);
+ inst_status = name_to_inst_status(ptr, true);
+ if (IS_ERR(inst_status)) {
+ ffs_log("failed to create status struct for (%s) instance\n",
+ ptr);
+ return -EINVAL;
+ }
+
+ mutex_lock(&inst_status->ffs_lock);
+ opts_prev = inst_status->opts;
+ if (opts_prev) {
+ mutex_unlock(&inst_status->ffs_lock);
+ ffs_log("instance (%s): prev inst do not freed yet\n",
+ inst_status->inst_name);
return -EBUSY;
}
- mutex_unlock(&ffs_ep_lock);
+ mutex_unlock(&inst_status->ffs_lock);
opts = to_f_fs_opts(fi);
tmp = NULL;
@@ -3983,8 +4090,9 @@
* ffs_private_data also need to update new allocated opts->dev
* address.
*/
- if (g_ffs_data)
- opts->dev->ffs_data = g_ffs_data;
+ ffs_data_tmp = inst_status->ffs_data;
+ if (ffs_data_tmp)
+ opts->dev->ffs_data = ffs_data_tmp;
if (opts->dev->ffs_data)
opts->dev->ffs_data->private_data = opts->dev;
@@ -3993,10 +4101,10 @@
kfree(tmp);
- mutex_lock(&ffs_ep_lock);
- ffs_inst_exist = true;
- g_opts = opts;
- mutex_unlock(&ffs_ep_lock);
+ mutex_lock(&inst_status->ffs_lock);
+ inst_status->inst_exist = true;
+ inst_status->opts = opts;
+ mutex_unlock(&inst_status->ffs_lock);
return 0;
}
@@ -4370,14 +4478,23 @@
: mutex_lock_interruptible(mutex);
}
-static char *ffs_prepare_buffer(const char __user *buf, size_t len)
+/**
+ * ffs_prepare_buffer() - copy userspace buffer into kernel.
+ * @buf: userspace buffer
+ * @len: length of the buffer
+ * @extra_alloc_buf: Extra buffer allocation if required by UDC.
+ *
+ * This function returns pointer to the copied buffer
+ */
+static char *ffs_prepare_buffer(const char __user *buf, size_t len,
+ size_t extra_buf_alloc)
{
char *data;
if (unlikely(!len))
return NULL;
- data = kmalloc(len, GFP_KERNEL);
+ data = kmalloc(len + extra_buf_alloc, GFP_KERNEL);
if (unlikely(!data))
return ERR_PTR(-ENOMEM);
@@ -4392,6 +4509,24 @@
return data;
}
+static void __exit ffs_exit(void)
+{
+ struct ffs_inst_status *inst_status, *inst_status_tmp = NULL;
+
+ list_for_each_entry(inst_status, &inst_list, list) {
+ if (inst_status_tmp) {
+ list_del(&inst_status_tmp->list);
+ kfree(inst_status_tmp);
+ }
+ inst_status_tmp = inst_status;
+ }
+ if (inst_status_tmp) {
+ list_del(&inst_status_tmp->list);
+ kfree(inst_status_tmp);
+ }
+}
+module_exit(ffs_exit);
+
DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michal Nazarewicz");
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index 41aa62d..7d509db 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -532,6 +532,9 @@
if (!usb_gsi_ep_op(gsi->d_port.in_ep, (void *) &f_suspend,
GSI_EP_OP_CHECK_FOR_SUSPEND)) {
ret = -EFAULT;
+ block_db = false;
+ usb_gsi_ep_op(d_port->in_ep, (void *)&block_db,
+ GSI_EP_OP_SET_CLR_BLOCK_DBL);
goto done;
}
@@ -2078,13 +2081,8 @@
/* for rndis and rmnet alt is always 0 update alt accordingly */
if (gsi->prot_id == IPA_USB_RNDIS ||
gsi->prot_id == IPA_USB_RMNET ||
- gsi->prot_id == IPA_USB_DIAG) {
- if (gsi->d_port.in_ep &&
- !gsi->d_port.in_ep->driver_data)
+ gsi->prot_id == IPA_USB_DIAG)
alt = 1;
- else
- alt = 0;
- }
if (alt > 1)
goto notify_ep_disable;
@@ -2377,7 +2375,7 @@
if (!ep)
goto fail;
gsi->d_port.in_ep = ep;
- msm_ep_config(gsi->d_port.in_ep);
+ msm_ep_config(gsi->d_port.in_ep, NULL);
ep->driver_data = cdev; /* claim */
}
@@ -2387,7 +2385,7 @@
if (!ep)
goto fail;
gsi->d_port.out_ep = ep;
- msm_ep_config(gsi->d_port.out_ep);
+ msm_ep_config(gsi->d_port.out_ep, NULL);
ep->driver_data = cdev; /* claim */
}
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 33ed64f..b24ad72 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -2750,7 +2750,8 @@
bh->next = bh + 1;
++bh;
buffhds_first_it:
- bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
+ bh->buf = kmalloc(FSG_BUFLEN + EXTRA_ALLOCATION_SIZE,
+ GFP_KERNEL);
if (unlikely(!bh->buf))
goto error_release;
} while (--i);
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index 239d9bf..4cc7d94 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -497,6 +497,7 @@
struct usb_composite_dev *cdev = dev->cdev;
struct usb_request *req;
struct usb_ep *ep;
+ size_t extra_buf_alloc = cdev->gadget->extra_buf_alloc;
int i;
DBG(cdev, "create_bulk_endpoints dev: %pK\n", dev);
@@ -531,7 +532,8 @@
retry_tx_alloc:
/* now allocate requests for our endpoints */
for (i = 0; i < mtp_tx_reqs; i++) {
- req = mtp_request_new(dev->ep_in, mtp_tx_req_len);
+ req = mtp_request_new(dev->ep_in,
+ mtp_tx_req_len + extra_buf_alloc);
if (!req) {
if (mtp_tx_req_len <= MTP_BULK_BUFFER_SIZE)
goto fail;
@@ -569,7 +571,8 @@
dev->rx_req[i] = req;
}
for (i = 0; i < INTR_REQ_MAX; i++) {
- req = mtp_request_new(dev->ep_intr, INTR_BUFFER_SIZE);
+ req = mtp_request_new(dev->ep_intr,
+ INTR_BUFFER_SIZE + extra_buf_alloc);
if (!req)
goto fail;
req->complete = mtp_complete_intr;
@@ -1890,7 +1893,6 @@
dev->function.disable = mtp_function_disable;
dev->function.setup = mtp_ctrlreq_configfs;
dev->function.free_func = mtp_free;
- fi->f = &dev->function;
return &dev->function;
}
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index b0d0020..6f3b623 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -1510,7 +1510,8 @@
ncm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
if (!ncm->notify_req)
goto fail;
- ncm->notify_req->buf = kmalloc(NCM_STATUS_BYTECOUNT, GFP_KERNEL);
+ ncm->notify_req->buf = kmalloc(NCM_STATUS_BYTECOUNT
+ + (cdev->gadget->extra_buf_alloc), GFP_KERNEL);
if (!ncm->notify_req->buf)
goto fail;
ncm->notify_req->context = ncm;
diff --git a/drivers/usb/gadget/function/f_qc_rndis.c b/drivers/usb/gadget/function/f_qc_rndis.c
index a8e7092..908805a 100644
--- a/drivers/usb/gadget/function/f_qc_rndis.c
+++ b/drivers/usb/gadget/function/f_qc_rndis.c
@@ -102,7 +102,7 @@
struct usb_ep *notify;
struct usb_request *notify_req;
atomic_t notify_count;
- struct gadget_ipa_port bam_port;
+ struct data_port bam_port;
struct cdev cdev;
struct device *dev;
u8 port_num;
diff --git a/drivers/usb/gadget/function/f_rmnet.c b/drivers/usb/gadget/function/f_rmnet.c
index 64532f6..ffc6897 100644
--- a/drivers/usb/gadget/function/f_rmnet.c
+++ b/drivers/usb/gadget/function/f_rmnet.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2018, 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
@@ -19,7 +19,6 @@
#include <linux/usb_bam.h>
#include <linux/module.h>
-#include "u_rmnet.h"
#include "u_data_ipa.h"
#include "configfs.h"
@@ -31,13 +30,15 @@
struct f_rmnet {
struct usb_function func;
enum qti_port_type qti_port_type;
- enum ipa_func_type func_type;
+ enum bam_dmux_func_type bam_dmux_func_type;
+ enum data_xport_type xport_type;
+ enum ipa_func_type ipa_func_type;
struct grmnet port;
int ifc_id;
atomic_t online;
atomic_t ctrl_online;
struct usb_composite_dev *cdev;
- struct gadget_ipa_port ipa_port;
+ struct data_port bam_port;
spinlock_t lock;
/* usb eps*/
@@ -219,6 +220,14 @@
.bInterfaceProtocol = 0xff,
};
+static struct usb_endpoint_descriptor dpl_fs_data_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(64),
+};
+
static struct usb_endpoint_descriptor dpl_hs_data_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -243,6 +252,12 @@
.wBytesPerInterval = 0,
};
+static struct usb_descriptor_header *dpl_fs_data_only_desc[] = {
+ (struct usb_descriptor_header *) &dpl_data_intf_desc,
+ (struct usb_descriptor_header *) &dpl_fs_data_desc,
+ NULL,
+};
+
static struct usb_descriptor_header *dpl_hs_data_only_desc[] = {
(struct usb_descriptor_header *) &dpl_data_intf_desc,
(struct usb_descriptor_header *) &dpl_hs_data_desc,
@@ -294,11 +309,22 @@
if (!strncasecmp("rmnet", name, MAX_INST_NAME_LEN)) {
dev->qti_port_type = QTI_PORT_RMNET;
- dev->func_type = USB_IPA_FUNC_RMNET;
+ dev->xport_type = BAM2BAM_IPA;
+ dev->ipa_func_type = USB_IPA_FUNC_RMNET;
} else if (!strncasecmp("dpl", name, MAX_INST_NAME_LEN)) {
dev->qti_port_type = QTI_PORT_DPL;
- dev->func_type = USB_IPA_FUNC_DPL;
+ dev->xport_type = BAM2BAM_IPA;
+ dev->ipa_func_type = USB_IPA_FUNC_DPL;
+ } else if (!strncasecmp("rmnet_bam_dmux", name, MAX_INST_NAME_LEN)) {
+ dev->qti_port_type = QTI_PORT_RMNET;
+ dev->xport_type = BAM_DMUX;
+ dev->bam_dmux_func_type = BAM_DMUX_FUNC_RMNET;
+ } else if (!strncasecmp("dpl_bam_dmux", name, MAX_INST_NAME_LEN)) {
+ dev->qti_port_type = QTI_PORT_DPL;
+ dev->xport_type = BAM_DMUX;
+ dev->bam_dmux_func_type = BAM_DMUX_FUNC_DPL;
}
+
return 0;
error:
@@ -306,7 +332,8 @@
}
static struct usb_request *
-frmnet_alloc_req(struct usb_ep *ep, unsigned int len, gfp_t flags)
+frmnet_alloc_req(struct usb_ep *ep, unsigned int len, size_t extra_buf_alloc,
+ gfp_t flags)
{
struct usb_request *req;
@@ -314,7 +341,7 @@
if (!req)
return ERR_PTR(-ENOMEM);
- req->buf = kmalloc(len, flags);
+ req->buf = kmalloc(len + extra_buf_alloc, flags);
if (!req->buf) {
usb_ep_free_request(ep, req);
return ERR_PTR(-ENOMEM);
@@ -366,7 +393,8 @@
enum usb_ctrl usb_bam_type;
int bam_pipe_num = (dev->qti_port_type == QTI_PORT_DPL) ? 1 : 0;
- ret = gqti_ctrl_connect(&dev->port, dev->qti_port_type, dev->ifc_id);
+ ret = gqti_ctrl_connect(&dev->port, dev->qti_port_type, dev->ifc_id,
+ dev->xport_type);
if (ret) {
pr_err("%s: gqti_ctrl_connect failed: err:%d\n",
__func__, ret);
@@ -374,31 +402,42 @@
}
if (dev->qti_port_type == QTI_PORT_DPL)
dev->port.send_encap_cmd(QTI_PORT_DPL, NULL, 0);
- dev->ipa_port.cdev = dev->cdev;
- ipa_data_port_select(dev->func_type);
- usb_bam_type = usb_bam_get_bam_type(gadget->name);
+ dev->bam_port.cdev = dev->cdev;
+ if (dev->xport_type == BAM_DMUX) {
+ ret = gbam_connect(&dev->bam_port, dev->bam_dmux_func_type);
+ if (ret)
+ pr_err("%s: gbam_connect failed: err:%d\n",
+ __func__, ret);
+ } else {
+ ipa_data_port_select(dev->ipa_func_type);
+ usb_bam_type = usb_bam_get_bam_type(gadget->name);
- if (dev->ipa_port.in) {
- dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
- IPA_P_BAM, PEER_PERIPHERAL_TO_USB,
- USB_BAM_DEVICE, bam_pipe_num);
+ if (dev->bam_port.in) {
+ dst_connection_idx = usb_bam_get_connection_idx(
+ usb_bam_type, IPA_P_BAM,
+ PEER_PERIPHERAL_TO_USB,
+ USB_BAM_DEVICE, bam_pipe_num);
+ }
+ if (dev->bam_port.out) {
+ src_connection_idx = usb_bam_get_connection_idx(
+ usb_bam_type, IPA_P_BAM,
+ USB_TO_PEER_PERIPHERAL,
+ USB_BAM_DEVICE, bam_pipe_num);
+ }
+ if (dst_connection_idx < 0 || src_connection_idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n",
+ __func__);
+ gqti_ctrl_disconnect(&dev->port, dev->qti_port_type);
+ return -EINVAL;
+ }
+ ret = ipa_data_connect(&dev->bam_port, dev->ipa_func_type,
+ src_connection_idx, dst_connection_idx);
+ if (ret)
+ pr_err("%s: ipa_data_connect failed: err:%d\n",
+ __func__, ret);
}
- if (dev->ipa_port.out) {
- src_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
- IPA_P_BAM, USB_TO_PEER_PERIPHERAL,
- USB_BAM_DEVICE, bam_pipe_num);
- }
- if (dst_connection_idx < 0 || src_connection_idx < 0) {
- pr_err("%s: usb_bam_get_connection_idx failed\n",
- __func__);
- gqti_ctrl_disconnect(&dev->port, dev->qti_port_type);
- return -EINVAL;
- }
- ret = ipa_data_connect(&dev->ipa_port, dev->func_type,
- src_connection_idx, dst_connection_idx);
+
if (ret) {
- pr_err("%s: ipa_data_connect failed: err:%d\n",
- __func__, ret);
gqti_ctrl_disconnect(&dev->port, dev->qti_port_type);
return ret;
}
@@ -408,7 +447,11 @@
static int gport_rmnet_disconnect(struct f_rmnet *dev)
{
gqti_ctrl_disconnect(&dev->port, dev->qti_port_type);
- ipa_data_disconnect(&dev->ipa_port, dev->func_type);
+ if (dev->xport_type == BAM_DMUX)
+ gbam_disconnect(&dev->bam_port, dev->bam_dmux_func_type);
+ else
+ ipa_data_disconnect(&dev->bam_port, dev->ipa_func_type);
+
return 0;
}
@@ -474,7 +517,10 @@
usb_ep_fifo_flush(dev->notify);
frmnet_purge_responses(dev);
}
- ipa_data_suspend(&dev->ipa_port, dev->func_type, remote_wakeup_allowed);
+
+ if (dev->xport_type == BAM2BAM_IPA)
+ ipa_data_suspend(&dev->bam_port, dev->ipa_func_type,
+ remote_wakeup_allowed);
}
static void frmnet_resume(struct usb_function *f)
@@ -489,8 +535,9 @@
pr_debug("%s: dev: %pK remote_wakeup: %d\n", __func__, dev,
remote_wakeup_allowed);
-
- ipa_data_resume(&dev->ipa_port, dev->func_type, remote_wakeup_allowed);
+ if (dev->xport_type == BAM2BAM_IPA)
+ ipa_data_resume(&dev->bam_port, dev->ipa_func_type,
+ remote_wakeup_allowed);
}
static void frmnet_disable(struct usb_function *f)
@@ -543,20 +590,20 @@
dev->notify->driver_data = dev;
}
- if (dev->ipa_port.in && !dev->ipa_port.in->desc
- && config_ep_by_speed(cdev->gadget, f, dev->ipa_port.in)) {
+ if (dev->bam_port.in && !dev->bam_port.in->desc
+ && config_ep_by_speed(cdev->gadget, f, dev->bam_port.in)) {
pr_err("%s(): config_ep_by_speed failed.\n",
__func__);
- dev->ipa_port.in->desc = NULL;
+ dev->bam_port.in->desc = NULL;
ret = -EINVAL;
goto err_disable_ep;
}
- if (dev->ipa_port.out && !dev->ipa_port.out->desc
- && config_ep_by_speed(cdev->gadget, f, dev->ipa_port.out)) {
+ if (dev->bam_port.out && !dev->bam_port.out->desc
+ && config_ep_by_speed(cdev->gadget, f, dev->bam_port.out)) {
pr_err("%s(): config_ep_by_speed failed.\n",
__func__);
- dev->ipa_port.out->desc = NULL;
+ dev->bam_port.out->desc = NULL;
ret = -EINVAL;
goto err_disable_ep;
}
@@ -940,7 +987,7 @@
__func__);
return -ENODEV;
}
- dev->ipa_port.in = ep;
+ dev->bam_port.in = ep;
ep->driver_data = cdev;
}
@@ -952,7 +999,7 @@
status = -ENODEV;
goto ep_auto_out_fail;
}
- dev->ipa_port.out = ep;
+ dev->bam_port.out = ep;
ep->driver_data = cdev;
}
@@ -968,6 +1015,7 @@
ep->driver_data = cdev;
dev->notify_req = frmnet_alloc_req(ep,
sizeof(struct usb_cdc_notification),
+ cdev->gadget->extra_buf_alloc,
GFP_KERNEL);
if (IS_ERR(dev->notify_req)) {
pr_err("%s: unable to allocate memory for notify req\n",
@@ -1044,11 +1092,11 @@
dev->notify->driver_data = NULL;
dev->notify = NULL;
ep_auto_notify_fail:
- dev->ipa_port.out->driver_data = NULL;
- dev->ipa_port.out = NULL;
+ dev->bam_port.out->driver_data = NULL;
+ dev->bam_port.out = NULL;
ep_auto_out_fail:
- dev->ipa_port.in->driver_data = NULL;
- dev->ipa_port.in = NULL;
+ dev->bam_port.in->driver_data = NULL;
+ dev->bam_port.in = NULL;
return status;
}
@@ -1087,10 +1135,10 @@
} else {
info.string_defs = dpl_string_defs;
info.data_desc = &dpl_data_intf_desc;
- info.fs_in_desc = &dpl_hs_data_desc;
+ info.fs_in_desc = &dpl_fs_data_desc;
info.hs_in_desc = &dpl_hs_data_desc;
info.ss_in_desc = &dpl_ss_data_desc;
- info.fs_desc_hdr = dpl_hs_data_only_desc;
+ info.fs_desc_hdr = dpl_fs_data_only_desc;
info.hs_desc_hdr = dpl_hs_data_only_desc;
info.ss_desc_hdr = dpl_ss_data_only_desc;
}
@@ -1149,7 +1197,11 @@
{
struct f_rmnet_opts *opts = container_of(f, struct f_rmnet_opts,
func_inst);
- ipa_data_free(opts->dev->func_type);
+ if (opts->dev->xport_type == BAM_DMUX)
+ gbam_cleanup(opts->dev->bam_dmux_func_type);
+ else
+ ipa_data_free(opts->dev->ipa_func_type);
+
kfree(opts->dev);
kfree(opts);
}
@@ -1180,14 +1232,20 @@
}
if (dev->qti_port_type >= QTI_NUM_PORTS ||
- dev->func_type >= USB_IPA_NUM_FUNCS) {
+ dev->xport_type >= NR_XPORT_TYPES ||
+ dev->ipa_func_type >= USB_IPA_NUM_FUNCS ||
+ dev->bam_dmux_func_type >= BAM_DMUX_NUM_FUNCS) {
pr_err("%s: invalid prot\n", __func__);
ret = -EINVAL;
goto fail;
}
INIT_LIST_HEAD(&dev->cpkt_resp_q);
- ret = ipa_data_setup(dev->func_type);
+ if (dev->xport_type == BAM_DMUX)
+ ret = gbam_setup(dev->bam_dmux_func_type);
+ else
+ ret = ipa_data_setup(dev->ipa_func_type);
+
if (ret)
goto fail;
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index 56a8e1b..6153c54 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -93,6 +93,9 @@
atomic_t notify_count;
};
+static struct f_rndis *__rndis;
+static spinlock_t _rndis_lock;
+
static inline struct f_rndis *func_to_rndis(struct usb_function *f)
{
return container_of(f, struct f_rndis, port.func);
@@ -422,10 +425,19 @@
static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct f_rndis *rndis = req->context;
- struct usb_composite_dev *cdev = rndis->port.func.config->cdev;
+ struct f_rndis *rndis;
+ struct usb_composite_dev *cdev;
int status = req->status;
+ struct usb_ep *notify_ep;
+ spin_lock(&_rndis_lock);
+ rndis = __rndis;
+ if (!rndis || !rndis->notify) {
+ spin_unlock(&_rndis_lock);
+ return;
+ }
+
+ cdev = rndis->port.func.config->cdev;
/* after TX:
* - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
* - RNDIS_RESPONSE_AVAILABLE (status/irq)
@@ -435,7 +447,7 @@
case -ESHUTDOWN:
/* connection gone */
atomic_set(&rndis->notify_count, 0);
- break;
+ goto out;
default:
DBG(cdev, "RNDIS %s response error %d, %d/%d\n",
ep->name, status,
@@ -443,29 +455,53 @@
/* FALLTHROUGH */
case 0:
if (ep != rndis->notify)
- break;
+ goto out;
/* handle multiple pending RNDIS_RESPONSE_AVAILABLE
* notifications by resending until we're done
*/
if (atomic_dec_and_test(&rndis->notify_count))
- break;
- status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC);
+ goto out;
+ notify_ep = rndis->notify;
+ spin_unlock(&_rndis_lock);
+ status = usb_ep_queue(notify_ep, req, GFP_ATOMIC);
if (status) {
- atomic_dec(&rndis->notify_count);
+ spin_lock(&_rndis_lock);
+ if (!__rndis)
+ goto out;
+ atomic_dec(&__rndis->notify_count);
DBG(cdev, "notify/1 --> %d\n", status);
+ spin_unlock(&_rndis_lock);
}
- break;
}
+
+ return;
+
+out:
+ spin_unlock(&_rndis_lock);
}
static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct f_rndis *rndis = req->context;
- struct usb_composite_dev *cdev = rndis->port.func.config->cdev;
+ struct f_rndis *rndis;
+ struct usb_composite_dev *cdev;
int status;
rndis_init_msg_type *buf;
+ if (req->status != 0) {
+ pr_err("%s: RNDIS command completion error:%d\n",
+ __func__, req->status);
+ return;
+ }
+
+ spin_lock(&_rndis_lock);
+ rndis = __rndis;
+ if (!rndis || !rndis->notify) {
+ spin_unlock(&_rndis_lock);
+ return;
+ }
+
+ cdev = rndis->port.func.config->cdev;
/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
// spin_lock(&dev->lock);
status = rndis_msg_parser(rndis->params, (u8 *) req->buf);
@@ -488,6 +524,7 @@
rndis->port.multi_pkt_xfer = 0;
}
// spin_unlock(&dev->lock);
+ spin_unlock(&_rndis_lock);
}
static int
@@ -639,13 +676,16 @@
{
struct f_rndis *rndis = func_to_rndis(f);
struct usb_composite_dev *cdev = f->config->cdev;
+ unsigned long flags;
if (!rndis->notify->enabled)
return;
DBG(cdev, "rndis deactivated\n");
+ spin_lock_irqsave(&_rndis_lock, flags);
rndis_uninit(rndis->params);
+ spin_unlock_irqrestore(&_rndis_lock, flags);
gether_disconnect(&rndis->port);
usb_ep_disable(rndis->notify);
@@ -793,7 +833,8 @@
rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
if (!rndis->notify_req)
goto fail;
- rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL);
+ rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT +
+ cdev->gadget->extra_buf_alloc, GFP_KERNEL);
if (!rndis->notify_req->buf)
goto fail;
rndis->notify_req->length = STATUS_BYTECOUNT;
@@ -937,6 +978,7 @@
opts->rndis_os_desc.ext_compat_id = opts->rndis_ext_compat_id;
mutex_init(&opts->lock);
+ spin_lock_init(&_rndis_lock);
opts->func_inst.free_func_inst = rndis_free_inst;
opts->net = gether_setup_default();
if (IS_ERR(opts->net)) {
@@ -966,11 +1008,15 @@
{
struct f_rndis *rndis;
struct f_rndis_opts *opts;
+ unsigned long flags;
rndis = func_to_rndis(f);
rndis_deregister(rndis->params);
opts = container_of(f->fi, struct f_rndis_opts, func_inst);
+ spin_lock_irqsave(&_rndis_lock, flags);
kfree(rndis);
+ __rndis = NULL;
+ spin_unlock_irqrestore(&_rndis_lock, flags);
mutex_lock(&opts->lock);
opts->refcnt--;
mutex_unlock(&opts->lock);
@@ -999,6 +1045,8 @@
if (!rndis)
return ERR_PTR(-ENOMEM);
+ __rndis = rndis;
+
opts = container_of(fi, struct f_rndis_opts, func_inst);
mutex_lock(&opts->lock);
opts->refcnt++;
diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c
index 9625248..405becf9 100644
--- a/drivers/usb/gadget/function/f_serial.c
+++ b/drivers/usb/gadget/function/f_serial.c
@@ -638,7 +638,7 @@
/* allocate notification */
gser->notify_req = gs_alloc_req(ep,
sizeof(struct usb_cdc_notification) + 2,
- GFP_KERNEL);
+ cdev->gadget->extra_buf_alloc, GFP_KERNEL);
if (!gser->notify_req)
goto fail;
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
index 5d8e6fa..038993d 100644
--- a/drivers/usb/gadget/function/rndis.c
+++ b/drivers/usb/gadget/function/rndis.c
@@ -932,6 +932,7 @@
}
#endif
+ spin_lock_init(¶ms->lock);
params->confignr = i;
params->used = 1;
params->state = RNDIS_UNINITIALIZED;
@@ -1096,29 +1097,36 @@
void rndis_free_response(struct rndis_params *params, u8 *buf)
{
rndis_resp_t *r, *n;
+ unsigned long flags;
+ spin_lock_irqsave(¶ms->lock, flags);
list_for_each_entry_safe(r, n, ¶ms->resp_queue, list) {
if (r->buf == buf) {
list_del(&r->list);
kfree(r);
}
}
+ spin_unlock_irqrestore(¶ms->lock, flags);
}
EXPORT_SYMBOL_GPL(rndis_free_response);
u8 *rndis_get_next_response(struct rndis_params *params, u32 *length)
{
rndis_resp_t *r, *n;
+ unsigned long flags;
if (!length) return NULL;
+ spin_lock_irqsave(¶ms->lock, flags);
list_for_each_entry_safe(r, n, ¶ms->resp_queue, list) {
if (!r->send) {
r->send = 1;
*length = r->length;
+ spin_unlock_irqrestore(¶ms->lock, flags);
return r->buf;
}
}
+ spin_unlock_irqrestore(¶ms->lock, flags);
return NULL;
}
@@ -1127,6 +1135,7 @@
static rndis_resp_t *rndis_add_response(struct rndis_params *params, u32 length)
{
rndis_resp_t *r;
+ unsigned long flags;
/* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */
r = kmalloc(sizeof(rndis_resp_t) + length, GFP_ATOMIC);
@@ -1136,7 +1145,9 @@
r->length = length;
r->send = 0;
+ spin_lock_irqsave(¶ms->lock, flags);
list_add_tail(&r->list, ¶ms->resp_queue);
+ spin_unlock_irqrestore(¶ms->lock, flags);
return r;
}
@@ -1144,7 +1155,7 @@
struct sk_buff *skb,
struct sk_buff_head *list)
{
- int num_pkts = 1;
+ int num_pkts = 0;
if (skb->len > rndis_ul_max_xfer_size_rcvd)
rndis_ul_max_xfer_size_rcvd = skb->len;
@@ -1154,12 +1165,6 @@
struct sk_buff *skb2;
u32 msg_len, data_offset, data_len;
- /* some rndis hosts send extra byte to avoid zlp, ignore it */
- if (skb->len == 1) {
- dev_kfree_skb_any(skb);
- return 0;
- }
-
if (skb->len < sizeof *hdr) {
pr_err("invalid rndis pkt: skblen:%u hdr_len:%zu",
skb->len, sizeof *hdr);
@@ -1188,9 +1193,12 @@
return -EINVAL;
}
+ num_pkts++;
+
skb_pull(skb, data_offset + 8);
- if (msg_len == skb->len) {
+ if (data_len == skb->len ||
+ data_len == (skb->len - 1)) {
skb_trim(skb, data_len);
break;
}
@@ -1205,8 +1213,6 @@
skb_pull(skb, msg_len - sizeof *hdr);
skb_trim(skb2, data_len);
skb_queue_tail(list, skb2);
-
- num_pkts++;
}
if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
@@ -1244,7 +1250,9 @@
"speed : %d\n"
"cable : %s\n"
"vendor ID : 0x%08X\n"
- "vendor : %s\n",
+ "vendor : %s\n"
+ "ul-max-xfer-size:%zu max-xfer-size-rcvd: %d\n"
+ "ul-max-pkts-per-xfer:%d max-pkts-per-xfer-rcvd:%d\n",
param->confignr, (param->used) ? "y" : "n",
({ char *s = "?";
switch (param->state) {
@@ -1258,7 +1266,13 @@
param->medium,
(param->media_state) ? 0 : param->speed*100,
(param->media_state) ? "disconnected" : "connected",
- param->vendorID, param->vendorDescr);
+ param->vendorID, param->vendorDescr,
+ param->dev ? param->max_pkt_per_xfer *
+ (param->dev->mtu + sizeof(struct ethhdr) +
+ sizeof(struct rndis_packet_msg_type) + 22) : 0,
+ rndis_ul_max_xfer_size_rcvd,
+ param->max_pkt_per_xfer,
+ rndis_ul_max_pkt_per_xfer_rcvd);
return 0;
}
diff --git a/drivers/usb/gadget/function/rndis.h b/drivers/usb/gadget/function/rndis.h
index a3051c4..2211146 100644
--- a/drivers/usb/gadget/function/rndis.h
+++ b/drivers/usb/gadget/function/rndis.h
@@ -203,6 +203,7 @@
void *v;
struct list_head resp_queue;
+ spinlock_t lock;
} rndis_params;
/* RNDIS Message parser and other useless functions */
diff --git a/drivers/usb/gadget/function/storage_common.h b/drivers/usb/gadget/function/storage_common.h
index e698489..614c281 100644
--- a/drivers/usb/gadget/function/storage_common.h
+++ b/drivers/usb/gadget/function/storage_common.h
@@ -128,6 +128,7 @@
/* Default size of buffer length. */
#define FSG_BUFLEN ((u32)16384)
+#define EXTRA_ALLOCATION_SIZE ((u32)256)
/* Maximal number of LUNs supported in mass storage function */
#define FSG_MAX_LUNS 16
diff --git a/drivers/usb/gadget/function/u_bam_dmux.c b/drivers/usb/gadget/function/u_bam_dmux.c
index 2ad184a..78dfe7b 100644
--- a/drivers/usb/gadget/function/u_bam_dmux.c
+++ b/drivers/usb/gadget/function/u_bam_dmux.c
@@ -21,6 +21,7 @@
#include <linux/debugfs.h>
#include <linux/bitops.h>
#include <linux/termios.h>
+#include <linux/platform_device.h>
#include <soc/qcom/bam_dmux.h>
@@ -28,32 +29,18 @@
#include <linux/usb/usb_ctrl_qti.h>
#include <linux/usb_bam.h>
-#include "usb_gadget_xport.h"
#include "u_rmnet.h"
-#define BAM_N_PORTS 2
-#define BAM2BAM_N_PORTS 4
-
static struct workqueue_struct *gbam_wq;
-static int n_bam_ports;
-static int n_bam2bam_ports;
static unsigned int n_tx_req_queued;
-static unsigned int bam_ch_ids[BAM_N_PORTS] = {
+static unsigned int bam_ch_ids[BAM_DMUX_NUM_FUNCS] = {
+ BAM_DMUX_USB_RMNET_0,
BAM_DMUX_USB_RMNET_0,
BAM_DMUX_USB_DPL
};
-static char bam_ch_names[BAM_N_PORTS][BAM_DMUX_CH_NAME_MAX_LEN];
-
-static const enum ipa_client_type usb_prod[BAM2BAM_N_PORTS] = {
- IPA_CLIENT_USB_PROD, IPA_CLIENT_USB2_PROD,
- IPA_CLIENT_USB3_PROD, IPA_CLIENT_USB4_PROD
-};
-static const enum ipa_client_type usb_cons[BAM2BAM_N_PORTS] = {
- IPA_CLIENT_USB_CONS, IPA_CLIENT_USB2_CONS,
- IPA_CLIENT_USB3_CONS, IPA_CLIENT_USB4_CONS
-};
+static char bam_ch_names[BAM_DMUX_NUM_FUNCS][BAM_DMUX_CH_NAME_MAX_LEN];
#define BAM_PENDING_PKTS_LIMIT 220
#define BAM_MUX_TX_PKT_DROP_THRESHOLD 1000
@@ -119,11 +106,6 @@
U_BAM_RESUME_E
};
-struct sys2ipa_sw {
- void *teth_priv;
- ipa_notify_cb teth_cb;
-};
-
struct bam_ch_info {
unsigned long flags;
unsigned int id;
@@ -141,22 +123,6 @@
struct usb_request *rx_req;
struct usb_request *tx_req;
- bool tx_req_dequeued;
- bool rx_req_dequeued;
-
- u32 src_pipe_idx;
- u32 dst_pipe_idx;
- u8 src_connection_idx;
- u8 dst_connection_idx;
- enum usb_ctrl usb_bam_type;
-
- enum transport_type trans;
- struct usb_bam_connect_ipa_params ipa_params;
-
- /* added to support sys to ipa sw UL path */
- struct sys2ipa_sw ul_params;
- enum usb_bam_pipe_type src_pipe_type;
- enum usb_bam_pipe_type dst_pipe_type;
/* stats */
unsigned int pending_pkts_with_bam;
@@ -184,21 +150,19 @@
spinlock_t port_lock_dl;
spinlock_t port_lock;
- struct grmnet *port_usb;
+ struct data_port *port_usb;
struct usb_gadget *gadget;
struct bam_ch_info data_ch;
struct work_struct connect_w;
struct work_struct disconnect_w;
- struct work_struct suspend_w;
- struct work_struct resume_w;
};
static struct bam_portmaster {
struct gbam_port *port;
struct platform_driver pdrv;
-} bam_ports[BAM_N_PORTS];
+} bam_ports[BAM_DMUX_NUM_FUNCS];
struct u_bam_data_connect_info {
u32 usb_bam_pipe_idx;
@@ -206,10 +170,7 @@
unsigned long usb_bam_handle;
};
-struct gbam_port *bam2bam_ports[BAM2BAM_N_PORTS];
static void gbam_start_rx(struct gbam_port *port);
-static void gbam_start_endless_rx(struct gbam_port *port);
-static void gbam_start_endless_tx(struct gbam_port *port);
static void gbam_notify(void *p, int event, unsigned long data);
static void gbam_data_write_tobam(struct work_struct *w);
@@ -260,7 +221,6 @@
struct bam_ch_info *d;
struct sk_buff *skb;
dma_addr_t skb_buf_dma_addr;
- struct usb_gadget *gadget;
if (!port)
return NULL;
@@ -283,24 +243,7 @@
goto alloc_exit;
skb_reserve(skb, BAM_MUX_HDR);
-
- if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
-
- gadget = port->port_usb->gadget;
-
- skb_buf_dma_addr =
- dma_map_single(&gadget->dev, skb->data,
- bam_mux_rx_req_size, DMA_BIDIRECTIONAL);
-
- if (dma_mapping_error(&gadget->dev, skb_buf_dma_addr)) {
- pr_err("%s: Could not DMA map SKB buffer\n",
- __func__);
- skb_buf_dma_addr = DMA_ERROR_CODE;
- }
- } else {
- skb_buf_dma_addr = DMA_ERROR_CODE;
- }
-
+ skb_buf_dma_addr = DMA_ERROR_CODE;
memcpy(skb->cb, &skb_buf_dma_addr,
sizeof(skb_buf_dma_addr));
@@ -308,6 +251,9 @@
} else {
pr_debug("%s: pull skb from pool\n", __func__);
skb = __skb_dequeue(&d->rx_skb_idle);
+ if (!skb)
+ goto alloc_exit;
+
if (skb_headroom(skb) < BAM_MUX_HDR)
skb_reserve(skb, BAM_MUX_HDR);
}
@@ -341,10 +287,13 @@
return;
d = &port->data_ch;
- gadget = port->port_usb->gadget;
+ gadget = port->port_usb->cdev->gadget;
while (d->rx_skb_idle.qlen > 0) {
skb = __skb_dequeue(&d->rx_skb_idle);
+ if (!skb)
+ break;
+
dma_addr = gbam_get_dma_from_skb(skb);
if (gadget && dma_addr != DMA_ERROR_CODE) {
@@ -359,36 +308,6 @@
}
}
-/*----- sys2bam towards the IPA --------------- */
-static void gbam_ipa_sys2bam_notify_cb(void *priv, enum ipa_dp_evt_type event,
- unsigned long data)
-{
- struct sys2ipa_sw *ul = (struct sys2ipa_sw *)priv;
- struct gbam_port *port;
- struct bam_ch_info *d;
-
- switch (event) {
- case IPA_WRITE_DONE:
- d = container_of(ul, struct bam_ch_info, ul_params);
- port = container_of(d, struct gbam_port, data_ch);
- /* call into bam_demux functionality that'll recycle the data */
- gbam_notify(port, BAM_DMUX_WRITE_DONE, data);
- break;
- case IPA_RECEIVE:
- /* call the callback given by tethering driver init function
- * (and was given to ipa_connect)
- */
- if (ul->teth_cb)
- ul->teth_cb(ul->teth_priv, event, data);
- break;
- default:
- /* unexpected event */
- pr_err("%s: unexpected event %d\n", __func__, event);
- break;
- }
-}
-
-
/*--------------------------------------------- */
/*------------data_path----------------------------*/
@@ -485,7 +404,7 @@
gbam_write_data_tohost(port);
}
-void gbam_data_recv_cb(void *p, struct sk_buff *skb)
+static void gbam_data_recv_cb(void *p, struct sk_buff *skb)
{
struct gbam_port *port = p;
struct bam_ch_info *d = &port->data_ch;
@@ -506,8 +425,7 @@
if (d->tx_skb_q.qlen > bam_mux_tx_pkt_drop_thld) {
d->tohost_drp_cnt++;
- if (printk_ratelimited())
- pr_err("%s: tx pkt dropped: tx_drop_cnt:%u\n",
+ printk_ratelimited(KERN_ERR "%s: tx pkt dropped: tx_drop_cnt:%u\n",
__func__, d->tohost_drp_cnt);
spin_unlock_irqrestore(&port->port_lock_dl, flags);
dev_kfree_skb_any(skb);
@@ -520,7 +438,7 @@
gbam_write_data_tohost(port);
}
-void gbam_data_write_done(void *p, struct sk_buff *skb)
+static void gbam_data_write_done(void *p, struct sk_buff *skb)
{
struct gbam_port *port = p;
struct bam_ch_info *d = &port->data_ch;
@@ -599,10 +517,7 @@
set_bit(BAM_CH_WRITE_INPROGRESS, &d->flags);
- while (!gbam_ul_bam_limit_reached(d) &&
- (d->trans != USB_GADGET_XPORT_BAM2BAM_IPA ||
- usb_bam_get_prod_granted(d->usb_bam_type,
- d->dst_connection_idx))) {
+ while (!gbam_ul_bam_limit_reached(d)) {
skb = __skb_dequeue(&d->rx_skb_q);
if (!skb)
break;
@@ -617,23 +532,7 @@
d->pending_bytes_with_bam, port->port_num);
spin_unlock_irqrestore(&port->port_lock_ul, flags);
- if (d->src_pipe_type == USB_BAM_PIPE_SYS2BAM) {
- dma_addr_t skb_dma_addr;
- struct ipa_tx_meta ipa_meta = {0x0};
-
- skb_dma_addr = gbam_get_dma_from_skb(skb);
- if (skb_dma_addr != DMA_ERROR_CODE) {
- ipa_meta.dma_address = skb_dma_addr;
- ipa_meta.dma_address_valid = true;
- }
-
- ret = ipa_tx_dp(usb_prod[port->port_num],
- skb,
- &ipa_meta);
- } else {
- ret = msm_bam_dmux_write(d->id, skb);
- }
-
+ ret = msm_bam_dmux_write(d->id, skb);
spin_lock_irqsave(&port->port_lock_ul, flags);
if (ret) {
pr_debug("%s: write error:%d\n", __func__, ret);
@@ -723,14 +622,12 @@
spin_lock(&port->port_lock_ul);
gbam_free_skb_to_pool(port, skb);
spin_unlock(&port->port_lock_ul);
- req->buf = 0;
+ req->buf = NULL;
usb_ep_free_request(ep, req);
return;
default:
- if (printk_ratelimited())
- pr_err("%s: %s response error %d, %d/%d\n",
- __func__, ep->name, status,
- req->actual, req->length);
+ printk_ratelimited(KERN_ERR "%s: %s response error %d, %d/%d\n",
+ __func__, ep->name, status, req->actual, req->length);
spin_lock(&port->port_lock_ul);
gbam_free_skb_to_pool(port, skb);
spin_unlock(&port->port_lock_ul);
@@ -741,14 +638,6 @@
if (queue) {
__skb_queue_tail(&d->rx_skb_q, skb);
- if ((d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) &&
- !usb_bam_get_prod_granted(d->usb_bam_type,
- d->dst_connection_idx)) {
- list_add_tail(&req->list, &d->rx_idle);
- spin_unlock(&port->port_lock_ul);
- return;
- }
-
queue_work(gbam_wq, &d->write_tobam_w);
}
@@ -778,11 +667,6 @@
req->dma = gbam_get_dma_from_skb(skb);
req->length = bam_mux_rx_req_size;
- if (req->dma != DMA_ERROR_CODE)
- req->dma_pre_mapped = true;
- else
- req->dma_pre_mapped = false;
-
req->context = skb;
status = usb_ep_queue(ep, req, GFP_ATOMIC);
@@ -791,8 +675,7 @@
gbam_free_skb_to_pool(port, skb);
spin_unlock(&port->port_lock_ul);
- if (printk_ratelimited())
- pr_err("%s: data rx enqueue err %d\n",
+ printk_ratelimited(KERN_ERR "%s: data rx enqueue err %d\n",
__func__, status);
spin_lock(&port->port_lock_ul);
@@ -801,20 +684,6 @@
}
}
-static void gbam_endless_rx_complete(struct usb_ep *ep, struct usb_request *req)
-{
- int status = req->status;
-
- pr_debug("%s status: %d\n", __func__, status);
-}
-
-static void gbam_endless_tx_complete(struct usb_ep *ep, struct usb_request *req)
-{
- int status = req->status;
-
- pr_debug("%s status: %d\n", __func__, status);
-}
-
static void gbam_start_rx(struct gbam_port *port)
{
struct usb_request *req;
@@ -850,11 +719,6 @@
req->dma = gbam_get_dma_from_skb(skb);
req->length = bam_mux_rx_req_size;
- if (req->dma != DMA_ERROR_CODE)
- req->dma_pre_mapped = true;
- else
- req->dma_pre_mapped = false;
-
req->context = skb;
spin_unlock_irqrestore(&port->port_lock_ul, flags);
@@ -863,8 +727,7 @@
if (ret) {
gbam_free_skb_to_pool(port, skb);
- if (printk_ratelimited())
- pr_err("%s: rx queue failed %d\n",
+ printk_ratelimited(KERN_ERR "%s: rx queue failed %d\n",
__func__, ret);
if (port->port_usb)
@@ -878,182 +741,6 @@
spin_unlock_irqrestore(&port->port_lock_ul, flags);
}
-static void gbam_start_endless_rx(struct gbam_port *port)
-{
- struct bam_ch_info *d = &port->data_ch;
- int status;
- struct usb_ep *ep;
- unsigned long flags;
-
- spin_lock_irqsave(&port->port_lock_ul, flags);
- if (!port->port_usb || !d->rx_req) {
- spin_unlock_irqrestore(&port->port_lock_ul, flags);
- pr_err("%s: port->port_usb is NULL", __func__);
- return;
- }
-
- ep = port->port_usb->out;
- spin_unlock_irqrestore(&port->port_lock_ul, flags);
- pr_debug("%s: enqueue\n", __func__);
- status = usb_ep_queue(ep, d->rx_req, GFP_ATOMIC);
- if (status)
- pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
-}
-
-static void gbam_start_endless_tx(struct gbam_port *port)
-{
- struct bam_ch_info *d = &port->data_ch;
- int status;
- struct usb_ep *ep;
- unsigned long flags;
-
- spin_lock_irqsave(&port->port_lock_dl, flags);
- if (!port->port_usb || !d->tx_req) {
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
- pr_err("%s: port->port_usb is NULL", __func__);
- return;
- }
-
- ep = port->port_usb->in;
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
- pr_debug("%s: enqueue\n", __func__);
- status = usb_ep_queue(ep, d->tx_req, GFP_ATOMIC);
- if (status)
- pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
-}
-
-static void gbam_stop_endless_rx(struct gbam_port *port)
-{
- struct bam_ch_info *d = &port->data_ch;
- int status;
- unsigned long flags;
- struct usb_ep *ep;
-
- spin_lock_irqsave(&port->port_lock_ul, flags);
- if (!port->port_usb) {
- spin_unlock_irqrestore(&port->port_lock_ul, flags);
- pr_err("%s: port->port_usb is NULL", __func__);
- return;
- }
-
- ep = port->port_usb->out;
- d->rx_req_dequeued = true;
- spin_unlock_irqrestore(&port->port_lock_ul, flags);
- pr_debug("%s: dequeue\n", __func__);
- status = usb_ep_dequeue(ep, d->rx_req);
- if (status)
- pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
-}
-
-static void gbam_stop_endless_tx(struct gbam_port *port)
-{
- struct bam_ch_info *d = &port->data_ch;
- int status;
- unsigned long flags;
- struct usb_ep *ep;
-
- spin_lock_irqsave(&port->port_lock_dl, flags);
- if (!port->port_usb) {
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
- pr_err("%s: port->port_usb is NULL", __func__);
- return;
- }
-
- ep = port->port_usb->in;
- d->tx_req_dequeued = true;
- spin_unlock_irqrestore(&port->port_lock_dl, flags);
- pr_debug("%s: dequeue\n", __func__);
- status = usb_ep_dequeue(ep, d->tx_req);
- if (status)
- pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
-}
-
-
-/*
- * This function configured data fifo based on index passed to get bam2bam
- * configuration.
- */
-static void configure_data_fifo(enum usb_ctrl bam_type, u8 idx,
- struct usb_ep *ep, enum usb_bam_pipe_type pipe_type)
-{
- struct u_bam_data_connect_info bam_info;
- struct sps_mem_buffer data_fifo = {0};
-
- if (pipe_type == USB_BAM_PIPE_BAM2BAM) {
- get_bam2bam_connection_info(bam_type, idx,
- &bam_info.usb_bam_pipe_idx,
- NULL, &data_fifo, NULL);
-
- msm_data_fifo_config(ep,
- data_fifo.phys_base,
- data_fifo.size,
- bam_info.usb_bam_pipe_idx);
- }
-}
-
-
-static void gbam_start(void *param, enum usb_bam_pipe_dir dir)
-{
- struct gbam_port *port = param;
- struct usb_gadget *gadget = NULL;
- struct bam_ch_info *d;
- unsigned long flags;
-
- if (port == NULL) {
- pr_err("%s: port is NULL\n", __func__);
- return;
- }
-
- spin_lock_irqsave(&port->port_lock, flags);
- if (port->port_usb == NULL) {
- pr_err("%s: port_usb is NULL, disconnected\n", __func__);
- spin_unlock_irqrestore(&port->port_lock, flags);
- return;
- }
-
- gadget = port->port_usb->gadget;
- d = &port->data_ch;
- spin_unlock_irqrestore(&port->port_lock, flags);
-
- if (gadget == NULL) {
- pr_err("%s: gadget is NULL\n", __func__);
- return;
- }
-
- if (dir == USB_TO_PEER_PERIPHERAL) {
- if (port->data_ch.src_pipe_type == USB_BAM_PIPE_BAM2BAM)
- gbam_start_endless_rx(port);
- else {
- gbam_start_rx(port);
- queue_work(gbam_wq, &d->write_tobam_w);
- }
- } else {
- if (gadget_is_dwc3(gadget) &&
- msm_dwc3_reset_ep_after_lpm(gadget)) {
- configure_data_fifo(d->usb_bam_type,
- d->dst_connection_idx,
- port->port_usb->in, d->dst_pipe_type);
- }
- gbam_start_endless_tx(port);
- }
-}
-
-static void gbam_stop(void *param, enum usb_bam_pipe_dir dir)
-{
- struct gbam_port *port = param;
-
- if (dir == USB_TO_PEER_PERIPHERAL) {
- /*
- * Only handling BAM2BAM, as there is no equivalent to
- * gbam_stop_endless_rx() for the SYS2BAM use case
- */
- if (port->data_ch.src_pipe_type == USB_BAM_PIPE_BAM2BAM)
- gbam_stop_endless_rx(port);
- } else {
- gbam_stop_endless_tx(port);
- }
-}
-
static int _gbam_start_io(struct gbam_port *port, bool in)
{
unsigned long flags;
@@ -1222,52 +909,6 @@
return;
}
-static void gbam2bam_disconnect_work(struct work_struct *w)
-{
- struct gbam_port *port =
- container_of(w, struct gbam_port, disconnect_w);
- struct bam_ch_info *d;
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&port->port_lock, flags);
-
- if (!port->is_connected) {
- pr_debug("%s: Port already disconnected. Bailing out.\n",
- __func__);
- spin_unlock_irqrestore(&port->port_lock, flags);
- return;
- }
-
- port->is_connected = false;
- d = &port->data_ch;
-
- /*
- * Unlock the port here and not at the end of this work,
- * because we do not want to activate usb_bam, ipa and
- * tethe bridge logic in atomic context and wait uneeded time.
- * Either way other works will not fire until end of this work
- * and event functions (as bam_data_connect) will not influance
- * while lower layers connect pipes, etc.
- */
- spin_unlock_irqrestore(&port->port_lock, flags);
-
- if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- ret = usb_bam_disconnect_ipa(d->usb_bam_type, &d->ipa_params);
- if (ret)
- pr_err("%s: usb_bam_disconnect_ipa failed: err:%d\n",
- __func__, ret);
- usb_bam_free_fifos(d->usb_bam_type, d->src_connection_idx);
- usb_bam_free_fifos(d->usb_bam_type, d->dst_connection_idx);
- teth_bridge_disconnect(d->ipa_params.src_client);
- /*
- * Decrement usage count which was incremented upon cable
- * connect or cable disconnect in suspended state
- */
- usb_gadget_autopm_put_async(port->gadget);
- }
-}
-
static void gbam_connect_work(struct work_struct *w)
{
struct gbam_port *port = container_of(w, struct gbam_port, connect_w);
@@ -1304,425 +945,6 @@
pr_debug("%s: done\n", __func__);
}
-static void gbam2bam_connect_work(struct work_struct *w)
-{
- struct gbam_port *port = container_of(w, struct gbam_port, connect_w);
- struct usb_gadget *gadget = NULL;
- struct teth_bridge_connect_params connect_params;
- struct teth_bridge_init_params teth_bridge_params;
- struct bam_ch_info *d;
- u32 sps_params;
- int ret;
- unsigned long flags, flags_ul;
-
- spin_lock_irqsave(&port->port_lock, flags);
-
- if (port->last_event == U_BAM_DISCONNECT_E) {
- pr_debug("%s: Port is about to disconnected. Bailing out.\n",
- __func__);
- spin_unlock_irqrestore(&port->port_lock, flags);
- return;
- }
-
- if (port->is_connected) {
- pr_debug("%s: Port already connected. Bail out.\n",
- __func__);
- spin_unlock_irqrestore(&port->port_lock, flags);
- return;
- }
- port->is_connected = true;
-
- spin_lock_irqsave(&port->port_lock_ul, flags_ul);
- spin_lock(&port->port_lock_dl);
- if (!port->port_usb) {
- pr_debug("%s: usb cable is disconnected, exiting\n", __func__);
- spin_unlock(&port->port_lock_dl);
- spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
- spin_unlock_irqrestore(&port->port_lock, flags);
- return;
- }
-
- gadget = port->port_usb->gadget;
- if (!gadget) {
- spin_unlock(&port->port_lock_dl);
- spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
- spin_unlock_irqrestore(&port->port_lock, flags);
- pr_err("%s: port_usb.gadget is NULL, exiting\n", __func__);
- return;
- }
- d = &port->data_ch;
-
- /*
- * Unlock the port here and not at the end of this work,
- * because we do not want to activate usb_bam, ipa and
- * tethe bridge logic in atomic context and wait uneeded time.
- * Either way other works will not fire until end of this work
- * and event functions (as bam_data_connect) will not influance
- * while lower layers connect pipes, etc.
- */
- spin_unlock(&port->port_lock_dl);
- spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
-
- d->ipa_params.usb_connection_speed = gadget->speed;
-
- /*
- * Invalidate prod and cons client handles from previous
- * disconnect.
- */
- d->ipa_params.cons_clnt_hdl = -1;
- d->ipa_params.prod_clnt_hdl = -1;
-
- if (usb_bam_get_pipe_type(d->usb_bam_type, d->ipa_params.src_idx,
- &d->src_pipe_type) ||
- usb_bam_get_pipe_type(d->usb_bam_type, d->ipa_params.dst_idx,
- &d->dst_pipe_type)) {
- spin_unlock_irqrestore(&port->port_lock, flags);
- pr_err("%s:usb_bam_get_pipe_type() failed\n", __func__);
- return;
- }
- if (d->dst_pipe_type != USB_BAM_PIPE_BAM2BAM) {
- spin_unlock_irqrestore(&port->port_lock, flags);
- pr_err("%s: no software preparation for DL not using bam2bam\n",
- __func__);
- return;
- }
-
- spin_unlock_irqrestore(&port->port_lock, flags);
- usb_bam_alloc_fifos(d->usb_bam_type, d->src_connection_idx);
- usb_bam_alloc_fifos(d->usb_bam_type, d->dst_connection_idx);
-
- spin_lock_irqsave(&port->port_lock, flags);
- /* check if USB cable is disconnected or not */
- if (!port || !port->port_usb) {
- pr_debug("%s: cable is disconnected.\n",
- __func__);
- spin_unlock_irqrestore(&port->port_lock,
- flags);
- goto free_fifos;
- }
- if (gadget_is_dwc3(gadget)) {
- /* Configure for RX */
- configure_data_fifo(d->usb_bam_type, d->src_connection_idx,
- port->port_usb->out, d->src_pipe_type);
- sps_params = MSM_SPS_MODE | MSM_DISABLE_WB | MSM_PRODUCER |
- d->src_pipe_idx;
- d->rx_req->length = 32*1024;
- d->rx_req->udc_priv = sps_params;
- msm_ep_config(port->port_usb->out, d->rx_req);
-
- /* Configure for TX */
- configure_data_fifo(d->usb_bam_type, d->dst_connection_idx,
- port->port_usb->in, d->dst_pipe_type);
- sps_params = MSM_SPS_MODE | MSM_DISABLE_WB | d->dst_pipe_idx;
- d->tx_req->length = 32*1024;
- d->tx_req->udc_priv = sps_params;
- msm_ep_config(port->port_usb->in, d->tx_req);
-
- } else {
- /* Configure for RX */
- get_bam2bam_connection_info(d->usb_bam_type,
- d->src_connection_idx,
- &d->src_pipe_idx,
- NULL, NULL, NULL);
- sps_params = (MSM_SPS_MODE | d->src_pipe_idx |
- MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
- d->rx_req->udc_priv = sps_params;
-
- /* Configure for TX */
- get_bam2bam_connection_info(d->usb_bam_type,
- d->dst_connection_idx,
- &d->dst_pipe_idx,
- NULL, NULL, NULL);
- sps_params = (MSM_SPS_MODE | d->dst_pipe_idx |
- MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
- d->tx_req->udc_priv = sps_params;
-
- }
-
- teth_bridge_params.client = d->ipa_params.src_client;
- ret = teth_bridge_init(&teth_bridge_params);
- if (ret) {
- spin_unlock_irqrestore(&port->port_lock, flags);
- pr_err("%s:teth_bridge_init() failed\n", __func__);
- goto ep_unconfig;
- }
-
- /* Support for UL using system-to-IPA */
- if (d->src_pipe_type == USB_BAM_PIPE_SYS2BAM) {
- d->ul_params.teth_priv =
- teth_bridge_params.private_data;
- d->ul_params.teth_cb =
- teth_bridge_params.usb_notify_cb;
- d->ipa_params.notify = gbam_ipa_sys2bam_notify_cb;
- d->ipa_params.priv = &d->ul_params;
- d->ipa_params.reset_pipe_after_lpm = false;
-
- } else {
- d->ipa_params.notify =
- teth_bridge_params.usb_notify_cb;
- d->ipa_params.priv =
- teth_bridge_params.private_data;
- d->ipa_params.reset_pipe_after_lpm =
- (gadget_is_dwc3(gadget) &&
- msm_dwc3_reset_ep_after_lpm(gadget));
- }
- d->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC;
- d->ipa_params.skip_ep_cfg = teth_bridge_params.skip_ep_cfg;
- d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
- spin_unlock_irqrestore(&port->port_lock, flags);
- ret = usb_bam_connect_ipa(d->usb_bam_type, &d->ipa_params);
- if (ret) {
- pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
- __func__, ret);
- goto ep_unconfig;
- }
-
- spin_lock_irqsave(&port->port_lock, flags);
- /* check if USB cable is disconnected or not */
- if (port->last_event == U_BAM_DISCONNECT_E) {
- spin_unlock_irqrestore(&port->port_lock, flags);
- pr_debug("%s:%d: cable is disconnected.\n",
- __func__, __LINE__);
- goto ep_unconfig;
- }
-
- /* Remove support for UL using system-to-IPA towards DL */
- if (d->src_pipe_type == USB_BAM_PIPE_SYS2BAM) {
- d->ipa_params.notify = d->ul_params.teth_cb;
- d->ipa_params.priv = d->ul_params.teth_priv;
- }
- if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
- d->ipa_params.reset_pipe_after_lpm =
- (gadget_is_dwc3(gadget) &&
- msm_dwc3_reset_ep_after_lpm(gadget));
- else
- d->ipa_params.reset_pipe_after_lpm = false;
- d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
- spin_unlock_irqrestore(&port->port_lock, flags);
- ret = usb_bam_connect_ipa(d->usb_bam_type, &d->ipa_params);
- if (ret) {
- pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
- __func__, ret);
- goto ep_unconfig;
- }
-
- spin_lock_irqsave(&port->port_lock, flags);
- /* check if USB cable is disconnected or not */
- if (port->last_event == U_BAM_DISCONNECT_E) {
- spin_unlock_irqrestore(&port->port_lock, flags);
- pr_debug("%s:%d: cable is disconnected.\n",
- __func__, __LINE__);
- goto ep_unconfig;
- }
-
- spin_unlock_irqrestore(&port->port_lock, flags);
- gqti_ctrl_update_ipa_pipes(port->port_usb, port->port_num,
- d->ipa_params.ipa_prod_ep_idx,
- d->ipa_params.ipa_cons_ep_idx);
-
- connect_params.ipa_usb_pipe_hdl = d->ipa_params.prod_clnt_hdl;
- connect_params.usb_ipa_pipe_hdl = d->ipa_params.cons_clnt_hdl;
- connect_params.tethering_mode = TETH_TETHERING_MODE_RMNET;
- connect_params.client_type = d->ipa_params.src_client;
- ret = teth_bridge_connect(&connect_params);
- if (ret) {
- pr_err("%s:teth_bridge_connect() failed\n", __func__);
- goto ep_unconfig;
- }
-
- /* queue in & out requests */
- if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM) {
- gbam_start_endless_rx(port);
- } else {
- /* The use-case of UL (OUT) ports using sys2bam is based on
- * partial reuse of the system-to-bam_demux code. The following
- * lines perform the branching out of the standard bam2bam flow
- * on the USB side of the UL channel
- */
- if (_gbam_start_io(port, false)) {
- pr_err("%s: _gbam_start_io failed\n", __func__);
- return;
- }
- gbam_start_rx(port);
- }
- gbam_start_endless_tx(port);
-
- pr_debug("%s: done\n", __func__);
- return;
-
-ep_unconfig:
- if (gadget_is_dwc3(gadget)) {
- spin_lock_irqsave(&port->port_lock, flags);
- /* check if USB cable is disconnected or not */
- if (port->port_usb) {
- msm_ep_unconfig(port->port_usb->in);
- msm_ep_unconfig(port->port_usb->out);
- }
- spin_unlock_irqrestore(&port->port_lock, flags);
- }
-free_fifos:
- usb_bam_free_fifos(d->usb_bam_type, d->src_connection_idx);
- usb_bam_free_fifos(d->usb_bam_type, d->dst_connection_idx);
-
-}
-
-static int gbam_wake_cb(void *param)
-{
- struct gbam_port *port = (struct gbam_port *)param;
- struct usb_gadget *gadget;
- unsigned long flags;
- struct usb_function *func;
- int ret;
-
- spin_lock_irqsave(&port->port_lock, flags);
- if (!port->port_usb) {
- pr_debug("%s: usb cable is disconnected, exiting\n",
- __func__);
- spin_unlock_irqrestore(&port->port_lock, flags);
- return -ENODEV;
- }
-
- gadget = port->port_usb->gadget;
- func = port->port_usb->f;
- spin_unlock_irqrestore(&port->port_lock, flags);
-
- pr_debug("%s: woken up by peer\n", __func__);
-
- if ((gadget->speed == USB_SPEED_SUPER) &&
- (func->func_is_suspended))
- ret = usb_func_wakeup(func);
- else
- ret = usb_gadget_wakeup(gadget);
-
- if ((ret == -EBUSY) || (ret == -EAGAIN))
- pr_debug("Remote wakeup is delayed due to LPM exit\n");
- else if (ret)
- pr_err("Failed to wake up the USB core. ret=%d\n", ret);
-
- return ret;
-}
-
-static void gbam2bam_suspend_work(struct work_struct *w)
-{
- struct gbam_port *port = container_of(w, struct gbam_port, suspend_w);
- struct bam_ch_info *d;
- int ret;
- unsigned long flags;
-
- pr_debug("%s: suspend work started\n", __func__);
-
- spin_lock_irqsave(&port->port_lock, flags);
-
- if ((port->last_event == U_BAM_DISCONNECT_E) ||
- (port->last_event == U_BAM_RESUME_E)) {
- pr_debug("%s: Port is about to disconnect/resume. Bail out\n",
- __func__);
- goto exit;
- }
-
- d = &port->data_ch;
-
- ret = usb_bam_register_wake_cb(d->usb_bam_type, d->dst_connection_idx,
- gbam_wake_cb, port);
- if (ret) {
- pr_err("%s(): Failed to register BAM wake callback.\n",
- __func__);
- goto exit;
- }
-
- if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- usb_bam_register_start_stop_cbs(d->usb_bam_type,
- d->dst_connection_idx, gbam_start, gbam_stop, port);
-
- /*
- * release lock here because gbam_start() or
- * gbam_stop() called from usb_bam_suspend()
- * re-acquires port lock.
- */
- spin_unlock_irqrestore(&port->port_lock, flags);
- usb_bam_suspend(d->usb_bam_type, &d->ipa_params);
- spin_lock_irqsave(&port->port_lock, flags);
- }
-
-exit:
- /*
- * Decrement usage count after IPA handshake is done to allow gadget
- * parent to go to lpm. This counter was incremented upon cable connect
- */
- usb_gadget_autopm_put_async(port->gadget);
-
- spin_unlock_irqrestore(&port->port_lock, flags);
-}
-
-static void gbam2bam_resume_work(struct work_struct *w)
-{
- struct gbam_port *port = container_of(w, struct gbam_port, resume_w);
- struct bam_ch_info *d;
- struct usb_gadget *gadget = NULL;
- int ret;
- unsigned long flags;
-
- pr_debug("%s: resume work started\n", __func__);
-
- spin_lock_irqsave(&port->port_lock, flags);
-
- if (port->last_event == U_BAM_DISCONNECT_E || !port->port_usb) {
- pr_debug("%s: usb cable is disconnected, exiting\n",
- __func__);
- goto exit;
- }
-
- d = &port->data_ch;
- gadget = port->port_usb->gadget;
-
- ret = usb_bam_register_wake_cb(d->usb_bam_type, d->dst_connection_idx,
- NULL, NULL);
- if (ret) {
- pr_err("%s(): Failed to register BAM wake callback.\n",
- __func__);
- goto exit;
- }
-
- if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- if (gadget_is_dwc3(gadget) &&
- msm_dwc3_reset_ep_after_lpm(gadget)) {
- if (d->tx_req_dequeued) {
- msm_ep_unconfig(port->port_usb->in);
- configure_data_fifo(d->usb_bam_type,
- d->dst_connection_idx,
- port->port_usb->in, d->dst_pipe_type);
- }
- if (d->rx_req_dequeued) {
- msm_ep_unconfig(port->port_usb->out);
- configure_data_fifo(d->usb_bam_type,
- d->src_connection_idx,
- port->port_usb->out, d->src_pipe_type);
- }
-
- spin_unlock_irqrestore(&port->port_lock, flags);
- if (d->tx_req_dequeued)
- msm_dwc3_reset_dbm_ep(port->port_usb->in);
- if (d->rx_req_dequeued)
- msm_dwc3_reset_dbm_ep(port->port_usb->out);
- spin_lock_irqsave(&port->port_lock, flags);
- if (port->port_usb) {
- if (d->tx_req_dequeued)
- msm_ep_config(port->port_usb->in,
- d->tx_req);
- if (d->rx_req_dequeued)
- msm_ep_config(port->port_usb->out,
- d->rx_req);
- }
- }
- d->tx_req_dequeued = false;
- d->rx_req_dequeued = false;
- usb_bam_resume(d->usb_bam_type, &d->ipa_params);
- }
-
-exit:
- spin_unlock_irqrestore(&port->port_lock, flags);
-}
-
/* BAM data channel ready, allow attempt to open */
static int gbam_data_ch_probe(struct platform_device *pdev)
{
@@ -1734,8 +956,11 @@
pr_debug("%s: name:%s\n", __func__, pdev->name);
- for (i = 0; i < n_bam_ports; i++) {
+ for (i = 0; i < BAM_DMUX_NUM_FUNCS; i++) {
port = bam_ports[i].port;
+ if (!port)
+ continue;
+
d = &port->data_ch;
if (!strcmp(bam_ch_names[i], pdev->name)) {
@@ -1770,9 +995,12 @@
pr_debug("%s: name:%s\n", __func__, pdev->name);
- for (i = 0; i < n_bam_ports; i++) {
+ for (i = 0; i < BAM_DMUX_NUM_FUNCS; i++) {
if (!strcmp(bam_ch_names[i], pdev->name)) {
port = bam_ports[i].port;
+ if (!port)
+ continue;
+
d = &port->data_ch;
spin_lock_irqsave(&port->port_lock_ul, flags);
@@ -1805,10 +1033,10 @@
return 0;
}
-static void gbam_port_free(int portno)
+static void gbam_port_free(enum bam_dmux_func_type func)
{
- struct gbam_port *port = bam_ports[portno].port;
- struct platform_driver *pdrv = &bam_ports[portno].pdrv;
+ struct gbam_port *port = bam_ports[func].port;
+ struct platform_driver *pdrv = &bam_ports[func].pdrv;
if (port)
platform_driver_unregister(pdrv);
@@ -1816,14 +1044,7 @@
kfree(port);
}
-static void gbam2bam_port_free(int portno)
-{
- struct gbam_port *port = bam2bam_ports[portno];
-
- kfree(port);
-}
-
-static int gbam_port_alloc(int portno)
+static int gbam_port_alloc(enum bam_dmux_func_type func)
{
struct gbam_port *port;
struct bam_ch_info *d;
@@ -1833,7 +1054,7 @@
if (!port)
return -ENOMEM;
- port->port_num = portno;
+ port->port_num = func;
/* port initialization */
port->is_connected = false;
@@ -1853,60 +1074,20 @@
skb_queue_head_init(&d->tx_skb_q);
skb_queue_head_init(&d->rx_skb_q);
skb_queue_head_init(&d->rx_skb_idle);
- d->id = bam_ch_ids[portno];
+ d->id = bam_ch_ids[func];
- bam_ports[portno].port = port;
+ bam_ports[func].port = port;
- scnprintf(bam_ch_names[portno], BAM_DMUX_CH_NAME_MAX_LEN,
- "bam_dmux_ch_%d", bam_ch_ids[portno]);
- pdrv = &bam_ports[portno].pdrv;
+ scnprintf(bam_ch_names[func], BAM_DMUX_CH_NAME_MAX_LEN,
+ "bam_dmux_ch_%d", bam_ch_ids[func]);
+ pdrv = &bam_ports[func].pdrv;
pdrv->probe = gbam_data_ch_probe;
pdrv->remove = gbam_data_ch_remove;
- pdrv->driver.name = bam_ch_names[portno];
+ pdrv->driver.name = bam_ch_names[func];
pdrv->driver.owner = THIS_MODULE;
platform_driver_register(pdrv);
- pr_debug("%s: port:%pK portno:%d\n", __func__, port, portno);
-
- return 0;
-}
-
-static int gbam2bam_port_alloc(int portno)
-{
- struct gbam_port *port;
- struct bam_ch_info *d;
-
- port = kzalloc(sizeof(struct gbam_port), GFP_KERNEL);
- if (!port)
- return -ENOMEM;
-
- port->port_num = portno;
-
- /* port initialization */
- port->is_connected = false;
- spin_lock_init(&port->port_lock_ul);
- spin_lock_init(&port->port_lock_dl);
- spin_lock_init(&port->port_lock);
-
- INIT_WORK(&port->connect_w, gbam2bam_connect_work);
- INIT_WORK(&port->disconnect_w, gbam2bam_disconnect_work);
- INIT_WORK(&port->suspend_w, gbam2bam_suspend_work);
- INIT_WORK(&port->resume_w, gbam2bam_resume_work);
-
- /* data ch */
- d = &port->data_ch;
- d->port = port;
- d->ipa_params.src_client = usb_prod[portno];
- d->ipa_params.dst_client = usb_cons[portno];
- bam2bam_ports[portno] = port;
-
- /* UL workaround requirements */
- skb_queue_head_init(&d->rx_skb_q);
- skb_queue_head_init(&d->rx_skb_idle);
- INIT_LIST_HEAD(&d->rx_idle);
- INIT_WORK(&d->write_tobam_w, gbam_data_write_tobam);
-
- pr_debug("%s: port:%pK portno:%d\n", __func__, port, portno);
+ pr_debug("%s: port:%pK portno:%d\n", __func__, port, func);
return 0;
}
@@ -1928,7 +1109,7 @@
if (!buf)
return -ENOMEM;
- for (i = 0; i < n_bam_ports; i++) {
+ for (i = 0; i < BAM_DMUX_NUM_FUNCS; i++) {
port = bam_ports[i].port;
if (!port)
continue;
@@ -1991,7 +1172,7 @@
int i;
unsigned long flags;
- for (i = 0; i < n_bam_ports; i++) {
+ for (i = 0; i < BAM_DMUX_NUM_FUNCS; i++) {
port = bam_ports[i].port;
if (!port)
continue;
@@ -2021,48 +1202,12 @@
return count;
}
-const struct file_operations gbam_stats_ops = {
+static const struct file_operations gbam_stats_ops = {
.read = gbam_read_stats,
.write = gbam_reset_stats,
};
-static ssize_t gbam_rw_write(struct file *file, const char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct gbam_port *port = bam2bam_ports[0];
- struct usb_function *func;
- struct usb_gadget *gadget;
- unsigned long flags;
-
- if (!port)
- return -ENODEV;
-
- spin_lock_irqsave(&port->port_lock, flags);
- if (!port->port_usb) {
- pr_debug("%s: usb cable is disconnected, exiting\n",
- __func__);
- spin_unlock_irqrestore(&port->port_lock, flags);
- return -ENODEV;
- }
-
- gadget = port->port_usb->gadget;
- func = port->port_usb->f;
- spin_unlock_irqrestore(&port->port_lock, flags);
-
- if ((gadget->speed == USB_SPEED_SUPER) && (func->func_is_suspended)) {
- pr_debug("%s Initiating usb_func rwakeup\n", __func__);
- usb_func_wakeup(func);
- }
-
- return count;
-}
-
-
-const struct file_operations debug_remote_wakeup_fops = {
- .write = gbam_rw_write,
-};
-
-struct dentry *gbam_dent;
+static struct dentry *gbam_dent;
static void gbam_debugfs_init(void)
{
struct dentry *dfile;
@@ -2070,14 +1215,11 @@
if (gbam_dent)
return;
- gbam_dent = debugfs_create_dir("usb_rmnet", 0);
+ gbam_dent = debugfs_create_dir("usb_rmnet", NULL);
if (!gbam_dent || IS_ERR(gbam_dent))
return;
- debugfs_create_file("remote_wakeup", 0444, gbam_dent, 0,
- &debug_remote_wakeup_fops);
-
- dfile = debugfs_create_file("status", 0444, gbam_dent, 0,
+ dfile = debugfs_create_file("status", 0444, gbam_dent, NULL,
&gbam_stats_ops);
if (!dfile || IS_ERR(dfile)) {
debugfs_remove(gbam_dent);
@@ -2094,29 +1236,16 @@
static inline void gbam_debugfs_remove(void) {}
#endif
-void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans)
+void gbam_disconnect(struct data_port *gr, enum bam_dmux_func_type func)
{
struct gbam_port *port;
- unsigned long flags, flags_ul, flags_dl;
+ unsigned long flags, flags_ul;
struct bam_ch_info *d;
- pr_debug("%s: grmnet:%pK port#%d\n", __func__, gr, port_num);
+ pr_debug("%s: grmnet:%pK port#%d\n", __func__, gr, func);
- if (trans == USB_GADGET_XPORT_BAM2BAM) {
- pr_err("%s: invalid xport#%d\n", __func__, trans);
- return;
- }
- if (trans == USB_GADGET_XPORT_BAM_DMUX &&
- port_num >= n_bam_ports) {
- pr_err("%s: invalid bam portno#%d\n",
- __func__, port_num);
- return;
- }
-
- if ((trans == USB_GADGET_XPORT_BAM2BAM_IPA) &&
- port_num >= n_bam2bam_ports) {
- pr_err("%s: invalid bam2bam portno#%d\n",
- __func__, port_num);
+ if (func >= BAM_DMUX_NUM_FUNCS) {
+ pr_err("%s: invalid bam portno#%d\n", __func__, func);
return;
}
@@ -2124,10 +1253,7 @@
pr_err("%s: grmnet port is null\n", __func__);
return;
}
- if (trans == USB_GADGET_XPORT_BAM_DMUX)
- port = bam_ports[port_num].port;
- else
- port = bam2bam_ports[port_num];
+ port = bam_ports[func].port;
if (!port) {
pr_err("%s: NULL port", __func__);
@@ -2142,124 +1268,58 @@
spin_unlock_irqrestore(&port->port_lock, flags);
return;
}
- /*
- * Suspend with remote wakeup enabled. Increment usage
- * count when disconnect happens in suspended state.
- * Corresponding decrement happens in the end of this
- * function if IPA handshake is already done or it is done
- * in disconnect work after finishing IPA handshake.
- */
- if (port->last_event == U_BAM_SUSPEND_E)
- usb_gadget_autopm_get_noresume(port->gadget);
port->port_usb = gr;
- if (trans == USB_GADGET_XPORT_BAM_DMUX)
- gbam_free_buffers(port);
- else if (trans == USB_GADGET_XPORT_BAM2BAM_IPA)
- gbam_free_rx_buffers(port);
+ gbam_free_buffers(port);
spin_lock_irqsave(&port->port_lock_ul, flags_ul);
spin_lock(&port->port_lock_dl);
- port->port_usb = 0;
+ port->port_usb = NULL;
n_tx_req_queued = 0;
spin_unlock(&port->port_lock_dl);
spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
usb_ep_disable(gr->in);
- if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- spin_lock_irqsave(&port->port_lock_dl, flags_dl);
- if (d->tx_req) {
- usb_ep_free_request(gr->in, d->tx_req);
- d->tx_req = NULL;
- }
- spin_unlock_irqrestore(&port->port_lock_dl, flags_dl);
- }
/* disable endpoints */
- if (gr->out) {
+ if (gr->out)
usb_ep_disable(gr->out);
- if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- spin_lock_irqsave(&port->port_lock_ul, flags_ul);
- if (d->rx_req) {
- usb_ep_free_request(gr->out, d->rx_req);
- d->rx_req = NULL;
- }
- spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
- }
- }
-
- /*
- * Set endless flag to false as USB Endpoint is already
- * disable.
- */
- if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
-
- if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
- gr->in->endless = false;
-
- if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM && gr->out)
- gr->out->endless = false;
- }
gr->in->driver_data = NULL;
if (gr->out)
gr->out->driver_data = NULL;
port->last_event = U_BAM_DISCONNECT_E;
- /* Disable usb irq for CI gadget. It will be enabled in
- * usb_bam_disconnect_pipe() after disconnecting all pipes
- * and USB BAM reset is done.
- */
- if (!gadget_is_dwc3(port->gadget) &&
- (trans == USB_GADGET_XPORT_BAM2BAM_IPA))
- msm_usb_irq_disable(true);
-
queue_work(gbam_wq, &port->disconnect_w);
spin_unlock_irqrestore(&port->port_lock, flags);
}
-int gbam_connect(struct grmnet *gr, u8 port_num,
- enum transport_type trans, u8 src_connection_idx,
- u8 dst_connection_idx)
+int gbam_connect(struct data_port *gr, enum bam_dmux_func_type func)
{
struct gbam_port *port;
struct bam_ch_info *d;
int ret;
unsigned long flags, flags_ul;
- pr_debug("%s: grmnet:%pK port#%d\n", __func__, gr, port_num);
+ pr_debug("%s: grmnet:%pK port#%d\n", __func__, gr, func);
if (!gr) {
pr_err("%s: grmnet port is null\n", __func__);
return -ENODEV;
}
- if (!gr->gadget) {
+ if (!gr->cdev->gadget) {
pr_err("%s: gadget handle not passed\n", __func__);
return -EINVAL;
}
- if (trans == USB_GADGET_XPORT_BAM2BAM) {
- pr_err("%s: invalid xport#%d\n", __func__, trans);
- return -EINVAL;
- }
-
- if (trans == USB_GADGET_XPORT_BAM_DMUX && port_num >= n_bam_ports) {
- pr_err("%s: invalid portno#%d\n", __func__, port_num);
+ if (func >= BAM_DMUX_NUM_FUNCS) {
+ pr_err("%s: invalid portno#%d\n", __func__, func);
return -ENODEV;
}
- if ((trans == USB_GADGET_XPORT_BAM2BAM_IPA)
- && port_num >= n_bam2bam_ports) {
- pr_err("%s: invalid portno#%d\n", __func__, port_num);
- return -ENODEV;
- }
-
- if (trans == USB_GADGET_XPORT_BAM_DMUX)
- port = bam_ports[port_num].port;
- else
- port = bam2bam_ports[port_num];
+ port = bam_ports[func].port;
if (!port) {
pr_err("%s: NULL port", __func__);
@@ -2269,108 +1329,28 @@
spin_lock_irqsave(&port->port_lock, flags);
d = &port->data_ch;
- d->trans = trans;
spin_lock_irqsave(&port->port_lock_ul, flags_ul);
spin_lock(&port->port_lock_dl);
port->port_usb = gr;
- port->gadget = port->port_usb->gadget;
+ port->gadget = port->port_usb->cdev->gadget;
- if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- d->rx_req = usb_ep_alloc_request(port->port_usb->out,
- GFP_ATOMIC);
- if (!d->rx_req) {
- pr_err("%s: RX request allocation failed\n", __func__);
- d->rx_req = NULL;
- spin_unlock(&port->port_lock_dl);
- spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
- spin_unlock_irqrestore(&port->port_lock, flags);
- return -ENOMEM;
- }
-
- d->rx_req->context = port;
- d->rx_req->complete = gbam_endless_rx_complete;
- d->rx_req->length = 0;
- d->rx_req->no_interrupt = 1;
-
- d->tx_req = usb_ep_alloc_request(port->port_usb->in,
- GFP_ATOMIC);
- if (!d->tx_req) {
- pr_err("%s: TX request allocation failed\n", __func__);
- d->tx_req = NULL;
- usb_ep_free_request(port->port_usb->out, d->rx_req);
- d->rx_req = NULL;
- spin_unlock(&port->port_lock_dl);
- spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
- spin_unlock_irqrestore(&port->port_lock, flags);
- return -ENOMEM;
- }
-
- d->tx_req->context = port;
- d->tx_req->complete = gbam_endless_tx_complete;
- d->tx_req->length = 0;
- d->tx_req->no_interrupt = 1;
- }
-
- if (d->trans == USB_GADGET_XPORT_BAM_DMUX) {
- d->to_host = 0;
- d->to_modem = 0;
- d->pending_pkts_with_bam = 0;
- d->pending_bytes_with_bam = 0;
- d->tohost_drp_cnt = 0;
- d->tomodem_drp_cnt = 0;
- d->rx_flow_control_disable = 0;
- d->rx_flow_control_enable = 0;
- d->rx_flow_control_triggered = 0;
- d->max_num_pkts_pending_with_bam = 0;
- d->max_bytes_pending_with_bam = 0;
- d->delayed_bam_mux_write_done = 0;
- }
+ d->to_host = 0;
+ d->to_modem = 0;
+ d->pending_pkts_with_bam = 0;
+ d->pending_bytes_with_bam = 0;
+ d->tohost_drp_cnt = 0;
+ d->tomodem_drp_cnt = 0;
+ d->rx_flow_control_disable = 0;
+ d->rx_flow_control_enable = 0;
+ d->rx_flow_control_triggered = 0;
+ d->max_num_pkts_pending_with_bam = 0;
+ d->max_bytes_pending_with_bam = 0;
+ d->delayed_bam_mux_write_done = 0;
spin_unlock(&port->port_lock_dl);
spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
- if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- d->src_connection_idx = src_connection_idx;
- d->dst_connection_idx = dst_connection_idx;
- d->usb_bam_type = usb_bam_get_bam_type(gr->gadget->name);
- d->ipa_params.src_pipe = &(d->src_pipe_idx);
- d->ipa_params.dst_pipe = &(d->dst_pipe_idx);
- d->ipa_params.src_idx = src_connection_idx;
- d->ipa_params.dst_idx = dst_connection_idx;
-
- /*
- * Query pipe type using IPA src/dst index with
- * usbbam driver. It is being set either as
- * BAM2BAM or SYS2BAM.
- */
- if (usb_bam_get_pipe_type(d->usb_bam_type,
- d->ipa_params.src_idx, &d->src_pipe_type) ||
- usb_bam_get_pipe_type(d->usb_bam_type,
- d->ipa_params.dst_idx, &d->dst_pipe_type)) {
- pr_err("%s:usb_bam_get_pipe_type() failed\n",
- __func__);
- ret = -EINVAL;
- usb_ep_free_request(port->port_usb->out, d->rx_req);
- d->rx_req = NULL;
- usb_ep_free_request(port->port_usb->in, d->tx_req);
- d->tx_req = NULL;
- goto exit;
- }
- /*
- * Check for pipe_type. If it is BAM2BAM, then it is required
- * to disable Xfer complete and Xfer not ready interrupts for
- * that particular endpoint. Hence it set endless flag based
- * it which is considered into UDC driver while enabling
- * USB Endpoint.
- */
- if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
- port->port_usb->in->endless = true;
-
- if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM)
- port->port_usb->out->endless = true;
- }
-
ret = usb_ep_enable(gr->in);
if (ret) {
pr_err("%s: usb_ep_enable failed eptype:IN ep:%pK",
@@ -2379,11 +1359,6 @@
d->rx_req = NULL;
usb_ep_free_request(port->port_usb->in, d->tx_req);
d->tx_req = NULL;
- if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
- port->port_usb->in->endless = false;
-
- if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM)
- port->port_usb->out->endless = false;
goto exit;
}
gr->in->driver_data = port;
@@ -2398,30 +1373,18 @@
if (ret) {
pr_err("%s: usb_ep_enable failed eptype:OUT ep:%pK",
__func__, gr->out);
- gr->in->driver_data = 0;
+ gr->in->driver_data = NULL;
usb_ep_disable(gr->in);
usb_ep_free_request(port->port_usb->out, d->rx_req);
d->rx_req = NULL;
usb_ep_free_request(port->port_usb->in, d->tx_req);
d->tx_req = NULL;
- if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
- port->port_usb->in->endless = false;
-
- if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM)
- port->port_usb->out->endless = false;
goto exit;
}
gr->out->driver_data = port;
}
port->last_event = U_BAM_CONNECT_E;
- /*
- * Increment usage count upon cable connect. Decrement after IPA
- * handshake is done in disconnect work (due to cable disconnect)
- * or in suspend work.
- */
- if (trans == USB_GADGET_XPORT_BAM2BAM_IPA)
- usb_gadget_autopm_get_noresume(port->gadget);
queue_work(gbam_wq, &port->connect_w);
ret = 0;
@@ -2430,24 +1393,14 @@
return ret;
}
-void gbam_data_flush_workqueue(void)
+int gbam_setup(enum bam_dmux_func_type func)
{
- pr_debug("%s(): Flushing workqueue\n", __func__);
- flush_workqueue(gbam_wq);
-}
-
-int gbam_setup(unsigned int no_bam_port)
-{
- int i;
int ret;
- int bam_port_start = n_bam_ports;
- int total_bam_ports = bam_port_start + no_bam_port;
- pr_debug("%s: requested BAM ports:%d\n", __func__, no_bam_port);
+ pr_debug("%s: requested BAM port:%d\n", __func__, func);
- if (!no_bam_port || total_bam_ports > BAM_N_PORTS) {
- pr_err("%s: Invalid num of ports count:%d\n",
- __func__, no_bam_port);
+ if (func >= BAM_DMUX_NUM_FUNCS) {
+ pr_err("%s: Invalid num of ports count:%d\n", __func__, func);
return -EINVAL;
}
@@ -2461,171 +1414,54 @@
}
}
- for (i = bam_port_start; i < (bam_port_start + no_bam_port); i++) {
- n_bam_ports++;
- pr_debug("gbam_port_alloc called for %d\n", i);
- ret = gbam_port_alloc(i);
- if (ret) {
- n_bam_ports--;
- pr_err("%s: Unable to alloc port:%d\n", __func__, i);
- goto free_bam_ports;
- }
+ ret = gbam_port_alloc(func);
+ if (ret) {
+ pr_err("%s: Unable to alloc port:%d\n", __func__, func);
+ goto destroy_wq;
}
gbam_debugfs_init();
- return bam_port_start;
+ return 0;
-free_bam_ports:
- for (i = 0; i < n_bam_ports; i++)
- gbam_port_free(i);
+destroy_wq:
destroy_workqueue(gbam_wq);
return ret;
}
-int gbam2bam_setup(unsigned int no_bam2bam_port)
-{
- int i;
- int ret;
- int bam2bam_port_start = n_bam2bam_ports;
- int total_bam2bam_ports = bam2bam_port_start + no_bam2bam_port;
-
- pr_debug("%s: requested BAM2BAM ports:%d\n", __func__, no_bam2bam_port);
-
- if (!no_bam2bam_port || total_bam2bam_ports > BAM2BAM_N_PORTS) {
- pr_err("%s: Invalid num of ports count:%d\n",
- __func__, no_bam2bam_port);
- return -EINVAL;
- }
-
- if (!gbam_wq) {
- gbam_wq = alloc_workqueue("k_gbam", WQ_UNBOUND |
- WQ_MEM_RECLAIM, 1);
- if (!gbam_wq) {
- pr_err("%s: Unable to create workqueue gbam_wq\n",
- __func__);
- return -ENOMEM;
- }
- }
-
- for (i = bam2bam_port_start; i < (bam2bam_port_start +
- no_bam2bam_port); i++) {
- n_bam2bam_ports++;
- ret = gbam2bam_port_alloc(i);
- if (ret) {
- n_bam2bam_ports--;
- pr_err("%s: Unable to alloc port:%d\n", __func__, i);
- goto free_bam2bam_ports;
- }
- }
-
- gbam_debugfs_init();
-
- return bam2bam_port_start;
-
-free_bam2bam_ports:
- for (i = 0; i < n_bam2bam_ports; i++)
- gbam2bam_port_free(i);
- destroy_workqueue(gbam_wq);
-
- return ret;
-}
-
-void gbam_cleanup(void)
+void gbam_cleanup(enum bam_dmux_func_type func)
{
gbam_debugfs_remove();
-}
-
-void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans)
-{
- struct gbam_port *port;
- struct bam_ch_info *d;
- unsigned long flags;
-
- if (trans != USB_GADGET_XPORT_BAM2BAM_IPA)
- return;
-
- port = bam2bam_ports[port_num];
-
- if (!port) {
- pr_err("%s: NULL port", __func__);
- return;
- }
-
- spin_lock_irqsave(&port->port_lock, flags);
-
- d = &port->data_ch;
-
- pr_debug("%s: suspended port %d\n", __func__, port_num);
-
- port->last_event = U_BAM_SUSPEND_E;
- queue_work(gbam_wq, &port->suspend_w);
-
- spin_unlock_irqrestore(&port->port_lock, flags);
-}
-
-void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans)
-{
- struct gbam_port *port;
- struct bam_ch_info *d;
- unsigned long flags;
-
- if (trans != USB_GADGET_XPORT_BAM2BAM_IPA)
- return;
-
- port = bam2bam_ports[port_num];
-
- if (!port) {
- pr_err("%s: NULL port", __func__);
- return;
- }
-
- spin_lock_irqsave(&port->port_lock, flags);
-
- d = &port->data_ch;
-
- pr_debug("%s: resumed port %d\n", __func__, port_num);
-
- port->last_event = U_BAM_RESUME_E;
- /*
- * Increment usage count here to disallow gadget parent suspend.
- * This counter will decrement after IPA handshake is done in
- * disconnect work (due to cable disconnect) or in bam_disconnect
- * in suspended state.
- */
- usb_gadget_autopm_get_noresume(port->gadget);
- queue_work(gbam_wq, &port->resume_w);
-
- spin_unlock_irqrestore(&port->port_lock, flags);
+ gbam_port_free(func);
}
int gbam_mbim_connect(struct usb_gadget *g, struct usb_ep *in,
struct usb_ep *out)
{
- struct grmnet *gr;
+ struct data_port *gr;
gr = kzalloc(sizeof(*gr), GFP_ATOMIC);
if (!gr)
return -ENOMEM;
gr->in = in;
gr->out = out;
- gr->gadget = g;
+ gr->cdev->gadget = g;
- return gbam_connect(gr, 0, USB_GADGET_XPORT_BAM_DMUX, 0, 0);
+ return gbam_connect(gr, BAM_DMUX_FUNC_MBIM);
}
void gbam_mbim_disconnect(void)
{
- struct gbam_port *port = bam_ports[0].port;
- struct grmnet *gr = port->port_usb;
+ struct gbam_port *port = bam_ports[BAM_DMUX_FUNC_MBIM].port;
+ struct data_port *gr = port->port_usb;
if (!gr) {
pr_err("%s: port_usb is NULL\n", __func__);
return;
}
- gbam_disconnect(gr, 0, USB_GADGET_XPORT_BAM_DMUX);
+ gbam_disconnect(gr, BAM_DMUX_FUNC_MBIM);
kfree(gr);
}
@@ -2633,13 +1469,7 @@
{
int ret = 0;
- /*
- * MBIM requires only 1 USB_GADGET_XPORT_BAM_DMUX
- * port. The port is always 0 and is shared
- * between RMNET and MBIM.
- */
- if (!n_bam_ports)
- ret = gbam_setup(1);
+ ret = gbam_setup(BAM_DMUX_FUNC_MBIM);
return ret;
}
diff --git a/drivers/usb/gadget/function/u_ctrl_qti.c b/drivers/usb/gadget/function/u_ctrl_qti.c
index 21839a3e..4ab7bc4 100644
--- a/drivers/usb/gadget/function/u_ctrl_qti.c
+++ b/drivers/usb/gadget/function/u_ctrl_qti.c
@@ -17,6 +17,8 @@
#include <linux/cdev.h>
#include <linux/debugfs.h>
+#include <soc/qcom/bam_dmux.h>
+
#include "u_rmnet.h"
#include "f_qdss.h"
@@ -206,7 +208,8 @@
qti_ctrl_queue_notify(port);
}
-int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned int intf)
+int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned int intf,
+ enum data_xport_type dxport)
{
struct qti_ctrl_port *port;
struct grmnet *g_rmnet = NULL;
@@ -226,8 +229,16 @@
spin_lock_irqsave(&port->lock, flags);
port->port_type = qport;
- port->ep_type = DATA_EP_TYPE_HSUSB;
- port->intf = intf;
+ if (dxport == BAM_DMUX) {
+ port->ep_type = DATA_EP_TYPE_BAM_DMUX;
+ port->intf = (qport == QTI_PORT_RMNET) ?
+ BAM_DMUX_USB_RMNET_0 : BAM_DMUX_USB_DPL;
+ port->ipa_prod_idx = 0;
+ port->ipa_cons_idx = 0;
+ } else {
+ port->ep_type = DATA_EP_TYPE_HSUSB;
+ port->intf = intf;
+ }
if (gr) {
port->port_usb = gr;
diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c
index f379028..7af152b3 100644
--- a/drivers/usb/gadget/function/u_data_ipa.c
+++ b/drivers/usb/gadget/function/u_data_ipa.c
@@ -23,7 +23,6 @@
#include <linux/usb_bam.h>
#include "u_data_ipa.h"
-#include "u_rmnet.h"
struct ipa_data_ch_info {
struct usb_request *rx_req;
@@ -45,7 +44,7 @@
u8 src_connection_idx;
u8 dst_connection_idx;
enum usb_ctrl usb_bam_type;
- struct gadget_ipa_port *port_usb;
+ struct data_port *port_usb;
struct usb_gadget *gadget;
atomic_t pipe_connect_notified;
struct usb_bam_connect_ipa_params ipa_params;
@@ -299,7 +298,7 @@
* switch is being trigger. This API performs restoring USB endpoint operation
* and disable USB endpoint used for accelerated path.
*/
-void ipa_data_disconnect(struct gadget_ipa_port *gp, enum ipa_func_type func)
+void ipa_data_disconnect(struct data_port *gp, enum ipa_func_type func)
{
struct ipa_data_ch_info *port;
unsigned long flags;
@@ -402,7 +401,7 @@
{
struct ipa_data_ch_info *port = container_of(w, struct ipa_data_ch_info,
connect_w);
- struct gadget_ipa_port *gport;
+ struct data_port *gport;
struct usb_gadget *gadget = NULL;
struct teth_bridge_connect_params connect_params;
struct teth_bridge_init_params teth_bridge_params;
@@ -478,7 +477,7 @@
configure_fifo(port->usb_bam_type,
port->src_connection_idx,
port->port_usb->out);
- ret = msm_ep_config(gport->out);
+ ret = msm_ep_config(gport->out, port->rx_req);
if (ret) {
pr_err("msm_ep_config() failed for OUT EP\n");
spin_unlock_irqrestore(&port->port_lock, flags);
@@ -503,7 +502,7 @@
port->tx_req->udc_priv = sps_params;
configure_fifo(port->usb_bam_type,
port->dst_connection_idx, gport->in);
- ret = msm_ep_config(gport->in);
+ ret = msm_ep_config(gport->in, port->tx_req);
if (ret) {
pr_err("msm_ep_config() failed for IN EP\n");
spin_unlock_irqrestore(&port->port_lock, flags);
@@ -730,7 +729,7 @@
* initiate USB BAM IPA connection. This API is enabling accelerated endpoints
* and schedule connect_work() which establishes USB IPA BAM communication.
*/
-int ipa_data_connect(struct gadget_ipa_port *gp, enum ipa_func_type func,
+int ipa_data_connect(struct data_port *gp, enum ipa_func_type func,
u8 src_connection_idx, u8 dst_connection_idx)
{
struct ipa_data_ch_info *port;
@@ -939,7 +938,7 @@
* It is being used to initiate USB BAM IPA suspend functionality
* for USB bus suspend functionality.
*/
-void ipa_data_suspend(struct gadget_ipa_port *gp, enum ipa_func_type func,
+void ipa_data_suspend(struct data_port *gp, enum ipa_func_type func,
bool remote_wakeup_enabled)
{
struct ipa_data_ch_info *port;
@@ -1050,7 +1049,7 @@
* It is being used to initiate USB resume functionality
* for USB bus resume case.
*/
-void ipa_data_resume(struct gadget_ipa_port *gp, enum ipa_func_type func,
+void ipa_data_resume(struct data_port *gp, enum ipa_func_type func,
bool remote_wakeup_enabled)
{
struct ipa_data_ch_info *port;
diff --git a/drivers/usb/gadget/function/u_data_ipa.h b/drivers/usb/gadget/function/u_data_ipa.h
index 70d4293..d2d419b 100644
--- a/drivers/usb/gadget/function/u_data_ipa.h
+++ b/drivers/usb/gadget/function/u_data_ipa.h
@@ -34,19 +34,6 @@
/* Max Number of IPA data ports supported */
#define IPA_N_PORTS USB_IPA_NUM_FUNCS
-struct gadget_ipa_port {
- struct usb_composite_dev *cdev;
- struct usb_function *func;
- int rx_buffer_size;
- struct usb_ep *in;
- struct usb_ep *out;
- int ipa_consumer_ep;
- int ipa_producer_ep;
- const struct usb_endpoint_descriptor *in_ep_desc_backup;
- const struct usb_endpoint_descriptor *out_ep_desc_backup;
-
-};
-
struct ipa_function_bind_info {
struct usb_string *string_defs;
int data_str_idx;
@@ -85,16 +72,16 @@
};
void ipa_data_port_select(enum ipa_func_type func);
-void ipa_data_disconnect(struct gadget_ipa_port *gp, enum ipa_func_type func);
-int ipa_data_connect(struct gadget_ipa_port *gp, enum ipa_func_type func,
+void ipa_data_disconnect(struct data_port *gp, enum ipa_func_type func);
+int ipa_data_connect(struct data_port *gp, enum ipa_func_type func,
u8 src_connection_idx, u8 dst_connection_idx);
int ipa_data_setup(enum ipa_func_type func);
void ipa_data_free(enum ipa_func_type func);
void ipa_data_flush_workqueue(void);
-void ipa_data_resume(struct gadget_ipa_port *gp, enum ipa_func_type func,
+void ipa_data_resume(struct data_port *gp, enum ipa_func_type func,
bool remote_wakeup_enabled);
-void ipa_data_suspend(struct gadget_ipa_port *gp, enum ipa_func_type func,
+void ipa_data_suspend(struct data_port *gp, enum ipa_func_type func,
bool remote_wakeup_enabled);
void ipa_data_set_ul_max_xfer_size(u32 ul_max_xfer_size);
@@ -109,11 +96,34 @@
void ipa_data_stop_rndis_ipa(enum ipa_func_type func);
+#ifdef CONFIG_USB_F_QCRNDIS
void *rndis_qc_get_ipa_priv(void);
void *rndis_qc_get_ipa_rx_cb(void);
bool rndis_qc_get_skip_ep_config(void);
void *rndis_qc_get_ipa_tx_cb(void);
void rndis_ipa_reset_trigger(void);
+#else
+static inline void *rndis_qc_get_ipa_priv(void)
+{
+ return NULL;
+}
+static inline void *rndis_qc_get_ipa_rx_cb(void)
+{
+ return NULL;
+}
+static inline bool rndis_qc_get_skip_ep_config(void)
+{
+ return true;
+}
+static inline void *rndis_qc_get_ipa_tx_cb(void)
+{
+ return NULL;
+}
+static inline void rndis_ipa_reset_trigger(void)
+{
+}
+#endif /* CONFIG_USB_F_QCRNDIS */
+
#if IS_ENABLED(CONFIG_USB_CONFIGFS_RMNET_BAM)
void gqti_ctrl_update_ipa_pipes(void *gr, enum qti_port_type qport,
u32 ipa_prod, u32 ipa_cons);
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index d50510f..9e38809 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -23,6 +23,8 @@
#include <linux/if_vlan.h>
#include <linux/if_arp.h>
#include <linux/msm_rmnet.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include "u_ether.h"
@@ -57,6 +59,9 @@
static struct workqueue_struct *uether_wq;
+/* Extra buffer size to allocate for tx */
+#define EXTRA_ALLOCATION_SIZE_U_ETH 128
+
struct eth_dev {
/* lock is held while accessing port_usb
*/
@@ -70,7 +75,7 @@
struct list_head tx_reqs, rx_reqs;
unsigned tx_qlen;
/* Minimum number of TX USB request queued to UDC */
-#define TX_REQ_THRESHOLD 5
+#define MAX_TX_REQ_WITH_NO_INT 5
int no_tx_req_used;
int tx_skb_hold_count;
u32 tx_req_bufsize;
@@ -99,14 +104,35 @@
bool no_skb_reserve;
u8 host_mac[ETH_ALEN];
u8 dev_mac[ETH_ALEN];
+ unsigned long tx_throttle;
+ unsigned long rx_throttle;
+ unsigned int tx_pkts_rcvd;
+ unsigned long skb_expand_cnt;
+ struct dentry *uether_dent;
+ struct dentry *uether_dfile;
};
+static void uether_debugfs_init(struct eth_dev *dev);
+static void uether_debugfs_exit(struct eth_dev *dev);
+
/*-------------------------------------------------------------------------*/
#define RX_EXTRA 20 /* bytes guarding against rx overflows */
#define DEFAULT_QLEN 2 /* double buffering by default */
+/*
+ * Usually downlink rates are higher than uplink rates and it
+ * deserve higher number of requests. For CAT-6 data rates of
+ * 300Mbps (~30 packets per milli-sec) 40 usb request may not
+ * be sufficient. At this rate and with interrupt moderation
+ * of interconnect, data can be very bursty. tx_qmult is the
+ * additional multipler on qmult.
+ */
+static unsigned int tx_qmult = 2;
+module_param(tx_qmult, uint, 0644);
+MODULE_PARM_DESC(tx_qmult, "Additional queue length multiplier for tx");
+
/* for dual-speed hardware, use deeper queues at high/super speed */
static inline int qlen(struct usb_gadget *gadget, unsigned qmult)
{
@@ -118,6 +144,10 @@
}
/*-------------------------------------------------------------------------*/
+#define U_ETHER_RX_PENDING_TSHOLD 500
+
+static unsigned int u_ether_rx_pending_thld = U_ETHER_RX_PENDING_TSHOLD;
+module_param(u_ether_rx_pending_thld, uint, 0644);
/* REVISIT there must be a better way than having two sets
* of debug calls ...
@@ -231,11 +261,11 @@
out = dev->port_usb->out_ep;
else
out = NULL;
- spin_unlock_irqrestore(&dev->lock, flags);
- if (!out)
+ if (!out) {
+ spin_unlock_irqrestore(&dev->lock, flags);
return -ENOTCONN;
-
+ }
/* Padding up to RX_EXTRA handles minor disagreements with host.
* Normally we use the USB "terminate on short read" convention;
@@ -259,9 +289,10 @@
if (dev->port_usb->is_fixed)
size = max_t(size_t, size, dev->port_usb->fixed_out_len);
+ spin_unlock_irqrestore(&dev->lock, flags);
DBG(dev, "%s: size: %zd\n", __func__, size);
- skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
+ skb = alloc_skb(size, gfp_flags);
if (skb == NULL) {
DBG(dev, "no rx skb\n");
goto enomem;
@@ -272,7 +303,7 @@
* RNDIS headers involve variable numbers of LE32 values.
*/
if (likely(!dev->no_skb_reserve))
- skb_reserve(skb, NET_IP_ALIGN);
+ skb_reserve(skb, 0);
req->buf = skb->data;
req->length = size;
@@ -356,9 +387,20 @@
}
clean:
- spin_lock(&dev->req_lock);
- list_add(&req->list, &dev->rx_reqs);
- spin_unlock(&dev->req_lock);
+ if (queue && dev->rx_frames.qlen <= u_ether_rx_pending_thld) {
+ if (rx_submit(dev, req, GFP_ATOMIC) < 0) {
+ spin_lock(&dev->req_lock);
+ list_add(&req->list, &dev->rx_reqs);
+ spin_unlock(&dev->req_lock);
+ }
+ } else {
+ /* rx buffers draining is delayed,defer further queuing to wq */
+ if (queue)
+ dev->rx_throttle++;
+ spin_lock(&dev->req_lock);
+ list_add(&req->list, &dev->rx_reqs);
+ spin_unlock(&dev->req_lock);
+ }
if (queue)
queue_work(uether_wq, &dev->rx_work);
@@ -409,7 +451,7 @@
spin_lock(&dev->req_lock);
if (link->in_ep) {
- status = prealloc(&dev->tx_reqs, link->in_ep, n);
+ status = prealloc(&dev->tx_reqs, link->in_ep, n * tx_qmult);
if (status < 0)
goto fail;
}
@@ -458,6 +500,31 @@
spin_unlock_irqrestore(&dev->req_lock, flags);
}
+static __be16 ether_ip_type_trans(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ __be16 protocol = 0;
+
+ skb->dev = dev;
+
+ switch (skb->data[0] & 0xf0) {
+ case 0x40:
+ protocol = htons(ETH_P_IP);
+ break;
+ case 0x60:
+ protocol = htons(ETH_P_IPV6);
+ break;
+ default:
+ if ((skb->data[0] & 0x40) == 0x00)
+ protocol = htons(ETH_P_MAP);
+ else
+ pr_debug_ratelimited("[%s] L3 protocol decode error: 0x%02x",
+ dev->name, skb->data[0] & 0xf0);
+ }
+
+ return protocol;
+}
+
static void process_rx_w(struct work_struct *work)
{
struct eth_dev *dev = container_of(work, struct eth_dev, rx_work);
@@ -477,7 +544,12 @@
dev_kfree_skb_any(skb);
continue;
}
- skb->protocol = eth_type_trans(skb, dev->net);
+
+ if (test_bit(RMNET_MODE_LLP_IP, &dev->flags))
+ skb->protocol = ether_ip_type_trans(skb, dev->net);
+ else
+ skb->protocol = eth_type_trans(skb, dev->net);
+
dev->net->stats.rx_packets++;
dev->net->stats.rx_bytes += skb->len;
@@ -511,6 +583,11 @@
int length;
int retval;
+ if (!dev->port_usb) {
+ usb_ep_free_request(ep, req);
+ return;
+ }
+
switch (req->status) {
default:
dev->net->stats.tx_errors++;
@@ -521,21 +598,21 @@
break;
case 0:
if (!req->zero)
- dev->net->stats.tx_bytes += req->length-1;
+ dev->net->stats.tx_bytes += req->actual-1;
else
- dev->net->stats.tx_bytes += req->length;
+ dev->net->stats.tx_bytes += req->actual;
}
dev->net->stats.tx_packets++;
spin_lock(&dev->req_lock);
- list_add_tail(&req->list, &dev->tx_reqs);
- if (dev->port_usb->multi_pkt_xfer) {
+ if (dev->port_usb->multi_pkt_xfer && !req->context) {
dev->no_tx_req_used--;
req->length = 0;
in = dev->port_usb->in_ep;
- if (!list_empty(&dev->tx_reqs)) {
+ /* Do not process further if no_interrupt is set */
+ if (!req->no_interrupt && !list_empty(&dev->tx_reqs)) {
new_req = container_of(dev->tx_reqs.next,
struct usb_request, list);
list_del(&new_req->list);
@@ -563,11 +640,27 @@
length++;
}
+ /* set when tx completion interrupt needed */
+ spin_lock(&dev->req_lock);
+ dev->tx_qlen++;
+ if (dev->tx_qlen == MAX_TX_REQ_WITH_NO_INT) {
+ new_req->no_interrupt = 0;
+ dev->tx_qlen = 0;
+ } else {
+ new_req->no_interrupt = 1;
+ }
+ spin_unlock(&dev->req_lock);
new_req->length = length;
+ new_req->complete = tx_complete;
retval = usb_ep_queue(in, new_req, GFP_ATOMIC);
switch (retval) {
default:
DBG(dev, "tx queue err %d\n", retval);
+ new_req->length = 0;
+ spin_lock(&dev->req_lock);
+ list_add_tail(&new_req->list,
+ &dev->tx_reqs);
+ spin_unlock(&dev->req_lock);
break;
case 0:
spin_lock(&dev->req_lock);
@@ -577,17 +670,37 @@
}
} else {
spin_lock(&dev->req_lock);
- list_add(&new_req->list, &dev->tx_reqs);
+ /*
+ * Put the idle request at the back of the
+ * queue. The xmit function will put the
+ * unfinished request at the beginning of the
+ * queue.
+ */
+ list_add_tail(&new_req->list, &dev->tx_reqs);
spin_unlock(&dev->req_lock);
}
} else {
spin_unlock(&dev->req_lock);
}
} else {
+ /* Is aggregation already enabled and buffers allocated ? */
+ if (dev->port_usb->multi_pkt_xfer && dev->tx_req_bufsize) {
+ req->buf = kzalloc(dev->tx_req_bufsize
+ + dev->gadget->extra_buf_alloc, GFP_ATOMIC);
+ req->context = NULL;
+ } else {
+ req->buf = NULL;
+ }
+
spin_unlock(&dev->req_lock);
dev_kfree_skb_any(skb);
}
+ /* put the completed req back to tx_reqs tail pool */
+ spin_lock(&dev->req_lock);
+ list_add_tail(&req->list, &dev->tx_reqs);
+ spin_unlock(&dev->req_lock);
+
if (netif_carrier_ok(dev->net))
netif_wake_queue(dev->net);
}
@@ -597,7 +710,7 @@
return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
}
-static void alloc_tx_buffer(struct eth_dev *dev)
+static int alloc_tx_buffer(struct eth_dev *dev)
{
struct list_head *act;
struct usb_request *req;
@@ -612,9 +725,26 @@
list_for_each(act, &dev->tx_reqs) {
req = container_of(act, struct usb_request, list);
if (!req->buf)
- req->buf = kmalloc(dev->tx_req_bufsize,
- GFP_ATOMIC);
+ req->buf = kmalloc(dev->tx_req_bufsize
+ + dev->gadget->extra_buf_alloc, GFP_ATOMIC);
+
+ if (!req->buf)
+ goto free_buf;
+
+ /* req->context is not used for multi_pkt_xfers */
+ req->context = NULL;
}
+ return 0;
+
+free_buf:
+ /* tx_req_bufsize = 0 retries mem alloc on next eth_start_xmit */
+ dev->tx_req_bufsize = 0;
+ list_for_each(act, &dev->tx_reqs) {
+ req = container_of(act, struct usb_request, list);
+ kfree(req->buf);
+ req->buf = NULL;
+ }
+ return -ENOMEM;
}
static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
@@ -622,19 +752,25 @@
{
struct eth_dev *dev = netdev_priv(net);
int length = 0;
+ int tail_room = 0;
+ int extra_alloc = 0;
int retval;
struct usb_request *req = NULL;
+ struct sk_buff *new_skb;
unsigned long flags;
- struct usb_ep *in;
- u16 cdc_filter;
+ struct usb_ep *in = NULL;
+ u16 cdc_filter = 0;
+ bool multi_pkt_xfer = false;
+ u32 fixed_in_len = 0;
+ bool is_fixed = false;
spin_lock_irqsave(&dev->lock, flags);
if (dev->port_usb) {
in = dev->port_usb->in_ep;
cdc_filter = dev->port_usb->cdc_filter;
- } else {
- in = NULL;
- cdc_filter = 0;
+ is_fixed = dev->port_usb->is_fixed;
+ fixed_in_len = dev->port_usb->fixed_in_len;
+ multi_pkt_xfer = dev->port_usb->multi_pkt_xfer;
}
spin_unlock_irqrestore(&dev->lock, flags);
@@ -643,12 +779,9 @@
return NETDEV_TX_OK;
}
- /* Allocate memory for tx_reqs to support multi packet transfer */
- if (dev->port_usb->multi_pkt_xfer && !dev->tx_req_bufsize)
- alloc_tx_buffer(dev);
-
/* apply outgoing CDC or RNDIS filters */
- if (skb && !is_promisc(cdc_filter)) {
+ if (!test_bit(RMNET_MODE_LLP_IP, &dev->flags) &&
+ !is_promisc(cdc_filter)) {
u8 *dest = skb->data;
if (is_multicast_ether_addr(dest)) {
@@ -662,6 +795,7 @@
else
type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
if (!(cdc_filter & type)) {
+ dev->net->stats.tx_dropped++;
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -669,7 +803,41 @@
/* ignores USB_CDC_PACKET_TYPE_DIRECTED */
}
+ dev->tx_pkts_rcvd++;
+ /*
+ * no buffer copies needed, unless the network stack did it
+ * or the hardware can't use skb buffers.
+ * or there's not enough space for extra headers we need
+ */
+ spin_lock_irqsave(&dev->lock, flags);
+ if (dev->wrap && dev->port_usb)
+ skb = dev->wrap(dev->port_usb, skb);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ if (!skb) {
+ if (dev->port_usb && dev->port_usb->supports_multi_frame) {
+ /*
+ * Multi frame CDC protocols may store the frame for
+ * later which is not a dropped frame.
+ */
+ } else {
+ dev->net->stats.tx_dropped++;
+ }
+
+ /* no error code for dropped packets */
+ return NETDEV_TX_OK;
+ }
+
+ /* Allocate memory for tx_reqs to support multi packet transfer */
spin_lock_irqsave(&dev->req_lock, flags);
+ if (multi_pkt_xfer && !dev->tx_req_bufsize) {
+ retval = alloc_tx_buffer(dev);
+ if (retval < 0) {
+ spin_unlock_irqrestore(&dev->req_lock, flags);
+ return -ENOMEM;
+ }
+ }
+
/*
* this freelist can be empty if an interrupt triggered disconnect()
* and reconfigured the gadget (shutting down this queue) after the
@@ -684,37 +852,20 @@
list_del(&req->list);
/* temporarily stop TX queue when the freelist empties */
- if (list_empty(&dev->tx_reqs))
+ if (list_empty(&dev->tx_reqs)) {
+ /*
+ * tx_throttle gives info about number of times u_ether
+ * asked network layer to stop queueing packets to it
+ * when transmit resources are unavailable
+ */
+ dev->tx_throttle++;
netif_stop_queue(net);
- spin_unlock_irqrestore(&dev->req_lock, flags);
-
- /* no buffer copies needed, unless the network stack did it
- * or the hardware can't use skb buffers.
- * or there's not enough space for extra headers we need
- */
- if (dev->wrap) {
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
- if (dev->port_usb)
- skb = dev->wrap(dev->port_usb, skb);
- spin_unlock_irqrestore(&dev->lock, flags);
- if (!skb) {
- /* Multi frame CDC protocols may store the frame for
- * later which is not a dropped frame.
- */
- if (dev->port_usb &&
- dev->port_usb->supports_multi_frame)
- goto multiframe;
- goto drop;
- }
}
- spin_lock_irqsave(&dev->req_lock, flags);
dev->tx_skb_hold_count++;
spin_unlock_irqrestore(&dev->req_lock, flags);
- if (dev->port_usb->multi_pkt_xfer) {
+ if (multi_pkt_xfer) {
memcpy(req->buf + req->length, skb->data, skb->len);
req->length = req->length + skb->len;
length = req->length;
@@ -722,7 +873,13 @@
spin_lock_irqsave(&dev->req_lock, flags);
if (dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer) {
- if (dev->no_tx_req_used > TX_REQ_THRESHOLD) {
+ /*
+ * should allow aggregation only, if the number of
+ * requests queued more than the tx requests that can
+ * be queued with no interrupt flag set sequentially.
+ * Otherwise, packets may be blocked forever.
+ */
+ if (dev->no_tx_req_used > MAX_TX_REQ_WITH_NO_INT) {
list_add(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->req_lock, flags);
goto success;
@@ -736,6 +893,35 @@
dev->tx_skb_hold_count = 0;
spin_unlock_irqrestore(&dev->lock, flags);
} else {
+ bool do_align = false;
+
+ /* Check if TX buffer should be aligned before queuing to hw */
+ if (dev->gadget->is_chipidea &&
+ !IS_ALIGNED((size_t)skb->data, 4))
+ do_align = true;
+
+ /*
+ * Some UDC requires allocation of some extra bytes for
+ * TX buffer due to hardware requirement. Check if extra
+ * bytes are already there, otherwise allocate new buffer
+ * with extra bytes and do memcpy to align skb as well.
+ */
+ if (dev->gadget->extra_buf_alloc)
+ extra_alloc = EXTRA_ALLOCATION_SIZE_U_ETH;
+ tail_room = skb_tailroom(skb);
+ if (do_align || tail_room < extra_alloc) {
+ pr_debug("%s:align skb and update tail_room %d to %d\n",
+ __func__, tail_room, extra_alloc);
+ tail_room = extra_alloc;
+ new_skb = skb_copy_expand(skb, 0, tail_room,
+ GFP_ATOMIC);
+ if (!new_skb)
+ return -ENOMEM;
+ dev_kfree_skb_any(skb);
+ skb = new_skb;
+ dev->skb_expand_cnt++;
+ }
+
length = skb->len;
req->buf = skb->data;
req->context = skb;
@@ -744,9 +930,7 @@
req->complete = tx_complete;
/* NCM requires no zlp if transfer is dwNtbInMaxSize */
- if (dev->port_usb &&
- dev->port_usb->is_fixed &&
- length == dev->port_usb->fixed_in_len &&
+ if (is_fixed && length == fixed_in_len &&
(length % in->maxpacket) == 0)
req->zero = 0;
else
@@ -766,13 +950,15 @@
/* throttle highspeed IRQ rate back slightly */
if (gadget_is_dualspeed(dev->gadget) &&
(dev->gadget->speed == USB_SPEED_HIGH)) {
+ spin_lock_irqsave(&dev->req_lock, flags);
dev->tx_qlen++;
- if (dev->tx_qlen == (dev->qmult/2)) {
+ if (dev->tx_qlen == MAX_TX_REQ_WITH_NO_INT) {
req->no_interrupt = 0;
dev->tx_qlen = 0;
} else {
req->no_interrupt = 1;
}
+ spin_unlock_irqrestore(&dev->req_lock, flags);
} else {
req->no_interrupt = 0;
}
@@ -787,11 +973,11 @@
}
if (retval) {
- if (!dev->port_usb->multi_pkt_xfer)
+ if (!multi_pkt_xfer)
dev_kfree_skb_any(skb);
-drop:
+ else
+ req->length = 0;
dev->net->stats.tx_dropped++;
-multiframe:
spin_lock_irqsave(&dev->req_lock, flags);
if (list_empty(&dev->tx_reqs))
netif_start_queue(net);
@@ -1174,6 +1360,7 @@
* - tx queueing enabled if open *and* carrier is "on"
*/
netif_carrier_off(net);
+ uether_debugfs_init(dev);
}
return dev;
@@ -1375,8 +1562,10 @@
if (!dev)
return;
+ uether_debugfs_exit(dev);
unregister_netdev(dev->net);
flush_work(&dev->work);
+ cancel_work_sync(&dev->rx_work);
free_netdev(dev->net);
}
EXPORT_SYMBOL_GPL(gether_cleanup);
@@ -1514,8 +1703,10 @@
list_del(&req->list);
spin_unlock(&dev->req_lock);
- if (link->multi_pkt_xfer)
+ if (link->multi_pkt_xfer) {
kfree(req->buf);
+ req->buf = NULL;
+ }
usb_ep_free_request(link->in_ep, req);
spin_lock(&dev->req_lock);
}
@@ -1545,6 +1736,12 @@
link->out_ep->desc = NULL;
}
+ pr_debug("%s(): tx_throttle count= %lu", __func__,
+ dev->tx_throttle);
+ /* reset tx_throttle count */
+ dev->tx_throttle = 0;
+ dev->rx_throttle = 0;
+
/* finish forgetting about this USB link episode */
dev->header_len = 0;
dev->unwrap = NULL;
@@ -1556,6 +1753,73 @@
}
EXPORT_SYMBOL_GPL(gether_disconnect);
+static int uether_stat_show(struct seq_file *s, void *unused)
+{
+ struct eth_dev *dev = s->private;
+ int ret = 0;
+
+ if (dev) {
+ seq_printf(s, "tx_throttle = %lu\n", dev->tx_throttle);
+ seq_printf(s, "tx_pkts_rcvd=%u\n", dev->tx_pkts_rcvd);
+ seq_printf(s, "rx_throttle = %lu\n", dev->rx_throttle);
+ seq_printf(s, "skb_expand_cnt = %lu\n",
+ dev->skb_expand_cnt);
+ }
+ return ret;
+}
+
+static int uether_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, uether_stat_show, inode->i_private);
+}
+
+static ssize_t uether_stat_reset(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ struct seq_file *s = file->private_data;
+ struct eth_dev *dev = s->private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ /* Reset tx_throttle */
+ dev->tx_throttle = 0;
+ dev->rx_throttle = 0;
+ dev->skb_expand_cnt = 0;
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return count;
+}
+
+static const struct file_operations uether_stats_ops = {
+ .open = uether_open,
+ .read = seq_read,
+ .write = uether_stat_reset,
+};
+
+static void uether_debugfs_init(struct eth_dev *dev)
+{
+ struct dentry *uether_dent;
+ struct dentry *uether_dfile;
+
+ uether_dent = debugfs_create_dir("uether_rndis", NULL);
+ if (IS_ERR(uether_dent))
+ return;
+ dev->uether_dent = uether_dent;
+
+ uether_dfile = debugfs_create_file("status", 0644,
+ uether_dent, dev, &uether_stats_ops);
+ if (!uether_dfile || IS_ERR(uether_dfile))
+ debugfs_remove(uether_dent);
+ dev->uether_dfile = uether_dfile;
+}
+
+static void uether_debugfs_exit(struct eth_dev *dev)
+{
+ debugfs_remove(dev->uether_dfile);
+ debugfs_remove(dev->uether_dent);
+ dev->uether_dent = NULL;
+ dev->uether_dfile = NULL;
+}
+
static int __init gether_init(void)
{
uether_wq = create_singlethread_workqueue("uether");
diff --git a/drivers/usb/gadget/function/u_qdss.c b/drivers/usb/gadget/function/u_qdss.c
index b4353ac..d445e51 100644
--- a/drivers/usb/gadget/function/u_qdss.c
+++ b/drivers/usb/gadget/function/u_qdss.c
@@ -131,11 +131,12 @@
static int init_data(struct usb_ep *ep)
{
+ struct f_qdss *qdss = ep->driver_data;
int res = 0;
pr_debug("init_data\n");
- res = msm_ep_config(ep);
+ res = msm_ep_config(ep, qdss->endless_req);
if (res)
pr_err("msm_ep_config failed\n");
diff --git a/drivers/usb/gadget/function/u_rmnet.h b/drivers/usb/gadget/function/u_rmnet.h
index 0126932..f639722 100644
--- a/drivers/usb/gadget/function/u_rmnet.h
+++ b/drivers/usb/gadget/function/u_rmnet.h
@@ -20,12 +20,32 @@
#include "f_qdss.h"
+enum bam_dmux_func_type {
+ BAM_DMUX_FUNC_RMNET,
+ BAM_DMUX_FUNC_MBIM,
+ BAM_DMUX_FUNC_DPL,
+ BAM_DMUX_NUM_FUNCS,
+};
+
struct rmnet_ctrl_pkt {
void *buf;
int len;
struct list_head list;
};
+struct data_port {
+ struct usb_composite_dev *cdev;
+ struct usb_function *func;
+ int rx_buffer_size;
+ struct usb_ep *in;
+ struct usb_ep *out;
+ int ipa_consumer_ep;
+ int ipa_producer_ep;
+ const struct usb_endpoint_descriptor *in_ep_desc_backup;
+ const struct usb_endpoint_descriptor *out_ep_desc_backup;
+
+};
+
struct grmnet {
/* to usb host, aka laptop, windows pc etc. Will
* be filled by usb driver of rmnet functionality
@@ -49,7 +69,23 @@
NR_CTRL_CLIENTS
};
-int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned int intf);
+enum data_xport_type {
+ BAM_DMUX,
+ BAM2BAM_IPA,
+ NR_XPORT_TYPES
+};
+
+int gbam_connect(struct data_port *gr, enum bam_dmux_func_type func);
+void gbam_disconnect(struct data_port *gr, enum bam_dmux_func_type func);
+void gbam_cleanup(enum bam_dmux_func_type func);
+int gbam_setup(enum bam_dmux_func_type func);
+int gbam_mbim_connect(struct usb_gadget *g, struct usb_ep *in,
+ struct usb_ep *out);
+void gbam_mbim_disconnect(void);
+int gbam_mbim_setup(void);
+
+int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned int intf,
+ enum data_xport_type dxport);
void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport);
int gqti_ctrl_init(void);
void gqti_ctrl_cleanup(void);
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index e0cd1e4..2ec28c8 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -304,7 +304,8 @@
* usb_request or NULL if there is an error.
*/
struct usb_request *
-gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)
+gs_alloc_req(struct usb_ep *ep, unsigned int len, size_t extra_sz,
+ gfp_t kmalloc_flags)
{
struct usb_request *req;
@@ -312,7 +313,7 @@
if (req != NULL) {
req->length = len;
- req->buf = kmalloc(len, kmalloc_flags);
+ req->buf = kmalloc(len + extra_sz, kmalloc_flags);
if (req->buf == NULL) {
usb_ep_free_request(ep, req);
return NULL;
@@ -654,6 +655,7 @@
}
static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head,
+ size_t extra_sz,
void (*fn)(struct usb_ep *, struct usb_request *),
int *allocated)
{
@@ -666,7 +668,7 @@
* be as speedy as we might otherwise be.
*/
for (i = 0; i < n; i++) {
- req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC);
+ req = gs_alloc_req(ep, ep->maxpacket, extra_sz, GFP_ATOMIC);
if (!req)
return list_empty(head) ? -ENOMEM : 0;
req->complete = fn;
@@ -688,6 +690,8 @@
*/
static int gs_start_io(struct gs_port *port)
{
+ struct usb_function *f = &port->port_usb->func;
+ struct usb_composite_dev *cdev = f->config->cdev;
struct list_head *head = &port->read_pool;
struct usb_ep *ep = port->port_usb->out;
int status;
@@ -699,12 +703,13 @@
* configurations may use different endpoints with a given port;
* and high speed vs full speed changes packet sizes too.
*/
- status = gs_alloc_requests(ep, head, gs_read_complete,
+ status = gs_alloc_requests(ep, head, 0, gs_read_complete,
&port->read_allocated);
if (status)
return status;
status = gs_alloc_requests(port->port_usb->in, &port->write_pool,
+ cdev->gadget->extra_buf_alloc,
gs_write_complete, &port->write_allocated);
if (status) {
gs_free_requests(ep, head, &port->read_allocated);
diff --git a/drivers/usb/gadget/function/u_serial.h b/drivers/usb/gadget/function/u_serial.h
index f367dc5..cc78165 100644
--- a/drivers/usb/gadget/function/u_serial.h
+++ b/drivers/usb/gadget/function/u_serial.h
@@ -65,7 +65,8 @@
};
/* utilities to allocate/free request and buffer */
-struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags);
+struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
+ size_t extra_sz, gfp_t flags);
void gs_free_req(struct usb_ep *, struct usb_request *req);
/* management of individual TTY ports */
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 984b1d7..ae0c12d 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -2221,12 +2221,12 @@
struct uvc_frame_mjpeg mf =
frm->frame.mf;
*size +=
- UVC_DT_FRAME_UNCOMPRESSED_SIZE(mf.bFrameIntervalType);
+ UVC_DT_FRAME_MJPEG_SIZE(mf.bFrameIntervalType);
} else if (frm->fmt_type == UVCG_H264) {
struct uvc_frame_h264 hf =
frm->frame.hf;
*size +=
- UVC_DT_FRAME_UNCOMPRESSED_SIZE(hf.bNumFrameIntervals);
+ UVC_DT_FRAME_H264_SIZE(hf.bNumFrameIntervals);
}
}
break;
@@ -2518,7 +2518,7 @@
.release = uvc_attr_release,
};
-#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit) \
+#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \
static ssize_t f_uvc_opts_##cname##_show( \
struct config_item *item, char *page) \
{ \
@@ -2565,12 +2565,12 @@
#define identity_conv(x) (x)
-UVCG_OPTS_ATTR(streaming_interval, identity_conv, kstrtou8, u8, identity_conv,
- 16);
-UVCG_OPTS_ATTR(streaming_maxpacket, le16_to_cpu, kstrtou16, u16, le16_to_cpu,
- 3072);
-UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv,
- 15);
+UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv,
+ kstrtou8, u8, identity_conv, 16);
+UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu,
+ kstrtou16, u16, le16_to_cpu, 3072);
+UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv,
+ kstrtou8, u8, identity_conv, 15);
#undef identity_conv
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index eb121b2..0e7cc71 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -628,14 +628,6 @@
bool
default y if ARCH_VT8500
-config USB_UHCI_BIG_ENDIAN_MMIO
- bool
- default y if SPARC_LEON
-
-config USB_UHCI_BIG_ENDIAN_DESC
- bool
- default y if SPARC_LEON
-
config USB_FHCI_HCD
tristate "Freescale QE USB Host Controller support"
depends on OF_GPIO && QE_GPIO && QUICC_ENGINE
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 74f62d6..b09392f 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -1267,7 +1267,7 @@
spin_lock_irqsave(&ehci->lock, flags);
/* Put all enabled ports into suspend */
- while (ports--) {
+ while (!ehci->no_testmode_suspend && ports--) {
u32 __iomem *sreg =
&ehci->regs->port_status[ports];
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 2f8d3af..3e36edd 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -1,6 +1,6 @@
/* ehci-msm.c - HSUSB Host Controller Driver Implementation
*
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
*
* Partly derived from ehci-fsl.c and ehci-hcd.c
* Copyright (c) 2000-2004 by David Brownell
@@ -29,11 +29,13 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
+
#include <linux/usb/otg.h>
+#include <linux/usb/msm_hsusb.h>
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
-#include <linux/acpi.h>
#include "ehci.h"
@@ -51,25 +53,32 @@
ehci->caps = USB_CAPLENGTH;
hcd->has_tt = 1;
+ ehci->no_testmode_suspend = true;
retval = ehci_setup(hcd);
if (retval)
return retval;
- /* select ULPI phy and clear other status/control bits in PORTSC */
- writel(PORTSC_PTS_ULPI, USB_PORTSC);
/* bursts of unspecified length. */
- writel(0, USB_AHBBURST);
- /* Use the AHB transactor, allow posted data writes */
- writel(0x8, USB_AHBMODE);
+ writel_relaxed(0, USB_AHBBURST);
+ /* Use the AHB transactor */
+ writel_relaxed(0x08, USB_AHBMODE);
/* Disable streaming mode and select host mode */
- writel(0x13, USB_USBMODE);
- /* Disable ULPI_TX_PKT_EN_CLR_FIX which is valid only for HSIC */
- writel(readl(USB_GENCONFIG_2) & ~ULPI_TX_PKT_EN_CLR_FIX, USB_GENCONFIG_2);
+ writel_relaxed(0x13, USB_USBMODE);
+ if (hcd->usb_phy->flags & ENABLE_SECONDARY_PHY) {
+ ehci_dbg(ehci, "using secondary hsphy\n");
+ writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+ USB_PHY_CTRL2);
+ }
+
+ /* Disable ULPI_TX_PKT_EN_CLR_FIX which is valid only for HSIC */
+ writel_relaxed(readl_relaxed(USB_GENCONFIG_2) & ~(1<<19),
+ USB_GENCONFIG_2);
return 0;
}
+static u64 msm_ehci_dma_mask = DMA_BIT_MASK(32);
static int ehci_msm_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
@@ -79,12 +88,20 @@
dev_dbg(&pdev->dev, "ehci_msm proble\n");
- hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev));
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &msm_ehci_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
if (!hcd) {
dev_err(&pdev->dev, "Unable to create HCD\n");
return -ENOMEM;
}
+ hcd_to_bus(hcd)->skip_resume = true;
+
ret = platform_get_irq(pdev, 0);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to get IRQ resource\n");
@@ -93,61 +110,43 @@
hcd->irq = ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get memory resource\n");
- ret = -ENODEV;
+ hcd->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hcd->regs)) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = PTR_ERR(hcd->regs);
goto put_hcd;
}
-
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
- hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len);
- if (!hcd->regs) {
- dev_err(&pdev->dev, "ioremap failed\n");
- ret = -ENOMEM;
- goto put_hcd;
- }
/*
- * If there is an OTG driver, let it take care of PHY initialization,
- * clock management, powering up VBUS, mapping of registers address
- * space and power management.
+ * OTG driver takes care of PHY initialization, clock management,
+ * powering up VBUS, mapping of registers address space and power
+ * management.
*/
if (pdev->dev.of_node)
phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0);
else
phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
- if (IS_ERR(phy)) {
- if (PTR_ERR(phy) == -EPROBE_DEFER) {
- dev_err(&pdev->dev, "unable to find transceiver\n");
- ret = -EPROBE_DEFER;
- goto put_hcd;
- }
- phy = NULL;
+ if (IS_ERR_OR_NULL(phy)) {
+ dev_err(&pdev->dev, "unable to find transceiver\n");
+ ret = -EPROBE_DEFER;
+ goto put_hcd;
+ }
+
+ ret = otg_set_host(phy->otg, &hcd->self);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register with transceiver\n");
+ goto put_hcd;
}
hcd->usb_phy = phy;
device_init_wakeup(&pdev->dev, 1);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
- if (phy && phy->otg) {
- /*
- * MSM OTG driver takes care of adding the HCD and
- * placing hardware into low power mode via runtime PM.
- */
- ret = otg_set_host(phy->otg, &hcd->self);
- if (ret < 0) {
- dev_err(&pdev->dev, "unable to register with transceiver\n");
- goto put_hcd;
- }
-
- pm_runtime_no_callbacks(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
- } else {
- ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
- if (ret)
- goto put_hcd;
- }
+ msm_bam_set_usb_host_dev(&pdev->dev);
return 0;
@@ -165,10 +164,8 @@
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
- if (hcd->usb_phy && hcd->usb_phy->otg)
- otg_set_host(hcd->usb_phy->otg, NULL);
- else
- usb_remove_hcd(hcd);
+ otg_set_host(hcd->usb_phy->otg, NULL);
+ hcd->usb_phy = NULL;
usb_put_hcd(hcd);
@@ -176,51 +173,34 @@
}
#ifdef CONFIG_PM
-static int ehci_msm_pm_suspend(struct device *dev)
+static int ehci_msm_runtime_suspend(struct device *dev)
{
- struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- bool do_wakeup = device_may_wakeup(dev);
-
- dev_dbg(dev, "ehci-msm PM suspend\n");
-
- /* Only call ehci_suspend if ehci_setup has been done */
- if (ehci->sbrn)
- return ehci_suspend(hcd, do_wakeup);
+ dev_dbg(dev, "ehci runtime suspend\n");
return 0;
}
-static int ehci_msm_pm_resume(struct device *dev)
+static int ehci_msm_runtime_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ u32 portsc;
- dev_dbg(dev, "ehci-msm PM resume\n");
+ dev_dbg(dev, "ehci runtime resume\n");
- /* Only call ehci_resume if ehci_setup has been done */
- if (ehci->sbrn)
- ehci_resume(hcd, false);
+ portsc = readl_relaxed(USB_PORTSC);
+ portsc &= ~PORT_RWC_BITS;
+ portsc |= PORT_RESUME;
+ writel_relaxed(portsc, USB_PORTSC);
return 0;
}
-
-#else
-#define ehci_msm_pm_suspend NULL
-#define ehci_msm_pm_resume NULL
#endif
static const struct dev_pm_ops ehci_msm_dev_pm_ops = {
- .suspend = ehci_msm_pm_suspend,
- .resume = ehci_msm_pm_resume,
+ SET_RUNTIME_PM_OPS(ehci_msm_runtime_suspend, ehci_msm_runtime_resume,
+ NULL)
};
-static const struct acpi_device_id msm_ehci_acpi_ids[] = {
- { "QCOM8040", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(acpi, msm_ehci_acpi_ids);
-
static const struct of_device_id msm_ehci_dt_match[] = {
{ .compatible = "qcom,ehci-host", },
{}
@@ -235,7 +215,6 @@
.name = "msm_hsusb_host",
.pm = &ehci_msm_dev_pm_ops,
.of_match_table = msm_ehci_dt_match,
- .acpi_match_table = ACPI_PTR(msm_ehci_acpi_ids),
},
};
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 3f3b74a..53f21da 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -229,6 +229,7 @@
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
unsigned need_oc_pp_cycle:1; /* MPC834X port power */
+ bool no_testmode_suspend; /* MSM Chipidea HC */
unsigned imx28_write_fix:1; /* For Freescale i.MX28 */
/* required for usb32 quirk */
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 09ae74e..7020b9e 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -334,29 +334,19 @@
&xhci->op_regs->cmd_ring);
/* Section 4.6.1.2 of xHCI 1.0 spec says software should
- * time the completion od all xHCI commands, including
+ * time the completion of all xHCI commands, including
* the Command Abort operation. If software doesn't see
- * CRR negated in a timely manner (e.g. longer than 5
- * seconds), then it should assume that the there are
- * larger problems with the xHC and assert HCRST.
+ * CRR negated in a timely manner, then it should assume
+ * that the there are larger problems with the xHC and assert HCRST.
*/
- ret = xhci_handshake(&xhci->op_regs->cmd_ring,
- CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
+ ret = xhci_handshake_check_state(xhci, &xhci->op_regs->cmd_ring,
+ CMD_RING_RUNNING, 0, 1000 * 1000);
if (ret < 0) {
- /* we are about to kill xhci, give it one more chance */
- xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
- &xhci->op_regs->cmd_ring);
- udelay(1000);
- ret = xhci_handshake(&xhci->op_regs->cmd_ring,
- CMD_RING_RUNNING, 0, 3 * 1000 * 1000);
- if (ret < 0) {
- xhci_err(xhci, "Stopped the command ring failed, "
- "maybe the host is dead\n");
- xhci->xhc_state |= XHCI_STATE_DYING;
- xhci_quiesce(xhci);
- xhci_halt(xhci);
- return -ESHUTDOWN;
- }
+ xhci_err(xhci,
+ "Stop command ring failed, maybe the host is dead\n");
+ xhci->xhc_state |= XHCI_STATE_DYING;
+ xhci_halt(xhci);
+ return -ESHUTDOWN;
}
/*
* Writing the CMD_RING_ABORT bit should cause a cmd completion event,
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index ac704d4..84ace86 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -78,6 +78,25 @@
return -ETIMEDOUT;
}
+int xhci_handshake_check_state(struct xhci_hcd *xhci,
+ void __iomem *ptr, u32 mask, u32 done, int usec)
+{
+ u32 result;
+
+ do {
+ result = readl_relaxed(ptr);
+ if (result == ~(u32)0 ||
+ xhci->xhc_state == XHCI_STATE_REMOVING) /* card removed */
+ return -ENODEV;
+ result &= mask;
+ if (result == done)
+ return 0;
+ udelay(1);
+ usec--;
+ } while (usec > 0);
+ return -ETIMEDOUT;
+}
+
/*
* Disable interrupts and begin the xHCI halting process.
*/
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index c11eab1..4c1f556 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1864,6 +1864,8 @@
/* xHCI host controller glue */
typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec);
+int xhci_handshake_check_state(struct xhci_hcd *xhci,
+ void __iomem *ptr, u32 mask, u32 done, int usec);
void xhci_quiesce(struct xhci_hcd *xhci);
int xhci_halt(struct xhci_hcd *xhci);
int xhci_reset(struct xhci_hcd *xhci);
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index e59334b..57e038d 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -348,7 +348,7 @@
rp->r.rnf_error = mon_text_error;
rp->r.rnf_complete = mon_text_complete;
- snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp);
+ snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%pK", rp);
rp->e_slab = kmem_cache_create(rp->slab_name,
sizeof(struct mon_event_text), sizeof(long), 0,
mon_text_ctor);
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index aac28d9..2d9a806 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -2043,6 +2043,7 @@
struct list_head node;
};
+#ifdef CONFIG_PM
/*
* Called from musb_runtime_resume(), musb_resume(), and
* musb_queue_resume_work(). Callers must take musb->lock.
@@ -2070,6 +2071,7 @@
return error;
}
+#endif
/*
* Called to run work if device is active or else queue the work to happen
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 4e223f5..3179b5c 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -155,6 +155,7 @@
depends on (USB || USB_GADGET) && (ARCH_QCOM || COMPILE_TEST)
depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
depends on RESET_CONTROLLER
+ depends on REGULATOR
depends on EXTCON
select USB_PHY
help
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index ad4c0a3..e28173b 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -71,6 +71,7 @@
#define SQ_CTRL1_CHIRP_DISABLE 0x20
#define SQ_CTRL2_CHIRP_DISABLE 0x80
+#define PORT_TUNE1_OVERRIDE_VAL 0xc5
#define DEBUG_CTRL1_OVERRIDE_VAL 0x09
/* PERIPH_SS_PHY_REFGEN_NORTH_BG_CTRL register bits */
@@ -151,6 +152,7 @@
struct hrtimer timer;
int soc_min_rev;
+ bool host_chirp_erratum;
};
#ifdef CONFIG_NVMEM
@@ -198,6 +200,9 @@
/* Reads the SoC version */
static int qusb_phy_get_socrev(struct device *dev, struct qusb_phy *qphy)
{
+ if (!qphy->host_chirp_erratum)
+ return 0;
+
qphy->soc_min_rev = qfprom_read(dev, "minor_rev");
if (qphy->soc_min_rev < 0)
dev_err(dev, "failed getting soc_min_rev, err : %d\n",
@@ -471,10 +476,24 @@
dev_dbg(phy->dev, "%s\n", __func__);
- qusb_phy_reset(qphy);
qusb_phy_write_seq(qphy->base, qphy->qusb_phy_host_init_seq,
qphy->host_init_seq_len, 0);
+ /* If soc revision is mentioned and host_chirp_erratum flag is set
+ * then override TUNE1 and DEBUG_CTRL1
+ */
+ if (qphy->soc_min_rev && qphy->host_chirp_erratum) {
+ writel_relaxed(PORT_TUNE1_OVERRIDE_VAL,
+ qphy->base + qphy->phy_reg[PORT_TUNE1]);
+ writel_relaxed(DEBUG_CTRL1_OVERRIDE_VAL,
+ qphy->base + qphy->phy_reg[DEBUG_CTRL1]);
+ }
+
+ if (qphy->refgen_north_bg_reg)
+ if (readl_relaxed(qphy->refgen_north_bg_reg) & BANDGAP_BYPASS)
+ writel_relaxed(BIAS_CTRL_2_OVERRIDE_VAL,
+ qphy->base + qphy->phy_reg[BIAS_CTRL_2]);
+
/* Ensure above write is completed before turning ON ref clk */
wmb();
@@ -504,6 +523,12 @@
qusb_phy_enable_clocks(qphy, true);
qusb_phy_reset(qphy);
+
+ if (qphy->qusb_phy_host_init_seq && qphy->phy.flags & PHY_HOST_MODE) {
+ qusb_phy_host_init(phy);
+ return 0;
+ }
+
if (qphy->emulation) {
if (qphy->emu_init_seq)
qusb_phy_write_seq(qphy->emu_phy_base + 0x8000,
@@ -560,11 +585,6 @@
writel_relaxed(BIAS_CTRL_2_OVERRIDE_VAL,
qphy->base + qphy->phy_reg[BIAS_CTRL_2]);
- /* if soc revision is mentioned override DEBUG_CTRL1 value */
- if (qphy->soc_min_rev)
- writel_relaxed(DEBUG_CTRL1_OVERRIDE_VAL,
- qphy->base + qphy->phy_reg[DEBUG_CTRL1]);
-
/* ensure above writes are completed before re-enabling PHY */
wmb();
@@ -754,9 +774,6 @@
qphy->cable_connected = true;
- if (qphy->qusb_phy_host_init_seq && qphy->phy.flags & PHY_HOST_MODE)
- qusb_phy_host_init(phy);
-
dev_dbg(phy->dev, "QUSB PHY: connect notification cable_connected=%d\n",
qphy->cable_connected);
return 0;
@@ -1170,6 +1187,9 @@
return -ENOMEM;
}
+ qphy->host_chirp_erratum = of_property_read_bool(dev->of_node,
+ "qcom,host-chirp-erratum");
+
ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level",
(u32 *) qphy->vdd_levels,
ARRAY_SIZE(qphy->vdd_levels));
diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c
index 3482c93..a259790 100644
--- a/drivers/usb/phy/phy-msm-snps-hs.c
+++ b/drivers/usb/phy/phy-msm-snps-hs.c
@@ -96,6 +96,9 @@
bool suspended;
bool cable_connected;
+ int *param_override_seq;
+ int param_override_seq_cnt;
+
/* emulation targets specific */
void __iomem *emu_phy_base;
int *emu_init_seq;
@@ -251,6 +254,7 @@
dev_err(phy->phy.dev, "Unable to set LPM of vdda18\n");
disable_vdd:
+ ret = regulator_disable(phy->vdd);
if (ret)
dev_err(phy->phy.dev, "Unable to disable vdd:%d\n",
ret);
@@ -381,6 +385,11 @@
msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1,
VBUSVLDEXT0, VBUSVLDEXT0);
+ /* set parameter ovrride if needed */
+ if (phy->param_override_seq)
+ hsusb_phy_write_seq(phy->base, phy->param_override_seq,
+ phy->param_override_seq_cnt, 0);
+
msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2,
VREGBYPASS, VREGBYPASS);
@@ -576,6 +585,34 @@
}
}
+ phy->param_override_seq_cnt = of_property_count_elems_of_size(
+ dev->of_node,
+ "qcom,param-override-seq",
+ sizeof(*phy->param_override_seq));
+ if (phy->param_override_seq_cnt > 0) {
+ phy->param_override_seq = devm_kcalloc(dev,
+ phy->param_override_seq_cnt,
+ sizeof(*phy->param_override_seq),
+ GFP_KERNEL);
+ if (!phy->param_override_seq)
+ return -ENOMEM;
+
+ if (phy->param_override_seq_cnt % 2) {
+ dev_err(dev, "invalid param_override_seq_len\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_array(dev->of_node,
+ "qcom,param-override-seq",
+ phy->param_override_seq,
+ phy->param_override_seq_cnt);
+ if (ret) {
+ dev_err(dev, "qcom,param-override-seq read failed %d\n",
+ ret);
+ return ret;
+ }
+ }
+
ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level",
(u32 *) phy->vdd_levels,
ARRAY_SIZE(phy->vdd_levels));
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
index d89714b..d99b582 100644
--- a/drivers/usb/phy/phy-msm-usb.c
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -1861,15 +1861,23 @@
motg->cur_power = mA;
}
-static int msm_otg_set_power(struct usb_phy *phy, unsigned int mA)
+static void msm_otg_notify_chg_current_work(struct work_struct *w)
{
- struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
-
+ struct msm_otg *motg = container_of(w,
+ struct msm_otg, notify_chg_current_work);
/*
* Gadget driver uses set_power method to notify about the
* available current based on suspend/configured states.
*/
- msm_otg_notify_chg_current(motg, mA);
+ msm_otg_notify_chg_current(motg, motg->notify_current_mA);
+}
+
+static int msm_otg_set_power(struct usb_phy *phy, unsigned int mA)
+{
+ struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+
+ motg->notify_current_mA = mA;
+ schedule_work(&motg->notify_chg_current_work);
return 0;
}
@@ -3835,6 +3843,8 @@
INIT_WORK(&motg->sm_work, msm_otg_sm_work);
INIT_DELAYED_WORK(&motg->id_status_work, msm_id_status_w);
INIT_DELAYED_WORK(&motg->perf_vote_work, msm_otg_perf_vote_work);
+ INIT_WORK(&motg->notify_chg_current_work,
+ msm_otg_notify_chg_current_work);
motg->otg_wq = alloc_ordered_workqueue("k_otg", 0);
if (!motg->otg_wq) {
pr_err("%s: Unable to create workqueue otg_wq\n",
@@ -4110,6 +4120,7 @@
remove_cdev:
pm_runtime_disable(&pdev->dev);
device_remove_file(&pdev->dev, &dev_attr_dpdm_pulldown_enable);
+ msm_otg_debugfs_cleanup();
phy_reg_deinit:
devm_regulator_unregister(motg->phy.dev, motg->dpdm_rdev);
remove_phy:
@@ -4188,6 +4199,7 @@
cancel_delayed_work_sync(&motg->perf_vote_work);
msm_otg_perf_vote_update(motg, false);
cancel_work_sync(&motg->sm_work);
+ cancel_work_sync(&motg->notify_chg_current_work);
destroy_workqueue(motg->otg_wq);
pm_runtime_resume(&pdev->dev);
diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c
index 1886d8e..3550224 100644
--- a/drivers/usb/usbip/stub_dev.c
+++ b/drivers/usb/usbip/stub_dev.c
@@ -87,6 +87,7 @@
goto err;
sdev->ud.tcp_socket = socket;
+ sdev->ud.sockfd = sockfd;
spin_unlock_irq(&sdev->ud.lock);
@@ -186,6 +187,7 @@
if (ud->tcp_socket) {
sockfd_put(ud->tcp_socket);
ud->tcp_socket = NULL;
+ ud->sockfd = -1;
}
/* 3. free used data */
@@ -280,6 +282,7 @@
sdev->ud.status = SDEV_ST_AVAILABLE;
spin_lock_init(&sdev->ud.lock);
sdev->ud.tcp_socket = NULL;
+ sdev->ud.sockfd = -1;
INIT_LIST_HEAD(&sdev->priv_init);
INIT_LIST_HEAD(&sdev->priv_tx);
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index dbe615b..9936a2f 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -832,6 +832,7 @@
if (vdev->ud.tcp_socket) {
sockfd_put(vdev->ud.tcp_socket);
vdev->ud.tcp_socket = NULL;
+ vdev->ud.sockfd = -1;
}
pr_info("release socket\n");
@@ -879,6 +880,7 @@
if (ud->tcp_socket) {
sockfd_put(ud->tcp_socket);
ud->tcp_socket = NULL;
+ ud->sockfd = -1;
}
ud->status = VDEV_ST_NULL;
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 96a0661..e5b7652 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -1078,6 +1078,7 @@
}
vhost_net_stop(n, &tx_sock, &rx_sock);
vhost_net_flush(n);
+ vhost_dev_stop(&n->dev);
vhost_dev_reset_owner(&n->dev, umem);
vhost_net_vq_reset(n);
done:
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 64613fb..cd38f5a 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -849,7 +849,7 @@
{
int i = 0;
for (i = 0; i < d->nvqs; ++i)
- mutex_lock(&d->vqs[i]->mutex);
+ mutex_lock_nested(&d->vqs[i]->mutex, i);
}
static void vhost_dev_unlock_vqs(struct vhost_dev *d)
diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c
index 9269d56..b90ef96 100644
--- a/drivers/video/console/dummycon.c
+++ b/drivers/video/console/dummycon.c
@@ -67,7 +67,6 @@
.con_switch = DUMMY,
.con_blank = DUMMY,
.con_font_set = DUMMY,
- .con_font_get = DUMMY,
.con_font_default = DUMMY,
.con_font_copy = DUMMY,
};
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index eb44e99..1809e66 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2334,8 +2334,7 @@
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
- select SYNC
- select SW_SYNC
+ select SYNC_FILE
---help---
The MSM driver implements a frame buffer interface to
provide access to the display hardware and provide
diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c
index 669ecc7..8f439fd 100644
--- a/drivers/video/fbdev/atmel_lcdfb.c
+++ b/drivers/video/fbdev/atmel_lcdfb.c
@@ -1119,7 +1119,7 @@
goto put_display_node;
}
- timings_np = of_find_node_by_name(display_np, "display-timings");
+ timings_np = of_get_child_by_name(display_np, "display-timings");
if (!timings_np) {
dev_err(dev, "failed to find display-timings node\n");
ret = -ENODEV;
@@ -1140,6 +1140,12 @@
fb_add_videomode(&fb_vm, &info->modelist);
}
+ /*
+ * FIXME: Make sure we are not referencing any fields in display_np
+ * and timings_np and drop our references to them before returning to
+ * avoid leaking the nodes on probe deferral and driver unbind.
+ */
+
return 0;
put_timings_node:
diff --git a/drivers/video/fbdev/geode/video_gx.c b/drivers/video/fbdev/geode/video_gx.c
index 6082f65..67773e8 100644
--- a/drivers/video/fbdev/geode/video_gx.c
+++ b/drivers/video/fbdev/geode/video_gx.c
@@ -127,7 +127,7 @@
int timeout = 1000;
/* Rev. 1 Geode GXs use a 14 MHz reference clock instead of 48 MHz. */
- if (cpu_data(0).x86_mask == 1) {
+ if (cpu_data(0).x86_stepping == 1) {
pll_table = gx_pll_table_14MHz;
pll_table_len = ARRAY_SIZE(gx_pll_table_14MHz);
} else {
diff --git a/drivers/video/fbdev/mmp/core.c b/drivers/video/fbdev/mmp/core.c
index a0f4960..3a6bb65 100644
--- a/drivers/video/fbdev/mmp/core.c
+++ b/drivers/video/fbdev/mmp/core.c
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/export.h>
+#include <linux/module.h>
#include <video/mmp_disp.h>
static struct mmp_overlay *path_get_overlay(struct mmp_path *path,
@@ -249,3 +250,7 @@
mutex_unlock(&disp_lock);
}
EXPORT_SYMBOL_GPL(mmp_unregister_path);
+
+MODULE_AUTHOR("Zhou Zhu <zzhu3@marvell.com>");
+MODULE_DESCRIPTION("Marvell MMP display framework");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/msm/Kconfig b/drivers/video/fbdev/msm/Kconfig
index 60b86e7..e8f902b 100644
--- a/drivers/video/fbdev/msm/Kconfig
+++ b/drivers/video/fbdev/msm/Kconfig
@@ -21,8 +21,7 @@
config FB_MSM_MDSS
bool "MDSS HW"
- select SYNC
- select SW_SYNC
+ select SYNC_FILE
select FB_MSM_MDSS_COMMON
---help---
The Mobile Display Sub System (MDSS) driver supports devices which
diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile
index e09dcdb..4ee7f4a 100644
--- a/drivers/video/fbdev/msm/Makefile
+++ b/drivers/video/fbdev/msm/Makefile
@@ -65,7 +65,7 @@
obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
-mdss-qpic-objs := mdss_qpic.o mdss_fb.o mdss_qpic_panel.o
+mdss-qpic-objs := mdss_qpic.o mdss_fb.o mdss_qpic_panel.o mdss_sync.o
obj-$(CONFIG_FB_MSM_QPIC) += mdss-qpic.o
obj-$(CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL) += qpic_panel_ili_qvga.o
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index 17bad06..12a3171 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -232,6 +232,13 @@
u32 *dest_scaler_off;
u32 *dest_scaler_lut_off;
struct mdss_mdp_qseed3_lut_tbl lut_tbl;
+
+ /*
+ * Lock is mainly to serialize access to LUT.
+ * LUT values come asynchronously from userspace
+ * via ioctl.
+ */
+ struct mutex scaler_lock;
};
struct mdss_data_type;
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 65b689f..ae9b7cf 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -279,7 +279,7 @@
enum led_brightness value)
{
struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
- int bl_lvl;
+ u64 bl_lvl;
if (mfd->boot_notification_led) {
led_trigger_event(mfd->boot_notification_led, 0);
@@ -518,13 +518,13 @@
{
struct fb_info *fbi = dev_get_drvdata(dev);
struct msm_fb_data_type *mfd = fbi->par;
- unsigned int fps_int, fps_float;
+ u64 fps_int, fps_float;
if (mfd->panel_power_state != MDSS_PANEL_POWER_ON)
mfd->fps_info.measured_fps = 0;
- fps_int = (unsigned int) mfd->fps_info.measured_fps;
+ fps_int = (u64) mfd->fps_info.measured_fps;
fps_float = do_div(fps_int, 10);
- return scnprintf(buf, PAGE_SIZE, "%d.%d\n", fps_int, fps_float);
+ return scnprintf(buf, PAGE_SIZE, "%llu.%llu\n", fps_int, fps_float);
}
@@ -2292,9 +2292,10 @@
pr_debug("vma=%pK, addr=%x len=%ld\n",
vma, (unsigned int)addr, len);
pr_debug("vm_start=%x vm_end=%x vm_page_prot=%ld\n",
- (unsigned int)vma->vm_start,
- (unsigned int)vma->vm_end,
- (unsigned long int)vma->vm_page_prot.pgprot);
+ (unsigned int)vma->vm_start,
+ (unsigned int)vma->vm_end,
+ (unsigned long int)pgprot_val(
+ vma->vm_page_prot));
io_remap_pfn_range(vma, addr, page_to_pfn(page), len,
vma->vm_page_prot);
@@ -3014,7 +3015,8 @@
if (sync_pt_data->timeline) {
val = sync_pt_data->threshold +
atomic_read(&sync_pt_data->commit_cnt);
- mdss_inc_timeline(sync_pt_data->timeline, val);
+ mdss_resync_timeline(sync_pt_data->timeline);
+ mdss_resync_timeline(sync_pt_data->timeline_retire);
sync_pt_data->timeline_value += val;
atomic_set(&sync_pt_data->commit_cnt, 0);
}
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index 19e6299..c85f033 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -307,7 +307,7 @@
u32 calib_mode;
u32 calib_mode_bl;
u32 ad_bl_level;
- u32 bl_level;
+ u64 bl_level;
u32 bl_scale;
u32 bl_min_lvl;
u32 unset_bl_level;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index a9a5d8f..13a4bb6 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -2124,6 +2124,7 @@
return -EINVAL;
}
+ mutex_init(&mdata->scaler_off->scaler_lock);
return 0;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 4f17310..5088117 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -4560,7 +4560,8 @@
u32 off[NUM_MIXERCFG_REGS];
int i;
- WARN_ON(!values || count < NUM_MIXERCFG_REGS);
+ if (WARN_ON(!values || count < NUM_MIXERCFG_REGS))
+ return;
__mdss_mdp_mixer_get_offsets(mixer_num, off, ARRAY_SIZE(off));
diff --git a/drivers/video/fbdev/msm/mdss_mdp_debug.c b/drivers/video/fbdev/msm/mdss_mdp_debug.c
index d24ff53..6024ea1 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_debug.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_debug.c
@@ -1414,7 +1414,7 @@
seq_printf(s, "vsync: %08u \tunderrun: %08u\n",
ctl->vsync_cnt, ctl->underrun_cnt);
if (ctl->mfd) {
- seq_printf(s, "user_bl: %08u \tmod_bl: %08u\n",
+ seq_printf(s, "user_bl: %08llu \tmod_bl: %08u\n",
ctl->mfd->bl_level, ctl->mfd->bl_level_scaled);
}
} else {
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index 7a0542a..4442f19 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
@@ -568,6 +568,12 @@
int rc = 0;
bool schedule_off = false;
+ if (!ctl) {
+ pr_err("%s invalid ctl\n", __func__);
+ rc = -EINVAL;
+ goto exit;
+ }
+
/* Get both controllers in the correct order for dual displays */
mdss_mdp_get_split_display_ctls(&ctl, &sctl);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 3144b6c..da24e84 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -2015,7 +2015,7 @@
{
int vsync_diff;
int round_up = 0;
- s64 ts_diff = (cur_ts - base_ts) * display_fp1000s;
+ u64 ts_diff = (cur_ts - base_ts) * display_fp1000s;
do_div(ts_diff, 1000000);
vsync_diff = (int)ts_diff;
@@ -2065,7 +2065,7 @@
struct mdss_mdp_frc_cadence_calc *calc = &frc_info->calc;
struct mdss_mdp_frc_data *first = &calc->samples[0];
struct mdss_mdp_frc_data *last = &calc->samples[cnt-1];
- s64 ts_diff =
+ u64 ts_diff =
(last->timestamp - first->timestamp)
* frc_info->display_fp1000s;
u32 fcnt_diff =
@@ -6787,19 +6787,23 @@
struct mdp_scale_luts_info *lut_tbl)
{
struct mdss_mdp_qseed3_lut_tbl *qseed3_lut_tbl;
- int ret;
+ int ret = 0;
if (!mdata->scaler_off)
return -EFAULT;
+ mutex_lock(&mdata->scaler_off->scaler_lock);
+
qseed3_lut_tbl = &mdata->scaler_off->lut_tbl;
if ((lut_tbl->dir_lut_size !=
DIR_LUT_IDX * DIR_LUT_COEFFS * sizeof(uint32_t)) ||
(lut_tbl->cir_lut_size !=
CIR_LUT_IDX * CIR_LUT_COEFFS * sizeof(uint32_t)) ||
(lut_tbl->sep_lut_size !=
- SEP_LUT_IDX * SEP_LUT_COEFFS * sizeof(uint32_t)))
+ SEP_LUT_IDX * SEP_LUT_COEFFS * sizeof(uint32_t))) {
+ mutex_unlock(&mdata->scaler_off->scaler_lock);
return -EINVAL;
+ }
if (!qseed3_lut_tbl->dir_lut) {
qseed3_lut_tbl->dir_lut = devm_kzalloc(&mdata->pdev->dev,
@@ -6807,7 +6811,7 @@
GFP_KERNEL);
if (!qseed3_lut_tbl->dir_lut) {
ret = -ENOMEM;
- goto fail;
+ goto err;
}
}
@@ -6817,7 +6821,7 @@
GFP_KERNEL);
if (!qseed3_lut_tbl->cir_lut) {
ret = -ENOMEM;
- goto fail;
+ goto fail_free_dir_lut;
}
}
@@ -6827,44 +6831,52 @@
GFP_KERNEL);
if (!qseed3_lut_tbl->sep_lut) {
ret = -ENOMEM;
- goto fail;
+ goto fail_free_cir_lut;
}
}
/* Invalidate before updating */
qseed3_lut_tbl->valid = false;
-
if (copy_from_user(qseed3_lut_tbl->dir_lut,
(void *)(unsigned long)lut_tbl->dir_lut,
lut_tbl->dir_lut_size)) {
ret = -EINVAL;
- goto err;
+ goto fail_free_sep_lut;
}
if (copy_from_user(qseed3_lut_tbl->cir_lut,
(void *)(unsigned long)lut_tbl->cir_lut,
lut_tbl->cir_lut_size)) {
ret = -EINVAL;
- goto err;
+ goto fail_free_sep_lut;
}
if (copy_from_user(qseed3_lut_tbl->sep_lut,
(void *)(unsigned long)lut_tbl->sep_lut,
lut_tbl->sep_lut_size)) {
ret = -EINVAL;
- goto err;
+ goto fail_free_sep_lut;
}
qseed3_lut_tbl->valid = true;
+ mutex_unlock(&mdata->scaler_off->scaler_lock);
+
return ret;
-fail:
- kfree(qseed3_lut_tbl->dir_lut);
- kfree(qseed3_lut_tbl->cir_lut);
- kfree(qseed3_lut_tbl->sep_lut);
+fail_free_sep_lut:
+ devm_kfree(&mdata->pdev->dev, qseed3_lut_tbl->sep_lut);
+fail_free_cir_lut:
+ devm_kfree(&mdata->pdev->dev, qseed3_lut_tbl->cir_lut);
+fail_free_dir_lut:
+ devm_kfree(&mdata->pdev->dev, qseed3_lut_tbl->dir_lut);
err:
+ qseed3_lut_tbl->dir_lut = NULL;
+ qseed3_lut_tbl->cir_lut = NULL;
+ qseed3_lut_tbl->sep_lut = NULL;
qseed3_lut_tbl->valid = false;
+ mutex_unlock(&mdata->scaler_off->scaler_lock);
+
return ret;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index 74b698c..13afa46 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -1578,11 +1578,16 @@
};
mdata = mdss_mdp_get_mdata();
+
+ mutex_lock(&mdata->scaler_off->scaler_lock);
+
lut_tbl = &mdata->scaler_off->lut_tbl;
if ((!lut_tbl) || (!lut_tbl->valid)) {
+ mutex_unlock(&mdata->scaler_off->scaler_lock);
pr_err("%s:Invalid QSEED3 LUT TABLE\n", __func__);
return -EINVAL;
}
+
if ((scaler->lut_flag & SCALER_LUT_DIR_WR) ||
(scaler->lut_flag & SCALER_LUT_Y_CIR_WR) ||
(scaler->lut_flag & SCALER_LUT_UV_CIR_WR) ||
@@ -1632,6 +1637,7 @@
if (scaler->lut_flag & SCALER_LUT_SWAP)
writel_relaxed(BIT(0), MDSS_MDP_REG_SCALER_COEF_LUT_CTRL +
offset);
+ mutex_unlock(&mdata->scaler_off->scaler_lock);
return 0;
}
@@ -5772,7 +5778,7 @@
struct mdss_ad_input *input, int wait) {
int ret = 0;
struct mdss_ad_info *ad;
- u32 bl;
+ u64 bl;
struct mdss_overlay_private *mdp5_data;
ret = mdss_mdp_get_ad(mfd, &ad);
diff --git a/drivers/video/fbdev/msm/mdss_qpic.c b/drivers/video/fbdev/msm/mdss_qpic.c
index 3e0ca75..aa8d783 100644
--- a/drivers/video/fbdev/msm/mdss_qpic.c
+++ b/drivers/video/fbdev/msm/mdss_qpic.c
@@ -649,7 +649,7 @@
if (use_irq && (!qpic_res->irq_requested)) {
ret = devm_request_irq(&qpic_res->pdev->dev,
qpic_res->irq, qpic_irq_handler,
- IRQF_DISABLED, "QPIC", qpic_res);
+ IRQF_TRIGGER_NONE, "QPIC", qpic_res);
if (ret) {
pr_err("qpic request_irq() failed!\n");
use_irq = false;
@@ -776,12 +776,15 @@
}
qpic_res->qpic_a_clk = clk_get(&pdev->dev, "core_a_clk");
- if (IS_ERR(qpic_res->qpic_a_clk))
+ if (IS_ERR(qpic_res->qpic_a_clk)) {
+ qpic_res->qpic_a_clk = NULL;
pr_err("%s: Can't find core_a_clk", __func__);
-
+ }
qpic_res->qpic_clk = clk_get(&pdev->dev, "core_clk");
- if (IS_ERR(qpic_res->qpic_clk))
+ if (IS_ERR(qpic_res->qpic_clk)) {
+ qpic_res->qpic_clk = NULL;
pr_err("%s: Can't find core_clk", __func__);
+ }
qpic_res->irq = res->start;
qpic_res->res_init = true;
diff --git a/drivers/video/fbdev/msm/mdss_smmu.c b/drivers/video/fbdev/msm/mdss_smmu.c
index 7a44824..fbbdaf2 100644
--- a/drivers/video/fbdev/msm/mdss_smmu.c
+++ b/drivers/video/fbdev/msm/mdss_smmu.c
@@ -316,7 +316,7 @@
}
ATRACE_END("map_buffer");
*iova = table->sgl->dma_address;
- *size = table->sgl->dma_length;
+ *size = sg_dma_len(table->sgl);
return 0;
}
diff --git a/drivers/video/fbdev/msm/mdss_sync.c b/drivers/video/fbdev/msm/mdss_sync.c
index ed611e7..22fdcf5 100644
--- a/drivers/video/fbdev/msm/mdss_sync.c
+++ b/drivers/video/fbdev/msm/mdss_sync.c
@@ -51,6 +51,7 @@
struct mdss_timeline {
struct kref kref;
spinlock_t lock;
+ spinlock_t list_lock;
char name[MDSS_SYNC_NAME_SIZE];
u32 next_value;
u32 value;
@@ -58,6 +59,7 @@
struct list_head fence_list_head;
};
+#if defined(CONFIG_SYNC_FILE)
/*
* to_mdss_fence - get mdss fence from fence base object
* @fence: Pointer to fence base object
@@ -148,12 +150,13 @@
static void mdss_fence_release(struct fence *fence)
{
struct mdss_fence *f = to_mdss_fence(fence);
- unsigned long flags;
+ struct mdss_timeline *tl = to_mdss_timeline(fence);
- spin_lock_irqsave(fence->lock, flags);
+ pr_debug("%s for fence %s\n", __func__, f->name);
+ spin_lock(&tl->list_lock);
if (!list_empty(&f->fence_list))
list_del(&f->fence_list);
- spin_unlock_irqrestore(fence->lock, flags);
+ spin_unlock(&tl->list_lock);
mdss_put_timeline(to_mdss_timeline(fence));
kfree_rcu(f, base.rcu);
}
@@ -202,6 +205,7 @@
kref_init(&tl->kref);
snprintf(tl->name, sizeof(tl->name), "%s", name);
spin_lock_init(&tl->lock);
+ spin_lock_init(&tl->list_lock);
tl->context = fence_context_alloc(1);
INIT_LIST_HEAD(&tl->fence_list_head);
@@ -226,12 +230,42 @@
int increment)
{
struct mdss_fence *f, *next;
+ s32 val;
+ bool is_signaled = false;
+ struct list_head local_list_head;
+ unsigned long flags;
- tl->value += increment;
- list_for_each_entry_safe(f, next, &tl->fence_list_head, fence_list) {
- if (fence_is_signaled_locked(&f->base)) {
+ INIT_LIST_HEAD(&local_list_head);
+
+ spin_lock(&tl->list_lock);
+ if (list_empty(&tl->fence_list_head)) {
+ pr_debug("fence list is empty\n");
+ spin_unlock(&tl->list_lock);
+ return 0;
+ }
+
+ list_for_each_entry_safe(f, next, &tl->fence_list_head, fence_list)
+ list_move(&f->fence_list, &local_list_head);
+ spin_unlock(&tl->list_lock);
+
+ spin_lock_irqsave(&tl->lock, flags);
+ val = tl->next_value - tl->value;
+ if (val >= increment)
+ tl->value += increment;
+ spin_unlock_irqrestore(&tl->lock, flags);
+
+ list_for_each_entry_safe(f, next, &local_list_head, fence_list) {
+ spin_lock_irqsave(&tl->lock, flags);
+ is_signaled = fence_is_signaled_locked(&f->base);
+ spin_unlock_irqrestore(&tl->lock, flags);
+ if (is_signaled) {
pr_debug("%s signaled\n", f->name);
list_del_init(&f->fence_list);
+ fence_put(&f->base);
+ } else {
+ spin_lock(&tl->list_lock);
+ list_move(&f->fence_list, &tl->fence_list_head);
+ spin_unlock(&tl->list_lock);
}
}
@@ -244,7 +278,6 @@
*/
void mdss_resync_timeline(struct mdss_timeline *tl)
{
- unsigned long flags;
s32 val;
if (!tl) {
@@ -252,13 +285,12 @@
return;
}
- spin_lock_irqsave(&tl->lock, flags);
val = tl->next_value - tl->value;
if (val > 0) {
- pr_warn("flush %s:%d\n", tl->name, val);
+ pr_warn("flush %s:%d TL(Nxt %d , Crnt %d)\n", tl->name, val,
+ tl->next_value, tl->value);
mdss_inc_timeline_locked(tl, val);
}
- spin_unlock_irqrestore(&tl->lock, flags);
}
/*
@@ -272,8 +304,8 @@
u32 *timestamp, int offset)
{
struct mdss_fence *f;
- unsigned long flags;
u32 val;
+ unsigned long flags;
if (!tl) {
pr_err("invalid parameters\n");
@@ -289,9 +321,12 @@
val = tl->next_value + offset;
tl->next_value += 1;
fence_init(&f->base, &mdss_fence_ops, &tl->lock, tl->context, val);
- list_add_tail(&f->fence_list, &tl->fence_list_head);
mdss_get_timeline(tl);
spin_unlock_irqrestore(&tl->lock, flags);
+
+ spin_lock(&tl->list_lock);
+ list_add_tail(&f->fence_list, &tl->fence_list_head);
+ spin_unlock(&tl->list_lock);
snprintf(f->name, sizeof(f->name), "%s_%u", fence_name, val);
if (timestamp)
@@ -310,7 +345,6 @@
*/
int mdss_inc_timeline(struct mdss_timeline *tl, int increment)
{
- unsigned long flags;
int rc;
if (!tl) {
@@ -318,10 +352,7 @@
return -EINVAL;
}
- spin_lock_irqsave(&tl->lock, flags);
rc = mdss_inc_timeline_locked(tl, increment);
- spin_unlock_irqrestore(&tl->lock, flags);
-
return rc;
}
@@ -388,7 +419,19 @@
pr_debug("fence signaled\n");
rc = 0;
} else if (rc == 0) {
- pr_debug("fence timeout\n");
+ struct fence *input_fence = (struct fence *) fence;
+ char timeline_str[MDSS_SYNC_NAME_SIZE];
+
+ if (input_fence->ops->timeline_value_str)
+ input_fence->ops->timeline_value_str(input_fence,
+ timeline_str, MDSS_SYNC_NAME_SIZE);
+ pr_err(
+ "drv:%s timeline:%s seqno:%d timeline:%s status:0x%x\n",
+ input_fence->ops->get_driver_name(input_fence),
+ input_fence->ops->get_timeline_name(input_fence),
+ input_fence->seqno, timeline_str,
+ input_fence->ops->signaled ?
+ input_fence->ops->signaled(input_fence) : 0xffffffff);
rc = -ETIMEDOUT;
}
@@ -451,3 +494,4 @@
return fence->name;
}
+#endif
diff --git a/drivers/video/fbdev/msm/mdss_sync.h b/drivers/video/fbdev/msm/mdss_sync.h
index 39a1aa7b..a2e84d4 100644
--- a/drivers/video/fbdev/msm/mdss_sync.h
+++ b/drivers/video/fbdev/msm/mdss_sync.h
@@ -112,11 +112,12 @@
{
return -EBADF;
}
+
+static inline
const char *mdss_get_sync_fence_name(struct mdss_fence *fence)
{
return NULL;
}
-}
#endif
#endif /* MDSS_SYNC_H */
diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
index 39d26a4..ec1ee60 100644
--- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c
+++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
@@ -2033,7 +2033,7 @@
{
int rc = 0;
struct mdss_dsi_ctrl_pdata *mctrl = NULL;
- int i, *vote_cnt;
+ int i, *vote_cnt = NULL;
void *m_clk_handle;
bool is_ecg = false;
diff --git a/drivers/video/fbdev/via/viafbdev.c b/drivers/video/fbdev/via/viafbdev.c
index f9718f0..badee04 100644
--- a/drivers/video/fbdev/via/viafbdev.c
+++ b/drivers/video/fbdev/via/viafbdev.c
@@ -1630,16 +1630,14 @@
}
static void viafb_remove_proc(struct viafb_shared *shared)
{
- struct proc_dir_entry *viafb_entry = shared->proc_entry,
- *iga1_entry = shared->iga1_proc_entry,
- *iga2_entry = shared->iga2_proc_entry;
+ struct proc_dir_entry *viafb_entry = shared->proc_entry;
if (!viafb_entry)
return;
- remove_proc_entry("output_devices", iga2_entry);
+ remove_proc_entry("output_devices", shared->iga2_proc_entry);
remove_proc_entry("iga2", viafb_entry);
- remove_proc_entry("output_devices", iga1_entry);
+ remove_proc_entry("output_devices", shared->iga1_proc_entry);
remove_proc_entry("iga1", viafb_entry);
remove_proc_entry("supported_output_devices", viafb_entry);
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index 4874b0f..518dfa1 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -169,15 +169,21 @@
return 0;
}
-static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
- unsigned int new_timeout)
+static void __imx2_wdt_set_timeout(struct watchdog_device *wdog,
+ unsigned int new_timeout)
{
struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
- wdog->timeout = new_timeout;
-
regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
WDOG_SEC_TO_COUNT(new_timeout));
+}
+
+static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
+ unsigned int new_timeout)
+{
+ __imx2_wdt_set_timeout(wdog, new_timeout);
+
+ wdog->timeout = new_timeout;
return 0;
}
@@ -371,7 +377,11 @@
/* The watchdog IP block is running */
if (imx2_wdt_is_running(wdev)) {
- imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
+ /*
+ * Don't update wdog->timeout, we'll restore the current value
+ * during resume.
+ */
+ __imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
imx2_wdt_ping(wdog);
}
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index f15bb3b7..98b8f32 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -246,7 +246,7 @@
config XEN_ACPI_PROCESSOR
tristate "Xen ACPI processor"
- depends on XEN && X86 && ACPI_PROCESSOR && CPU_FREQ
+ depends on XEN && XEN_DOM0 && X86 && ACPI_PROCESSOR && CPU_FREQ
default m
help
This ACPI processor uploads Power Management information to the Xen
diff --git a/fs/block_dev.c b/fs/block_dev.c
index cb936c9..9900693 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -614,6 +614,7 @@
#ifdef CONFIG_SYSFS
INIT_LIST_HEAD(&bdev->bd_holder_disks);
#endif
+ bdev->bd_bdi = &noop_backing_dev_info;
inode_init_once(&ei->vfs_inode);
/* Initialize mutex for freeze. */
mutex_init(&bdev->bd_fsfreeze_mutex);
@@ -628,6 +629,12 @@
spin_lock(&bdev_lock);
list_del_init(&bdev->bd_list);
spin_unlock(&bdev_lock);
+ /* Detach inode from wb early as bdi_put() may free bdi->wb */
+ inode_detach_wb(inode);
+ if (bdev->bd_bdi != &noop_backing_dev_info) {
+ bdi_put(bdev->bd_bdi);
+ bdev->bd_bdi = &noop_backing_dev_info;
+ }
}
static const struct super_operations bdev_sops = {
@@ -698,6 +705,21 @@
static LIST_HEAD(all_bdevs);
+/*
+ * If there is a bdev inode for this device, unhash it so that it gets evicted
+ * as soon as last inode reference is dropped.
+ */
+void bdev_unhash_inode(dev_t dev)
+{
+ struct inode *inode;
+
+ inode = ilookup5(blockdev_superblock, hash(dev), bdev_test, &dev);
+ if (inode) {
+ remove_inode_hash(inode);
+ iput(inode);
+ }
+}
+
struct block_device *bdget(dev_t dev)
{
struct block_device *bdev;
@@ -769,13 +791,22 @@
spin_lock(&bdev_lock);
bdev = inode->i_bdev;
- if (bdev) {
+ if (bdev && !inode_unhashed(bdev->bd_inode)) {
bdgrab(bdev);
spin_unlock(&bdev_lock);
return bdev;
}
spin_unlock(&bdev_lock);
+ /*
+ * i_bdev references block device inode that was already shut down
+ * (corresponding device got removed). Remove the reference and look
+ * up block device inode again just in case new device got
+ * reestablished under the same device number.
+ */
+ if (bdev)
+ bd_forget(inode);
+
bdev = bdget(inode->i_rdev);
if (bdev) {
spin_lock(&bdev_lock);
@@ -1334,6 +1365,9 @@
}
bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9);
}
+
+ if (bdev->bd_bdi == &noop_backing_dev_info)
+ bdev->bd_bdi = bdi_get(disk->queue->backing_dev_info);
} else {
if (bdev->bd_contains == bdev) {
ret = 0;
@@ -1586,12 +1620,6 @@
kill_bdev(bdev);
bdev_write_inode(bdev);
- /*
- * Detaching bdev inode from its wb in __destroy_inode()
- * is too late: the queue which embeds its bdi (along with
- * root wb) can be gone as soon as we put_disk() below.
- */
- inode_detach_wb(bdev->bd_inode);
}
if (bdev->bd_contains == bdev) {
if (disk->fops->release)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 1cd3257..c66054c 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1816,7 +1816,7 @@
list_for_each_entry_rcu(device, &info->fs_devices->devices, dev_list) {
if (!device->bdev)
continue;
- bdi = blk_get_backing_dev_info(device->bdev);
+ bdi = device->bdev->bd_bdi;
if (bdi_congested(bdi, bdi_bits)) {
ret = 1;
break;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 894d563..d196ce4 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1320,8 +1320,11 @@
leaf = path->nodes[0];
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
ret = btrfs_next_leaf(root, path);
- if (ret < 0)
+ if (ret < 0) {
+ if (cow_start != (u64)-1)
+ cur_offset = cow_start;
goto error;
+ }
if (ret > 0)
break;
leaf = path->nodes[0];
@@ -2063,8 +2066,15 @@
goto out;
}
- btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state,
- 0);
+ ret = btrfs_set_extent_delalloc(inode, page_start, page_end,
+ &cached_state, 0);
+ if (ret) {
+ mapping_set_error(page->mapping, ret);
+ end_extent_writepage(page, ret, page_start, page_end);
+ ClearPageChecked(page);
+ goto out;
+ }
+
ClearPageChecked(page);
set_page_dirty(page);
out:
@@ -5219,7 +5229,7 @@
trace_btrfs_inode_evict(inode);
if (!root) {
- kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
+ clear_inode(inode);
return;
}
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 0fe346c..d3dd631 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2244,7 +2244,7 @@
if (!path)
return -ENOMEM;
- ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX];
+ ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX - 1];
key.objectid = tree_id;
key.type = BTRFS_ROOT_ITEM_KEY;
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 309313b..5539f0b 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -28,6 +28,7 @@
#include "hash.h"
#include "compression.h"
#include "qgroup.h"
+#include "inode-map.h"
/* magic values for the inode_only field in btrfs_log_inode:
*
@@ -2463,6 +2464,9 @@
next);
btrfs_wait_tree_block_writeback(next);
btrfs_tree_unlock(next);
+ } else {
+ if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+ clear_extent_buffer_dirty(next);
}
WARN_ON(root_owner !=
@@ -2542,6 +2546,9 @@
next);
btrfs_wait_tree_block_writeback(next);
btrfs_tree_unlock(next);
+ } else {
+ if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+ clear_extent_buffer_dirty(next);
}
WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
@@ -2618,6 +2625,9 @@
clean_tree_block(trans, log->fs_info, next);
btrfs_wait_tree_block_writeback(next);
btrfs_tree_unlock(next);
+ } else {
+ if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+ clear_extent_buffer_dirty(next);
}
WARN_ON(log->root_key.objectid !=
@@ -3004,13 +3014,14 @@
while (1) {
ret = find_first_extent_bit(&log->dirty_log_pages,
- 0, &start, &end, EXTENT_DIRTY | EXTENT_NEW,
+ 0, &start, &end,
+ EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT,
NULL);
if (ret)
break;
clear_extent_bits(&log->dirty_log_pages, start, end,
- EXTENT_DIRTY | EXTENT_NEW);
+ EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT);
}
/*
@@ -5651,6 +5662,23 @@
path);
}
+ if (!ret && wc.stage == LOG_WALK_REPLAY_ALL) {
+ struct btrfs_root *root = wc.replay_dest;
+
+ btrfs_release_path(path);
+
+ /*
+ * We have just replayed everything, and the highest
+ * objectid of fs roots probably has changed in case
+ * some inode_item's got replayed.
+ *
+ * root->objectid_mutex is not acquired as log replay
+ * could only happen during mount.
+ */
+ ret = btrfs_find_highest_objectid(root,
+ &root->highest_objectid);
+ }
+
key.offset = found_key.offset - 1;
wc.replay_dest->log_root = NULL;
free_extent_buffer(log->node);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 06a77e4..fad7b37 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -366,7 +366,7 @@
*/
blk_start_plug(&plug);
- bdi = blk_get_backing_dev_info(device->bdev);
+ bdi = device->bdev->bd_bdi;
fs_info = device->dev_root->fs_info;
limit = btrfs_async_submit_limit(fs_info);
limit = limit * 2 / 3;
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 5eb0412..73360df 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -318,9 +318,8 @@
{
int i;
int rc;
- char password_with_pad[CIFS_ENCPWD_SIZE];
+ char password_with_pad[CIFS_ENCPWD_SIZE] = {0};
- memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
if (password)
strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 580b3a4..c4a27f6 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1667,7 +1667,7 @@
tmp_end++;
if (!(tmp_end < end && tmp_end[1] == delim)) {
/* No it is not. Set the password to NULL */
- kfree(vol->password);
+ kzfree(vol->password);
vol->password = NULL;
break;
}
@@ -1705,7 +1705,7 @@
options = end;
}
- kfree(vol->password);
+ kzfree(vol->password);
/* Now build new password string */
temp_len = strlen(value);
vol->password = kzalloc(temp_len+1, GFP_KERNEL);
@@ -2439,7 +2439,7 @@
}
down_read(&key->sem);
- upayload = user_key_payload(key);
+ upayload = user_key_payload_locked(key);
if (IS_ERR_OR_NULL(upayload)) {
rc = upayload ? PTR_ERR(upayload) : -EINVAL;
goto out_key_put;
@@ -4159,7 +4159,7 @@
reset_cifs_unix_caps(0, tcon, NULL, vol_info);
out:
kfree(vol_info->username);
- kfree(vol_info->password);
+ kzfree(vol_info->password);
kfree(vol_info);
return tcon;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index cf192f9..02e403a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -3285,20 +3285,18 @@
int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
{
- int rc, xid;
+ int xid, rc = 0;
struct inode *inode = file_inode(file);
xid = get_xid();
- if (!CIFS_CACHE_READ(CIFS_I(inode))) {
+ if (!CIFS_CACHE_READ(CIFS_I(inode)))
rc = cifs_zap_mapping(inode);
- if (rc)
- return rc;
- }
-
- rc = generic_file_mmap(file, vma);
- if (rc == 0)
+ if (!rc)
+ rc = generic_file_mmap(file, vma);
+ if (!rc)
vma->vm_ops = &cifs_file_vm_ops;
+
free_xid(xid);
return rc;
}
@@ -3308,16 +3306,16 @@
int rc, xid;
xid = get_xid();
+
rc = cifs_revalidate_file(file);
- if (rc) {
+ if (rc)
cifs_dbg(FYI, "Validation prior to mmap failed, error=%d\n",
rc);
- free_xid(xid);
- return rc;
- }
- rc = generic_file_mmap(file, vma);
- if (rc == 0)
+ if (!rc)
+ rc = generic_file_mmap(file, vma);
+ if (!rc)
vma->vm_ops = &cifs_file_vm_ops;
+
free_xid(xid);
return rc;
}
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 5419afe..323d8e3 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -99,14 +99,11 @@
kfree(buf_to_free->serverOS);
kfree(buf_to_free->serverDomain);
kfree(buf_to_free->serverNOS);
- if (buf_to_free->password) {
- memset(buf_to_free->password, 0, strlen(buf_to_free->password));
- kfree(buf_to_free->password);
- }
+ kzfree(buf_to_free->password);
kfree(buf_to_free->user_name);
kfree(buf_to_free->domainName);
- kfree(buf_to_free->auth_key.response);
- kfree(buf_to_free);
+ kzfree(buf_to_free->auth_key.response);
+ kzfree(buf_to_free);
}
struct cifs_tcon *
@@ -137,10 +134,7 @@
}
atomic_dec(&tconInfoAllocCount);
kfree(buf_to_free->nativeFileSystem);
- if (buf_to_free->password) {
- memset(buf_to_free->password, 0, strlen(buf_to_free->password));
- kfree(buf_to_free->password);
- }
+ kzfree(buf_to_free->password);
kfree(buf_to_free);
}
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 69b610ad..94c4c19 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -585,8 +585,7 @@
}
/* check validate negotiate info response matches what we got earlier */
- if (pneg_rsp->Dialect !=
- cpu_to_le16(tcon->ses->server->vals->protocol_id))
+ if (pneg_rsp->Dialect != cpu_to_le16(tcon->ses->server->dialect))
goto vneg_out;
if (pneg_rsp->SecurityMode != cpu_to_le16(tcon->ses->server->sec_mode))
diff --git a/fs/compat_binfmt_elf.c b/fs/compat_binfmt_elf.c
index 4d24d17..943be5e 100644
--- a/fs/compat_binfmt_elf.c
+++ b/fs/compat_binfmt_elf.c
@@ -51,6 +51,7 @@
#define elf_prstatus compat_elf_prstatus
#define elf_prpsinfo compat_elf_prpsinfo
+#ifdef CONFIG_ELF_CORE
/*
* Compat version of cputime_to_compat_timeval, perhaps this
* should be an inline in <linux/compat.h>.
@@ -63,6 +64,7 @@
value->tv_sec = tv.tv_sec;
value->tv_usec = tv.tv_usec;
}
+#endif
#undef cputime_to_timeval
#define cputime_to_timeval cputime_to_compat_timeval
diff --git a/fs/crypto/Kconfig b/fs/crypto/Kconfig
index 92348fa..08b46e6 100644
--- a/fs/crypto/Kconfig
+++ b/fs/crypto/Kconfig
@@ -1,6 +1,5 @@
config FS_ENCRYPTION
tristate "FS Encryption (Per-file encryption)"
- depends on BLOCK
select CRYPTO
select CRYPTO_AES
select CRYPTO_CBC
@@ -8,9 +7,7 @@
select CRYPTO_XTS
select CRYPTO_CTS
select CRYPTO_CTR
- select CRYPTO_SHA256
select KEYS
- select ENCRYPTED_KEYS
help
Enable encryption of files and directories. This
feature is similar to ecryptfs, but it is more memory
diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile
index facf63c..cb49698 100644
--- a/fs/crypto/Makefile
+++ b/fs/crypto/Makefile
@@ -1,4 +1,4 @@
obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o
-ccflags-y += -Ifs/ext4
-fscrypto-y := crypto.o fname.o policy.o keyinfo.o
+fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o
+fscrypto-$(CONFIG_BLOCK) += bio.o
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
new file mode 100644
index 0000000..2596c9a
--- /dev/null
+++ b/fs/crypto/bio.c
@@ -0,0 +1,145 @@
+/*
+ * This contains encryption functions for per-file encryption.
+ *
+ * Copyright (C) 2015, Google, Inc.
+ * Copyright (C) 2015, Motorola Mobility
+ *
+ * Written by Michael Halcrow, 2014.
+ *
+ * Filename encryption additions
+ * Uday Savagaonkar, 2014
+ * Encryption policy handling additions
+ * Ildar Muslukhov, 2014
+ * Add fscrypt_pullback_bio_page()
+ * Jaegeuk Kim, 2015.
+ *
+ * This has not yet undergone a rigorous security audit.
+ *
+ * The usage of AES-XTS should conform to recommendations in NIST
+ * Special Publication 800-38E and IEEE P1619/D16.
+ */
+
+#include <linux/pagemap.h>
+#include <linux/module.h>
+#include <linux/bio.h>
+#include <linux/namei.h>
+#include "fscrypt_private.h"
+
+/*
+ * Call fscrypt_decrypt_page on every single page, reusing the encryption
+ * context.
+ */
+static void completion_pages(struct work_struct *work)
+{
+ struct fscrypt_ctx *ctx =
+ container_of(work, struct fscrypt_ctx, r.work);
+ struct bio *bio = ctx->r.bio;
+ struct bio_vec *bv;
+ int i;
+
+ bio_for_each_segment_all(bv, bio, i) {
+ struct page *page = bv->bv_page;
+ int ret = fscrypt_decrypt_page(page->mapping->host, page,
+ PAGE_SIZE, 0, page->index);
+
+ if (ret) {
+ WARN_ON_ONCE(1);
+ SetPageError(page);
+ } else {
+ SetPageUptodate(page);
+ }
+ unlock_page(page);
+ }
+ fscrypt_release_ctx(ctx);
+ bio_put(bio);
+}
+
+void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio)
+{
+ INIT_WORK(&ctx->r.work, completion_pages);
+ ctx->r.bio = bio;
+ queue_work(fscrypt_read_workqueue, &ctx->r.work);
+}
+EXPORT_SYMBOL(fscrypt_decrypt_bio_pages);
+
+void fscrypt_pullback_bio_page(struct page **page, bool restore)
+{
+ struct fscrypt_ctx *ctx;
+ struct page *bounce_page;
+
+ /* The bounce data pages are unmapped. */
+ if ((*page)->mapping)
+ return;
+
+ /* The bounce data page is unmapped. */
+ bounce_page = *page;
+ ctx = (struct fscrypt_ctx *)page_private(bounce_page);
+
+ /* restore control page */
+ *page = ctx->w.control_page;
+
+ if (restore)
+ fscrypt_restore_control_page(bounce_page);
+}
+EXPORT_SYMBOL(fscrypt_pullback_bio_page);
+
+int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
+ sector_t pblk, unsigned int len)
+{
+ struct fscrypt_ctx *ctx;
+ struct page *ciphertext_page = NULL;
+ struct bio *bio;
+ int ret, err = 0;
+
+ BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE);
+
+ ctx = fscrypt_get_ctx(inode, GFP_NOFS);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ciphertext_page = fscrypt_alloc_bounce_page(ctx, GFP_NOWAIT);
+ if (IS_ERR(ciphertext_page)) {
+ err = PTR_ERR(ciphertext_page);
+ goto errout;
+ }
+
+ while (len--) {
+ err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk,
+ ZERO_PAGE(0), ciphertext_page,
+ PAGE_SIZE, 0, GFP_NOFS);
+ if (err)
+ goto errout;
+
+ bio = bio_alloc(GFP_NOWAIT, 1);
+ if (!bio) {
+ err = -ENOMEM;
+ goto errout;
+ }
+ bio->bi_bdev = inode->i_sb->s_bdev;
+ bio->bi_iter.bi_sector =
+ pblk << (inode->i_sb->s_blocksize_bits - 9);
+ bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
+ ret = bio_add_page(bio, ciphertext_page,
+ inode->i_sb->s_blocksize, 0);
+ if (ret != inode->i_sb->s_blocksize) {
+ /* should never happen! */
+ WARN_ON(1);
+ bio_put(bio);
+ err = -EIO;
+ goto errout;
+ }
+ err = submit_bio_wait(bio);
+ if (err == 0 && bio->bi_error)
+ err = -EIO;
+ bio_put(bio);
+ if (err)
+ goto errout;
+ lblk++;
+ pblk++;
+ }
+ err = 0;
+errout:
+ fscrypt_release_ctx(ctx);
+ return err;
+}
+EXPORT_SYMBOL(fscrypt_zeroout_range);
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index ab6e7dc..732a786 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -24,11 +24,10 @@
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/ratelimit.h>
-#include <linux/bio.h>
#include <linux/dcache.h>
#include <linux/namei.h>
-#include <linux/fscrypto.h>
-#include "ext4_ice.h"
+#include <crypto/aes.h>
+#include "fscrypt_private.h"
static unsigned int num_prealloc_crypto_pages = 32;
static unsigned int num_prealloc_crypto_ctxs = 128;
@@ -45,7 +44,7 @@
static LIST_HEAD(fscrypt_free_ctxs);
static DEFINE_SPINLOCK(fscrypt_ctx_lock);
-static struct workqueue_struct *fscrypt_read_workqueue;
+struct workqueue_struct *fscrypt_read_workqueue;
static DEFINE_MUTEX(fscrypt_init_mutex);
static struct kmem_cache *fscrypt_ctx_cachep;
@@ -64,7 +63,7 @@
{
unsigned long flags;
- if (ctx->flags & FS_WRITE_PATH_FL && ctx->w.bounce_page) {
+ if (ctx->flags & FS_CTX_HAS_BOUNCE_BUFFER_FL && ctx->w.bounce_page) {
mempool_free(ctx->w.bounce_page, fscrypt_bounce_page_pool);
ctx->w.bounce_page = NULL;
}
@@ -89,7 +88,7 @@
* Return: An allocated and initialized encryption context on success; error
* value or NULL otherwise.
*/
-struct fscrypt_ctx *fscrypt_get_ctx(struct inode *inode, gfp_t gfp_flags)
+struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags)
{
struct fscrypt_ctx *ctx = NULL;
struct fscrypt_info *ci = inode->i_crypt_info;
@@ -122,47 +121,39 @@
} else {
ctx->flags &= ~FS_CTX_REQUIRES_FREE_ENCRYPT_FL;
}
- ctx->flags &= ~FS_WRITE_PATH_FL;
+ ctx->flags &= ~FS_CTX_HAS_BOUNCE_BUFFER_FL;
return ctx;
}
EXPORT_SYMBOL(fscrypt_get_ctx);
-/**
- * page_crypt_complete() - completion callback for page crypto
- * @req: The asynchronous cipher request context
- * @res: The result of the cipher operation
- */
-static void page_crypt_complete(struct crypto_async_request *req, int res)
-{
- struct fscrypt_completion_result *ecr = req->data;
-
- if (res == -EINPROGRESS)
- return;
- ecr->res = res;
- complete(&ecr->completion);
-}
-
-typedef enum {
- FS_DECRYPT = 0,
- FS_ENCRYPT,
-} fscrypt_direction_t;
-
-static int do_page_crypto(struct inode *inode,
- fscrypt_direction_t rw, pgoff_t index,
- struct page *src_page, struct page *dest_page,
- gfp_t gfp_flags)
+int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
+ u64 lblk_num, struct page *src_page,
+ struct page *dest_page, unsigned int len,
+ unsigned int offs, gfp_t gfp_flags)
{
struct {
__le64 index;
- u8 padding[FS_XTS_TWEAK_SIZE - sizeof(__le64)];
- } xts_tweak;
+ u8 padding[FS_IV_SIZE - sizeof(__le64)];
+ } iv;
struct skcipher_request *req = NULL;
- DECLARE_FS_COMPLETION_RESULT(ecr);
+ DECLARE_CRYPTO_WAIT(wait);
struct scatterlist dst, src;
struct fscrypt_info *ci = inode->i_crypt_info;
struct crypto_skcipher *tfm = ci->ci_ctfm;
int res = 0;
+ BUG_ON(len == 0);
+
+ BUILD_BUG_ON(sizeof(iv) != FS_IV_SIZE);
+ BUILD_BUG_ON(AES_BLOCK_SIZE != FS_IV_SIZE);
+ iv.index = cpu_to_le64(lblk_num);
+ memset(iv.padding, 0, sizeof(iv.padding));
+
+ if (ci->ci_essiv_tfm != NULL) {
+ crypto_cipher_encrypt_one(ci->ci_essiv_tfm, (u8 *)&iv,
+ (u8 *)&iv);
+ }
+
req = skcipher_request_alloc(tfm, gfp_flags);
if (!req) {
printk_ratelimited(KERN_ERR
@@ -173,26 +164,17 @@
skcipher_request_set_callback(
req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
- page_crypt_complete, &ecr);
-
- BUILD_BUG_ON(sizeof(xts_tweak) != FS_XTS_TWEAK_SIZE);
- xts_tweak.index = cpu_to_le64(index);
- memset(xts_tweak.padding, 0, sizeof(xts_tweak.padding));
+ crypto_req_done, &wait);
sg_init_table(&dst, 1);
- sg_set_page(&dst, dest_page, PAGE_SIZE, 0);
+ sg_set_page(&dst, dest_page, len, offs);
sg_init_table(&src, 1);
- sg_set_page(&src, src_page, PAGE_SIZE, 0);
- skcipher_request_set_crypt(req, &src, &dst, PAGE_SIZE, &xts_tweak);
+ sg_set_page(&src, src_page, len, offs);
+ skcipher_request_set_crypt(req, &src, &dst, len, &iv);
if (rw == FS_DECRYPT)
- res = crypto_skcipher_decrypt(req);
+ res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
else
- res = crypto_skcipher_encrypt(req);
- if (res == -EINPROGRESS || res == -EBUSY) {
- BUG_ON(req->base.data != &ecr);
- wait_for_completion(&ecr.completion);
- res = ecr.res;
- }
+ res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
skcipher_request_free(req);
if (res) {
printk_ratelimited(KERN_ERR
@@ -203,53 +185,86 @@
return 0;
}
-static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags)
+struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx,
+ gfp_t gfp_flags)
{
ctx->w.bounce_page = mempool_alloc(fscrypt_bounce_page_pool, gfp_flags);
if (ctx->w.bounce_page == NULL)
return ERR_PTR(-ENOMEM);
- ctx->flags |= FS_WRITE_PATH_FL;
+ ctx->flags |= FS_CTX_HAS_BOUNCE_BUFFER_FL;
return ctx->w.bounce_page;
}
/**
* fscypt_encrypt_page() - Encrypts a page
- * @inode: The inode for which the encryption should take place
- * @plaintext_page: The page to encrypt. Must be locked.
- * @gfp_flags: The gfp flag for memory allocation
+ * @inode: The inode for which the encryption should take place
+ * @page: The page to encrypt. Must be locked for bounce-page
+ * encryption.
+ * @len: Length of data to encrypt in @page and encrypted
+ * data in returned page.
+ * @offs: Offset of data within @page and returned
+ * page holding encrypted data.
+ * @lblk_num: Logical block number. This must be unique for multiple
+ * calls with same inode, except when overwriting
+ * previously written data.
+ * @gfp_flags: The gfp flag for memory allocation
*
- * Allocates a ciphertext page and encrypts plaintext_page into it using the ctx
- * encryption context.
+ * Encrypts @page using the ctx encryption context. Performs encryption
+ * either in-place or into a newly allocated bounce page.
+ * Called on the page write path.
*
- * Called on the page write path. The caller must call
+ * Bounce page allocation is the default.
+ * In this case, the contents of @page are encrypted and stored in an
+ * allocated bounce page. @page has to be locked and the caller must call
* fscrypt_restore_control_page() on the returned ciphertext page to
* release the bounce buffer and the encryption context.
*
- * Return: An allocated page with the encrypted content on success. Else, an
+ * In-place encryption is used by setting the FS_CFLG_OWN_PAGES flag in
+ * fscrypt_operations. Here, the input-page is returned with its content
+ * encrypted.
+ *
+ * Return: A page with the encrypted content on success. Else, an
* error value or NULL.
*/
-struct page *fscrypt_encrypt_page(struct inode *inode,
- struct page *plaintext_page, gfp_t gfp_flags)
+struct page *fscrypt_encrypt_page(const struct inode *inode,
+ struct page *page,
+ unsigned int len,
+ unsigned int offs,
+ u64 lblk_num, gfp_t gfp_flags)
+
{
struct fscrypt_ctx *ctx;
- struct page *ciphertext_page = NULL;
+ struct page *ciphertext_page = page;
int err;
- BUG_ON(!PageLocked(plaintext_page));
+ BUG_ON(len % FS_CRYPTO_BLOCK_SIZE != 0);
+
+ if (inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES) {
+ /* with inplace-encryption we just encrypt the page */
+ err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num, page,
+ ciphertext_page, len, offs,
+ gfp_flags);
+ if (err)
+ return ERR_PTR(err);
+
+ return ciphertext_page;
+ }
+
+ BUG_ON(!PageLocked(page));
ctx = fscrypt_get_ctx(inode, gfp_flags);
if (IS_ERR(ctx))
return (struct page *)ctx;
/* The encryption operation will require a bounce page. */
- ciphertext_page = alloc_bounce_page(ctx, gfp_flags);
+ ciphertext_page = fscrypt_alloc_bounce_page(ctx, gfp_flags);
if (IS_ERR(ciphertext_page))
goto errout;
- ctx->w.control_page = plaintext_page;
- err = do_page_crypto(inode, FS_ENCRYPT, plaintext_page->index,
- plaintext_page, ciphertext_page,
- gfp_flags);
+ ctx->w.control_page = page;
+ err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num,
+ page, ciphertext_page, len, offs,
+ gfp_flags);
if (err) {
ciphertext_page = ERR_PTR(err);
goto errout;
@@ -266,8 +281,13 @@
EXPORT_SYMBOL(fscrypt_encrypt_page);
/**
- * f2crypt_decrypt_page() - Decrypts a page in-place
- * @page: The page to decrypt. Must be locked.
+ * fscrypt_decrypt_page() - Decrypts a page in-place
+ * @inode: The corresponding inode for the page to decrypt.
+ * @page: The page to decrypt. Must be locked in case
+ * it is a writeback page (FS_CFLG_OWN_PAGES unset).
+ * @len: Number of bytes in @page to be decrypted.
+ * @offs: Start of data in @page.
+ * @lblk_num: Logical block number.
*
* Decrypts page in-place using the ctx encryption context.
*
@@ -275,76 +295,17 @@
*
* Return: Zero on success, non-zero otherwise.
*/
-int fscrypt_decrypt_page(struct page *page)
+int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
+ unsigned int len, unsigned int offs, u64 lblk_num)
{
- BUG_ON(!PageLocked(page));
+ if (!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES))
+ BUG_ON(!PageLocked(page));
- return do_page_crypto(page->mapping->host,
- FS_DECRYPT, page->index, page, page, GFP_NOFS);
+ return fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page,
+ len, offs, GFP_NOFS);
}
EXPORT_SYMBOL(fscrypt_decrypt_page);
-int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk,
- sector_t pblk, unsigned int len)
-{
- struct fscrypt_ctx *ctx;
- struct page *ciphertext_page = NULL;
- struct bio *bio;
- int ret, err = 0;
-
- BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE);
-
- ctx = fscrypt_get_ctx(inode, GFP_NOFS);
- if (IS_ERR(ctx))
- return PTR_ERR(ctx);
-
- ciphertext_page = alloc_bounce_page(ctx, GFP_NOWAIT);
- if (IS_ERR(ciphertext_page)) {
- err = PTR_ERR(ciphertext_page);
- goto errout;
- }
-
- while (len--) {
- err = do_page_crypto(inode, FS_ENCRYPT, lblk,
- ZERO_PAGE(0), ciphertext_page,
- GFP_NOFS);
- if (err)
- goto errout;
-
- bio = bio_alloc(GFP_NOWAIT, 1);
- if (!bio) {
- err = -ENOMEM;
- goto errout;
- }
- bio->bi_bdev = inode->i_sb->s_bdev;
- bio->bi_iter.bi_sector =
- pblk << (inode->i_sb->s_blocksize_bits - 9);
- bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
- ret = bio_add_page(bio, ciphertext_page,
- inode->i_sb->s_blocksize, 0);
- if (ret != inode->i_sb->s_blocksize) {
- /* should never happen! */
- WARN_ON(1);
- bio_put(bio);
- err = -EIO;
- goto errout;
- }
- err = submit_bio_wait(bio);
- if ((err == 0) && bio->bi_error)
- err = -EIO;
- bio_put(bio);
- if (err)
- goto errout;
- lblk++;
- pblk++;
- }
- err = 0;
-errout:
- fscrypt_release_ctx(ctx);
- return err;
-}
-EXPORT_SYMBOL(fscrypt_zeroout_range);
-
/*
* Validate dentries for encrypted directories to make sure we aren't
* potentially caching stale data after a key has been added or
@@ -359,7 +320,7 @@
return -ECHILD;
dir = dget_parent(dentry);
- if (!d_inode(dir)->i_sb->s_cop->is_encrypted(d_inode(dir))) {
+ if (!IS_ENCRYPTED(d_inode(dir))) {
dput(dir);
return 0;
}
@@ -393,67 +354,6 @@
};
EXPORT_SYMBOL(fscrypt_d_ops);
-/*
- * Call fscrypt_decrypt_page on every single page, reusing the encryption
- * context.
- */
-static void completion_pages(struct work_struct *work)
-{
- struct fscrypt_ctx *ctx =
- container_of(work, struct fscrypt_ctx, r.work);
- struct bio *bio = ctx->r.bio;
- struct bio_vec *bv;
- int i;
-
- bio_for_each_segment_all(bv, bio, i) {
- struct page *page = bv->bv_page;
- if (ext4_is_ice_enabled())
- SetPageUptodate(page);
- else {
- int ret = fscrypt_decrypt_page(page);
-
- if (ret) {
- WARN_ON_ONCE(1);
- SetPageError(page);
- } else {
- SetPageUptodate(page);
- }
- }
- unlock_page(page);
- }
- fscrypt_release_ctx(ctx);
- bio_put(bio);
-}
-
-void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio)
-{
- INIT_WORK(&ctx->r.work, completion_pages);
- ctx->r.bio = bio;
- queue_work(fscrypt_read_workqueue, &ctx->r.work);
-}
-EXPORT_SYMBOL(fscrypt_decrypt_bio_pages);
-
-void fscrypt_pullback_bio_page(struct page **page, bool restore)
-{
- struct fscrypt_ctx *ctx;
- struct page *bounce_page;
-
- /* The bounce data pages are unmapped. */
- if ((*page)->mapping)
- return;
-
- /* The bounce data page is unmapped. */
- bounce_page = *page;
- ctx = (struct fscrypt_ctx *)page_private(bounce_page);
-
- /* restore control page */
- *page = ctx->w.control_page;
-
- if (restore)
- fscrypt_restore_control_page(bounce_page);
-}
-EXPORT_SYMBOL(fscrypt_pullback_bio_page);
-
void fscrypt_restore_control_page(struct page *page)
{
struct fscrypt_ctx *ctx;
@@ -479,16 +379,21 @@
/**
* fscrypt_initialize() - allocate major buffers for fs encryption.
+ * @cop_flags: fscrypt operations flags
*
* We only call this when we start accessing encrypted files, since it
* results in memory getting allocated that wouldn't otherwise be used.
*
* Return: Zero on success, non-zero otherwise.
*/
-int fscrypt_initialize(void)
+int fscrypt_initialize(unsigned int cop_flags)
{
int i, res = -ENOMEM;
+ /* No need to allocate a bounce page pool if this FS won't use it. */
+ if (cop_flags & FS_CFLG_OWN_PAGES)
+ return 0;
+
mutex_lock(&fscrypt_init_mutex);
if (fscrypt_bounce_page_pool)
goto already_initialized;
@@ -515,7 +420,6 @@
mutex_unlock(&fscrypt_init_mutex);
return res;
}
-EXPORT_SYMBOL(fscrypt_initialize);
/**
* fscrypt_init() - Set up for fs encryption.
@@ -557,6 +461,8 @@
destroy_workqueue(fscrypt_read_workqueue);
kmem_cache_destroy(fscrypt_ctx_cachep);
kmem_cache_destroy(fscrypt_info_cachep);
+
+ fscrypt_essiv_cleanup();
}
module_exit(fscrypt_exit);
diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
index e14bb7b..6eb4343 100644
--- a/fs/crypto/fname.c
+++ b/fs/crypto/fname.c
@@ -12,22 +12,7 @@
#include <linux/scatterlist.h>
#include <linux/ratelimit.h>
-#include <linux/fscrypto.h>
-
-/**
- * fname_crypt_complete() - completion callback for filename crypto
- * @req: The asynchronous cipher request context
- * @res: The result of the cipher operation
- */
-static void fname_crypt_complete(struct crypto_async_request *req, int res)
-{
- struct fscrypt_completion_result *ecr = req->data;
-
- if (res == -EINPROGRESS)
- return;
- ecr->res = res;
- complete(&ecr->completion);
-}
+#include "fscrypt_private.h"
/**
* fname_encrypt() - encrypt a filename
@@ -40,7 +25,7 @@
const struct qstr *iname, struct fscrypt_str *oname)
{
struct skcipher_request *req = NULL;
- DECLARE_FS_COMPLETION_RESULT(ecr);
+ DECLARE_CRYPTO_WAIT(wait);
struct fscrypt_info *ci = inode->i_crypt_info;
struct crypto_skcipher *tfm = ci->ci_ctfm;
int res = 0;
@@ -76,17 +61,12 @@
}
skcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
- fname_crypt_complete, &ecr);
+ crypto_req_done, &wait);
sg_init_one(&sg, oname->name, cryptlen);
skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv);
/* Do the encryption */
- res = crypto_skcipher_encrypt(req);
- if (res == -EINPROGRESS || res == -EBUSY) {
- /* Request is being completed asynchronously; wait for it */
- wait_for_completion(&ecr.completion);
- res = ecr.res;
- }
+ res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
skcipher_request_free(req);
if (res < 0) {
printk_ratelimited(KERN_ERR
@@ -110,7 +90,7 @@
struct fscrypt_str *oname)
{
struct skcipher_request *req = NULL;
- DECLARE_FS_COMPLETION_RESULT(ecr);
+ DECLARE_CRYPTO_WAIT(wait);
struct scatterlist src_sg, dst_sg;
struct fscrypt_info *ci = inode->i_crypt_info;
struct crypto_skcipher *tfm = ci->ci_ctfm;
@@ -131,7 +111,7 @@
}
skcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
- fname_crypt_complete, &ecr);
+ crypto_req_done, &wait);
/* Initialize IV */
memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
@@ -140,11 +120,7 @@
sg_init_one(&src_sg, iname->name, iname->len);
sg_init_one(&dst_sg, oname->name, oname->len);
skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv);
- res = crypto_skcipher_decrypt(req);
- if (res == -EINPROGRESS || res == -EBUSY) {
- wait_for_completion(&ecr.completion);
- res = ecr.res;
- }
+ res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
skcipher_request_free(req);
if (res < 0) {
printk_ratelimited(KERN_ERR
@@ -159,6 +135,8 @@
static const char *lookup_table =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
+#define BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
+
/**
* digest_encode() -
*
@@ -209,7 +187,7 @@
return cp - dst;
}
-u32 fscrypt_fname_encrypted_size(struct inode *inode, u32 ilen)
+u32 fscrypt_fname_encrypted_size(const struct inode *inode, u32 ilen)
{
int padding = 32;
struct fscrypt_info *ci = inode->i_crypt_info;
@@ -227,14 +205,17 @@
* Allocates an output buffer that is sufficient for the crypto operation
* specified by the context and the direction.
*/
-int fscrypt_fname_alloc_buffer(struct inode *inode,
+int fscrypt_fname_alloc_buffer(const struct inode *inode,
u32 ilen, struct fscrypt_str *crypto_str)
{
- unsigned int olen = fscrypt_fname_encrypted_size(inode, ilen);
+ u32 olen = fscrypt_fname_encrypted_size(inode, ilen);
+ const u32 max_encoded_len =
+ max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE),
+ 1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)));
crypto_str->len = olen;
- if (olen < FS_FNAME_CRYPTO_DIGEST_SIZE * 2)
- olen = FS_FNAME_CRYPTO_DIGEST_SIZE * 2;
+ olen = max(olen, max_encoded_len);
+
/*
* Allocated buffer can hold one more character to null-terminate the
* string
@@ -266,6 +247,10 @@
*
* The caller must have allocated sufficient memory for the @oname string.
*
+ * If the key is available, we'll decrypt the disk name; otherwise, we'll encode
+ * it for presentation. Short names are directly base64-encoded, while long
+ * names are encoded in fscrypt_digested_name format.
+ *
* Return: 0 on success, -errno on failure
*/
int fscrypt_fname_disk_to_usr(struct inode *inode,
@@ -274,7 +259,7 @@
struct fscrypt_str *oname)
{
const struct qstr qname = FSTR_TO_QSTR(iname);
- char buf[24];
+ struct fscrypt_digested_name digested_name;
if (fscrypt_is_dot_dotdot(&qname)) {
oname->name[0] = '.';
@@ -289,20 +274,24 @@
if (inode->i_crypt_info)
return fname_decrypt(inode, iname, oname);
- if (iname->len <= FS_FNAME_CRYPTO_DIGEST_SIZE) {
+ if (iname->len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE) {
oname->len = digest_encode(iname->name, iname->len,
oname->name);
return 0;
}
if (hash) {
- memcpy(buf, &hash, 4);
- memcpy(buf + 4, &minor_hash, 4);
+ digested_name.hash = hash;
+ digested_name.minor_hash = minor_hash;
} else {
- memset(buf, 0, 8);
+ digested_name.hash = 0;
+ digested_name.minor_hash = 0;
}
- memcpy(buf + 8, iname->name + ((iname->len - 17) & ~15), 16);
+ memcpy(digested_name.digest,
+ FSCRYPT_FNAME_DIGEST(iname->name, iname->len),
+ FSCRYPT_FNAME_DIGEST_SIZE);
oname->name[0] = '_';
- oname->len = 1 + digest_encode(buf, 24, oname->name + 1);
+ oname->len = 1 + digest_encode((const char *)&digested_name,
+ sizeof(digested_name), oname->name + 1);
return 0;
}
EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
@@ -336,16 +325,40 @@
}
EXPORT_SYMBOL(fscrypt_fname_usr_to_disk);
+/**
+ * fscrypt_setup_filename() - prepare to search a possibly encrypted directory
+ * @dir: the directory that will be searched
+ * @iname: the user-provided filename being searched for
+ * @lookup: 1 if we're allowed to proceed without the key because it's
+ * ->lookup() or we're finding the dir_entry for deletion; 0 if we cannot
+ * proceed without the key because we're going to create the dir_entry.
+ * @fname: the filename information to be filled in
+ *
+ * Given a user-provided filename @iname, this function sets @fname->disk_name
+ * to the name that would be stored in the on-disk directory entry, if possible.
+ * If the directory is unencrypted this is simply @iname. Else, if we have the
+ * directory's encryption key, then @iname is the plaintext, so we encrypt it to
+ * get the disk_name.
+ *
+ * Else, for keyless @lookup operations, @iname is the presented ciphertext, so
+ * we decode it to get either the ciphertext disk_name (for short names) or the
+ * fscrypt_digested_name (for long names). Non-@lookup operations will be
+ * impossible in this case, so we fail them with ENOKEY.
+ *
+ * If successful, fscrypt_free_filename() must be called later to clean up.
+ *
+ * Return: 0 on success, -errno on failure
+ */
int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
int lookup, struct fscrypt_name *fname)
{
- int ret = 0, bigname = 0;
+ int ret;
+ int digested;
memset(fname, 0, sizeof(struct fscrypt_name));
fname->usr_fname = iname;
- if (!dir->i_sb->s_cop->is_encrypted(dir) ||
- fscrypt_is_dot_dotdot(iname)) {
+ if (!IS_ENCRYPTED(dir) || fscrypt_is_dot_dotdot(iname)) {
fname->disk_name.name = (unsigned char *)iname->name;
fname->disk_name.len = iname->len;
return 0;
@@ -373,25 +386,37 @@
* We don't have the key and we are doing a lookup; decode the
* user-supplied name
*/
- if (iname->name[0] == '_')
- bigname = 1;
- if ((bigname && (iname->len != 33)) || (!bigname && (iname->len > 43)))
- return -ENOENT;
+ if (iname->name[0] == '_') {
+ if (iname->len !=
+ 1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)))
+ return -ENOENT;
+ digested = 1;
+ } else {
+ if (iname->len >
+ BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE))
+ return -ENOENT;
+ digested = 0;
+ }
- fname->crypto_buf.name = kmalloc(32, GFP_KERNEL);
+ fname->crypto_buf.name =
+ kmalloc(max_t(size_t, FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE,
+ sizeof(struct fscrypt_digested_name)),
+ GFP_KERNEL);
if (fname->crypto_buf.name == NULL)
return -ENOMEM;
- ret = digest_decode(iname->name + bigname, iname->len - bigname,
+ ret = digest_decode(iname->name + digested, iname->len - digested,
fname->crypto_buf.name);
if (ret < 0) {
ret = -ENOENT;
goto errout;
}
fname->crypto_buf.len = ret;
- if (bigname) {
- memcpy(&fname->hash, fname->crypto_buf.name, 4);
- memcpy(&fname->minor_hash, fname->crypto_buf.name + 4, 4);
+ if (digested) {
+ const struct fscrypt_digested_name *n =
+ (const void *)fname->crypto_buf.name;
+ fname->hash = n->hash;
+ fname->minor_hash = n->minor_hash;
} else {
fname->disk_name.name = fname->crypto_buf.name;
fname->disk_name.len = fname->crypto_buf.len;
@@ -403,12 +428,3 @@
return ret;
}
EXPORT_SYMBOL(fscrypt_setup_filename);
-
-void fscrypt_free_filename(struct fscrypt_name *fname)
-{
- kfree(fname->crypto_buf.name);
- fname->crypto_buf.name = NULL;
- fname->usr_fname = NULL;
- fname->disk_name.name = NULL;
-}
-EXPORT_SYMBOL(fscrypt_free_filename);
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
new file mode 100644
index 0000000..4688a64
--- /dev/null
+++ b/fs/crypto/fscrypt_private.h
@@ -0,0 +1,88 @@
+/*
+ * fscrypt_private.h
+ *
+ * Copyright (C) 2015, Google, Inc.
+ *
+ * This contains encryption key functions.
+ *
+ * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015.
+ */
+
+#ifndef _FSCRYPT_PRIVATE_H
+#define _FSCRYPT_PRIVATE_H
+
+#define __FS_HAS_ENCRYPTION 1
+#include <linux/fscrypt.h>
+#include <crypto/hash.h>
+
+/* Encryption parameters */
+#define FS_IV_SIZE 16
+#define FS_AES_128_ECB_KEY_SIZE 16
+#define FS_AES_128_CBC_KEY_SIZE 16
+#define FS_AES_128_CTS_KEY_SIZE 16
+#define FS_AES_256_GCM_KEY_SIZE 32
+#define FS_AES_256_CBC_KEY_SIZE 32
+#define FS_AES_256_CTS_KEY_SIZE 32
+#define FS_AES_256_XTS_KEY_SIZE 64
+
+#define FS_KEY_DERIVATION_NONCE_SIZE 16
+
+/**
+ * Encryption context for inode
+ *
+ * Protector format:
+ * 1 byte: Protector format (1 = this version)
+ * 1 byte: File contents encryption mode
+ * 1 byte: File names encryption mode
+ * 1 byte: Flags
+ * 8 bytes: Master Key descriptor
+ * 16 bytes: Encryption Key derivation nonce
+ */
+struct fscrypt_context {
+ u8 format;
+ u8 contents_encryption_mode;
+ u8 filenames_encryption_mode;
+ u8 flags;
+ u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
+ u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
+} __packed;
+
+#define FS_ENCRYPTION_CONTEXT_FORMAT_V1 1
+
+/*
+ * A pointer to this structure is stored in the file system's in-core
+ * representation of an inode.
+ */
+struct fscrypt_info {
+ u8 ci_data_mode;
+ u8 ci_filename_mode;
+ u8 ci_flags;
+ struct crypto_skcipher *ci_ctfm;
+ struct crypto_cipher *ci_essiv_tfm;
+ u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE];
+};
+
+typedef enum {
+ FS_DECRYPT = 0,
+ FS_ENCRYPT,
+} fscrypt_direction_t;
+
+#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001
+#define FS_CTX_HAS_BOUNCE_BUFFER_FL 0x00000002
+
+/* crypto.c */
+extern int fscrypt_initialize(unsigned int cop_flags);
+extern struct workqueue_struct *fscrypt_read_workqueue;
+extern int fscrypt_do_page_crypto(const struct inode *inode,
+ fscrypt_direction_t rw, u64 lblk_num,
+ struct page *src_page,
+ struct page *dest_page,
+ unsigned int len, unsigned int offs,
+ gfp_t gfp_flags);
+extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx,
+ gfp_t gfp_flags);
+
+/* keyinfo.c */
+extern void __exit fscrypt_essiv_cleanup(void);
+
+#endif /* _FSCRYPT_PRIVATE_H */
diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c
new file mode 100644
index 0000000..9f5fb2e
--- /dev/null
+++ b/fs/crypto/hooks.c
@@ -0,0 +1,112 @@
+/*
+ * fs/crypto/hooks.c
+ *
+ * Encryption hooks for higher-level filesystem operations.
+ */
+
+#include <linux/ratelimit.h>
+#include "fscrypt_private.h"
+
+/**
+ * fscrypt_file_open - prepare to open a possibly-encrypted regular file
+ * @inode: the inode being opened
+ * @filp: the struct file being set up
+ *
+ * Currently, an encrypted regular file can only be opened if its encryption key
+ * is available; access to the raw encrypted contents is not supported.
+ * Therefore, we first set up the inode's encryption key (if not already done)
+ * and return an error if it's unavailable.
+ *
+ * We also verify that if the parent directory (from the path via which the file
+ * is being opened) is encrypted, then the inode being opened uses the same
+ * encryption policy. This is needed as part of the enforcement that all files
+ * in an encrypted directory tree use the same encryption policy, as a
+ * protection against certain types of offline attacks. Note that this check is
+ * needed even when opening an *unencrypted* file, since it's forbidden to have
+ * an unencrypted file in an encrypted directory.
+ *
+ * Return: 0 on success, -ENOKEY if the key is missing, or another -errno code
+ */
+int fscrypt_file_open(struct inode *inode, struct file *filp)
+{
+ int err;
+ struct dentry *dir;
+
+ err = fscrypt_require_key(inode);
+ if (err)
+ return err;
+
+ dir = dget_parent(file_dentry(filp));
+ if (IS_ENCRYPTED(d_inode(dir)) &&
+ !fscrypt_has_permitted_context(d_inode(dir), inode)) {
+ pr_warn_ratelimited("fscrypt: inconsistent encryption contexts: %lu/%lu",
+ d_inode(dir)->i_ino, inode->i_ino);
+ err = -EPERM;
+ }
+ dput(dir);
+ return err;
+}
+EXPORT_SYMBOL_GPL(fscrypt_file_open);
+
+int __fscrypt_prepare_link(struct inode *inode, struct inode *dir)
+{
+ int err;
+
+ err = fscrypt_require_key(dir);
+ if (err)
+ return err;
+
+ if (!fscrypt_has_permitted_context(dir, inode))
+ return -EPERM;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__fscrypt_prepare_link);
+
+int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
+{
+ int err;
+
+ err = fscrypt_require_key(old_dir);
+ if (err)
+ return err;
+
+ err = fscrypt_require_key(new_dir);
+ if (err)
+ return err;
+
+ if (old_dir != new_dir) {
+ if (IS_ENCRYPTED(new_dir) &&
+ !fscrypt_has_permitted_context(new_dir,
+ d_inode(old_dentry)))
+ return -EPERM;
+
+ if ((flags & RENAME_EXCHANGE) &&
+ IS_ENCRYPTED(old_dir) &&
+ !fscrypt_has_permitted_context(old_dir,
+ d_inode(new_dentry)))
+ return -EPERM;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__fscrypt_prepare_rename);
+
+int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry)
+{
+ int err = fscrypt_get_encryption_info(dir);
+
+ if (err)
+ return err;
+
+ if (fscrypt_has_encryption_key(dir)) {
+ spin_lock(&dentry->d_lock);
+ dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY;
+ spin_unlock(&dentry->d_lock);
+ }
+
+ d_set_d_op(dentry, &fscrypt_d_ops);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);
diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
index 106e55c..c891d2e 100644
--- a/fs/crypto/keyinfo.c
+++ b/fs/crypto/keyinfo.c
@@ -10,35 +10,28 @@
#include <keys/user-type.h>
#include <linux/scatterlist.h>
-#include <linux/fscrypto.h>
-#include "ext4_ice.h"
+#include <linux/ratelimit.h>
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include "fscrypt_private.h"
-static void derive_crypt_complete(struct crypto_async_request *req, int rc)
-{
- struct fscrypt_completion_result *ecr = req->data;
-
- if (rc == -EINPROGRESS)
- return;
-
- ecr->res = rc;
- complete(&ecr->completion);
-}
+static struct crypto_shash *essiv_hash_tfm;
/**
* derive_key_aes() - Derive a key using AES-128-ECB
* @deriving_key: Encryption key used for derivation.
* @source_key: Source key to which to apply derivation.
- * @derived_key: Derived key.
+ * @derived_raw_key: Derived raw key.
*
* Return: Zero on success; non-zero otherwise.
*/
static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE],
- u8 source_key[FS_AES_256_XTS_KEY_SIZE],
- u8 derived_key[FS_AES_256_XTS_KEY_SIZE])
+ const struct fscrypt_key *source_key,
+ u8 derived_raw_key[FS_MAX_KEY_SIZE])
{
int res = 0;
struct skcipher_request *req = NULL;
- DECLARE_FS_COMPLETION_RESULT(ecr);
+ DECLARE_CRYPTO_WAIT(wait);
struct scatterlist src_sg, dst_sg;
struct crypto_skcipher *tfm = crypto_alloc_skcipher("ecb(aes)", 0, 0);
@@ -55,21 +48,17 @@
}
skcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
- derive_crypt_complete, &ecr);
+ crypto_req_done, &wait);
res = crypto_skcipher_setkey(tfm, deriving_key,
FS_AES_128_ECB_KEY_SIZE);
if (res < 0)
goto out;
- sg_init_one(&src_sg, source_key, FS_AES_256_XTS_KEY_SIZE);
- sg_init_one(&dst_sg, derived_key, FS_AES_256_XTS_KEY_SIZE);
- skcipher_request_set_crypt(req, &src_sg, &dst_sg,
- FS_AES_256_XTS_KEY_SIZE, NULL);
- res = crypto_skcipher_encrypt(req);
- if (res == -EINPROGRESS || res == -EBUSY) {
- wait_for_completion(&ecr.completion);
- res = ecr.res;
- }
+ sg_init_one(&src_sg, source_key->raw, source_key->size);
+ sg_init_one(&dst_sg, derived_raw_key, source_key->size);
+ skcipher_request_set_crypt(req, &src_sg, &dst_sg, source_key->size,
+ NULL);
+ res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
out:
skcipher_request_free(req);
crypto_free_skcipher(tfm);
@@ -78,26 +67,22 @@
static int validate_user_key(struct fscrypt_info *crypt_info,
struct fscrypt_context *ctx, u8 *raw_key,
- u8 *prefix, int prefix_size)
+ const char *prefix, int min_keysize)
{
- u8 *full_key_descriptor;
+ char *description;
struct key *keyring_key;
struct fscrypt_key *master_key;
const struct user_key_payload *ukp;
- int full_key_len = prefix_size + (FS_KEY_DESCRIPTOR_SIZE * 2) + 1;
int res;
- full_key_descriptor = kmalloc(full_key_len, GFP_NOFS);
- if (!full_key_descriptor)
+ description = kasprintf(GFP_NOFS, "%s%*phN", prefix,
+ FS_KEY_DESCRIPTOR_SIZE,
+ ctx->master_key_descriptor);
+ if (!description)
return -ENOMEM;
- memcpy(full_key_descriptor, prefix, prefix_size);
- sprintf(full_key_descriptor + prefix_size,
- "%*phN", FS_KEY_DESCRIPTOR_SIZE,
- ctx->master_key_descriptor);
- full_key_descriptor[full_key_len - 1] = '\0';
- keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL);
- kfree(full_key_descriptor);
+ keyring_key = request_key(&key_type_logon, description, NULL);
+ kfree(description);
if (IS_ERR(keyring_key))
return PTR_ERR(keyring_key);
down_read(&keyring_key->sem);
@@ -108,7 +93,7 @@
res = -ENOKEY;
goto out;
}
- ukp = user_key_payload(keyring_key);
+ ukp = user_key_payload_locked(keyring_key);
if (!ukp) {
/* key was revoked before we acquired its semaphore */
res = -EKEYREVOKED;
@@ -121,55 +106,60 @@
master_key = (struct fscrypt_key *)ukp->data;
BUILD_BUG_ON(FS_AES_128_ECB_KEY_SIZE != FS_KEY_DERIVATION_NONCE_SIZE);
- if (master_key->size != FS_AES_256_XTS_KEY_SIZE) {
+ if (master_key->size < min_keysize || master_key->size > FS_MAX_KEY_SIZE
+ || master_key->size % AES_BLOCK_SIZE != 0) {
printk_once(KERN_WARNING
"%s: key size incorrect: %d\n",
__func__, master_key->size);
res = -ENOKEY;
goto out;
}
- res = derive_key_aes(ctx->nonce, master_key->raw, raw_key);
+ res = derive_key_aes(ctx->nonce, master_key, raw_key);
out:
up_read(&keyring_key->sem);
key_put(keyring_key);
return res;
}
+static const struct {
+ const char *cipher_str;
+ int keysize;
+} available_modes[] = {
+ [FS_ENCRYPTION_MODE_AES_256_XTS] = { "xts(aes)",
+ FS_AES_256_XTS_KEY_SIZE },
+ [FS_ENCRYPTION_MODE_AES_256_CTS] = { "cts(cbc(aes))",
+ FS_AES_256_CTS_KEY_SIZE },
+ [FS_ENCRYPTION_MODE_AES_128_CBC] = { "cbc(aes)",
+ FS_AES_128_CBC_KEY_SIZE },
+ [FS_ENCRYPTION_MODE_AES_128_CTS] = { "cts(cbc(aes))",
+ FS_AES_128_CTS_KEY_SIZE },
+};
+
static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode,
- const char **cipher_str_ret, int *keysize_ret, int *fname)
+ const char **cipher_str_ret, int *keysize_ret)
{
+ u32 mode;
+
+ if (!fscrypt_valid_enc_modes(ci->ci_data_mode, ci->ci_filename_mode)) {
+ pr_warn_ratelimited("fscrypt: inode %lu uses unsupported encryption modes (contents mode %d, filenames mode %d)\n",
+ inode->i_ino,
+ ci->ci_data_mode, ci->ci_filename_mode);
+ return -EINVAL;
+ }
+
if (S_ISREG(inode->i_mode)) {
- if (ci->ci_data_mode == FS_ENCRYPTION_MODE_AES_256_XTS) {
- *cipher_str_ret = "xts(aes)";
- *keysize_ret = FS_AES_256_XTS_KEY_SIZE;
- return 0;
- } else if (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE) {
- *cipher_str_ret = "bugon";
- *keysize_ret = FS_AES_256_XTS_KEY_SIZE;
- return 0;
- }
- pr_warn_once("fscrypto: unsupported contents encryption mode "
- "%d for inode %lu\n",
- ci->ci_data_mode, inode->i_ino);
- return -ENOKEY;
+ mode = ci->ci_data_mode;
+ } else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) {
+ mode = ci->ci_filename_mode;
+ } else {
+ WARN_ONCE(1, "fscrypt: filesystem tried to load encryption info for inode %lu, which is not encryptable (file type %d)\n",
+ inode->i_ino, (inode->i_mode & S_IFMT));
+ return -EINVAL;
}
- if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) {
- if (ci->ci_filename_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
- *cipher_str_ret = "cts(cbc(aes))";
- *keysize_ret = FS_AES_256_CTS_KEY_SIZE;
- *fname = 1;
- return 0;
- }
- pr_warn_once("fscrypto: unsupported filenames encryption mode "
- "%d for inode %lu\n",
- ci->ci_filename_mode, inode->i_ino);
- return -ENOKEY;
- }
-
- pr_warn_once("fscrypto: unsupported file type %d for inode %lu\n",
- (inode->i_mode & S_IFMT), inode->i_ino);
- return -ENOKEY;
+ *cipher_str_ret = available_modes[mode].cipher_str;
+ *keysize_ret = available_modes[mode].keysize;
+ return 0;
}
static void put_crypt_info(struct fscrypt_info *ci)
@@ -178,25 +168,75 @@
return;
crypto_free_skcipher(ci->ci_ctfm);
- memzero_explicit(ci->ci_raw_key,
- sizeof(ci->ci_raw_key));
+ crypto_free_cipher(ci->ci_essiv_tfm);
kmem_cache_free(fscrypt_info_cachep, ci);
}
-static int fs_data_encryption_mode(void)
+static int derive_essiv_salt(const u8 *key, int keysize, u8 *salt)
{
- return ext4_is_ice_enabled() ? FS_ENCRYPTION_MODE_PRIVATE :
- FS_ENCRYPTION_MODE_AES_256_XTS;
+ struct crypto_shash *tfm = READ_ONCE(essiv_hash_tfm);
+
+ /* init hash transform on demand */
+ if (unlikely(!tfm)) {
+ struct crypto_shash *prev_tfm;
+
+ tfm = crypto_alloc_shash("sha256", 0, 0);
+ if (IS_ERR(tfm)) {
+ pr_warn_ratelimited("fscrypt: error allocating SHA-256 transform: %ld\n",
+ PTR_ERR(tfm));
+ return PTR_ERR(tfm);
+ }
+ prev_tfm = cmpxchg(&essiv_hash_tfm, NULL, tfm);
+ if (prev_tfm) {
+ crypto_free_shash(tfm);
+ tfm = prev_tfm;
+ }
+ }
+
+ {
+ SHASH_DESC_ON_STACK(desc, tfm);
+ desc->tfm = tfm;
+ desc->flags = 0;
+
+ return crypto_shash_digest(desc, key, keysize, salt);
+ }
}
-int fs_using_hardware_encryption(struct inode *inode)
+static int init_essiv_generator(struct fscrypt_info *ci, const u8 *raw_key,
+ int keysize)
{
- struct fscrypt_info *ci = inode->i_crypt_info;
+ int err;
+ struct crypto_cipher *essiv_tfm;
+ u8 salt[SHA256_DIGEST_SIZE];
- return S_ISREG(inode->i_mode) && ci &&
- ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE;
+ essiv_tfm = crypto_alloc_cipher("aes", 0, 0);
+ if (IS_ERR(essiv_tfm))
+ return PTR_ERR(essiv_tfm);
+
+ ci->ci_essiv_tfm = essiv_tfm;
+
+ err = derive_essiv_salt(raw_key, keysize, salt);
+ if (err)
+ goto out;
+
+ /*
+ * Using SHA256 to derive the salt/key will result in AES-256 being
+ * used for IV generation. File contents encryption will still use the
+ * configured keysize (AES-128) nevertheless.
+ */
+ err = crypto_cipher_setkey(essiv_tfm, salt, sizeof(salt));
+ if (err)
+ goto out;
+
+out:
+ memzero_explicit(salt, sizeof(salt));
+ return err;
}
-EXPORT_SYMBOL(fs_using_hardware_encryption);
+
+void __exit fscrypt_essiv_cleanup(void)
+{
+ crypto_free_shash(essiv_hash_tfm);
+}
int fscrypt_get_encryption_info(struct inode *inode)
{
@@ -205,27 +245,27 @@
struct crypto_skcipher *ctfm;
const char *cipher_str;
int keysize;
+ u8 *raw_key = NULL;
int res;
- int fname = 0;
if (inode->i_crypt_info)
return 0;
- res = fscrypt_initialize();
+ res = fscrypt_initialize(inode->i_sb->s_cop->flags);
if (res)
return res;
- if (!inode->i_sb->s_cop->get_context)
- return -EOPNOTSUPP;
-
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
if (res < 0) {
- if (!fscrypt_dummy_context_enabled(inode))
+ if (!fscrypt_dummy_context_enabled(inode) ||
+ IS_ENCRYPTED(inode))
return res;
+ /* Fake up a context for an unencrypted directory */
+ memset(&ctx, 0, sizeof(ctx));
ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
- ctx.contents_encryption_mode = fs_data_encryption_mode();
+ ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
- ctx.flags = 0;
+ memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE);
} else if (res != sizeof(ctx)) {
return -EINVAL;
}
@@ -244,11 +284,11 @@
crypt_info->ci_data_mode = ctx.contents_encryption_mode;
crypt_info->ci_filename_mode = ctx.filenames_encryption_mode;
crypt_info->ci_ctfm = NULL;
+ crypt_info->ci_essiv_tfm = NULL;
memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
sizeof(crypt_info->ci_master_key));
- res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize,
- &fname);
+ res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize);
if (res)
goto out;
@@ -257,21 +297,16 @@
* crypto API as part of key derivation.
*/
res = -ENOMEM;
+ raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS);
+ if (!raw_key)
+ goto out;
- if (fscrypt_dummy_context_enabled(inode)) {
- memset(crypt_info->ci_raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
- goto got_key;
- }
-
- res = validate_user_key(crypt_info, &ctx, crypt_info->ci_raw_key,
- FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE);
+ res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX,
+ keysize);
if (res && inode->i_sb->s_cop->key_prefix) {
- u8 *prefix = NULL;
- int prefix_size, res2;
-
- prefix_size = inode->i_sb->s_cop->key_prefix(inode, &prefix);
- res2 = validate_user_key(crypt_info, &ctx,
- crypt_info->ci_raw_key, prefix, prefix_size);
+ int res2 = validate_user_key(crypt_info, &ctx, raw_key,
+ inode->i_sb->s_cop->key_prefix,
+ keysize);
if (res2) {
if (res2 == -ENOKEY)
res = -ENOKEY;
@@ -280,27 +315,32 @@
} else if (res) {
goto out;
}
-got_key:
- if (crypt_info->ci_data_mode != FS_ENCRYPTION_MODE_PRIVATE || fname) {
- ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
- if (!ctfm || IS_ERR(ctfm)) {
- res = ctfm ? PTR_ERR(ctfm) : -ENOMEM;
- pr_err("%s: error %d inode %u allocating crypto tfm\n",
- __func__, res, (unsigned int) inode->i_ino);
+ ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
+ if (!ctfm || IS_ERR(ctfm)) {
+ res = ctfm ? PTR_ERR(ctfm) : -ENOMEM;
+ pr_debug("%s: error %d (inode %lu) allocating crypto tfm\n",
+ __func__, res, inode->i_ino);
+ goto out;
+ }
+ crypt_info->ci_ctfm = ctfm;
+ crypto_skcipher_clear_flags(ctfm, ~0);
+ crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY);
+ /*
+ * if the provided key is longer than keysize, we use the first
+ * keysize bytes of the derived key only
+ */
+ res = crypto_skcipher_setkey(ctfm, raw_key, keysize);
+ if (res)
+ goto out;
+
+ if (S_ISREG(inode->i_mode) &&
+ crypt_info->ci_data_mode == FS_ENCRYPTION_MODE_AES_128_CBC) {
+ res = init_essiv_generator(crypt_info, raw_key, keysize);
+ if (res) {
+ pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n",
+ __func__, res, inode->i_ino);
goto out;
}
- crypt_info->ci_ctfm = ctfm;
- crypto_skcipher_clear_flags(ctfm, ~0);
- crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY);
- res = crypto_skcipher_setkey(ctfm, crypt_info->ci_raw_key,
- keysize);
- if (res)
- goto out;
- } else if (!ext4_is_ice_enabled()) {
- pr_warn("%s: ICE support not available\n",
- __func__);
- res = -EINVAL;
- goto out;
}
if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL)
crypt_info = NULL;
@@ -308,6 +348,7 @@
if (res == -ENOKEY)
res = 0;
put_crypt_info(crypt_info);
+ kzfree(raw_key);
return res;
}
EXPORT_SYMBOL(fscrypt_get_encryption_info);
diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
index c160d2d..2f2c53f 100644
--- a/fs/crypto/policy.c
+++ b/fs/crypto/policy.c
@@ -10,76 +10,37 @@
#include <linux/random.h>
#include <linux/string.h>
-#include <linux/fscrypto.h>
#include <linux/mount.h>
-
-static int inode_has_encryption_context(struct inode *inode)
-{
- if (!inode->i_sb->s_cop->get_context)
- return 0;
- return (inode->i_sb->s_cop->get_context(inode, NULL, 0L) > 0);
-}
+#include "fscrypt_private.h"
/*
- * check whether the policy is consistent with the encryption context
- * for the inode
+ * check whether an encryption policy is consistent with an encryption context
*/
-static int is_encryption_context_consistent_with_policy(struct inode *inode,
+static bool is_encryption_context_consistent_with_policy(
+ const struct fscrypt_context *ctx,
const struct fscrypt_policy *policy)
{
- struct fscrypt_context ctx;
- int res;
-
- if (!inode->i_sb->s_cop->get_context)
- return 0;
-
- res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
- if (res != sizeof(ctx))
- return 0;
-
- return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor,
- FS_KEY_DESCRIPTOR_SIZE) == 0 &&
- (ctx.flags == policy->flags) &&
- (ctx.contents_encryption_mode ==
- policy->contents_encryption_mode) &&
- (ctx.filenames_encryption_mode ==
- policy->filenames_encryption_mode));
+ return memcmp(ctx->master_key_descriptor, policy->master_key_descriptor,
+ FS_KEY_DESCRIPTOR_SIZE) == 0 &&
+ (ctx->flags == policy->flags) &&
+ (ctx->contents_encryption_mode ==
+ policy->contents_encryption_mode) &&
+ (ctx->filenames_encryption_mode ==
+ policy->filenames_encryption_mode);
}
static int create_encryption_context_from_policy(struct inode *inode,
const struct fscrypt_policy *policy)
{
struct fscrypt_context ctx;
- int res;
-
- if (!inode->i_sb->s_cop->set_context)
- return -EOPNOTSUPP;
-
- if (inode->i_sb->s_cop->prepare_context) {
- res = inode->i_sb->s_cop->prepare_context(inode);
- if (res)
- return res;
- }
ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
memcpy(ctx.master_key_descriptor, policy->master_key_descriptor,
FS_KEY_DESCRIPTOR_SIZE);
- if (!fscrypt_valid_contents_enc_mode(
- policy->contents_encryption_mode)) {
- printk(KERN_WARNING
- "%s: Invalid contents encryption mode %d\n", __func__,
- policy->contents_encryption_mode);
+ if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode,
+ policy->filenames_encryption_mode))
return -EINVAL;
- }
-
- if (!fscrypt_valid_filenames_enc_mode(
- policy->filenames_encryption_mode)) {
- printk(KERN_WARNING
- "%s: Invalid filenames encryption mode %d\n", __func__,
- policy->filenames_encryption_mode);
- return -EINVAL;
- }
if (policy->flags & ~FS_POLICY_FLAGS_VALID)
return -EINVAL;
@@ -93,16 +54,20 @@
return inode->i_sb->s_cop->set_context(inode, &ctx, sizeof(ctx), NULL);
}
-int fscrypt_process_policy(struct file *filp,
- const struct fscrypt_policy *policy)
+int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
{
+ struct fscrypt_policy policy;
struct inode *inode = file_inode(filp);
int ret;
+ struct fscrypt_context ctx;
+
+ if (copy_from_user(&policy, arg, sizeof(policy)))
+ return -EFAULT;
if (!inode_owner_or_capable(inode))
return -EACCES;
- if (policy->version != 0)
+ if (policy.version != 0)
return -EINVAL;
ret = mnt_want_write_file(filp);
@@ -111,22 +76,23 @@
inode_lock(inode);
- if (!inode_has_encryption_context(inode)) {
+ ret = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
+ if (ret == -ENODATA) {
if (!S_ISDIR(inode->i_mode))
ret = -ENOTDIR;
- else if (!inode->i_sb->s_cop->empty_dir)
- ret = -EOPNOTSUPP;
else if (!inode->i_sb->s_cop->empty_dir(inode))
ret = -ENOTEMPTY;
else
ret = create_encryption_context_from_policy(inode,
- policy);
- } else if (!is_encryption_context_consistent_with_policy(inode,
- policy)) {
- printk(KERN_WARNING
- "%s: Policy inconsistent with encryption context\n",
- __func__);
- ret = -EINVAL;
+ &policy);
+ } else if (ret == sizeof(ctx) &&
+ is_encryption_context_consistent_with_policy(&ctx,
+ &policy)) {
+ /* The file already uses the same encryption policy. */
+ ret = 0;
+ } else if (ret >= 0 || ret == -ERANGE) {
+ /* The file already uses a different encryption policy. */
+ ret = -EEXIST;
}
inode_unlock(inode);
@@ -134,32 +100,38 @@
mnt_drop_write_file(filp);
return ret;
}
-EXPORT_SYMBOL(fscrypt_process_policy);
+EXPORT_SYMBOL(fscrypt_ioctl_set_policy);
-int fscrypt_get_policy(struct inode *inode, struct fscrypt_policy *policy)
+int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg)
{
+ struct inode *inode = file_inode(filp);
struct fscrypt_context ctx;
+ struct fscrypt_policy policy;
int res;
- if (!inode->i_sb->s_cop->get_context ||
- !inode->i_sb->s_cop->is_encrypted(inode))
+ if (!IS_ENCRYPTED(inode))
return -ENODATA;
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
+ if (res < 0 && res != -ERANGE)
+ return res;
if (res != sizeof(ctx))
- return -ENODATA;
+ return -EINVAL;
if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1)
return -EINVAL;
- policy->version = 0;
- policy->contents_encryption_mode = ctx.contents_encryption_mode;
- policy->filenames_encryption_mode = ctx.filenames_encryption_mode;
- policy->flags = ctx.flags;
- memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor,
+ policy.version = 0;
+ policy.contents_encryption_mode = ctx.contents_encryption_mode;
+ policy.filenames_encryption_mode = ctx.filenames_encryption_mode;
+ policy.flags = ctx.flags;
+ memcpy(policy.master_key_descriptor, ctx.master_key_descriptor,
FS_KEY_DESCRIPTOR_SIZE);
+
+ if (copy_to_user(arg, &policy, sizeof(policy)))
+ return -EFAULT;
return 0;
}
-EXPORT_SYMBOL(fscrypt_get_policy);
+EXPORT_SYMBOL(fscrypt_ioctl_get_policy);
/**
* fscrypt_has_permitted_context() - is a file's encryption policy permitted
@@ -194,11 +166,11 @@
return 1;
/* No restrictions if the parent directory is unencrypted */
- if (!cops->is_encrypted(parent))
+ if (!IS_ENCRYPTED(parent))
return 1;
/* Encrypted directories must not contain unencrypted files */
- if (!cops->is_encrypted(child))
+ if (!IS_ENCRYPTED(child))
return 0;
/*
@@ -258,9 +230,9 @@
* @parent: Parent inode from which the context is inherited.
* @child: Child inode that inherits the context from @parent.
* @fs_data: private data given by FS.
- * @preload: preload child i_crypt_info
+ * @preload: preload child i_crypt_info if true
*
- * Return: Zero on success, non-zero otherwise
+ * Return: 0 on success, -errno on failure
*/
int fscrypt_inherit_context(struct inode *parent, struct inode *child,
void *fs_data, bool preload)
@@ -269,9 +241,6 @@
struct fscrypt_info *ci;
int res;
- if (!parent->i_sb->s_cop->set_context)
- return -EOPNOTSUPP;
-
res = fscrypt_get_encryption_info(parent);
if (res < 0)
return res;
@@ -281,19 +250,11 @@
return -ENOKEY;
ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
- if (fscrypt_dummy_context_enabled(parent)) {
- ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
- ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
- ctx.flags = 0;
- memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE);
- res = 0;
- } else {
- ctx.contents_encryption_mode = ci->ci_data_mode;
- ctx.filenames_encryption_mode = ci->ci_filename_mode;
- ctx.flags = ci->ci_flags;
- memcpy(ctx.master_key_descriptor, ci->ci_master_key,
- FS_KEY_DESCRIPTOR_SIZE);
- }
+ ctx.contents_encryption_mode = ci->ci_data_mode;
+ ctx.filenames_encryption_mode = ci->ci_filename_mode;
+ ctx.flags = ci->ci_flags;
+ memcpy(ctx.master_key_descriptor, ci->ci_master_key,
+ FS_KEY_DESCRIPTOR_SIZE);
get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);
res = parent->i_sb->s_cop->set_context(child, &ctx,
sizeof(ctx), fs_data);
diff --git a/fs/direct-io.c b/fs/direct-io.c
index bf03a92..c6220a2 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -411,7 +411,6 @@
if (dio->is_async && dio->op == REQ_OP_READ && dio->should_dirty)
bio_set_pages_dirty(bio);
- bio->bi_dio_inode = dio->inode;
dio->bio_bdev = bio->bi_bdev;
if (sdio->submit_io) {
@@ -425,18 +424,6 @@
sdio->logical_offset_in_bio = 0;
}
-struct inode *dio_bio_get_inode(struct bio *bio)
-{
- struct inode *inode = NULL;
-
- if (bio == NULL)
- return NULL;
-
- inode = bio->bi_dio_inode;
-
- return inode;
-}
-EXPORT_SYMBOL(dio_bio_get_inode);
/*
* Release any resources in case of a failure
*/
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index a896e46..d4d8ad1 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -125,7 +125,7 @@
if (auth_tok)
return auth_tok;
- ukp = user_key_payload(key);
+ ukp = user_key_payload_locked(key);
if (!ukp)
return ERR_PTR(-EKEYREVOKED);
diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig
index e9232a0..e38039f 100644
--- a/fs/ext4/Kconfig
+++ b/fs/ext4/Kconfig
@@ -109,16 +109,10 @@
decrypted pages in the page cache.
config EXT4_FS_ENCRYPTION
- bool "Ext4 FS Encryption"
- default n
+ bool
+ default y
depends on EXT4_ENCRYPTION
-config EXT4_FS_ICE_ENCRYPTION
- bool "Ext4 Encryption with ICE support"
- default n
- depends on EXT4_FS_ENCRYPTION
- depends on PFK
-
config EXT4_DEBUG
bool "EXT4 debugging support"
depends on EXT4_FS
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index d9e563a..354103f 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -1,7 +1,6 @@
#
# Makefile for the linux ext4-filesystem routines.
#
-ccflags-y += -Ifs/crypto
obj-$(CONFIG_EXT4_FS) += ext4.o
@@ -13,4 +12,3 @@
ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o
-ext4-$(CONFIG_EXT4_FS_ICE_ENCRYPTION) += ext4_ice.o
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 9b67de7..c175391 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -32,13 +32,15 @@
#include <linux/percpu_counter.h>
#include <linux/ratelimit.h>
#include <crypto/hash.h>
-#include <linux/fscrypto.h>
#include <linux/falloc.h>
#include <linux/percpu-rwsem.h>
#ifdef __KERNEL__
#include <linux/compat.h>
#endif
+#define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_EXT4_FS_ENCRYPTION)
+#include <linux/fscrypt.h>
+
/*
* The fourth extended filesystem constants/structures
*/
@@ -1342,11 +1344,6 @@
/* Number of quota types we support */
#define EXT4_MAXQUOTAS 3
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
-#define EXT4_KEY_DESC_PREFIX "ext4:"
-#define EXT4_KEY_DESC_PREFIX_SIZE 5
-#endif
-
/*
* fourth extended-fs super-block data in memory
*/
@@ -1516,12 +1513,6 @@
/* Barrier between changing inodes' journal flags and writepages ops. */
struct percpu_rw_semaphore s_journal_flag_rwsem;
-
- /* Encryption support */
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
- u8 key_prefix[EXT4_KEY_DESC_PREFIX_SIZE];
- u8 key_prefix_size;
-#endif
};
static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
@@ -2277,11 +2268,6 @@
struct ext4_group_desc *gdp);
ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
-static inline int ext4_sb_has_crypto(struct super_block *sb)
-{
- return ext4_has_feature_encrypt(sb);
-}
-
static inline bool ext4_encrypted_inode(struct inode *inode)
{
return ext4_test_inode_flag(inode, EXT4_INODE_ENCRYPT);
@@ -2330,29 +2316,6 @@
}
static inline void ext4_fname_free_filename(struct ext4_filename *fname) { }
-#define fscrypt_set_d_op(i)
-#define fscrypt_get_ctx fscrypt_notsupp_get_ctx
-#define fscrypt_release_ctx fscrypt_notsupp_release_ctx
-#define fscrypt_encrypt_page fscrypt_notsupp_encrypt_page
-#define fscrypt_decrypt_page fscrypt_notsupp_decrypt_page
-#define fscrypt_decrypt_bio_pages fscrypt_notsupp_decrypt_bio_pages
-#define fscrypt_pullback_bio_page fscrypt_notsupp_pullback_bio_page
-#define fscrypt_restore_control_page fscrypt_notsupp_restore_control_page
-#define fscrypt_zeroout_range fscrypt_notsupp_zeroout_range
-#define fscrypt_process_policy fscrypt_notsupp_process_policy
-#define fscrypt_get_policy fscrypt_notsupp_get_policy
-#define fscrypt_has_permitted_context fscrypt_notsupp_has_permitted_context
-#define fscrypt_inherit_context fscrypt_notsupp_inherit_context
-#define fscrypt_get_encryption_info fscrypt_notsupp_get_encryption_info
-#define fscrypt_put_encryption_info fscrypt_notsupp_put_encryption_info
-#define fscrypt_setup_filename fscrypt_notsupp_setup_filename
-#define fscrypt_free_filename fscrypt_notsupp_free_filename
-#define fscrypt_fname_encrypted_size fscrypt_notsupp_fname_encrypted_size
-#define fscrypt_fname_alloc_buffer fscrypt_notsupp_fname_alloc_buffer
-#define fscrypt_fname_free_buffer fscrypt_notsupp_fname_free_buffer
-#define fscrypt_fname_disk_to_usr fscrypt_notsupp_fname_disk_to_usr
-#define fscrypt_fname_usr_to_disk fscrypt_notsupp_fname_usr_to_disk
-#define fs_using_hardware_encryption fs_notsupp_using_hardware_encryption
#endif
/* dir.c */
@@ -2374,17 +2337,16 @@
void *buf, int buf_size,
struct ext4_filename *fname,
struct ext4_dir_entry_2 **dest_de);
-int ext4_insert_dentry(struct inode *dir,
- struct inode *inode,
- struct ext4_dir_entry_2 *de,
- int buf_size,
- struct ext4_filename *fname);
+void ext4_insert_dentry(struct inode *inode,
+ struct ext4_dir_entry_2 *de,
+ int buf_size,
+ struct ext4_filename *fname);
static inline void ext4_update_dx_flag(struct inode *inode)
{
if (!ext4_has_feature_dir_index(inode->i_sb))
ext4_clear_inode_flag(inode, EXT4_INODE_INDEX);
}
-static unsigned char ext4_filetype_table[] = {
+static const unsigned char ext4_filetype_table[] = {
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
};
@@ -3072,7 +3034,7 @@
struct inode *inode,
struct buffer_head *bh);
#define S_SHIFT 12
-static unsigned char ext4_type_by_mode[S_IFMT >> S_SHIFT] = {
+static const unsigned char ext4_type_by_mode[S_IFMT >> S_SHIFT] = {
[S_IFREG >> S_SHIFT] = EXT4_FT_REG_FILE,
[S_IFDIR >> S_SHIFT] = EXT4_FT_DIR,
[S_IFCHR >> S_SHIFT] = EXT4_FT_CHRDEV,
diff --git a/fs/ext4/ext4_ice.c b/fs/ext4/ext4_ice.c
deleted file mode 100644
index 25f79ae..0000000
--- a/fs/ext4/ext4_ice.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/* 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 "ext4_ice.h"
-
-/*
- * Retrieves encryption key from the inode
- */
-char *ext4_get_ice_encryption_key(const struct inode *inode)
-{
- struct fscrypt_info *ci = NULL;
-
- if (!inode)
- return NULL;
-
- ci = inode->i_crypt_info;
- if (!ci)
- return NULL;
-
- return &(ci->ci_raw_key[0]);
-}
-
-/*
- * Retrieves encryption salt from the inode
- */
-char *ext4_get_ice_encryption_salt(const struct inode *inode)
-{
- struct fscrypt_info *ci = NULL;
-
- if (!inode)
- return NULL;
-
- ci = inode->i_crypt_info;
- if (!ci)
- return NULL;
-
- return &(ci->ci_raw_key[ext4_get_ice_encryption_key_size(inode)]);
-}
-
-/*
- * returns true if the cipher mode in inode is AES XTS
- */
-int ext4_is_aes_xts_cipher(const struct inode *inode)
-{
- struct fscrypt_info *ci = NULL;
-
- ci = inode->i_crypt_info;
- if (!ci)
- return 0;
-
- return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE);
-}
-
-/*
- * returns true if encryption info in both inodes is equal
- */
-int ext4_is_ice_encryption_info_equal(const struct inode *inode1,
- const struct inode *inode2)
-{
- char *key1 = NULL;
- char *key2 = NULL;
- char *salt1 = NULL;
- char *salt2 = NULL;
-
- if (!inode1 || !inode2)
- return 0;
-
- if (inode1 == inode2)
- return 1;
-
- /* both do not belong to ice, so we don't care, they are equal for us */
- if (!ext4_should_be_processed_by_ice(inode1) &&
- !ext4_should_be_processed_by_ice(inode2))
- return 1;
-
- /* one belongs to ice, the other does not -> not equal */
- if (ext4_should_be_processed_by_ice(inode1) ^
- ext4_should_be_processed_by_ice(inode2))
- return 0;
-
- key1 = ext4_get_ice_encryption_key(inode1);
- key2 = ext4_get_ice_encryption_key(inode2);
- salt1 = ext4_get_ice_encryption_salt(inode1);
- salt2 = ext4_get_ice_encryption_salt(inode2);
-
- /* key and salt should not be null by this point */
- if (!key1 || !key2 || !salt1 || !salt2 ||
- (ext4_get_ice_encryption_key_size(inode1) !=
- ext4_get_ice_encryption_key_size(inode2)) ||
- (ext4_get_ice_encryption_salt_size(inode1) !=
- ext4_get_ice_encryption_salt_size(inode2)))
- return 0;
-
- return ((memcmp(key1, key2,
- ext4_get_ice_encryption_key_size(inode1)) == 0) &&
- (memcmp(salt1, salt2,
- ext4_get_ice_encryption_salt_size(inode1)) == 0));
-}
diff --git a/fs/ext4/ext4_ice.h b/fs/ext4/ext4_ice.h
deleted file mode 100644
index 04e09bf..0000000
--- a/fs/ext4/ext4_ice.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef _EXT4_ICE_H
-#define _EXT4_ICE_H
-
-#include "ext4.h"
-#include <linux/fscrypto.h>
-
-#ifdef CONFIG_EXT4_FS_ICE_ENCRYPTION
-static inline int ext4_should_be_processed_by_ice(const struct inode *inode)
-{
- if (!ext4_encrypted_inode((struct inode *)inode))
- return 0;
-
- return fs_using_hardware_encryption((struct inode *)inode);
-}
-
-static inline int ext4_is_ice_enabled(void)
-{
- return 1;
-}
-
-int ext4_is_aes_xts_cipher(const struct inode *inode);
-
-char *ext4_get_ice_encryption_key(const struct inode *inode);
-char *ext4_get_ice_encryption_salt(const struct inode *inode);
-
-int ext4_is_ice_encryption_info_equal(const struct inode *inode1,
- const struct inode *inode2);
-
-static inline size_t ext4_get_ice_encryption_key_size(
- const struct inode *inode)
-{
- return FS_AES_256_XTS_KEY_SIZE / 2;
-}
-
-static inline size_t ext4_get_ice_encryption_salt_size(
- const struct inode *inode)
-{
- return FS_AES_256_XTS_KEY_SIZE / 2;
-}
-
-#else
-static inline int ext4_should_be_processed_by_ice(const struct inode *inode)
-{
- return 0;
-}
-static inline int ext4_is_ice_enabled(void)
-{
- return 0;
-}
-
-static inline char *ext4_get_ice_encryption_key(const struct inode *inode)
-{
- return NULL;
-}
-
-static inline char *ext4_get_ice_encryption_salt(const struct inode *inode)
-{
- return NULL;
-}
-
-static inline size_t ext4_get_ice_encryption_key_size(
- const struct inode *inode)
-{
- return 0;
-}
-
-static inline size_t ext4_get_ice_encryption_salt_size(
- const struct inode *inode)
-{
- return 0;
-}
-
-static inline int ext4_is_xts_cipher(const struct inode *inode)
-{
- return 0;
-}
-
-static inline int ext4_is_ice_encryption_info_equal(
- const struct inode *inode1,
- const struct inode *inode2)
-{
- return 0;
-}
-
-static inline int ext4_is_aes_xts_cipher(const struct inode *inode)
-{
- return 0;
-}
-
-#endif
-
-#endif /* _EXT4_ICE_H */
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 2d94e85..2cec605 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -1093,6 +1093,17 @@
if (err)
goto fail_drop;
+ /*
+ * Since the encryption xattr will always be unique, create it first so
+ * that it's less likely to end up in an external xattr block and
+ * prevent its deduplication.
+ */
+ if (encrypt) {
+ err = fscrypt_inherit_context(dir, inode, handle, true);
+ if (err)
+ goto fail_free_drop;
+ }
+
err = ext4_init_acl(handle, inode, dir);
if (err)
goto fail_free_drop;
@@ -1114,13 +1125,6 @@
ei->i_datasync_tid = handle->h_transaction->t_tid;
}
- if (encrypt) {
- /* give pointer to avoid set_context with journal ops. */
- err = fscrypt_inherit_context(dir, inode, &encrypt, true);
- if (err)
- goto fail_free_drop;
- }
-
err = ext4_mark_inode_dirty(handle, inode);
if (err) {
ext4_std_error(sb, err);
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index a5807fd..4d78b93 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1035,7 +1035,7 @@
err = ext4_journal_get_write_access(handle, iloc->bh);
if (err)
return err;
- ext4_insert_dentry(dir, inode, de, inline_size, fname);
+ ext4_insert_dentry(inode, de, inline_size, fname);
ext4_show_inline_dir(dir, iloc->bh, inline_start, inline_size);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index dcb9669..21c0670 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -42,7 +42,6 @@
#include "xattr.h"
#include "acl.h"
#include "truncate.h"
-#include "ext4_ice.h"
#include <trace/events/ext4.h>
#include <trace/events/android_fs.h>
@@ -1153,8 +1152,7 @@
ll_rw_block(REQ_OP_READ, 0, 1, &bh);
*wait_bh++ = bh;
decrypt = ext4_encrypted_inode(inode) &&
- S_ISREG(inode->i_mode) &&
- !ext4_is_ice_enabled();
+ S_ISREG(inode->i_mode);
}
}
/*
@@ -1168,7 +1166,8 @@
if (unlikely(err))
page_zero_new_buffers(page, from, to);
else if (decrypt)
- err = fscrypt_decrypt_page(page);
+ err = fscrypt_decrypt_page(page->mapping->host, page,
+ PAGE_SIZE, 0, page->index);
return err;
}
#endif
@@ -3511,8 +3510,7 @@
get_block_func = ext4_dio_get_block_unwritten_async;
dio_flags = DIO_LOCKING;
}
-#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \
-!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION)
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode));
#endif
if (IS_DAX(inode)) {
@@ -3553,10 +3551,18 @@
/* Credits for sb + inode write */
handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
if (IS_ERR(handle)) {
- /* This is really bad luck. We've written the data
- * but cannot extend i_size. Bail out and pretend
- * the write failed... */
- ret = PTR_ERR(handle);
+ /*
+ * We wrote the data but cannot extend
+ * i_size. Bail out. In async io case, we do
+ * not return error here because we have
+ * already submmitted the corresponding
+ * bio. Returning error here makes the caller
+ * think that this IO is done and failed
+ * resulting in race with bio's completion
+ * handler.
+ */
+ if (!ret)
+ ret = PTR_ERR(handle);
if (inode->i_nlink)
ext4_orphan_del(NULL, inode);
@@ -3626,8 +3632,7 @@
ssize_t ret;
int rw = iov_iter_rw(iter);
-#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \
-!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION)
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode))
return 0;
#endif
@@ -3824,12 +3829,12 @@
if (!buffer_uptodate(bh))
goto unlock;
if (S_ISREG(inode->i_mode) &&
- ext4_encrypted_inode(inode) &&
- !fs_using_hardware_encryption(inode)) {
+ ext4_encrypted_inode(inode)) {
/* We expect the key to be set. */
BUG_ON(!fscrypt_has_encryption_key(inode));
BUG_ON(blocksize != PAGE_SIZE);
- WARN_ON_ONCE(fscrypt_decrypt_page(page));
+ WARN_ON_ONCE(fscrypt_decrypt_page(page->mapping->host,
+ page, PAGE_SIZE, 0, page->index));
}
}
if (ext4_should_journal_data(inode)) {
@@ -4453,8 +4458,11 @@
new_fl |= S_DIRSYNC;
if (test_opt(inode->i_sb, DAX) && S_ISREG(inode->i_mode))
new_fl |= S_DAX;
+ if (flags & EXT4_ENCRYPT_FL)
+ new_fl |= S_ENCRYPTED;
inode_set_flags(inode, new_fl,
- S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_DAX);
+ S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_DAX|
+ S_ENCRYPTED);
}
/* Propagate flags from i_flags to EXT4_I(inode)->i_flags */
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 1ddceb6..15ca15c 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -191,6 +191,7 @@
return err;
}
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
static int uuid_is_zero(__u8 u[16])
{
int i;
@@ -200,6 +201,7 @@
return 0;
return 1;
}
+#endif
static int ext4_ioctl_setflags(struct inode *inode,
unsigned int flags)
@@ -770,24 +772,19 @@
}
case EXT4_IOC_PRECACHE_EXTENTS:
return ext4_ext_precache(inode);
- case EXT4_IOC_SET_ENCRYPTION_POLICY: {
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
- struct fscrypt_policy policy;
- if (copy_from_user(&policy,
- (struct fscrypt_policy __user *)arg,
- sizeof(policy)))
- return -EFAULT;
- return fscrypt_process_policy(filp, &policy);
-#else
- return -EOPNOTSUPP;
-#endif
- }
+
+ case EXT4_IOC_SET_ENCRYPTION_POLICY:
+ if (!ext4_has_feature_encrypt(sb))
+ return -EOPNOTSUPP;
+ return fscrypt_ioctl_set_policy(filp, (const void __user *)arg);
+
case EXT4_IOC_GET_ENCRYPTION_PWSALT: {
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
int err, err2;
struct ext4_sb_info *sbi = EXT4_SB(sb);
handle_t *handle;
- if (!ext4_sb_has_crypto(sb))
+ if (!ext4_has_feature_encrypt(sb))
return -EOPNOTSUPP;
if (uuid_is_zero(sbi->s_es->s_encrypt_pw_salt)) {
err = mnt_want_write_file(filp);
@@ -817,30 +814,18 @@
sbi->s_es->s_encrypt_pw_salt, 16))
return -EFAULT;
return 0;
- }
- case EXT4_IOC_GET_ENCRYPTION_POLICY: {
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
- struct fscrypt_policy policy;
- int err = 0;
-
- if (!ext4_encrypted_inode(inode))
- return -ENOENT;
- err = fscrypt_get_policy(inode, &policy);
- if (err)
- return err;
- if (copy_to_user((void __user *)arg, &policy, sizeof(policy)))
- return -EFAULT;
- return 0;
#else
return -EOPNOTSUPP;
#endif
}
+ case EXT4_IOC_GET_ENCRYPTION_POLICY:
+ return fscrypt_ioctl_get_policy(filp, (void __user *)arg);
+
case EXT4_IOC_FSGETXATTR:
{
struct fsxattr fa;
memset(&fa, 0, sizeof(struct fsxattr));
- ext4_get_inode_flags(ei);
fa.fsx_xflags = ext4_iflags_to_xflags(ei->i_flags & EXT4_FL_USER_VISIBLE);
if (ext4_has_feature_project(inode->i_sb)) {
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index b1766a6..8338cd4 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1237,37 +1237,24 @@
}
/*
- * NOTE! unlike strncmp, ext4_match returns 1 for success, 0 for failure.
+ * Test whether a directory entry matches the filename being searched for.
*
- * `len <= EXT4_NAME_LEN' is guaranteed by caller.
- * `de != NULL' is guaranteed by caller.
+ * Return: %true if the directory entry matches, otherwise %false.
*/
-static inline int ext4_match(struct ext4_filename *fname,
- struct ext4_dir_entry_2 *de)
+static inline bool ext4_match(const struct ext4_filename *fname,
+ const struct ext4_dir_entry_2 *de)
{
- const void *name = fname_name(fname);
- u32 len = fname_len(fname);
+ struct fscrypt_name f;
if (!de->inode)
- return 0;
+ return false;
+ f.usr_fname = fname->usr_fname;
+ f.disk_name = fname->disk_name;
#ifdef CONFIG_EXT4_FS_ENCRYPTION
- if (unlikely(!name)) {
- if (fname->usr_fname->name[0] == '_') {
- int ret;
- if (de->name_len <= 32)
- return 0;
- ret = memcmp(de->name + ((de->name_len - 17) & ~15),
- fname->crypto_buf.name + 8, 16);
- return (ret == 0) ? 1 : 0;
- }
- name = fname->crypto_buf.name;
- len = fname->crypto_buf.len;
- }
+ f.crypto_buf = fname->crypto_buf;
#endif
- if (de->name_len != len)
- return 0;
- return (memcmp(de->name, name, len) == 0) ? 1 : 0;
+ return fscrypt_match_name(&f, de->name, de->name_len);
}
/*
@@ -1281,48 +1268,31 @@
struct ext4_dir_entry_2 * de;
char * dlimit;
int de_len;
- int res;
de = (struct ext4_dir_entry_2 *)search_buf;
dlimit = search_buf + buf_size;
while ((char *) de < dlimit) {
/* this code is executed quadratically often */
/* do minimal checking `by hand' */
- if ((char *) de + de->name_len <= dlimit) {
- res = ext4_match(fname, de);
- if (res < 0) {
- res = -1;
- goto return_result;
- }
- if (res > 0) {
- /* found a match - just to be sure, do
- * a full check */
- if (ext4_check_dir_entry(dir, NULL, de, bh,
- bh->b_data,
- bh->b_size, offset)) {
- res = -1;
- goto return_result;
- }
- *res_dir = de;
- res = 1;
- goto return_result;
- }
-
+ if ((char *) de + de->name_len <= dlimit &&
+ ext4_match(fname, de)) {
+ /* found a match - just to be sure, do
+ * a full check */
+ if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data,
+ bh->b_size, offset))
+ return -1;
+ *res_dir = de;
+ return 1;
}
/* prevent looping on a bad block */
de_len = ext4_rec_len_from_disk(de->rec_len,
dir->i_sb->s_blocksize);
- if (de_len <= 0) {
- res = -1;
- goto return_result;
- }
+ if (de_len <= 0)
+ return -1;
offset += de_len;
de = (struct ext4_dir_entry_2 *) ((char *) de + de_len);
}
-
- res = 0;
-return_result:
- return res;
+ return 0;
}
static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block,
@@ -1620,16 +1590,9 @@
if (!IS_ERR(inode) && ext4_encrypted_inode(dir) &&
(S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
!fscrypt_has_permitted_context(dir, inode)) {
- int nokey = ext4_encrypted_inode(inode) &&
- !fscrypt_has_encryption_key(inode);
- if (nokey) {
- iput(inode);
- return ERR_PTR(-ENOKEY);
- }
ext4_warning(inode->i_sb,
"Inconsistent encryption contexts: %lu/%lu",
- (unsigned long) dir->i_ino,
- (unsigned long) inode->i_ino);
+ dir->i_ino, inode->i_ino);
iput(inode);
return ERR_PTR(-EPERM);
}
@@ -1837,24 +1800,15 @@
int nlen, rlen;
unsigned int offset = 0;
char *top;
- int res;
de = (struct ext4_dir_entry_2 *)buf;
top = buf + buf_size - reclen;
while ((char *) de <= top) {
if (ext4_check_dir_entry(dir, NULL, de, bh,
- buf, buf_size, offset)) {
- res = -EFSCORRUPTED;
- goto return_result;
- }
- /* Provide crypto context and crypto buffer to ext4 match */
- res = ext4_match(fname, de);
- if (res < 0)
- goto return_result;
- if (res > 0) {
- res = -EEXIST;
- goto return_result;
- }
+ buf, buf_size, offset))
+ return -EFSCORRUPTED;
+ if (ext4_match(fname, de))
+ return -EEXIST;
nlen = EXT4_DIR_REC_LEN(de->name_len);
rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
if ((de->inode ? rlen - nlen : rlen) >= reclen)
@@ -1862,22 +1816,17 @@
de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
offset += rlen;
}
-
if ((char *) de > top)
- res = -ENOSPC;
- else {
- *dest_de = de;
- res = 0;
- }
-return_result:
- return res;
+ return -ENOSPC;
+
+ *dest_de = de;
+ return 0;
}
-int ext4_insert_dentry(struct inode *dir,
- struct inode *inode,
- struct ext4_dir_entry_2 *de,
- int buf_size,
- struct ext4_filename *fname)
+void ext4_insert_dentry(struct inode *inode,
+ struct ext4_dir_entry_2 *de,
+ int buf_size,
+ struct ext4_filename *fname)
{
int nlen, rlen;
@@ -1896,7 +1845,6 @@
ext4_set_de_type(inode->i_sb, de, inode->i_mode);
de->name_len = fname_len(fname);
memcpy(de->name, fname_name(fname), fname_len(fname));
- return 0;
}
/*
@@ -1932,11 +1880,8 @@
return err;
}
- /* By now the buffer is marked for journaling. Due to crypto operations,
- * the following function call may fail */
- err = ext4_insert_dentry(dir, inode, de, blocksize, fname);
- if (err < 0)
- return err;
+ /* By now the buffer is marked for journaling */
+ ext4_insert_dentry(inode, de, blocksize, fname);
/*
* XXX shouldn't update any times until successful
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index d8a0770..0718a86 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -24,12 +24,10 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/backing-dev.h>
-#include <linux/fscrypto.h>
#include "ext4_jbd2.h"
#include "xattr.h"
#include "acl.h"
-#include "ext4_ice.h"
static struct kmem_cache *io_end_cachep;
@@ -471,8 +469,8 @@
gfp_t gfp_flags = GFP_NOFS;
retry_encrypt:
- if (!fs_using_hardware_encryption(inode))
- data_page = fscrypt_encrypt_page(inode, page, gfp_flags);
+ data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, 0,
+ page->index, gfp_flags);
if (IS_ERR(data_page)) {
ret = PTR_ERR(data_page);
if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) {
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 1f58179..43ce5fc 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -720,6 +720,7 @@
}
ext4_unlock_group(sb, grp);
+ ext4_commit_super(sb, 1);
ext4_handle_error(sb);
/*
* We only get here in the ERRORS_RO case; relocking the group
@@ -1102,57 +1103,75 @@
EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, len);
}
-static int ext4_key_prefix(struct inode *inode, u8 **key)
-{
- *key = EXT4_SB(inode->i_sb)->key_prefix;
- return EXT4_SB(inode->i_sb)->key_prefix_size;
-}
-
-static int ext4_prepare_context(struct inode *inode)
-{
- return ext4_convert_inline_data(inode);
-}
-
static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
void *fs_data)
{
- handle_t *handle;
- int res, res2;
+ handle_t *handle = fs_data;
+ int res, res2, retries = 0;
- /* fs_data is null when internally used. */
- if (fs_data) {
- res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
- EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx,
- len, 0);
+ res = ext4_convert_inline_data(inode);
+ if (res)
+ return res;
+
+ /*
+ * If a journal handle was specified, then the encryption context is
+ * being set on a new inode via inheritance and is part of a larger
+ * transaction to create the inode. Otherwise the encryption context is
+ * being set on an existing inode in its own transaction. Only in the
+ * latter case should the "retry on ENOSPC" logic be used.
+ */
+
+ if (handle) {
+ res = ext4_xattr_set_handle(handle, inode,
+ EXT4_XATTR_INDEX_ENCRYPTION,
+ EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
+ ctx, len, 0);
if (!res) {
ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
ext4_clear_inode_state(inode,
EXT4_STATE_MAY_INLINE_DATA);
+ /*
+ * Update inode->i_flags - S_ENCRYPTED will be enabled,
+ * S_DAX may be disabled
+ */
+ ext4_set_inode_flags(inode);
}
return res;
}
+ res = dquot_initialize(inode);
+ if (res)
+ return res;
+retry:
handle = ext4_journal_start(inode, EXT4_HT_MISC,
ext4_jbd2_credits_xattr(inode));
if (IS_ERR(handle))
return PTR_ERR(handle);
- res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
- EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx,
- len, 0);
+ res = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_ENCRYPTION,
+ EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
+ ctx, len, 0);
if (!res) {
ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
+ /*
+ * Update inode->i_flags - S_ENCRYPTED will be enabled,
+ * S_DAX may be disabled
+ */
+ ext4_set_inode_flags(inode);
res = ext4_mark_inode_dirty(handle, inode);
if (res)
EXT4_ERROR_INODE(inode, "Failed to mark inode dirty");
}
res2 = ext4_journal_stop(handle);
+
+ if (res == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
if (!res)
res = res2;
return res;
}
-static int ext4_dummy_context(struct inode *inode)
+static bool ext4_dummy_context(struct inode *inode)
{
return DUMMY_ENCRYPTION_ENABLED(EXT4_SB(inode->i_sb));
}
@@ -1163,20 +1182,14 @@
EXT4_NAME_LEN;
}
-static struct fscrypt_operations ext4_cryptops = {
+static const struct fscrypt_operations ext4_cryptops = {
+ .key_prefix = "ext4:",
.get_context = ext4_get_context,
- .key_prefix = ext4_key_prefix,
- .prepare_context = ext4_prepare_context,
.set_context = ext4_set_context,
.dummy_context = ext4_dummy_context,
- .is_encrypted = ext4_encrypted_inode,
.empty_dir = ext4_empty_dir,
.max_namelen = ext4_max_namelen,
};
-#else
-static struct fscrypt_operations ext4_cryptops = {
- .is_encrypted = ext4_encrypted_inode,
-};
#endif
#ifdef CONFIG_QUOTA
@@ -3906,7 +3919,9 @@
sb->s_op = &ext4_sops;
sb->s_export_op = &ext4_export_ops;
sb->s_xattr = ext4_xattr_handlers;
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
sb->s_cop = &ext4_cryptops;
+#endif
#ifdef CONFIG_QUOTA
sb->dq_op = &ext4_quota_operations;
if (ext4_has_feature_quota(sb))
@@ -4220,11 +4235,6 @@
ratelimit_state_init(&sbi->s_msg_ratelimit_state, 5 * HZ, 10);
kfree(orig_data);
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
- memcpy(sbi->key_prefix, EXT4_KEY_DESC_PREFIX,
- EXT4_KEY_DESC_PREFIX_SIZE);
- sbi->key_prefix_size = EXT4_KEY_DESC_PREFIX_SIZE;
-#endif
return 0;
cantfind_ext4:
diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile
index ca949ea..a0dc559 100644
--- a/fs/f2fs/Makefile
+++ b/fs/f2fs/Makefile
@@ -2,7 +2,7 @@
f2fs-y := dir.o file.o inode.o namei.o hash.o super.o inline.o
f2fs-y += checkpoint.o gc.o data.o node.o segment.o recovery.o
-f2fs-y += shrinker.o extent_cache.o
+f2fs-y += shrinker.o extent_cache.o sysfs.o
f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o
f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o
f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
index 55aa29c..2bb7c9f 100644
--- a/fs/f2fs/acl.c
+++ b/fs/f2fs/acl.c
@@ -207,15 +207,16 @@
void *value = NULL;
size_t size = 0;
int error;
+ umode_t mode = inode->i_mode;
switch (type) {
case ACL_TYPE_ACCESS:
name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl && !ipage) {
- error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ error = posix_acl_update_mode(inode, &mode, &acl);
if (error)
return error;
- set_acl_inode(inode, inode->i_mode);
+ set_acl_inode(inode, mode);
}
break;
@@ -233,7 +234,7 @@
value = f2fs_acl_to_disk(F2FS_I_SB(inode), acl, &size);
if (IS_ERR(value)) {
clear_inode_flag(inode, FI_ACL_MODE);
- return (int)PTR_ERR(value);
+ return PTR_ERR(value);
}
}
@@ -249,6 +250,9 @@
int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
{
+ if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
+ return -EIO;
+
return __f2fs_set_acl(inode, type, acl, NULL);
}
@@ -384,7 +388,7 @@
if (error)
return error;
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, true);
if (default_acl) {
error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl,
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index b4dbc2f..701781a 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -29,9 +29,8 @@
void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io)
{
set_ckpt_flags(sbi, CP_ERROR_FLAG);
- sbi->sb->s_flags |= MS_RDONLY;
if (!end_io)
- f2fs_flush_merged_bios(sbi);
+ f2fs_flush_merged_writes(sbi);
}
/*
@@ -65,7 +64,7 @@
.sbi = sbi,
.type = META,
.op = REQ_OP_READ,
- .op_flags = READ_SYNC | REQ_META | REQ_PRIO,
+ .op_flags = REQ_META | REQ_PRIO,
.old_blkaddr = index,
.new_blkaddr = index,
.encrypted_page = NULL,
@@ -160,8 +159,9 @@
.sbi = sbi,
.type = META,
.op = REQ_OP_READ,
- .op_flags = sync ? (READ_SYNC | REQ_META | REQ_PRIO) : REQ_RAHEAD,
+ .op_flags = sync ? (REQ_META | REQ_PRIO) : REQ_RAHEAD,
.encrypted_page = NULL,
+ .in_list = false,
};
struct blk_plug plug;
@@ -207,12 +207,10 @@
}
fio.page = page;
- fio.old_blkaddr = fio.new_blkaddr;
- f2fs_submit_page_mbio(&fio);
+ f2fs_submit_page_bio(&fio);
f2fs_put_page(page, 0);
}
out:
- f2fs_submit_merged_bio(sbi, META, READ);
blk_finish_plug(&plug);
return blkno - start;
}
@@ -228,33 +226,38 @@
f2fs_put_page(page, 0);
if (readahead)
- ra_meta_pages(sbi, index, MAX_BIO_BLOCKS(sbi), META_POR, true);
+ ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true);
}
-static int f2fs_write_meta_page(struct page *page,
- struct writeback_control *wbc)
+static int __f2fs_write_meta_page(struct page *page,
+ struct writeback_control *wbc,
+ enum iostat_type io_type)
{
struct f2fs_sb_info *sbi = F2FS_P_SB(page);
trace_f2fs_writepage(page, META);
+ if (unlikely(f2fs_cp_error(sbi))) {
+ dec_page_count(sbi, F2FS_DIRTY_META);
+ unlock_page(page);
+ return 0;
+ }
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
goto redirty_out;
if (wbc->for_reclaim && page->index < GET_SUM_BLOCK(sbi, 0))
goto redirty_out;
- if (unlikely(f2fs_cp_error(sbi)))
- goto redirty_out;
- write_meta_page(sbi, page);
+ write_meta_page(sbi, page, io_type);
dec_page_count(sbi, F2FS_DIRTY_META);
if (wbc->for_reclaim)
- f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, META, WRITE);
+ f2fs_submit_merged_write_cond(sbi, page->mapping->host,
+ 0, page->index, META);
unlock_page(page);
if (unlikely(f2fs_cp_error(sbi)))
- f2fs_submit_merged_bio(sbi, META, WRITE);
+ f2fs_submit_merged_write(sbi, META);
return 0;
@@ -263,23 +266,33 @@
return AOP_WRITEPAGE_ACTIVATE;
}
+static int f2fs_write_meta_page(struct page *page,
+ struct writeback_control *wbc)
+{
+ return __f2fs_write_meta_page(page, wbc, FS_META_IO);
+}
+
static int f2fs_write_meta_pages(struct address_space *mapping,
struct writeback_control *wbc)
{
struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
long diff, written;
+ if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
+ goto skip_write;
+
/* collect a number of dirty meta pages and write together */
if (wbc->for_kupdate ||
get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META))
goto skip_write;
- trace_f2fs_writepages(mapping->host, wbc, META);
+ /* if locked failed, cp will flush dirty pages instead */
+ if (!mutex_trylock(&sbi->cp_mutex))
+ goto skip_write;
- /* if mounting is failed, skip writing node pages */
- mutex_lock(&sbi->cp_mutex);
+ trace_f2fs_writepages(mapping->host, wbc, META);
diff = nr_pages_to_write(sbi, META, wbc);
- written = sync_meta_pages(sbi, META, wbc->nr_to_write);
+ written = sync_meta_pages(sbi, META, wbc->nr_to_write, FS_META_IO);
mutex_unlock(&sbi->cp_mutex);
wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff);
return 0;
@@ -291,7 +304,7 @@
}
long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
- long nr_to_write)
+ long nr_to_write, enum iostat_type io_type)
{
struct address_space *mapping = META_MAPPING(sbi);
pgoff_t index = 0, end = ULONG_MAX, prev = ULONG_MAX;
@@ -342,7 +355,7 @@
if (!clear_page_dirty_for_io(page))
goto continue_unlock;
- if (mapping->a_ops->writepage(page, &wbc)) {
+ if (__f2fs_write_meta_page(page, &wbc, io_type)) {
unlock_page(page);
break;
}
@@ -356,7 +369,7 @@
}
stop:
if (nwritten)
- f2fs_submit_merged_bio(sbi, type, WRITE);
+ f2fs_submit_merged_write(sbi, type);
blk_finish_plug(&plug);
@@ -390,24 +403,23 @@
#endif
};
-static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
+static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino,
+ unsigned int devidx, int type)
{
struct inode_management *im = &sbi->im[type];
struct ino_entry *e, *tmp;
tmp = f2fs_kmem_cache_alloc(ino_entry_slab, GFP_NOFS);
-retry:
+
radix_tree_preload(GFP_NOFS | __GFP_NOFAIL);
spin_lock(&im->ino_lock);
e = radix_tree_lookup(&im->ino_root, ino);
if (!e) {
e = tmp;
- if (radix_tree_insert(&im->ino_root, ino, e)) {
- spin_unlock(&im->ino_lock);
- radix_tree_preload_end();
- goto retry;
- }
+ if (unlikely(radix_tree_insert(&im->ino_root, ino, e)))
+ f2fs_bug_on(sbi, 1);
+
memset(e, 0, sizeof(struct ino_entry));
e->ino = ino;
@@ -415,6 +427,10 @@
if (type != ORPHAN_INO)
im->ino_num++;
}
+
+ if (type == FLUSH_INO)
+ f2fs_set_bit(devidx, (char *)&e->dirty_device);
+
spin_unlock(&im->ino_lock);
radix_tree_preload_end();
@@ -443,7 +459,7 @@
void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
{
/* add new dirty ino entry into list */
- __add_ino_entry(sbi, ino, type);
+ __add_ino_entry(sbi, ino, 0, type);
}
void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
@@ -469,7 +485,7 @@
struct ino_entry *e, *tmp;
int i;
- for (i = all ? ORPHAN_INO: APPEND_INO; i <= UPDATE_INO; i++) {
+ for (i = all ? ORPHAN_INO : APPEND_INO; i < MAX_INO_ENTRY; i++) {
struct inode_management *im = &sbi->im[i];
spin_lock(&im->ino_lock);
@@ -483,6 +499,27 @@
}
}
+void set_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
+ unsigned int devidx, int type)
+{
+ __add_ino_entry(sbi, ino, devidx, type);
+}
+
+bool is_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
+ unsigned int devidx, int type)
+{
+ struct inode_management *im = &sbi->im[type];
+ struct ino_entry *e;
+ bool is_dirty = false;
+
+ spin_lock(&im->ino_lock);
+ e = radix_tree_lookup(&im->ino_root, ino);
+ if (e && f2fs_test_bit(devidx, (char *)&e->dirty_device))
+ is_dirty = true;
+ spin_unlock(&im->ino_lock);
+ return is_dirty;
+}
+
int acquire_orphan_inode(struct f2fs_sb_info *sbi)
{
struct inode_management *im = &sbi->im[ORPHAN_INO];
@@ -493,6 +530,7 @@
#ifdef CONFIG_F2FS_FAULT_INJECTION
if (time_to_inject(sbi, FAULT_ORPHAN)) {
spin_unlock(&im->ino_lock);
+ f2fs_show_injection_info(FAULT_ORPHAN);
return -ENOSPC;
}
#endif
@@ -518,7 +556,7 @@
void add_orphan_inode(struct inode *inode)
{
/* add new orphan ino entry into list */
- __add_ino_entry(F2FS_I_SB(inode), inode->i_ino, ORPHAN_INO);
+ __add_ino_entry(F2FS_I_SB(inode), inode->i_ino, 0, ORPHAN_INO);
update_inode_page(inode);
}
@@ -542,7 +580,7 @@
return err;
}
- __add_ino_entry(sbi, ino, ORPHAN_INO);
+ __add_ino_entry(sbi, ino, 0, ORPHAN_INO);
inode = f2fs_iget_retry(sbi->sb, ino);
if (IS_ERR(inode)) {
@@ -565,7 +603,7 @@
if (ni.blk_addr != NULL_ADDR) {
set_sbi_flag(sbi, SBI_NEED_FSCK);
f2fs_msg(sbi->sb, KERN_WARNING,
- "%s: orphan failed (ino=%x), run fsck to fix.",
+ "%s: orphan failed (ino=%x) by kernel, retry mount.",
__func__, ino);
return -EIO;
}
@@ -576,11 +614,28 @@
int recover_orphan_inodes(struct f2fs_sb_info *sbi)
{
block_t start_blk, orphan_blocks, i, j;
- int err;
+ unsigned int s_flags = sbi->sb->s_flags;
+ int err = 0;
+#ifdef CONFIG_QUOTA
+ int quota_enabled;
+#endif
if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
return 0;
+ if (s_flags & MS_RDONLY) {
+ f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs");
+ sbi->sb->s_flags &= ~MS_RDONLY;
+ }
+
+#ifdef CONFIG_QUOTA
+ /* Needed for iput() to work correctly and not trash data */
+ sbi->sb->s_flags |= MS_ACTIVE;
+
+ /* Turn on quotas so that they are updated correctly */
+ quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
+#endif
+
start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
orphan_blocks = __start_sum_addr(sbi) - 1 - __cp_payload(sbi);
@@ -596,14 +651,22 @@
err = recover_orphan_inode(sbi, ino);
if (err) {
f2fs_put_page(page, 1);
- return err;
+ goto out;
}
}
f2fs_put_page(page, 1);
}
/* clear Orphan Flag */
clear_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG);
- return 0;
+out:
+#ifdef CONFIG_QUOTA
+ /* Turn quotas off */
+ if (quota_enabled)
+ f2fs_quota_off_umount(sbi->sb);
+#endif
+ sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
+
+ return err;
}
static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
@@ -675,14 +738,13 @@
*cp_block = (struct f2fs_checkpoint *)page_address(*cp_page);
crc_offset = le32_to_cpu((*cp_block)->checksum_offset);
- if (crc_offset >= blk_size) {
+ if (crc_offset > (blk_size - sizeof(__le32))) {
f2fs_msg(sbi->sb, KERN_WARNING,
"invalid crc_offset: %zu", crc_offset);
return -EINVAL;
}
- crc = le32_to_cpu(*((__le32 *)((unsigned char *)*cp_block
- + crc_offset)));
+ crc = cur_cp_crc(*cp_block);
if (!f2fs_crc_valid(sbi, crc, *cp_block, crc_offset)) {
f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");
return -EINVAL;
@@ -737,7 +799,7 @@
block_t cp_blk_no;
int i;
- sbi->ckpt = kzalloc(cp_blks * blk_size, GFP_KERNEL);
+ sbi->ckpt = f2fs_kzalloc(sbi, cp_blks * blk_size, GFP_KERNEL);
if (!sbi->ckpt)
return -ENOMEM;
/*
@@ -770,7 +832,7 @@
/* Sanity checking of checkpoint */
if (sanity_check_ckpt(sbi))
- goto fail_no_cp;
+ goto free_fail_no_cp;
if (cur_page == cp1)
sbi->cur_cp_pack = 1;
@@ -798,6 +860,9 @@
f2fs_put_page(cp2, 1);
return 0;
+free_fail_no_cp:
+ f2fs_put_page(cp1, 1);
+ f2fs_put_page(cp2, 1);
fail_no_cp:
kfree(sbi->ckpt);
return -EINVAL;
@@ -812,7 +877,9 @@
return;
set_inode_flag(inode, flag);
- list_add_tail(&F2FS_I(inode)->dirty_list, &sbi->inode_list[type]);
+ if (!f2fs_is_volatile_file(inode))
+ list_add_tail(&F2FS_I(inode)->dirty_list,
+ &sbi->inode_list[type]);
stat_inc_dirty_inode(sbi, type);
}
@@ -870,6 +937,7 @@
struct inode *inode;
struct f2fs_inode_info *fi;
bool is_dir = (type == DIR_INODE);
+ unsigned long ino = 0;
trace_f2fs_sync_dirty_inodes_enter(sbi->sb, is_dir,
get_pages(sbi, is_dir ?
@@ -888,18 +956,34 @@
F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA));
return 0;
}
- fi = list_entry(head->next, struct f2fs_inode_info, dirty_list);
+ fi = list_first_entry(head, struct f2fs_inode_info, dirty_list);
inode = igrab(&fi->vfs_inode);
spin_unlock(&sbi->inode_lock[type]);
if (inode) {
+ unsigned long cur_ino = inode->i_ino;
+
+ if (is_dir)
+ F2FS_I(inode)->cp_task = current;
+
filemap_fdatawrite(inode->i_mapping);
+
+ if (is_dir)
+ F2FS_I(inode)->cp_task = NULL;
+
iput(inode);
+ /* We need to give cpu to another writers. */
+ if (ino == cur_ino) {
+ congestion_wait(BLK_RW_ASYNC, HZ/50);
+ cond_resched();
+ } else {
+ ino = cur_ino;
+ }
} else {
/*
* We should submit bio, since it exists several
* wribacking dentry pages in the freeing inode.
*/
- f2fs_submit_merged_bio(sbi, DATA, WRITE);
+ f2fs_submit_merged_write(sbi, DATA);
cond_resched();
}
goto retry;
@@ -921,18 +1005,35 @@
spin_unlock(&sbi->inode_lock[DIRTY_META]);
return 0;
}
- fi = list_entry(head->next, struct f2fs_inode_info,
+ fi = list_first_entry(head, struct f2fs_inode_info,
gdirty_list);
inode = igrab(&fi->vfs_inode);
spin_unlock(&sbi->inode_lock[DIRTY_META]);
if (inode) {
- update_inode_page(inode);
+ sync_inode_metadata(inode, 0);
+
+ /* it's on eviction */
+ if (is_inode_flag_set(inode, FI_DIRTY_INODE))
+ update_inode_page(inode);
iput(inode);
}
- };
+ }
return 0;
}
+static void __prepare_cp_block(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+ nid_t last_nid = nm_i->next_scan_nid;
+
+ next_free_nid(sbi, &last_nid);
+ ckpt->valid_block_count = cpu_to_le64(valid_user_blocks(sbi));
+ ckpt->valid_node_count = cpu_to_le32(valid_node_count(sbi));
+ ckpt->valid_inode_count = cpu_to_le32(valid_inode_count(sbi));
+ ckpt->next_free_nid = cpu_to_le32(last_nid);
+}
+
/*
* Freeze all the FS-operations for checkpoint.
*/
@@ -956,33 +1057,47 @@
err = sync_dirty_inodes(sbi, DIR_INODE);
if (err)
goto out;
- goto retry_flush_dents;
- }
-
- if (get_pages(sbi, F2FS_DIRTY_IMETA)) {
- f2fs_unlock_all(sbi);
- err = f2fs_sync_inode_meta(sbi);
- if (err)
- goto out;
+ cond_resched();
goto retry_flush_dents;
}
/*
* POR: we should ensure that there are no dirty node pages
- * until finishing nat/sit flush.
+ * until finishing nat/sit flush. inode->i_blocks can be updated.
*/
+ down_write(&sbi->node_change);
+
+ if (get_pages(sbi, F2FS_DIRTY_IMETA)) {
+ up_write(&sbi->node_change);
+ f2fs_unlock_all(sbi);
+ err = f2fs_sync_inode_meta(sbi);
+ if (err)
+ goto out;
+ cond_resched();
+ goto retry_flush_dents;
+ }
+
retry_flush_nodes:
down_write(&sbi->node_write);
if (get_pages(sbi, F2FS_DIRTY_NODES)) {
up_write(&sbi->node_write);
- err = sync_node_pages(sbi, &wbc);
+ err = sync_node_pages(sbi, &wbc, false, FS_CP_NODE_IO);
if (err) {
+ up_write(&sbi->node_change);
f2fs_unlock_all(sbi);
goto out;
}
+ cond_resched();
goto retry_flush_nodes;
}
+
+ /*
+ * sbi->node_change is used only for AIO write_begin path which produces
+ * dirty node blocks and some checkpoint values by block allocation.
+ */
+ __prepare_cp_block(sbi);
+ up_write(&sbi->node_change);
out:
blk_finish_plug(&plug);
return err;
@@ -991,8 +1106,6 @@
static void unblock_operations(struct f2fs_sb_info *sbi)
{
up_write(&sbi->node_write);
-
- build_free_nids(sbi);
f2fs_unlock_all(sbi);
}
@@ -1003,7 +1116,7 @@
for (;;) {
prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE);
- if (!atomic_read(&sbi->nr_wb_bios))
+ if (!get_pages(sbi, F2FS_WB_CP_DATA))
break;
io_schedule_timeout(5*HZ);
@@ -1015,15 +1128,24 @@
{
unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num;
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+ unsigned long flags;
- spin_lock(&sbi->cp_lock);
+ spin_lock_irqsave(&sbi->cp_lock, flags);
- if (cpc->reason == CP_UMOUNT)
+ if ((cpc->reason & CP_UMOUNT) &&
+ le32_to_cpu(ckpt->cp_pack_total_block_count) >
+ sbi->blocks_per_seg - NM_I(sbi)->nat_bits_blocks)
+ disable_nat_bits(sbi, false);
+
+ if (cpc->reason & CP_TRIMMED)
+ __set_ckpt_flags(ckpt, CP_TRIMMED_FLAG);
+
+ if (cpc->reason & CP_UMOUNT)
__set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
else
__clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
- if (cpc->reason == CP_FASTBOOT)
+ if (cpc->reason & CP_FASTBOOT)
__set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
else
__clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
@@ -1038,16 +1160,16 @@
/* set this flag to activate crc|cp_ver for recovery */
__set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG);
+ __clear_ckpt_flags(ckpt, CP_NOCRC_RECOVERY_FLAG);
- spin_unlock(&sbi->cp_lock);
+ spin_unlock_irqrestore(&sbi->cp_lock, flags);
}
static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct f2fs_nm_info *nm_i = NM_I(sbi);
- unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num;
- nid_t last_nid = nm_i->next_scan_nid;
+ unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num, flags;
block_t start_blk;
unsigned int data_sum_blocks, orphan_blocks;
__u32 crc32 = 0;
@@ -1056,22 +1178,20 @@
struct super_block *sb = sbi->sb;
struct curseg_info *seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE);
u64 kbytes_written;
+ int err;
/* Flush all the NAT/SIT pages */
while (get_pages(sbi, F2FS_DIRTY_META)) {
- sync_meta_pages(sbi, META, LONG_MAX);
+ sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
}
- next_free_nid(sbi, &last_nid);
-
/*
* modify checkpoint
* version number is already updated
*/
ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi));
- ckpt->valid_block_count = cpu_to_le64(valid_user_blocks(sbi));
ckpt->free_segment_count = cpu_to_le32(free_segments(sbi));
for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
ckpt->cur_node_segno[i] =
@@ -1090,18 +1210,14 @@
curseg_alloc_type(sbi, i + CURSEG_HOT_DATA);
}
- ckpt->valid_node_count = cpu_to_le32(valid_node_count(sbi));
- ckpt->valid_inode_count = cpu_to_le32(valid_inode_count(sbi));
- ckpt->next_free_nid = cpu_to_le32(last_nid);
-
/* 2 cp + n data seg summary + orphan inode blocks */
data_sum_blocks = npages_for_summary_flush(sbi, false);
- spin_lock(&sbi->cp_lock);
+ spin_lock_irqsave(&sbi->cp_lock, flags);
if (data_sum_blocks < NR_CURSEG_DATA_TYPE)
__set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
else
__clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
- spin_unlock(&sbi->cp_lock);
+ spin_unlock_irqrestore(&sbi->cp_lock, flags);
orphan_blocks = GET_ORPHAN_BLOCKS(orphan_num);
ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks +
@@ -1130,11 +1246,37 @@
start_blk = __start_cp_next_addr(sbi);
+ /* write nat bits */
+ if (enabled_nat_bits(sbi, cpc)) {
+ __u64 cp_ver = cur_cp_version(ckpt);
+ block_t blk;
+
+ cp_ver |= ((__u64)crc32 << 32);
+ *(__le64 *)nm_i->nat_bits = cpu_to_le64(cp_ver);
+
+ blk = start_blk + sbi->blocks_per_seg - nm_i->nat_bits_blocks;
+ for (i = 0; i < nm_i->nat_bits_blocks; i++)
+ update_meta_page(sbi, nm_i->nat_bits +
+ (i << F2FS_BLKSIZE_BITS), blk + i);
+
+ /* Flush all the NAT BITS pages */
+ while (get_pages(sbi, F2FS_DIRTY_META)) {
+ sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
+ if (unlikely(f2fs_cp_error(sbi)))
+ return -EIO;
+ }
+ }
+
/* need to wait for end_io results */
wait_on_all_pages_writeback(sbi);
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
+ /* flush all device cache */
+ err = f2fs_flush_device_cache(sbi);
+ if (err)
+ return err;
+
/* write out checkpoint buffer at block 0 */
update_meta_page(sbi, ckpt, start_blk++);
@@ -1179,7 +1321,7 @@
percpu_counter_set(&sbi->alloc_valid_block_count, 0);
/* Here, we only have one bio having CP pack */
- sync_meta_pages(sbi, META_FLUSH, LONG_MAX);
+ sync_meta_pages(sbi, META_FLUSH, LONG_MAX, FS_CP_META_IO);
/* wait for previous submitted meta pages writeback */
wait_on_all_pages_writeback(sbi);
@@ -1189,7 +1331,6 @@
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
- clear_prefree_segments(sbi, cpc);
clear_sbi_flag(sbi, SBI_IS_DIRTY);
clear_sbi_flag(sbi, SBI_NEED_CP);
__set_cp_next_pack(sbi);
@@ -1219,8 +1360,8 @@
mutex_lock(&sbi->cp_mutex);
if (!is_sbi_flag_set(sbi, SBI_IS_DIRTY) &&
- (cpc->reason == CP_FASTBOOT || cpc->reason == CP_SYNC ||
- (cpc->reason == CP_DISCARD && !sbi->discard_blks)))
+ ((cpc->reason & CP_FASTBOOT) || (cpc->reason & CP_SYNC) ||
+ ((cpc->reason & CP_DISCARD) && !sbi->discard_blks)))
goto out;
if (unlikely(f2fs_cp_error(sbi))) {
err = -EIO;
@@ -1239,18 +1380,23 @@
trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish block_ops");
- f2fs_flush_merged_bios(sbi);
+ f2fs_flush_merged_writes(sbi);
/* this is the case of multiple fstrims without any changes */
- if (cpc->reason == CP_DISCARD && !is_sbi_flag_set(sbi, SBI_IS_DIRTY)) {
- f2fs_bug_on(sbi, NM_I(sbi)->dirty_nat_cnt);
- f2fs_bug_on(sbi, SIT_I(sbi)->dirty_sentries);
- f2fs_bug_on(sbi, prefree_segments(sbi));
- flush_sit_entries(sbi, cpc);
- clear_prefree_segments(sbi, cpc);
- f2fs_wait_all_discard_bio(sbi);
- unblock_operations(sbi);
- goto out;
+ if (cpc->reason & CP_DISCARD) {
+ if (!exist_trim_candidates(sbi, cpc)) {
+ unblock_operations(sbi);
+ goto out;
+ }
+
+ if (NM_I(sbi)->dirty_nat_cnt == 0 &&
+ SIT_I(sbi)->dirty_sentries == 0 &&
+ prefree_segments(sbi) == 0) {
+ flush_sit_entries(sbi, cpc);
+ clear_prefree_segments(sbi, cpc);
+ unblock_operations(sbi);
+ goto out;
+ }
}
/*
@@ -1262,18 +1408,20 @@
ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver);
/* write cached NAT/SIT entries to NAT/SIT area */
- flush_nat_entries(sbi);
+ flush_nat_entries(sbi, cpc);
flush_sit_entries(sbi, cpc);
/* unlock all the fs_lock[] in do_checkpoint() */
err = do_checkpoint(sbi, cpc);
-
- f2fs_wait_all_discard_bio(sbi);
+ if (err)
+ release_discard_addrs(sbi);
+ else
+ clear_prefree_segments(sbi, cpc);
unblock_operations(sbi);
stat_inc_cp_count(sbi->stat_info);
- if (cpc->reason == CP_RECOVERY)
+ if (cpc->reason & CP_RECOVERY)
f2fs_msg(sbi->sb, KERN_NOTICE,
"checkpoint: version = %llx", ckpt_ver);
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 08b3f62..6c13ee3 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -30,14 +30,36 @@
#include <trace/events/f2fs.h>
#include <trace/events/android_fs.h>
+static bool __is_cp_guaranteed(struct page *page)
+{
+ struct address_space *mapping = page->mapping;
+ struct inode *inode;
+ struct f2fs_sb_info *sbi;
+
+ if (!mapping)
+ return false;
+
+ inode = mapping->host;
+ sbi = F2FS_I_SB(inode);
+
+ if (inode->i_ino == F2FS_META_INO(sbi) ||
+ inode->i_ino == F2FS_NODE_INO(sbi) ||
+ S_ISDIR(inode->i_mode) ||
+ is_cold_data(page))
+ return true;
+ return false;
+}
+
static void f2fs_read_end_io(struct bio *bio)
{
struct bio_vec *bvec;
int i;
#ifdef CONFIG_F2FS_FAULT_INJECTION
- if (time_to_inject(F2FS_P_SB(bio->bi_io_vec->bv_page), FAULT_IO))
+ if (time_to_inject(F2FS_P_SB(bio->bi_io_vec->bv_page), FAULT_IO)) {
+ f2fs_show_injection_info(FAULT_IO);
bio->bi_error = -EIO;
+ }
#endif
if (f2fs_bio_encrypted(bio)) {
@@ -72,16 +94,35 @@
bio_for_each_segment_all(bvec, bio, i) {
struct page *page = bvec->bv_page;
+ enum count_type type = WB_DATA_TYPE(page);
+
+ if (IS_DUMMY_WRITTEN_PAGE(page)) {
+ set_page_private(page, (unsigned long)NULL);
+ ClearPagePrivate(page);
+ unlock_page(page);
+ mempool_free(page, sbi->write_io_dummy);
+
+ if (unlikely(bio->bi_error))
+ f2fs_stop_checkpoint(sbi, true);
+ continue;
+ }
fscrypt_pullback_bio_page(&page, true);
if (unlikely(bio->bi_error)) {
mapping_set_error(page->mapping, -EIO);
- f2fs_stop_checkpoint(sbi, true);
+ if (type == F2FS_WB_CP_DATA)
+ f2fs_stop_checkpoint(sbi, true);
}
+
+ f2fs_bug_on(sbi, page->mapping == NODE_MAPPING(sbi) &&
+ page->index != nid_of_node(page));
+
+ dec_page_count(sbi, type);
+ clear_cold_data(page);
end_page_writeback(page);
}
- if (atomic_dec_and_test(&sbi->nr_wb_bios) &&
+ if (!get_pages(sbi, F2FS_WB_CP_DATA) &&
wq_has_sleeper(&sbi->cp_wait))
wake_up(&sbi->cp_wait);
@@ -89,19 +130,61 @@
}
/*
+ * Return true, if pre_bio's bdev is same as its target device.
+ */
+struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi,
+ block_t blk_addr, struct bio *bio)
+{
+ struct block_device *bdev = sbi->sb->s_bdev;
+ int i;
+
+ for (i = 0; i < sbi->s_ndevs; i++) {
+ if (FDEV(i).start_blk <= blk_addr &&
+ FDEV(i).end_blk >= blk_addr) {
+ blk_addr -= FDEV(i).start_blk;
+ bdev = FDEV(i).bdev;
+ break;
+ }
+ }
+ if (bio) {
+ bio->bi_bdev = bdev;
+ bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(blk_addr);
+ }
+ return bdev;
+}
+
+int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr)
+{
+ int i;
+
+ for (i = 0; i < sbi->s_ndevs; i++)
+ if (FDEV(i).start_blk <= blkaddr && FDEV(i).end_blk >= blkaddr)
+ return i;
+ return 0;
+}
+
+static bool __same_bdev(struct f2fs_sb_info *sbi,
+ block_t blk_addr, struct bio *bio)
+{
+ return f2fs_target_device(sbi, blk_addr, NULL) == bio->bi_bdev;
+}
+
+/*
* Low-level block read/write IO operations.
*/
static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
+ struct writeback_control *wbc,
int npages, bool is_read)
{
struct bio *bio;
- bio = f2fs_bio_alloc(npages);
+ bio = f2fs_bio_alloc(sbi, npages, true);
- bio->bi_bdev = sbi->sb->s_bdev;
- bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(blk_addr);
+ f2fs_target_device(sbi, blk_addr, bio);
bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io;
bio->bi_private = is_read ? NULL : sbi;
+ if (wbc)
+ wbc_init_bio(wbc, bio);
return bio;
}
@@ -110,11 +193,46 @@
struct bio *bio, enum page_type type)
{
if (!is_read_io(bio_op(bio))) {
- atomic_inc(&sbi->nr_wb_bios);
- if (f2fs_sb_mounted_hmsmr(sbi->sb) &&
+ unsigned int start;
+
+ if (f2fs_sb_mounted_blkzoned(sbi->sb) &&
current->plug && (type == DATA || type == NODE))
blk_finish_plug(current->plug);
+
+ if (type != DATA && type != NODE)
+ goto submit_io;
+
+ start = bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS;
+ start %= F2FS_IO_SIZE(sbi);
+
+ if (start == 0)
+ goto submit_io;
+
+ /* fill dummy pages */
+ for (; start < F2FS_IO_SIZE(sbi); start++) {
+ struct page *page =
+ mempool_alloc(sbi->write_io_dummy,
+ GFP_NOIO | __GFP_ZERO | __GFP_NOFAIL);
+ f2fs_bug_on(sbi, !page);
+
+ SetPagePrivate(page);
+ set_page_private(page, (unsigned long)DUMMY_WRITTEN_PAGE);
+ lock_page(page);
+ if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE)
+ f2fs_bug_on(sbi, 1);
+ }
+ /*
+ * In the NODE case, we lose next block address chain. So, we
+ * need to do checkpoint in f2fs_sync_file.
+ */
+ if (type == NODE)
+ set_sbi_flag(sbi, SBI_NEED_CP);
}
+submit_io:
+ if (is_read_io(bio_op(bio)))
+ trace_f2fs_submit_read_bio(sbi->sb, type, bio);
+ else
+ trace_f2fs_submit_write_bio(sbi->sb, type, bio);
submit_bio(bio);
}
@@ -125,19 +243,19 @@
if (!io->bio)
return;
- if (is_read_io(fio->op))
- trace_f2fs_submit_read_bio(io->sbi->sb, fio, io->bio);
- else
- trace_f2fs_submit_write_bio(io->sbi->sb, fio, io->bio);
-
bio_set_op_attrs(io->bio, fio->op, fio->op_flags);
+ if (is_read_io(fio->op))
+ trace_f2fs_prepare_read_bio(io->sbi->sb, fio->type, io->bio);
+ else
+ trace_f2fs_prepare_write_bio(io->sbi->sb, fio->type, io->bio);
+
__submit_bio(io->sbi, io->bio, fio->type);
io->bio = NULL;
}
-static bool __has_merged_page(struct f2fs_bio_info *io, struct inode *inode,
- struct page *page, nid_t ino)
+static bool __has_merged_page(struct f2fs_bio_info *io,
+ struct inode *inode, nid_t ino, pgoff_t idx)
{
struct bio_vec *bvec;
struct page *target;
@@ -146,7 +264,7 @@
if (!io->bio)
return false;
- if (!inode && !page && !ino)
+ if (!inode && !ino)
return true;
bio_for_each_segment_all(bvec, io->bio, i) {
@@ -156,10 +274,11 @@
else
target = fscrypt_control_page(bvec->bv_page);
+ if (idx != target->index)
+ continue;
+
if (inode && inode == target->mapping->host)
return true;
- if (page && page == target)
- return true;
if (ino && ino == ino_of_node(target))
return true;
}
@@ -168,72 +287,88 @@
}
static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
- struct page *page, nid_t ino,
- enum page_type type)
+ nid_t ino, pgoff_t idx, enum page_type type)
{
enum page_type btype = PAGE_TYPE_OF_BIO(type);
- struct f2fs_bio_info *io = &sbi->write_io[btype];
- bool ret;
+ enum temp_type temp;
+ struct f2fs_bio_info *io;
+ bool ret = false;
- down_read(&io->io_rwsem);
- ret = __has_merged_page(io, inode, page, ino);
- up_read(&io->io_rwsem);
+ for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
+ io = sbi->write_io[btype] + temp;
+
+ down_read(&io->io_rwsem);
+ ret = __has_merged_page(io, inode, ino, idx);
+ up_read(&io->io_rwsem);
+
+ /* TODO: use HOT temp only for meta pages now. */
+ if (ret || btype == META)
+ break;
+ }
return ret;
}
-static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
- struct inode *inode, struct page *page,
- nid_t ino, enum page_type type, int rw)
+static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
+ enum page_type type, enum temp_type temp)
{
enum page_type btype = PAGE_TYPE_OF_BIO(type);
- struct f2fs_bio_info *io;
-
- io = is_read_io(rw) ? &sbi->read_io : &sbi->write_io[btype];
+ struct f2fs_bio_info *io = sbi->write_io[btype] + temp;
down_write(&io->io_rwsem);
- if (!__has_merged_page(io, inode, page, ino))
- goto out;
-
/* change META to META_FLUSH in the checkpoint procedure */
if (type >= META_FLUSH) {
io->fio.type = META_FLUSH;
io->fio.op = REQ_OP_WRITE;
- if (test_opt(sbi, NOBARRIER))
- io->fio.op_flags = WRITE_FLUSH | REQ_META | REQ_PRIO;
- else
- io->fio.op_flags = WRITE_FLUSH_FUA | REQ_META |
- REQ_PRIO;
+ io->fio.op_flags = REQ_META | REQ_PRIO | REQ_SYNC;
+ if (!test_opt(sbi, NOBARRIER))
+ io->fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
}
__submit_merged_bio(io);
-out:
up_write(&io->io_rwsem);
}
-void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type,
- int rw)
+static void __submit_merged_write_cond(struct f2fs_sb_info *sbi,
+ struct inode *inode, nid_t ino, pgoff_t idx,
+ enum page_type type, bool force)
{
- __f2fs_submit_merged_bio(sbi, NULL, NULL, 0, type, rw);
+ enum temp_type temp;
+
+ if (!force && !has_merged_page(sbi, inode, ino, idx, type))
+ return;
+
+ for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
+
+ __f2fs_submit_merged_write(sbi, type, temp);
+
+ /* TODO: use HOT temp only for meta pages now. */
+ if (type >= META)
+ break;
+ }
}
-void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *sbi,
- struct inode *inode, struct page *page,
- nid_t ino, enum page_type type, int rw)
+void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type)
{
- if (has_merged_page(sbi, inode, page, ino, type))
- __f2fs_submit_merged_bio(sbi, inode, page, ino, type, rw);
+ __submit_merged_write_cond(sbi, NULL, 0, 0, type, true);
}
-void f2fs_flush_merged_bios(struct f2fs_sb_info *sbi)
+void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi,
+ struct inode *inode, nid_t ino, pgoff_t idx,
+ enum page_type type)
{
- f2fs_submit_merged_bio(sbi, DATA, WRITE);
- f2fs_submit_merged_bio(sbi, NODE, WRITE);
- f2fs_submit_merged_bio(sbi, META, WRITE);
+ __submit_merged_write_cond(sbi, inode, ino, idx, type, false);
+}
+
+void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi)
+{
+ f2fs_submit_merged_write(sbi, DATA);
+ f2fs_submit_merged_write(sbi, NODE);
+ f2fs_submit_merged_write(sbi, META);
}
/*
* Fill the locked page with data located in the block address.
- * Return unlocked page.
+ * A caller needs to unlock the page on failure.
*/
int f2fs_submit_page_bio(struct f2fs_io_info *fio)
{
@@ -245,7 +380,8 @@
f2fs_trace_ios(fio, 0);
/* Allocate a new bio */
- bio = __bio_alloc(fio->sbi, fio->new_blkaddr, 1, is_read_io(fio->op));
+ bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc,
+ 1, is_read_io(fio->op));
if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
bio_put(bio);
@@ -254,60 +390,143 @@
bio_set_op_attrs(bio, fio->op, fio->op_flags);
__submit_bio(fio->sbi, bio, fio->type);
+
+ if (!is_read_io(fio->op))
+ inc_page_count(fio->sbi, WB_DATA_TYPE(fio->page));
return 0;
}
-void f2fs_submit_page_mbio(struct f2fs_io_info *fio)
+int f2fs_submit_page_write(struct f2fs_io_info *fio)
{
struct f2fs_sb_info *sbi = fio->sbi;
enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
- struct f2fs_bio_info *io;
- bool is_read = is_read_io(fio->op);
+ struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;
struct page *bio_page;
+ int err = 0;
- io = is_read ? &sbi->read_io : &sbi->write_io[btype];
+ f2fs_bug_on(sbi, is_read_io(fio->op));
+
+ down_write(&io->io_rwsem);
+next:
+ if (fio->in_list) {
+ spin_lock(&io->io_lock);
+ if (list_empty(&io->io_list)) {
+ spin_unlock(&io->io_lock);
+ goto out_fail;
+ }
+ fio = list_first_entry(&io->io_list,
+ struct f2fs_io_info, list);
+ list_del(&fio->list);
+ spin_unlock(&io->io_lock);
+ }
if (fio->old_blkaddr != NEW_ADDR)
verify_block_addr(sbi, fio->old_blkaddr);
verify_block_addr(sbi, fio->new_blkaddr);
- down_write(&io->io_rwsem);
+ bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;
+
+ /* set submitted = true as a return value */
+ fio->submitted = true;
+
+ inc_page_count(sbi, WB_DATA_TYPE(bio_page));
if (io->bio && (io->last_block_in_bio != fio->new_blkaddr - 1 ||
- (io->fio.op != fio->op || io->fio.op_flags != fio->op_flags)))
+ (io->fio.op != fio->op || io->fio.op_flags != fio->op_flags) ||
+ !__same_bdev(sbi, fio->new_blkaddr, io->bio)))
__submit_merged_bio(io);
alloc_new:
if (io->bio == NULL) {
- int bio_blocks = MAX_BIO_BLOCKS(sbi);
-
- io->bio = __bio_alloc(sbi, fio->new_blkaddr,
- bio_blocks, is_read);
+ if ((fio->type == DATA || fio->type == NODE) &&
+ fio->new_blkaddr & F2FS_IO_SIZE_MASK(sbi)) {
+ err = -EAGAIN;
+ dec_page_count(sbi, WB_DATA_TYPE(bio_page));
+ goto out_fail;
+ }
+ io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc,
+ BIO_MAX_PAGES, false);
io->fio = *fio;
}
- bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;
-
- if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) <
- PAGE_SIZE) {
+ if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) < PAGE_SIZE) {
__submit_merged_bio(io);
goto alloc_new;
}
+ if (fio->io_wbc)
+ wbc_account_io(fio->io_wbc, bio_page, PAGE_SIZE);
+
io->last_block_in_bio = fio->new_blkaddr;
f2fs_trace_ios(fio, 0);
+ trace_f2fs_submit_page_write(fio->page, fio);
+
+ if (fio->in_list)
+ goto next;
+out_fail:
up_write(&io->io_rwsem);
- trace_f2fs_submit_page_mbio(fio->page, fio);
+ return err;
+}
+
+static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
+ unsigned nr_pages)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct fscrypt_ctx *ctx = NULL;
+ struct bio *bio;
+
+ if (f2fs_encrypted_file(inode)) {
+ ctx = fscrypt_get_ctx(inode, GFP_NOFS);
+ if (IS_ERR(ctx))
+ return ERR_CAST(ctx);
+
+ /* wait the page to be moved by cleaning */
+ f2fs_wait_on_block_writeback(sbi, blkaddr);
+ }
+
+ bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false);
+ if (!bio) {
+ if (ctx)
+ fscrypt_release_ctx(ctx);
+ return ERR_PTR(-ENOMEM);
+ }
+ f2fs_target_device(sbi, blkaddr, bio);
+ bio->bi_end_io = f2fs_read_end_io;
+ bio->bi_private = ctx;
+ bio_set_op_attrs(bio, REQ_OP_READ, 0);
+
+ return bio;
+}
+
+/* This can handle encryption stuffs */
+static int f2fs_submit_page_read(struct inode *inode, struct page *page,
+ block_t blkaddr)
+{
+ struct bio *bio = f2fs_grab_read_bio(inode, blkaddr, 1);
+
+ if (IS_ERR(bio))
+ return PTR_ERR(bio);
+
+ if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
+ bio_put(bio);
+ return -EFAULT;
+ }
+ __submit_bio(F2FS_I_SB(inode), bio, DATA);
+ return 0;
}
static void __set_data_blkaddr(struct dnode_of_data *dn)
{
struct f2fs_node *rn = F2FS_NODE(dn->node_page);
__le32 *addr_array;
+ int base = 0;
+
+ if (IS_INODE(dn->node_page) && f2fs_has_extra_attr(dn->inode))
+ base = get_extra_isize(dn->inode);
/* Get physical address of data block */
addr_array = blkaddr_in_node(rn);
- addr_array[dn->ofs_in_node] = cpu_to_le32(dn->data_blkaddr);
+ addr_array[base + dn->ofs_in_node] = cpu_to_le32(dn->data_blkaddr);
}
/*
@@ -335,14 +554,15 @@
int reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
+ int err;
if (!count)
return 0;
if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC)))
return -EPERM;
- if (unlikely(!inc_valid_block_count(sbi, dn->inode, &count)))
- return -ENOSPC;
+ if (unlikely((err = inc_valid_block_count(sbi, dn->inode, &count))))
+ return err;
trace_f2fs_reserve_new_blocks(dn->inode, dn->nid,
dn->ofs_in_node, count);
@@ -350,8 +570,8 @@
f2fs_wait_on_page_writeback(dn->node_page, NODE, true);
for (; count > 0; dn->ofs_in_node++) {
- block_t blkaddr =
- datablock_addr(dn->node_page, dn->ofs_in_node);
+ block_t blkaddr = datablock_addr(dn->inode,
+ dn->node_page, dn->ofs_in_node);
if (blkaddr == NULL_ADDR) {
dn->data_blkaddr = NEW_ADDR;
__set_data_blkaddr(dn);
@@ -393,7 +613,7 @@
int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index)
{
- struct extent_info ei;
+ struct extent_info ei = {0,0,0};
struct inode *inode = dn->inode;
if (f2fs_lookup_extent_cache(inode, index, &ei)) {
@@ -410,18 +630,8 @@
struct address_space *mapping = inode->i_mapping;
struct dnode_of_data dn;
struct page *page;
- struct extent_info ei;
+ struct extent_info ei = {0,0,0};
int err;
- struct f2fs_io_info fio = {
- .sbi = F2FS_I_SB(inode),
- .type = DATA,
- .op = REQ_OP_READ,
- .op_flags = op_flags,
- .encrypted_page = NULL,
- };
-
- if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
- return read_mapping_page(mapping, index, NULL);
page = f2fs_grab_cache_page(mapping, index, for_write);
if (!page)
@@ -462,9 +672,7 @@
return page;
}
- fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr;
- fio.page = page;
- err = f2fs_submit_page_bio(&fio);
+ err = f2fs_submit_page_read(inode, page, dn.data_blkaddr);
if (err)
goto put_err;
return page;
@@ -484,7 +692,7 @@
return page;
f2fs_put_page(page, 0);
- page = get_read_data_page(inode, index, READ_SYNC, false);
+ page = get_read_data_page(inode, index, 0, false);
if (IS_ERR(page))
return page;
@@ -510,7 +718,7 @@
struct address_space *mapping = inode->i_mapping;
struct page *page;
repeat:
- page = get_read_data_page(inode, index, READ_SYNC, for_write);
+ page = get_read_data_page(inode, index, 0, for_write);
if (IS_ERR(page))
return page;
@@ -586,34 +794,32 @@
return page;
}
-static int __allocate_data_block(struct dnode_of_data *dn)
+static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
struct f2fs_summary sum;
struct node_info ni;
- int seg = CURSEG_WARM_DATA;
pgoff_t fofs;
blkcnt_t count = 1;
+ int err;
if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC)))
return -EPERM;
- dn->data_blkaddr = datablock_addr(dn->node_page, dn->ofs_in_node);
+ dn->data_blkaddr = datablock_addr(dn->inode,
+ dn->node_page, dn->ofs_in_node);
if (dn->data_blkaddr == NEW_ADDR)
goto alloc;
- if (unlikely(!inc_valid_block_count(sbi, dn->inode, &count)))
- return -ENOSPC;
+ if (unlikely((err = inc_valid_block_count(sbi, dn->inode, &count))))
+ return err;
alloc:
get_node_info(sbi, dn->nid, &ni);
set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
- if (dn->ofs_in_node == 0 && dn->inode_page == dn->node_page)
- seg = CURSEG_DIRECT_IO;
-
allocate_data_block(sbi, NULL, dn->data_blkaddr, &dn->data_blkaddr,
- &sum, seg);
+ &sum, seg_type, NULL, false);
set_data_blkaddr(dn);
/* update i_size */
@@ -625,11 +831,30 @@
return 0;
}
-ssize_t f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
+static inline bool __force_buffered_io(struct inode *inode, int rw)
+{
+ return (f2fs_encrypted_file(inode) ||
+ (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) ||
+ F2FS_I_SB(inode)->s_ndevs);
+}
+
+int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
{
struct inode *inode = file_inode(iocb->ki_filp);
struct f2fs_map_blocks map;
- ssize_t ret = 0;
+ int flag;
+ int err = 0;
+ bool direct_io = iocb->ki_flags & IOCB_DIRECT;
+
+ /* convert inline data for Direct I/O*/
+ if (direct_io) {
+ err = f2fs_convert_inline_inode(inode);
+ if (err)
+ return err;
+ }
+
+ if (is_inode_flag_set(inode, FI_NO_PREALLOC))
+ return 0;
map.m_lblk = F2FS_BLK_ALIGN(iocb->ki_pos);
map.m_len = F2FS_BYTES_TO_BLK(iocb->ki_pos + iov_iter_count(from));
@@ -639,21 +864,50 @@
map.m_len = 0;
map.m_next_pgofs = NULL;
+ map.m_next_extent = NULL;
+ map.m_seg_type = NO_CHECK_TYPE;
- if (iocb->ki_flags & IOCB_DIRECT) {
- ret = f2fs_convert_inline_inode(inode);
- if (ret)
- return ret;
- return f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_DIO);
+ if (direct_io) {
+ /* map.m_seg_type = rw_hint_to_seg_type(iocb->ki_hint); */
+ map.m_seg_type = rw_hint_to_seg_type(WRITE_LIFE_NOT_SET);
+ flag = __force_buffered_io(inode, WRITE) ?
+ F2FS_GET_BLOCK_PRE_AIO :
+ F2FS_GET_BLOCK_PRE_DIO;
+ goto map_blocks;
}
- if (iocb->ki_pos + iov_iter_count(from) > MAX_INLINE_DATA) {
- ret = f2fs_convert_inline_inode(inode);
- if (ret)
- return ret;
+ if (iocb->ki_pos + iov_iter_count(from) > MAX_INLINE_DATA(inode)) {
+ err = f2fs_convert_inline_inode(inode);
+ if (err)
+ return err;
}
- if (!f2fs_has_inline_data(inode))
- return f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO);
- return ret;
+ if (f2fs_has_inline_data(inode))
+ return err;
+
+ flag = F2FS_GET_BLOCK_PRE_AIO;
+
+map_blocks:
+ err = f2fs_map_blocks(inode, &map, 1, flag);
+ if (map.m_len > 0 && err == -ENOSPC) {
+ if (!direct_io)
+ set_inode_flag(inode, FI_NO_PREALLOC);
+ err = 0;
+ }
+ return err;
+}
+
+static inline void __do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock)
+{
+ if (flag == F2FS_GET_BLOCK_PRE_AIO) {
+ if (lock)
+ down_read(&sbi->node_change);
+ else
+ up_read(&sbi->node_change);
+ } else {
+ if (lock)
+ f2fs_lock_op(sbi);
+ else
+ f2fs_unlock_op(sbi);
+ }
}
/*
@@ -676,9 +930,9 @@
int err = 0, ofs = 1;
unsigned int ofs_in_node, last_ofs_in_node;
blkcnt_t prealloc;
- struct extent_info ei;
- bool allocated = false;
+ struct extent_info ei = {0,0,0};
block_t blkaddr;
+ unsigned int start_pgofs;
if (!maxblocks)
return 0;
@@ -694,12 +948,14 @@
map->m_pblk = ei.blk + pgofs - ei.fofs;
map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs);
map->m_flags = F2FS_MAP_MAPPED;
+ if (map->m_next_extent)
+ *map->m_next_extent = pgofs + map->m_len;
goto out;
}
next_dnode:
if (create)
- f2fs_lock_op(sbi);
+ __do_map_lock(sbi, flag, true);
/* When reading holes, we need its node page */
set_new_dnode(&dn, inode, NULL, NULL, 0);
@@ -712,16 +968,20 @@
if (map->m_next_pgofs)
*map->m_next_pgofs =
get_next_page_offset(&dn, pgofs);
+ if (map->m_next_extent)
+ *map->m_next_extent =
+ get_next_page_offset(&dn, pgofs);
}
goto unlock_out;
}
+ start_pgofs = pgofs;
prealloc = 0;
last_ofs_in_node = ofs_in_node = dn.ofs_in_node;
end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
next_block:
- blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
+ blkaddr = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) {
if (create) {
@@ -735,29 +995,34 @@
last_ofs_in_node = dn.ofs_in_node;
}
} else {
- err = __allocate_data_block(&dn);
- if (!err) {
+ err = __allocate_data_block(&dn,
+ map->m_seg_type);
+ if (!err)
set_inode_flag(inode, FI_APPEND_WRITE);
- allocated = true;
- }
}
if (err)
goto sync_out;
- map->m_flags = F2FS_MAP_NEW;
+ map->m_flags |= F2FS_MAP_NEW;
blkaddr = dn.data_blkaddr;
} else {
if (flag == F2FS_GET_BLOCK_BMAP) {
map->m_pblk = 0;
goto sync_out;
}
+ if (flag == F2FS_GET_BLOCK_PRECACHE)
+ goto sync_out;
if (flag == F2FS_GET_BLOCK_FIEMAP &&
blkaddr == NULL_ADDR) {
if (map->m_next_pgofs)
*map->m_next_pgofs = pgofs + 1;
- }
- if (flag != F2FS_GET_BLOCK_FIEMAP ||
- blkaddr != NEW_ADDR)
goto sync_out;
+ }
+ if (flag != F2FS_GET_BLOCK_FIEMAP) {
+ /* for defragment case */
+ if (map->m_next_pgofs)
+ *map->m_next_pgofs = pgofs + 1;
+ goto sync_out;
+ }
}
}
@@ -794,7 +1059,6 @@
err = reserve_new_blocks(&dn, prealloc);
if (err)
goto sync_out;
- allocated = dn.node_changed;
map->m_len += dn.ofs_in_node - ofs_in_node;
if (prealloc && dn.ofs_in_node != last_ofs_in_node + 1) {
@@ -809,21 +1073,41 @@
else if (dn.ofs_in_node < end_offset)
goto next_block;
+ if (flag == F2FS_GET_BLOCK_PRECACHE) {
+ if (map->m_flags & F2FS_MAP_MAPPED) {
+ unsigned int ofs = start_pgofs - map->m_lblk;
+
+ f2fs_update_extent_cache_range(&dn,
+ start_pgofs, map->m_pblk + ofs,
+ map->m_len - ofs);
+ }
+ }
+
f2fs_put_dnode(&dn);
if (create) {
- f2fs_unlock_op(sbi);
- f2fs_balance_fs(sbi, allocated);
+ __do_map_lock(sbi, flag, false);
+ f2fs_balance_fs(sbi, dn.node_changed);
}
- allocated = false;
goto next_dnode;
sync_out:
+ if (flag == F2FS_GET_BLOCK_PRECACHE) {
+ if (map->m_flags & F2FS_MAP_MAPPED) {
+ unsigned int ofs = start_pgofs - map->m_lblk;
+
+ f2fs_update_extent_cache_range(&dn,
+ start_pgofs, map->m_pblk + ofs,
+ map->m_len - ofs);
+ }
+ if (map->m_next_extent)
+ *map->m_next_extent = pgofs + 1;
+ }
f2fs_put_dnode(&dn);
unlock_out:
if (create) {
- f2fs_unlock_op(sbi);
- f2fs_balance_fs(sbi, allocated);
+ __do_map_lock(sbi, flag, false);
+ f2fs_balance_fs(sbi, dn.node_changed);
}
out:
trace_f2fs_map_blocks(inode, map, err);
@@ -832,22 +1116,24 @@
static int __get_data_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh, int create, int flag,
- pgoff_t *next_pgofs)
+ pgoff_t *next_pgofs, int seg_type)
{
struct f2fs_map_blocks map;
- int ret;
+ int err;
map.m_lblk = iblock;
map.m_len = bh->b_size >> inode->i_blkbits;
map.m_next_pgofs = next_pgofs;
+ map.m_next_extent = NULL;
+ map.m_seg_type = seg_type;
- ret = f2fs_map_blocks(inode, &map, create, flag);
- if (!ret) {
+ err = f2fs_map_blocks(inode, &map, create, flag);
+ if (!err) {
map_bh(bh, inode->i_sb, map.m_pblk);
bh->b_state = (bh->b_state & ~F2FS_MAP_FLAGS) | map.m_flags;
- bh->b_size = map.m_len << inode->i_blkbits;
+ bh->b_size = (u64)map.m_len << inode->i_blkbits;
}
- return ret;
+ return err;
}
static int get_data_block(struct inode *inode, sector_t iblock,
@@ -855,14 +1141,18 @@
pgoff_t *next_pgofs)
{
return __get_data_block(inode, iblock, bh_result, create,
- flag, next_pgofs);
+ flag, next_pgofs,
+ NO_CHECK_TYPE);
}
static int get_data_block_dio(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
return __get_data_block(inode, iblock, bh_result, create,
- F2FS_GET_BLOCK_DIO, NULL);
+ F2FS_GET_BLOCK_DEFAULT, NULL,
+ rw_hint_to_seg_type(
+ WRITE_LIFE_NOT_SET));
+ /* inode->i_write_hint)); */
}
static int get_data_block_bmap(struct inode *inode, sector_t iblock,
@@ -873,7 +1163,8 @@
return -EFBIG;
return __get_data_block(inode, iblock, bh_result, create,
- F2FS_GET_BLOCK_BMAP, NULL);
+ F2FS_GET_BLOCK_BMAP, NULL,
+ NO_CHECK_TYPE);
}
static inline sector_t logical_to_blk(struct inode *inode, loff_t offset)
@@ -886,36 +1177,101 @@
return (blk << inode->i_blkbits);
}
+static int f2fs_xattr_fiemap(struct inode *inode,
+ struct fiemap_extent_info *fieinfo)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct page *page;
+ struct node_info ni;
+ __u64 phys = 0, len;
+ __u32 flags;
+ nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+ int err = 0;
+
+ if (f2fs_has_inline_xattr(inode)) {
+ int offset;
+
+ page = f2fs_grab_cache_page(NODE_MAPPING(sbi),
+ inode->i_ino, false);
+ if (!page)
+ return -ENOMEM;
+
+ get_node_info(sbi, inode->i_ino, &ni);
+
+ phys = (__u64)blk_to_logical(inode, ni.blk_addr);
+ offset = offsetof(struct f2fs_inode, i_addr) +
+ sizeof(__le32) * (DEF_ADDRS_PER_INODE -
+ get_inline_xattr_addrs(inode));
+
+ phys += offset;
+ len = inline_xattr_size(inode);
+
+ f2fs_put_page(page, 1);
+
+ flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED;
+
+ if (!xnid)
+ flags |= FIEMAP_EXTENT_LAST;
+
+ err = fiemap_fill_next_extent(fieinfo, 0, phys, len, flags);
+ if (err || err == 1)
+ return err;
+ }
+
+ if (xnid) {
+ page = f2fs_grab_cache_page(NODE_MAPPING(sbi), xnid, false);
+ if (!page)
+ return -ENOMEM;
+
+ get_node_info(sbi, xnid, &ni);
+
+ phys = (__u64)blk_to_logical(inode, ni.blk_addr);
+ len = inode->i_sb->s_blocksize;
+
+ f2fs_put_page(page, 1);
+
+ flags = FIEMAP_EXTENT_LAST;
+ }
+
+ if (phys)
+ err = fiemap_fill_next_extent(fieinfo, 0, phys, len, flags);
+
+ return (err < 0 ? err : 0);
+}
+
int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
u64 start, u64 len)
{
struct buffer_head map_bh;
sector_t start_blk, last_blk;
pgoff_t next_pgofs;
- loff_t isize;
u64 logical = 0, phys = 0, size = 0;
u32 flags = 0;
int ret = 0;
- ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
+ if (fieinfo->fi_flags & FIEMAP_FLAG_CACHE) {
+ ret = f2fs_precache_extents(inode);
+ if (ret)
+ return ret;
+ }
+
+ ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR);
if (ret)
return ret;
+ inode_lock(inode);
+
+ if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
+ ret = f2fs_xattr_fiemap(inode, fieinfo);
+ goto out;
+ }
+
if (f2fs_has_inline_data(inode)) {
ret = f2fs_inline_data_fiemap(inode, fieinfo, start, len);
if (ret != -EAGAIN)
- return ret;
+ goto out;
}
- inode_lock(inode);
-
- isize = i_size_read(inode);
- if (start >= isize)
- goto out;
-
- if (start + len > isize)
- len = isize - start;
-
if (logical_to_blk(inode, len) == 0)
len = blk_to_logical(inode, 1);
@@ -934,13 +1290,11 @@
/* HOLE */
if (!buffer_mapped(&map_bh)) {
start_blk = next_pgofs;
- /* Go through holes util pass the EOF */
- if (blk_to_logical(inode, start_blk) < isize)
+
+ if (blk_to_logical(inode, start_blk) < blk_to_logical(inode,
+ F2FS_I_SB(inode)->max_file_blocks))
goto prep_next;
- /* Found a hole beyond isize means no more extents.
- * Note that the premise is that filesystems don't
- * punch holes beyond isize and keep size unchanged.
- */
+
flags |= FIEMAP_EXTENT_LAST;
}
@@ -978,37 +1332,6 @@
return ret;
}
-static struct bio *f2fs_grab_bio(struct inode *inode, block_t blkaddr,
- unsigned nr_pages)
-{
- struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- struct fscrypt_ctx *ctx = NULL;
- struct block_device *bdev = sbi->sb->s_bdev;
- struct bio *bio;
-
- if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
- ctx = fscrypt_get_ctx(inode, GFP_NOFS);
- if (IS_ERR(ctx))
- return ERR_CAST(ctx);
-
- /* wait the page to be moved by cleaning */
- f2fs_wait_on_encrypted_page_writeback(sbi, blkaddr);
- }
-
- bio = bio_alloc(GFP_KERNEL, min_t(int, nr_pages, BIO_MAX_PAGES));
- if (!bio) {
- if (ctx)
- fscrypt_release_ctx(ctx);
- return ERR_PTR(-ENOMEM);
- }
- bio->bi_bdev = bdev;
- bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(blkaddr);
- bio->bi_end_io = f2fs_read_end_io;
- bio->bi_private = ctx;
-
- return bio;
-}
-
/*
* This function was originally taken from fs/mpage.c, and customized for f2fs.
* Major change was from block_size == page_size in f2fs by default.
@@ -1018,7 +1341,6 @@
unsigned nr_pages)
{
struct bio *bio = NULL;
- unsigned page_idx;
sector_t last_block_in_bio = 0;
struct inode *inode = mapping->host;
const unsigned blkbits = inode->i_blkbits;
@@ -1034,12 +1356,14 @@
map.m_len = 0;
map.m_flags = 0;
map.m_next_pgofs = NULL;
+ map.m_next_extent = NULL;
+ map.m_seg_type = NO_CHECK_TYPE;
- for (page_idx = 0; nr_pages; page_idx++, nr_pages--) {
-
- prefetchw(&page->flags);
+ for (; nr_pages; nr_pages--) {
if (pages) {
- page = list_entry(pages->prev, struct page, lru);
+ page = list_last_entry(pages, struct page, lru);
+
+ prefetchw(&page->flags);
list_del(&page->lru);
if (add_to_page_cache_lru(page, mapping,
page->index,
@@ -1073,7 +1397,7 @@
map.m_len = last_block - block_in_file;
if (f2fs_map_blocks(inode, &map, 0,
- F2FS_GET_BLOCK_READ))
+ F2FS_GET_BLOCK_DEFAULT))
goto set_error_page;
}
got_it:
@@ -1097,18 +1421,18 @@
* This page will go to BIO. Do we need to send this
* BIO off first?
*/
- if (bio && (last_block_in_bio != block_nr - 1)) {
+ if (bio && (last_block_in_bio != block_nr - 1 ||
+ !__same_bdev(F2FS_I_SB(inode), block_nr, bio))) {
submit_and_realloc:
__submit_bio(F2FS_I_SB(inode), bio, DATA);
bio = NULL;
}
if (bio == NULL) {
- bio = f2fs_grab_bio(inode, block_nr, nr_pages);
+ bio = f2fs_grab_read_bio(inode, block_nr, nr_pages);
if (IS_ERR(bio)) {
bio = NULL;
goto set_error_page;
}
- bio_set_op_attrs(bio, REQ_OP_READ, 0);
}
if (bio_add_page(bio, page, blocksize, 0) < blocksize)
@@ -1156,8 +1480,8 @@
struct address_space *mapping,
struct list_head *pages, unsigned nr_pages)
{
- struct inode *inode = file->f_mapping->host;
- struct page *page = list_entry(pages->prev, struct page, lru);
+ struct inode *inode = mapping->host;
+ struct page *page = list_last_entry(pages, struct page, lru);
trace_f2fs_readpages(inode, page, nr_pages);
@@ -1168,17 +1492,145 @@
return f2fs_mpage_readpages(mapping, pages, NULL, nr_pages);
}
+static int encrypt_one_page(struct f2fs_io_info *fio)
+{
+ struct inode *inode = fio->page->mapping->host;
+ gfp_t gfp_flags = GFP_NOFS;
+
+ if (!f2fs_encrypted_file(inode))
+ return 0;
+
+ /* wait for GCed encrypted page writeback */
+ f2fs_wait_on_block_writeback(fio->sbi, fio->old_blkaddr);
+
+retry_encrypt:
+ fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page,
+ PAGE_SIZE, 0, fio->page->index, gfp_flags);
+ if (!IS_ERR(fio->encrypted_page))
+ return 0;
+
+ /* flush pending IOs and wait for a while in the ENOMEM case */
+ if (PTR_ERR(fio->encrypted_page) == -ENOMEM) {
+ f2fs_flush_merged_writes(fio->sbi);
+ congestion_wait(BLK_RW_ASYNC, HZ/50);
+ gfp_flags |= __GFP_NOFAIL;
+ goto retry_encrypt;
+ }
+ return PTR_ERR(fio->encrypted_page);
+}
+
+static inline bool check_inplace_update_policy(struct inode *inode,
+ struct f2fs_io_info *fio)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ unsigned int policy = SM_I(sbi)->ipu_policy;
+
+ if (policy & (0x1 << F2FS_IPU_FORCE))
+ return true;
+ if (policy & (0x1 << F2FS_IPU_SSR) && need_SSR(sbi))
+ return true;
+ if (policy & (0x1 << F2FS_IPU_UTIL) &&
+ utilization(sbi) > SM_I(sbi)->min_ipu_util)
+ return true;
+ if (policy & (0x1 << F2FS_IPU_SSR_UTIL) && need_SSR(sbi) &&
+ utilization(sbi) > SM_I(sbi)->min_ipu_util)
+ return true;
+
+ /*
+ * IPU for rewrite async pages
+ */
+ if (policy & (0x1 << F2FS_IPU_ASYNC) &&
+ fio && fio->op == REQ_OP_WRITE &&
+ !(fio->op_flags & REQ_SYNC) &&
+ !f2fs_encrypted_inode(inode))
+ return true;
+
+ /* this is only set during fdatasync */
+ if (policy & (0x1 << F2FS_IPU_FSYNC) &&
+ is_inode_flag_set(inode, FI_NEED_IPU))
+ return true;
+
+ return false;
+}
+
+bool should_update_inplace(struct inode *inode, struct f2fs_io_info *fio)
+{
+ if (f2fs_is_pinned_file(inode))
+ return true;
+
+ /* if this is cold file, we should overwrite to avoid fragmentation */
+ if (file_is_cold(inode))
+ return true;
+
+ return check_inplace_update_policy(inode, fio);
+}
+
+bool should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+ if (test_opt(sbi, LFS))
+ return true;
+ if (S_ISDIR(inode->i_mode))
+ return true;
+ if (f2fs_is_atomic_file(inode))
+ return true;
+ if (fio) {
+ if (is_cold_data(fio->page))
+ return true;
+ if (IS_ATOMIC_WRITTEN_PAGE(fio->page))
+ return true;
+ }
+ return false;
+}
+
+static inline bool need_inplace_update(struct f2fs_io_info *fio)
+{
+ struct inode *inode = fio->page->mapping->host;
+
+ if (should_update_outplace(inode, fio))
+ return false;
+
+ return should_update_inplace(inode, fio);
+}
+
+static inline bool valid_ipu_blkaddr(struct f2fs_io_info *fio)
+{
+ if (fio->old_blkaddr == NEW_ADDR)
+ return false;
+ if (fio->old_blkaddr == NULL_ADDR)
+ return false;
+ return true;
+}
+
int do_write_data_page(struct f2fs_io_info *fio)
{
struct page *page = fio->page;
struct inode *inode = page->mapping->host;
struct dnode_of_data dn;
+ struct extent_info ei = {0,0,0};
+ bool ipu_force = false;
int err = 0;
set_new_dnode(&dn, inode, NULL, NULL, 0);
+ if (need_inplace_update(fio) &&
+ f2fs_lookup_extent_cache(inode, page->index, &ei)) {
+ fio->old_blkaddr = ei.blk + page->index - ei.fofs;
+
+ if (valid_ipu_blkaddr(fio)) {
+ ipu_force = true;
+ fio->need_lock = LOCK_DONE;
+ goto got_it;
+ }
+ }
+
+ /* Deadlock due to between page->lock and f2fs_lock_op */
+ if (fio->need_lock == LOCK_REQ && !f2fs_trylock_op(fio->sbi))
+ return -EAGAIN;
+
err = get_dnode_of_data(&dn, page->index, LOOKUP_NODE);
if (err)
- return err;
+ goto out;
fio->old_blkaddr = dn.data_blkaddr;
@@ -1187,57 +1639,57 @@
ClearPageUptodate(page);
goto out_writepage;
}
-
- if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
- gfp_t gfp_flags = GFP_NOFS;
-
- /* wait for GCed encrypted page writeback */
- f2fs_wait_on_encrypted_page_writeback(F2FS_I_SB(inode),
- fio->old_blkaddr);
-retry_encrypt:
- fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page,
- gfp_flags);
- if (IS_ERR(fio->encrypted_page)) {
- err = PTR_ERR(fio->encrypted_page);
- if (err == -ENOMEM) {
- /* flush pending ios and wait for a while */
- f2fs_flush_merged_bios(F2FS_I_SB(inode));
- congestion_wait(BLK_RW_ASYNC, HZ/50);
- gfp_flags |= __GFP_NOFAIL;
- err = 0;
- goto retry_encrypt;
- }
- goto out_writepage;
- }
- }
-
- set_page_writeback(page);
-
+got_it:
/*
* If current allocation needs SSR,
* it had better in-place writes for updated data.
*/
- if (unlikely(fio->old_blkaddr != NEW_ADDR &&
- !is_cold_data(page) &&
- !IS_ATOMIC_WRITTEN_PAGE(page) &&
- need_inplace_update(inode))) {
- rewrite_data_page(fio);
+ if (ipu_force || (valid_ipu_blkaddr(fio) && need_inplace_update(fio))) {
+ err = encrypt_one_page(fio);
+ if (err)
+ goto out_writepage;
+
+ set_page_writeback(page);
+ f2fs_put_dnode(&dn);
+ if (fio->need_lock == LOCK_REQ)
+ f2fs_unlock_op(fio->sbi);
+ err = rewrite_data_page(fio);
+ trace_f2fs_do_write_data_page(fio->page, IPU);
set_inode_flag(inode, FI_UPDATE_WRITE);
- trace_f2fs_do_write_data_page(page, IPU);
- } else {
- write_data_page(&dn, fio);
- trace_f2fs_do_write_data_page(page, OPU);
- set_inode_flag(inode, FI_APPEND_WRITE);
- if (page->index == 0)
- set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
+ return err;
}
+
+ if (fio->need_lock == LOCK_RETRY) {
+ if (!f2fs_trylock_op(fio->sbi)) {
+ err = -EAGAIN;
+ goto out_writepage;
+ }
+ fio->need_lock = LOCK_REQ;
+ }
+
+ err = encrypt_one_page(fio);
+ if (err)
+ goto out_writepage;
+
+ set_page_writeback(page);
+
+ /* LFS mode write path */
+ write_data_page(&dn, fio);
+ trace_f2fs_do_write_data_page(page, OPU);
+ set_inode_flag(inode, FI_APPEND_WRITE);
+ if (page->index == 0)
+ set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
out_writepage:
f2fs_put_dnode(&dn);
+out:
+ if (fio->need_lock == LOCK_REQ)
+ f2fs_unlock_op(fio->sbi);
return err;
}
-static int f2fs_write_data_page(struct page *page,
- struct writeback_control *wbc)
+static int __write_data_page(struct page *page, bool *submitted,
+ struct writeback_control *wbc,
+ enum iostat_type io_type)
{
struct inode *inode = page->mapping->host;
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
@@ -1250,15 +1702,30 @@
int err = 0;
struct f2fs_io_info fio = {
.sbi = sbi,
+ .ino = inode->i_ino,
.type = DATA,
.op = REQ_OP_WRITE,
- .op_flags = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : 0,
+ .op_flags = wbc_to_write_flags(wbc),
+ .old_blkaddr = NULL_ADDR,
.page = page,
.encrypted_page = NULL,
+ .submitted = false,
+ .need_lock = LOCK_RETRY,
+ .io_type = io_type,
+ .io_wbc = wbc,
};
trace_f2fs_writepage(page, DATA);
+ /* we should bypass data pages to proceed the kworkder jobs */
+ if (unlikely(f2fs_cp_error(sbi))) {
+ mapping_set_error(page->mapping, -EIO);
+ goto out;
+ }
+
+ if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
+ goto redirty_out;
+
if (page->index < end_index)
goto write;
@@ -1272,8 +1739,6 @@
zero_user_segment(page, offset, PAGE_SIZE);
write:
- if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
- goto redirty_out;
if (f2fs_is_drop_cache(inode))
goto out;
/* we should not write 0'th page having journal header */
@@ -1282,14 +1747,9 @@
available_free_memory(sbi, BASE_CHECK))))
goto redirty_out;
- /* we should bypass data pages to proceed the kworkder jobs */
- if (unlikely(f2fs_cp_error(sbi))) {
- mapping_set_error(page->mapping, -EIO);
- goto out;
- }
-
/* Dentry blocks are controlled by checkpoint */
if (S_ISDIR(inode->i_mode)) {
+ fio.need_lock = LOCK_DONE;
err = do_write_data_page(&fio);
goto done;
}
@@ -1298,52 +1758,85 @@
need_balance_fs = true;
else if (has_not_enough_free_secs(sbi, 0, 0))
goto redirty_out;
+ else
+ set_inode_flag(inode, FI_HOT_DATA);
err = -EAGAIN;
- f2fs_lock_op(sbi);
- if (f2fs_has_inline_data(inode))
+ if (f2fs_has_inline_data(inode)) {
err = f2fs_write_inline_data(inode, page);
- if (err == -EAGAIN)
+ if (!err)
+ goto out;
+ }
+
+ if (err == -EAGAIN) {
err = do_write_data_page(&fio);
- if (F2FS_I(inode)->last_disk_size < psize)
- F2FS_I(inode)->last_disk_size = psize;
- f2fs_unlock_op(sbi);
+ if (err == -EAGAIN) {
+ fio.need_lock = LOCK_REQ;
+ err = do_write_data_page(&fio);
+ }
+ }
+
+ if (err) {
+ file_set_keep_isize(inode);
+ } else {
+ down_write(&F2FS_I(inode)->i_sem);
+ if (F2FS_I(inode)->last_disk_size < psize)
+ F2FS_I(inode)->last_disk_size = psize;
+ up_write(&F2FS_I(inode)->i_sem);
+ }
+
done:
if (err && err != -ENOENT)
goto redirty_out;
- clear_cold_data(page);
out:
inode_dec_dirty_pages(inode);
if (err)
ClearPageUptodate(page);
if (wbc->for_reclaim) {
- f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, DATA, WRITE);
+ f2fs_submit_merged_write_cond(sbi, inode, 0, page->index, DATA);
+ clear_inode_flag(inode, FI_HOT_DATA);
remove_dirty_inode(inode);
+ submitted = NULL;
}
unlock_page(page);
- f2fs_balance_fs(sbi, need_balance_fs);
+ if (!S_ISDIR(inode->i_mode))
+ f2fs_balance_fs(sbi, need_balance_fs);
- if (unlikely(f2fs_cp_error(sbi)))
- f2fs_submit_merged_bio(sbi, DATA, WRITE);
+ if (unlikely(f2fs_cp_error(sbi))) {
+ f2fs_submit_merged_write(sbi, DATA);
+ submitted = NULL;
+ }
+
+ if (submitted)
+ *submitted = fio.submitted;
return 0;
redirty_out:
redirty_page_for_writepage(wbc, page);
+ if (!err)
+ return AOP_WRITEPAGE_ACTIVATE;
unlock_page(page);
return err;
}
+static int f2fs_write_data_page(struct page *page,
+ struct writeback_control *wbc)
+{
+ return __write_data_page(page, NULL, wbc, FS_DATA_IO);
+}
+
/*
* This function was copied from write_cche_pages from mm/page-writeback.c.
* The major change is making write step of cold data page separately from
* warm/hot data page.
*/
static int f2fs_write_cache_pages(struct address_space *mapping,
- struct writeback_control *wbc)
+ struct writeback_control *wbc,
+ enum iostat_type io_type)
{
int ret = 0;
int done = 0;
@@ -1353,13 +1846,19 @@
pgoff_t index;
pgoff_t end; /* Inclusive */
pgoff_t done_index;
+ pgoff_t last_idx = ULONG_MAX;
int cycled;
int range_whole = 0;
int tag;
- int nwritten = 0;
pagevec_init(&pvec, 0);
+ if (get_dirty_pages(mapping->host) <=
+ SM_I(F2FS_M_SB(mapping))->min_hot_blocks)
+ set_inode_flag(mapping->host, FI_HOT_DATA);
+ else
+ clear_inode_flag(mapping->host, FI_HOT_DATA);
+
if (wbc->range_cyclic) {
writeback_index = mapping->writeback_index; /* prev offset */
index = writeback_index;
@@ -1393,6 +1892,7 @@
for (i = 0; i < nr_pages; i++) {
struct page *page = pvec.pages[i];
+ bool submitted = false;
if (page->index > end) {
done = 1;
@@ -1400,7 +1900,7 @@
}
done_index = page->index;
-
+retry_write:
lock_page(page);
if (unlikely(page->mapping != mapping)) {
@@ -1426,17 +1926,37 @@
if (!clear_page_dirty_for_io(page))
goto continue_unlock;
- ret = mapping->a_ops->writepage(page, wbc);
+ ret = __write_data_page(page, &submitted, wbc, io_type);
if (unlikely(ret)) {
+ /*
+ * keep nr_to_write, since vfs uses this to
+ * get # of written pages.
+ */
+ if (ret == AOP_WRITEPAGE_ACTIVATE) {
+ unlock_page(page);
+ ret = 0;
+ continue;
+ } else if (ret == -EAGAIN) {
+ ret = 0;
+ if (wbc->sync_mode == WB_SYNC_ALL) {
+ cond_resched();
+ congestion_wait(BLK_RW_ASYNC,
+ HZ/50);
+ goto retry_write;
+ }
+ continue;
+ }
done_index = page->index + 1;
done = 1;
break;
- } else {
- nwritten++;
+ } else if (submitted) {
+ last_idx = page->index;
}
- if (--wbc->nr_to_write <= 0 &&
- wbc->sync_mode == WB_SYNC_NONE) {
+ /* give a priority to WB_SYNC threads */
+ if ((atomic_read(&F2FS_M_SB(mapping)->wb_sync_req) ||
+ --wbc->nr_to_write <= 0) &&
+ wbc->sync_mode == WB_SYNC_NONE) {
done = 1;
break;
}
@@ -1454,15 +1974,16 @@
if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
mapping->writeback_index = done_index;
- if (nwritten)
- f2fs_submit_merged_bio_cond(F2FS_M_SB(mapping), mapping->host,
- NULL, 0, DATA, WRITE);
+ if (last_idx != ULONG_MAX)
+ f2fs_submit_merged_write_cond(F2FS_M_SB(mapping), mapping->host,
+ 0, last_idx, DATA);
return ret;
}
-static int f2fs_write_data_pages(struct address_space *mapping,
- struct writeback_control *wbc)
+int __f2fs_write_data_pages(struct address_space *mapping,
+ struct writeback_control *wbc,
+ enum iostat_type io_type)
{
struct inode *inode = mapping->host;
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
@@ -1477,6 +1998,10 @@
if (!get_dirty_pages(inode) && wbc->sync_mode == WB_SYNC_NONE)
return 0;
+ /* during POR, we don't need to trigger writepage at all. */
+ if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
+ goto skip_write;
+
if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE &&
get_dirty_pages(inode) < nr_pages_to_skip(sbi, DATA) &&
available_free_memory(sbi, DIRTY_DENTS))
@@ -1486,15 +2011,20 @@
if (is_inode_flag_set(inode, FI_DO_DEFRAG))
goto skip_write;
- /* during POR, we don't need to trigger writepage at all. */
- if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
- goto skip_write;
-
trace_f2fs_writepages(mapping->host, wbc, DATA);
+ /* to avoid spliting IOs due to mixed WB_SYNC_ALL and WB_SYNC_NONE */
+ if (wbc->sync_mode == WB_SYNC_ALL)
+ atomic_inc(&sbi->wb_sync_req);
+ else if (atomic_read(&sbi->wb_sync_req))
+ goto skip_write;
+
blk_start_plug(&plug);
- ret = f2fs_write_cache_pages(mapping, wbc);
+ ret = f2fs_write_cache_pages(mapping, wbc, io_type);
blk_finish_plug(&plug);
+
+ if (wbc->sync_mode == WB_SYNC_ALL)
+ atomic_dec(&sbi->wb_sync_req);
/*
* if some pages were truncated, we cannot guarantee its mapping->host
* to detect pending bios.
@@ -1509,14 +2039,26 @@
return 0;
}
+static int f2fs_write_data_pages(struct address_space *mapping,
+ struct writeback_control *wbc)
+{
+ struct inode *inode = mapping->host;
+
+ return __f2fs_write_data_pages(mapping, wbc,
+ F2FS_I(inode)->cp_task == current ?
+ FS_CP_DATA_IO : FS_DATA_IO);
+}
+
static void f2fs_write_failed(struct address_space *mapping, loff_t to)
{
struct inode *inode = mapping->host;
loff_t i_size = i_size_read(inode);
if (to > i_size) {
+ down_write(&F2FS_I(inode)->i_mmap_sem);
truncate_pagecache(inode, i_size);
truncate_blocks(inode, i_size, true);
+ up_write(&F2FS_I(inode)->i_mmap_sem);
}
}
@@ -1529,19 +2071,20 @@
struct dnode_of_data dn;
struct page *ipage;
bool locked = false;
- struct extent_info ei;
+ struct extent_info ei = {0,0,0};
int err = 0;
/*
* we already allocated all the blocks, so we don't need to get
* the block addresses when there is no need to fill the page.
*/
- if (!f2fs_has_inline_data(inode) && len == PAGE_SIZE)
+ if (!f2fs_has_inline_data(inode) && len == PAGE_SIZE &&
+ !is_inode_flag_set(inode, FI_NO_PREALLOC))
return 0;
if (f2fs_has_inline_data(inode) ||
(pos & PAGE_MASK) >= i_size_read(inode)) {
- f2fs_lock_op(sbi);
+ __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
locked = true;
}
restart:
@@ -1555,7 +2098,7 @@
set_new_dnode(&dn, inode, ipage, ipage, 0);
if (f2fs_has_inline_data(inode)) {
- if (pos + len <= MAX_INLINE_DATA) {
+ if (pos + len <= MAX_INLINE_DATA(inode)) {
read_inline_data(page, ipage);
set_inode_flag(inode, FI_DATA_EXIST);
if (inode->i_nlink)
@@ -1577,7 +2120,8 @@
err = get_dnode_of_data(&dn, index, LOOKUP_NODE);
if (err || dn.data_blkaddr == NULL_ADDR) {
f2fs_put_dnode(&dn);
- f2fs_lock_op(sbi);
+ __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO,
+ true);
locked = true;
goto restart;
}
@@ -1591,7 +2135,7 @@
f2fs_put_dnode(&dn);
unlock_out:
if (locked)
- f2fs_unlock_op(sbi);
+ __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
return err;
}
@@ -1603,7 +2147,7 @@
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct page *page = NULL;
pgoff_t index = ((unsigned long long) pos) >> PAGE_SHIFT;
- bool need_balance = false;
+ bool need_balance = false, drop_atomic = false;
block_t blkaddr = NULL_ADDR;
int err = 0;
@@ -1619,6 +2163,13 @@
}
trace_f2fs_write_begin(inode, pos, len, flags);
+ if (f2fs_is_atomic_file(inode) &&
+ !available_free_memory(sbi, INMEM_PAGES)) {
+ err = -ENOMEM;
+ drop_atomic = true;
+ goto fail;
+ }
+
/*
* We should check this at this moment to avoid deadlock on inode page
* and #0 page. The locking rule for inline_data conversion should be:
@@ -1634,7 +2185,7 @@
* Do not use grab_cache_page_write_begin() to avoid deadlock due to
* wait_for_stable_page. Will wait that below with our IO control.
*/
- page = pagecache_get_page(mapping, index,
+ page = f2fs_pagecache_get_page(mapping, index,
FGP_LOCK | FGP_WRITE | FGP_CREAT, GFP_NOFS);
if (!page) {
err = -ENOMEM;
@@ -1662,31 +2213,24 @@
f2fs_wait_on_page_writeback(page, DATA, false);
/* wait for GCed encrypted page writeback */
- if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
- f2fs_wait_on_encrypted_page_writeback(sbi, blkaddr);
+ if (f2fs_encrypted_file(inode))
+ f2fs_wait_on_block_writeback(sbi, blkaddr);
if (len == PAGE_SIZE || PageUptodate(page))
return 0;
+ if (!(pos & (PAGE_SIZE - 1)) && (pos + len) >= i_size_read(inode)) {
+ zero_user_segment(page, len, PAGE_SIZE);
+ return 0;
+ }
+
if (blkaddr == NEW_ADDR) {
zero_user_segment(page, 0, PAGE_SIZE);
SetPageUptodate(page);
} else {
- struct bio *bio;
-
- bio = f2fs_grab_bio(inode, blkaddr, 1);
- if (IS_ERR(bio)) {
- err = PTR_ERR(bio);
+ err = f2fs_submit_page_read(inode, page, blkaddr);
+ if (err)
goto fail;
- }
- bio_set_op_attrs(bio, REQ_OP_READ, READ_SYNC);
- if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
- bio_put(bio);
- err = -EFAULT;
- goto fail;
- }
-
- __submit_bio(sbi, bio, DATA);
lock_page(page);
if (unlikely(page->mapping != mapping)) {
@@ -1703,6 +2247,8 @@
fail:
f2fs_put_page(page, 1);
f2fs_write_failed(mapping, pos + len);
+ if (drop_atomic)
+ drop_inmem_pages_all(sbi);
return err;
}
@@ -1722,7 +2268,7 @@
* let generic_perform_write() try to copy data again through copied=0.
*/
if (!PageUptodate(page)) {
- if (unlikely(copied != PAGE_SIZE))
+ if (unlikely(copied != len))
copied = 0;
else
SetPageUptodate(page);
@@ -1731,7 +2277,6 @@
goto unlock_out;
set_page_dirty(page);
- clear_cold_data(page);
if (pos + copied > i_size_read(inode))
f2fs_i_size_write(inode, pos + copied);
@@ -1768,9 +2313,7 @@
if (err)
return err;
- if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
- return 0;
- if (test_opt(F2FS_I_SB(inode), LFS))
+ if (__force_buffered_io(inode, rw))
return 0;
trace_f2fs_direct_IO_enter(inode, offset, count, rw);
@@ -1803,10 +2346,13 @@
up_read(&F2FS_I(inode)->dio_rwsem[rw]);
if (rw == WRITE) {
- if (err > 0)
+ if (err > 0) {
+ f2fs_update_iostat(F2FS_I_SB(inode), APP_DIRECT_IO,
+ err);
set_inode_flag(inode, FI_UPDATE_WRITE);
- else if (err < 0)
+ } else if (err < 0) {
f2fs_write_failed(mapping, offset + count);
+ }
}
if (trace_android_fs_dataread_start_enabled() &&
@@ -1832,17 +2378,19 @@
return;
if (PageDirty(page)) {
- if (inode->i_ino == F2FS_META_INO(sbi))
+ if (inode->i_ino == F2FS_META_INO(sbi)) {
dec_page_count(sbi, F2FS_DIRTY_META);
- else if (inode->i_ino == F2FS_NODE_INO(sbi))
+ } else if (inode->i_ino == F2FS_NODE_INO(sbi)) {
dec_page_count(sbi, F2FS_DIRTY_NODES);
- else
+ } else {
inode_dec_dirty_pages(inode);
+ remove_dirty_inode(inode);
+ }
}
/* This is atomic written page, keep Private */
if (IS_ATOMIC_WRITTEN_PAGE(page))
- return;
+ return drop_inmem_page(inode, page);
set_page_private(page, 0);
ClearPagePrivate(page);
@@ -1902,7 +2450,7 @@
if (!PageUptodate(page))
SetPageUptodate(page);
- if (f2fs_is_atomic_file(inode)) {
+ if (f2fs_is_atomic_file(inode) && !f2fs_is_commit_atomic_write(inode)) {
if (!IS_ATOMIC_WRITTEN_PAGE(page)) {
register_inmem_page(inode, page);
return 1;
@@ -1949,8 +2497,12 @@
BUG_ON(PageWriteback(page));
/* migrating an atomic written page is safe with the inmem_lock hold */
- if (atomic_written && !mutex_trylock(&fi->inmem_lock))
- return -EAGAIN;
+ if (atomic_written) {
+ if (mode != MIGRATE_SYNC)
+ return -EBUSY;
+ if (!mutex_trylock(&fi->inmem_lock))
+ return -EAGAIN;
+ }
/*
* A reference is expected if PagePrivate set when move mapping,
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
index 687998e9..a66107b 100644
--- a/fs/f2fs/debug.c
+++ b/fs/f2fs/debug.c
@@ -45,12 +45,36 @@
si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS);
si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META);
si->ndirty_data = get_pages(sbi, F2FS_DIRTY_DATA);
+ si->ndirty_qdata = get_pages(sbi, F2FS_DIRTY_QDATA);
si->ndirty_imeta = get_pages(sbi, F2FS_DIRTY_IMETA);
si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE];
si->ndirty_files = sbi->ndirty_inode[FILE_INODE];
+ si->nquota_files = sbi->nquota_files;
si->ndirty_all = sbi->ndirty_inode[DIRTY_META];
si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
- si->wb_bios = atomic_read(&sbi->nr_wb_bios);
+ si->aw_cnt = atomic_read(&sbi->aw_cnt);
+ si->vw_cnt = atomic_read(&sbi->vw_cnt);
+ si->max_aw_cnt = atomic_read(&sbi->max_aw_cnt);
+ si->max_vw_cnt = atomic_read(&sbi->max_vw_cnt);
+ si->nr_wb_cp_data = get_pages(sbi, F2FS_WB_CP_DATA);
+ si->nr_wb_data = get_pages(sbi, F2FS_WB_DATA);
+ if (SM_I(sbi) && SM_I(sbi)->fcc_info) {
+ si->nr_flushed =
+ atomic_read(&SM_I(sbi)->fcc_info->issued_flush);
+ si->nr_flushing =
+ atomic_read(&SM_I(sbi)->fcc_info->issing_flush);
+ si->flush_list_empty =
+ llist_empty(&SM_I(sbi)->fcc_info->issue_list);
+ }
+ if (SM_I(sbi) && SM_I(sbi)->dcc_info) {
+ si->nr_discarded =
+ atomic_read(&SM_I(sbi)->dcc_info->issued_discard);
+ si->nr_discarding =
+ atomic_read(&SM_I(sbi)->dcc_info->issing_discard);
+ si->nr_discard_cmd =
+ atomic_read(&SM_I(sbi)->dcc_info->discard_cmd_cnt);
+ si->undiscard_blks = SM_I(sbi)->dcc_info->undiscard_blks;
+ }
si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
si->rsvd_segs = reserved_segments(sbi);
si->overp_segs = overprovision_segments(sbi);
@@ -61,6 +85,8 @@
si->inline_xattr = atomic_read(&sbi->inline_xattr);
si->inline_inode = atomic_read(&sbi->inline_inode);
si->inline_dir = atomic_read(&sbi->inline_dir);
+ si->append = sbi->im[APPEND_INO].ino_num;
+ si->update = sbi->im[UPDATE_INO].ino_num;
si->orphans = sbi->im[ORPHAN_INO].ino_num;
si->utilization = utilization(sbi);
@@ -74,7 +100,9 @@
si->dirty_nats = NM_I(sbi)->dirty_nat_cnt;
si->sits = MAIN_SEGS(sbi);
si->dirty_sits = SIT_I(sbi)->dirty_sentries;
- si->fnids = NM_I(sbi)->fcnt;
+ si->free_nids = NM_I(sbi)->nid_cnt[FREE_NID];
+ si->avail_nids = NM_I(sbi)->available_nids;
+ si->alloc_nids = NM_I(sbi)->nid_cnt[PREALLOC_NID];
si->bg_gc = sbi->bg_gc;
si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg)
* 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
@@ -87,8 +115,8 @@
for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_NODE; i++) {
struct curseg_info *curseg = CURSEG_I(sbi, i);
si->curseg[i] = curseg->segno;
- si->cursec[i] = curseg->segno / sbi->segs_per_sec;
- si->curzone[i] = si->cursec[i] / sbi->secs_per_zone;
+ si->cursec[i] = GET_SEC_FROM_SEG(sbi, curseg->segno);
+ si->curzone[i] = GET_ZONE_FROM_SEC(sbi, si->cursec[i]);
}
for (i = 0; i < 2; i++) {
@@ -112,10 +140,10 @@
bimodal = 0;
total_vblocks = 0;
- blks_per_sec = sbi->segs_per_sec * sbi->blocks_per_seg;
+ blks_per_sec = BLKS_PER_SEC(sbi);
hblks_per_sec = blks_per_sec / 2;
for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
- vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec);
+ vblocks = get_valid_blocks(sbi, segno, true);
dist = abs(vblocks - hblks_per_sec);
bimodal += dist * dist;
@@ -144,10 +172,13 @@
if (si->base_mem)
goto get_cache;
- si->base_mem = sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize;
+ /* build stat */
+ si->base_mem = sizeof(struct f2fs_stat_info);
+
+ /* build superblock */
+ si->base_mem += sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize;
si->base_mem += 2 * sizeof(struct f2fs_inode_info);
si->base_mem += sizeof(*sbi->ckpt);
- si->base_mem += sizeof(struct percpu_counter) * NR_COUNT_TYPE;
/* build sm */
si->base_mem += sizeof(struct f2fs_sm_info);
@@ -181,6 +212,10 @@
/* build nm */
si->base_mem += sizeof(struct f2fs_nm_info);
si->base_mem += __bitmap_size(sbi, NAT_BITMAP);
+ si->base_mem += (NM_I(sbi)->nat_bits_blocks << F2FS_BLKSIZE_BITS);
+ si->base_mem += NM_I(sbi)->nat_blocks * NAT_ENTRY_BITMAP_SIZE;
+ si->base_mem += NM_I(sbi)->nat_blocks / 8;
+ si->base_mem += NM_I(sbi)->nat_blocks * sizeof(unsigned short);
get_cache:
si->cache_mem = 0;
@@ -190,16 +225,23 @@
si->cache_mem += sizeof(struct f2fs_gc_kthread);
/* build merge flush thread */
- if (SM_I(sbi)->cmd_control_info)
+ if (SM_I(sbi)->fcc_info)
si->cache_mem += sizeof(struct flush_cmd_control);
+ if (SM_I(sbi)->dcc_info) {
+ si->cache_mem += sizeof(struct discard_cmd_control);
+ si->cache_mem += sizeof(struct discard_cmd) *
+ atomic_read(&SM_I(sbi)->dcc_info->discard_cmd_cnt);
+ }
/* free nids */
- si->cache_mem += NM_I(sbi)->fcnt * sizeof(struct free_nid);
+ si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID] +
+ NM_I(sbi)->nid_cnt[PREALLOC_NID]) *
+ sizeof(struct free_nid);
si->cache_mem += NM_I(sbi)->nat_cnt * sizeof(struct nat_entry);
si->cache_mem += NM_I(sbi)->dirty_nat_cnt *
sizeof(struct nat_entry_set);
si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages);
- for (i = 0; i <= ORPHAN_INO; i++)
+ for (i = 0; i < MAX_INO_ENTRY; i++)
si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry);
si->cache_mem += atomic_read(&sbi->total_ext_tree) *
sizeof(struct extent_tree);
@@ -223,9 +265,10 @@
list_for_each_entry(si, &f2fs_stat_list, stat_list) {
update_general_status(si->sbi);
- seq_printf(s, "\n=====[ partition info(%pg). #%d, %s]=====\n",
+ seq_printf(s, "\n=====[ partition info(%pg). #%d, %s, CP: %s]=====\n",
si->sbi->sb->s_bdev, i++,
- f2fs_readonly(si->sbi->sb) ? "RO": "RW");
+ f2fs_readonly(si->sbi->sb) ? "RO": "RW",
+ f2fs_cp_error(si->sbi) ? "Error": "Good");
seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ",
si->sit_area_segs, si->nat_area_segs);
seq_printf(s, "[SSA: %d] [MAIN: %d",
@@ -250,8 +293,8 @@
si->inline_inode);
seq_printf(s, " - Inline_dentry Inode: %u\n",
si->inline_dir);
- seq_printf(s, " - Orphan Inode: %u\n",
- si->orphans);
+ seq_printf(s, " - Orphan/Append/Update Inode: %u, %u, %u\n",
+ si->orphans, si->append, si->update);
seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n",
si->main_area_segs, si->main_area_sections,
si->main_area_zones);
@@ -310,22 +353,33 @@
seq_printf(s, " - Inner Struct Count: tree: %d(%d), node: %d\n",
si->ext_tree, si->zombie_tree, si->ext_node);
seq_puts(s, "\nBalancing F2FS Async:\n");
- seq_printf(s, " - inmem: %4d, wb_bios: %4d\n",
- si->inmem_pages, si->wb_bios);
+ seq_printf(s, " - IO (CP: %4d, Data: %4d, Flush: (%4d %4d %4d), "
+ "Discard: (%4d %4d)) cmd: %4d undiscard:%4u\n",
+ si->nr_wb_cp_data, si->nr_wb_data,
+ si->nr_flushing, si->nr_flushed,
+ si->flush_list_empty,
+ si->nr_discarding, si->nr_discarded,
+ si->nr_discard_cmd, si->undiscard_blks);
+ seq_printf(s, " - inmem: %4d, atomic IO: %4d (Max. %4d), "
+ "volatile IO: %4d (Max. %4d)\n",
+ si->inmem_pages, si->aw_cnt, si->max_aw_cnt,
+ si->vw_cnt, si->max_vw_cnt);
seq_printf(s, " - nodes: %4d in %4d\n",
si->ndirty_node, si->node_pages);
seq_printf(s, " - dents: %4d in dirs:%4d (%4d)\n",
si->ndirty_dent, si->ndirty_dirs, si->ndirty_all);
seq_printf(s, " - datas: %4d in files:%4d\n",
si->ndirty_data, si->ndirty_files);
+ seq_printf(s, " - quota datas: %4d in quota files:%4d\n",
+ si->ndirty_qdata, si->nquota_files);
seq_printf(s, " - meta: %4d in %4d\n",
si->ndirty_meta, si->meta_pages);
seq_printf(s, " - imeta: %4d\n",
si->ndirty_imeta);
seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n",
si->dirty_nats, si->nats, si->dirty_sits, si->sits);
- seq_printf(s, " - free_nids: %9d\n",
- si->fnids);
+ seq_printf(s, " - free_nids: %9d/%9d\n - alloc_nids: %9d\n",
+ si->free_nids, si->avail_nids, si->alloc_nids);
seq_puts(s, "\nDistribution of User Blocks:");
seq_puts(s, " [ valid | invalid | free ]\n");
seq_puts(s, " [");
@@ -385,7 +439,7 @@
struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
struct f2fs_stat_info *si;
- si = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL);
+ si = f2fs_kzalloc(sbi, sizeof(struct f2fs_stat_info), GFP_KERNEL);
if (!si)
return -ENOMEM;
@@ -410,6 +464,11 @@
atomic_set(&sbi->inline_dir, 0);
atomic_set(&sbi->inplace_count, 0);
+ atomic_set(&sbi->aw_cnt, 0);
+ atomic_set(&sbi->vw_cnt, 0);
+ atomic_set(&sbi->max_aw_cnt, 0);
+ atomic_set(&sbi->max_vw_cnt, 0);
+
mutex_lock(&f2fs_stat_mutex);
list_add_tail(&si->stat_list, &f2fs_stat_list);
mutex_unlock(&f2fs_stat_mutex);
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 8add4e8..6ef3c83 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -10,10 +10,12 @@
*/
#include <linux/fs.h>
#include <linux/f2fs_fs.h>
+#include <linux/sched.h>
#include "f2fs.h"
#include "node.h"
#include "acl.h"
#include "xattr.h"
+#include <trace/events/f2fs.h>
static unsigned long dir_blocks(struct inode *inode)
{
@@ -94,7 +96,7 @@
dentry_blk = (struct f2fs_dentry_block *)kmap(dentry_page);
- make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1);
+ make_dentry_ptr_block(NULL, &d, dentry_blk);
de = find_target_dentry(fname, namehash, max_slots, &d);
if (de)
*res_page = dentry_page;
@@ -111,8 +113,6 @@
struct f2fs_dir_entry *de;
unsigned long bit_pos = 0;
int max_len = 0;
- struct fscrypt_str de_name = FSTR_INIT(NULL, 0);
- struct fscrypt_str *name = &fname->disk_name;
if (max_slots)
*max_slots = 0;
@@ -130,29 +130,11 @@
continue;
}
- if (de->hash_code != namehash)
- goto not_match;
-
- de_name.name = d->filename[bit_pos];
- de_name.len = le16_to_cpu(de->name_len);
-
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
- if (unlikely(!name->name)) {
- if (fname->usr_fname->name[0] == '_') {
- if (de_name.len > 32 &&
- !memcmp(de_name.name + ((de_name.len - 17) & ~15),
- fname->crypto_buf.name + 8, 16))
- goto found;
- goto not_match;
- }
- name->name = fname->crypto_buf.name;
- name->len = fname->crypto_buf.len;
- }
-#endif
- if (de_name.len == name->len &&
- !memcmp(de_name.name, name->name, name->len))
+ if (de->hash_code == namehash &&
+ fscrypt_match_name(fname, d->filename[bit_pos],
+ le16_to_cpu(de->name_len)))
goto found;
-not_match:
+
if (max_slots && max_len > *max_slots)
*max_slots = max_len;
max_len = 0;
@@ -212,13 +194,9 @@
f2fs_put_page(dentry_page, 0);
}
- /* This is to increase the speed of f2fs_create */
- if (!de && room) {
- F2FS_I(dir)->task = current;
- if (F2FS_I(dir)->chash != namehash) {
- F2FS_I(dir)->chash = namehash;
- F2FS_I(dir)->clevel = level;
- }
+ if (!de && room && F2FS_I(dir)->chash != namehash) {
+ F2FS_I(dir)->chash = namehash;
+ F2FS_I(dir)->clevel = level;
}
return de;
@@ -259,6 +237,9 @@
break;
}
out:
+ /* This is to increase the speed of f2fs_create */
+ if (!de)
+ F2FS_I(dir)->task = current;
return de;
}
@@ -325,7 +306,7 @@
set_page_dirty(page);
dir->i_mtime = dir->i_ctime = current_time(dir);
- f2fs_mark_inode_dirty_sync(dir);
+ f2fs_mark_inode_dirty_sync(dir, false);
f2fs_put_page(page, 1);
}
@@ -342,24 +323,6 @@
set_page_dirty(ipage);
}
-int update_dent_inode(struct inode *inode, struct inode *to,
- const struct qstr *name)
-{
- struct page *page;
-
- if (file_enc_name(to))
- return 0;
-
- page = get_node_page(F2FS_I_SB(inode), inode->i_ino);
- if (IS_ERR(page))
- return PTR_ERR(page);
-
- init_dent_inode(name, page);
- f2fs_put_page(page, 1);
-
- return 0;
-}
-
void do_make_empty_dir(struct inode *inode, struct inode *parent,
struct f2fs_dentry_ptr *d)
{
@@ -389,7 +352,7 @@
dentry_blk = kmap_atomic(dentry_page);
- make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1);
+ make_dentry_ptr_block(NULL, &d, dentry_blk);
do_make_empty_dir(inode, parent, &d);
kunmap_atomic(dentry_blk);
@@ -443,15 +406,19 @@
set_cold_node(inode, page);
}
- if (new_name)
+ if (new_name) {
init_dent_inode(new_name, page);
+ if (f2fs_encrypted_inode(dir))
+ file_set_enc_name(inode);
+ }
/*
* This file should be checkpointed during fsync.
* We lost i_pino from now on.
*/
if (is_inode_flag_set(inode, FI_INC_LINK)) {
- file_lost_pino(inode);
+ if (!S_ISDIR(inode->i_mode))
+ file_lost_pino(inode);
/*
* If link the tmpfile to alias through linkat path,
* we should remove this inode from orphan list.
@@ -478,7 +445,7 @@
clear_inode_flag(inode, FI_NEW_INODE);
}
dir->i_mtime = dir->i_ctime = current_time(dir);
- f2fs_mark_inode_dirty_sync(dir);
+ f2fs_mark_inode_dirty_sync(dir, false);
if (F2FS_I(dir)->i_current_depth != current_depth)
f2fs_i_depth_write(dir, current_depth);
@@ -557,8 +524,10 @@
start:
#ifdef CONFIG_F2FS_FAULT_INJECTION
- if (time_to_inject(F2FS_I_SB(dir), FAULT_DIR_DEPTH))
+ if (time_to_inject(F2FS_I_SB(dir), FAULT_DIR_DEPTH)) {
+ f2fs_show_injection_info(FAULT_DIR_DEPTH);
return -ENOSPC;
+ }
#endif
if (unlikely(current_depth == MAX_DIR_HASH_DEPTH))
return -ENOSPC;
@@ -602,11 +571,9 @@
err = PTR_ERR(page);
goto fail;
}
- if (f2fs_encrypted_inode(dir))
- file_set_enc_name(inode);
}
- make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1);
+ make_dentry_ptr_block(NULL, &d, dentry_blk);
f2fs_update_dentry(ino, mode, &d, new_name, dentry_hash, bit_pos);
set_page_dirty(dentry_page);
@@ -740,10 +707,14 @@
struct f2fs_dentry_block *dentry_blk;
unsigned int bit_pos;
int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len));
+ struct address_space *mapping = page_mapping(page);
+ unsigned long flags;
int i;
f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
+ add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO);
+
if (f2fs_has_inline_dentry(dir))
return f2fs_delete_inline_entry(dentry, page, dir, inode);
@@ -753,7 +724,7 @@
dentry_blk = page_address(page);
bit_pos = dentry - dentry_blk->dentry;
for (i = 0; i < slots; i++)
- clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap);
+ __clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap);
/* Let's check and deallocate this dentry page */
bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
@@ -763,17 +734,23 @@
set_page_dirty(page);
dir->i_ctime = dir->i_mtime = current_time(dir);
- f2fs_mark_inode_dirty_sync(dir);
+ f2fs_mark_inode_dirty_sync(dir, false);
if (inode)
f2fs_drop_nlink(dir, inode);
if (bit_pos == NR_DENTRY_IN_BLOCK &&
!truncate_hole(dir, page->index, page->index + 1)) {
+ spin_lock_irqsave(&mapping->tree_lock, flags);
+ radix_tree_tag_clear(&mapping->page_tree, page_index(page),
+ PAGECACHE_TAG_DIRTY);
+ spin_unlock_irqrestore(&mapping->tree_lock, flags);
+
clear_page_dirty_for_io(page);
ClearPagePrivate(page);
ClearPageUptodate(page);
inode_dec_dirty_pages(dir);
+ remove_dirty_inode(dir);
}
f2fs_put_page(page, 1);
}
@@ -816,13 +793,14 @@
return true;
}
-bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
+int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
unsigned int start_pos, struct fscrypt_str *fstr)
{
unsigned char d_type = DT_UNKNOWN;
unsigned int bit_pos;
struct f2fs_dir_entry *de = NULL;
struct fscrypt_str de_name = FSTR_INIT(NULL, 0);
+ struct f2fs_sb_info *sbi = F2FS_I_SB(d->inode);
bit_pos = ((unsigned long)ctx->pos % d->max);
@@ -851,7 +829,7 @@
(u32)de->hash_code, 0,
&de_name, fstr);
if (err)
- return true;
+ return err;
de_name = *fstr;
fstr->len = save_len;
@@ -859,12 +837,15 @@
if (!dir_emit(ctx, de_name.name, de_name.len,
le32_to_cpu(de->ino), d_type))
- return true;
+ return 1;
+
+ if (sbi->readdir_ra == 1)
+ ra_node_page(sbi, le32_to_cpu(de->ino));
bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
ctx->pos = start_pos + bit_pos;
}
- return false;
+ return 0;
}
static int f2fs_readdir(struct file *file, struct dir_context *ctx)
@@ -874,6 +855,7 @@
struct f2fs_dentry_block *dentry_blk = NULL;
struct page *dentry_page = NULL;
struct file_ra_state *ra = &file->f_ra;
+ loff_t start_pos = ctx->pos;
unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK);
struct f2fs_dentry_ptr d;
struct fscrypt_str fstr = FSTR_INIT(NULL, 0);
@@ -882,51 +864,63 @@
if (f2fs_encrypted_inode(inode)) {
err = fscrypt_get_encryption_info(inode);
if (err && err != -ENOKEY)
- return err;
+ goto out;
err = fscrypt_fname_alloc_buffer(inode, F2FS_NAME_LEN, &fstr);
if (err < 0)
- return err;
+ goto out;
}
if (f2fs_has_inline_dentry(inode)) {
err = f2fs_read_inline_dir(file, ctx, &fstr);
- goto out;
+ goto out_free;
}
- /* readahead for multi pages of dir */
- if (npages - n > 1 && !ra_has_index(ra, n))
- page_cache_sync_readahead(inode->i_mapping, ra, file, n,
+ for (; n < npages; n++, ctx->pos = n * NR_DENTRY_IN_BLOCK) {
+
+ /* allow readdir() to be interrupted */
+ if (fatal_signal_pending(current)) {
+ err = -ERESTARTSYS;
+ goto out_free;
+ }
+ cond_resched();
+
+ /* readahead for multi pages of dir */
+ if (npages - n > 1 && !ra_has_index(ra, n))
+ page_cache_sync_readahead(inode->i_mapping, ra, file, n,
min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES));
- for (; n < npages; n++) {
dentry_page = get_lock_data_page(inode, n, false);
if (IS_ERR(dentry_page)) {
err = PTR_ERR(dentry_page);
- if (err == -ENOENT)
+ if (err == -ENOENT) {
+ err = 0;
continue;
- else
- goto out;
+ } else {
+ goto out_free;
+ }
}
dentry_blk = kmap(dentry_page);
- make_dentry_ptr(inode, &d, (void *)dentry_blk, 1);
+ make_dentry_ptr_block(inode, &d, dentry_blk);
- if (f2fs_fill_dentries(ctx, &d, n * NR_DENTRY_IN_BLOCK, &fstr)) {
+ err = f2fs_fill_dentries(ctx, &d,
+ n * NR_DENTRY_IN_BLOCK, &fstr);
+ if (err) {
kunmap(dentry_page);
f2fs_put_page(dentry_page, 1);
break;
}
- ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK;
kunmap(dentry_page);
f2fs_put_page(dentry_page, 1);
}
- err = 0;
-out:
+out_free:
fscrypt_fname_free_buffer(&fstr);
- return err;
+out:
+ trace_f2fs_readdir(inode, start_pos, ctx->pos, err);
+ return err < 0 ? err : 0;
}
static int f2fs_dir_open(struct inode *inode, struct file *filp)
diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c
index 7b32ce9..ff2352a 100644
--- a/fs/f2fs/extent_cache.c
+++ b/fs/f2fs/extent_cache.c
@@ -18,6 +18,179 @@
#include "node.h"
#include <trace/events/f2fs.h>
+static struct rb_entry *__lookup_rb_tree_fast(struct rb_entry *cached_re,
+ unsigned int ofs)
+{
+ if (cached_re) {
+ if (cached_re->ofs <= ofs &&
+ cached_re->ofs + cached_re->len > ofs) {
+ return cached_re;
+ }
+ }
+ return NULL;
+}
+
+static struct rb_entry *__lookup_rb_tree_slow(struct rb_root *root,
+ unsigned int ofs)
+{
+ struct rb_node *node = root->rb_node;
+ struct rb_entry *re;
+
+ while (node) {
+ re = rb_entry(node, struct rb_entry, rb_node);
+
+ if (ofs < re->ofs)
+ node = node->rb_left;
+ else if (ofs >= re->ofs + re->len)
+ node = node->rb_right;
+ else
+ return re;
+ }
+ return NULL;
+}
+
+struct rb_entry *__lookup_rb_tree(struct rb_root *root,
+ struct rb_entry *cached_re, unsigned int ofs)
+{
+ struct rb_entry *re;
+
+ re = __lookup_rb_tree_fast(cached_re, ofs);
+ if (!re)
+ return __lookup_rb_tree_slow(root, ofs);
+
+ return re;
+}
+
+struct rb_node **__lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi,
+ struct rb_root *root, struct rb_node **parent,
+ unsigned int ofs)
+{
+ struct rb_node **p = &root->rb_node;
+ struct rb_entry *re;
+
+ while (*p) {
+ *parent = *p;
+ re = rb_entry(*parent, struct rb_entry, rb_node);
+
+ if (ofs < re->ofs)
+ p = &(*p)->rb_left;
+ else if (ofs >= re->ofs + re->len)
+ p = &(*p)->rb_right;
+ else
+ f2fs_bug_on(sbi, 1);
+ }
+
+ return p;
+}
+
+/*
+ * lookup rb entry in position of @ofs in rb-tree,
+ * if hit, return the entry, otherwise, return NULL
+ * @prev_ex: extent before ofs
+ * @next_ex: extent after ofs
+ * @insert_p: insert point for new extent at ofs
+ * in order to simpfy the insertion after.
+ * tree must stay unchanged between lookup and insertion.
+ */
+struct rb_entry *__lookup_rb_tree_ret(struct rb_root *root,
+ struct rb_entry *cached_re,
+ unsigned int ofs,
+ struct rb_entry **prev_entry,
+ struct rb_entry **next_entry,
+ struct rb_node ***insert_p,
+ struct rb_node **insert_parent,
+ bool force)
+{
+ struct rb_node **pnode = &root->rb_node;
+ struct rb_node *parent = NULL, *tmp_node;
+ struct rb_entry *re = cached_re;
+
+ *insert_p = NULL;
+ *insert_parent = NULL;
+ *prev_entry = NULL;
+ *next_entry = NULL;
+
+ if (RB_EMPTY_ROOT(root))
+ return NULL;
+
+ if (re) {
+ if (re->ofs <= ofs && re->ofs + re->len > ofs)
+ goto lookup_neighbors;
+ }
+
+ while (*pnode) {
+ parent = *pnode;
+ re = rb_entry(*pnode, struct rb_entry, rb_node);
+
+ if (ofs < re->ofs)
+ pnode = &(*pnode)->rb_left;
+ else if (ofs >= re->ofs + re->len)
+ pnode = &(*pnode)->rb_right;
+ else
+ goto lookup_neighbors;
+ }
+
+ *insert_p = pnode;
+ *insert_parent = parent;
+
+ re = rb_entry(parent, struct rb_entry, rb_node);
+ tmp_node = parent;
+ if (parent && ofs > re->ofs)
+ tmp_node = rb_next(parent);
+ *next_entry = rb_entry_safe(tmp_node, struct rb_entry, rb_node);
+
+ tmp_node = parent;
+ if (parent && ofs < re->ofs)
+ tmp_node = rb_prev(parent);
+ *prev_entry = rb_entry_safe(tmp_node, struct rb_entry, rb_node);
+ return NULL;
+
+lookup_neighbors:
+ if (ofs == re->ofs || force) {
+ /* lookup prev node for merging backward later */
+ tmp_node = rb_prev(&re->rb_node);
+ *prev_entry = rb_entry_safe(tmp_node, struct rb_entry, rb_node);
+ }
+ if (ofs == re->ofs + re->len - 1 || force) {
+ /* lookup next node for merging frontward later */
+ tmp_node = rb_next(&re->rb_node);
+ *next_entry = rb_entry_safe(tmp_node, struct rb_entry, rb_node);
+ }
+ return re;
+}
+
+bool __check_rb_tree_consistence(struct f2fs_sb_info *sbi,
+ struct rb_root *root)
+{
+#ifdef CONFIG_F2FS_CHECK_FS
+ struct rb_node *cur = rb_first(root), *next;
+ struct rb_entry *cur_re, *next_re;
+
+ if (!cur)
+ return true;
+
+ while (cur) {
+ next = rb_next(cur);
+ if (!next)
+ return true;
+
+ cur_re = rb_entry(cur, struct rb_entry, rb_node);
+ next_re = rb_entry(next, struct rb_entry, rb_node);
+
+ if (cur_re->ofs + cur_re->len > next_re->ofs) {
+ f2fs_msg(sbi->sb, KERN_INFO, "inconsistent rbtree, "
+ "cur(%u, %u) next(%u, %u)",
+ cur_re->ofs, cur_re->len,
+ next_re->ofs, next_re->len);
+ return false;
+ }
+
+ cur = next;
+ }
+#endif
+ return true;
+}
+
static struct kmem_cache *extent_tree_slab;
static struct kmem_cache *extent_node_slab;
@@ -77,7 +250,7 @@
struct extent_tree *et;
nid_t ino = inode->i_ino;
- down_write(&sbi->extent_tree_lock);
+ mutex_lock(&sbi->extent_tree_lock);
et = radix_tree_lookup(&sbi->extent_tree_root, ino);
if (!et) {
et = f2fs_kmem_cache_alloc(extent_tree_slab, GFP_NOFS);
@@ -94,7 +267,7 @@
atomic_dec(&sbi->total_zombie_tree);
list_del_init(&et->list);
}
- up_write(&sbi->extent_tree_lock);
+ mutex_unlock(&sbi->extent_tree_lock);
/* never died until evict_inode */
F2FS_I(inode)->extent_tree = et;
@@ -102,36 +275,6 @@
return et;
}
-static struct extent_node *__lookup_extent_tree(struct f2fs_sb_info *sbi,
- struct extent_tree *et, unsigned int fofs)
-{
- struct rb_node *node = et->root.rb_node;
- struct extent_node *en = et->cached_en;
-
- if (en) {
- struct extent_info *cei = &en->ei;
-
- if (cei->fofs <= fofs && cei->fofs + cei->len > fofs) {
- stat_inc_cached_node_hit(sbi);
- return en;
- }
- }
-
- while (node) {
- en = rb_entry(node, struct extent_node, rb_node);
-
- if (fofs < en->ei.fofs) {
- node = node->rb_left;
- } else if (fofs >= en->ei.fofs + en->ei.len) {
- node = node->rb_right;
- } else {
- stat_inc_rbtree_node_hit(sbi);
- return en;
- }
- }
- return NULL;
-}
-
static struct extent_node *__init_extent_tree(struct f2fs_sb_info *sbi,
struct extent_tree *et, struct extent_info *ei)
{
@@ -172,12 +315,12 @@
if (fofs < largest->fofs + largest->len && fofs + len > largest->fofs) {
largest->len = 0;
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, true);
}
}
/* return true, if inode page is changed */
-bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
+static bool __f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct extent_tree *et;
@@ -215,6 +358,16 @@
return false;
}
+bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
+{
+ bool ret = __f2fs_init_extent_tree(inode, i_ext);
+
+ if (!F2FS_I(inode)->extent_tree)
+ set_inode_flag(inode, FI_NO_EXTENT);
+
+ return ret;
+}
+
static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
struct extent_info *ei)
{
@@ -237,17 +390,24 @@
goto out;
}
- en = __lookup_extent_tree(sbi, et, pgofs);
- if (en) {
- *ei = en->ei;
- spin_lock(&sbi->extent_lock);
- if (!list_empty(&en->list)) {
- list_move_tail(&en->list, &sbi->extent_list);
- et->cached_en = en;
- }
- spin_unlock(&sbi->extent_lock);
- ret = true;
+ en = (struct extent_node *)__lookup_rb_tree(&et->root,
+ (struct rb_entry *)et->cached_en, pgofs);
+ if (!en)
+ goto out;
+
+ if (en == et->cached_en)
+ stat_inc_cached_node_hit(sbi);
+ else
+ stat_inc_rbtree_node_hit(sbi);
+
+ *ei = en->ei;
+ spin_lock(&sbi->extent_lock);
+ if (!list_empty(&en->list)) {
+ list_move_tail(&en->list, &sbi->extent_list);
+ et->cached_en = en;
}
+ spin_unlock(&sbi->extent_lock);
+ ret = true;
out:
stat_inc_total_hit(sbi);
read_unlock(&et->lock);
@@ -256,87 +416,6 @@
return ret;
}
-
-/*
- * lookup extent at @fofs, if hit, return the extent
- * if not, return NULL and
- * @prev_ex: extent before fofs
- * @next_ex: extent after fofs
- * @insert_p: insert point for new extent at fofs
- * in order to simpfy the insertion after.
- * tree must stay unchanged between lookup and insertion.
- */
-static struct extent_node *__lookup_extent_tree_ret(struct extent_tree *et,
- unsigned int fofs,
- struct extent_node **prev_ex,
- struct extent_node **next_ex,
- struct rb_node ***insert_p,
- struct rb_node **insert_parent)
-{
- struct rb_node **pnode = &et->root.rb_node;
- struct rb_node *parent = NULL, *tmp_node;
- struct extent_node *en = et->cached_en;
-
- *insert_p = NULL;
- *insert_parent = NULL;
- *prev_ex = NULL;
- *next_ex = NULL;
-
- if (RB_EMPTY_ROOT(&et->root))
- return NULL;
-
- if (en) {
- struct extent_info *cei = &en->ei;
-
- if (cei->fofs <= fofs && cei->fofs + cei->len > fofs)
- goto lookup_neighbors;
- }
-
- while (*pnode) {
- parent = *pnode;
- en = rb_entry(*pnode, struct extent_node, rb_node);
-
- if (fofs < en->ei.fofs)
- pnode = &(*pnode)->rb_left;
- else if (fofs >= en->ei.fofs + en->ei.len)
- pnode = &(*pnode)->rb_right;
- else
- goto lookup_neighbors;
- }
-
- *insert_p = pnode;
- *insert_parent = parent;
-
- en = rb_entry(parent, struct extent_node, rb_node);
- tmp_node = parent;
- if (parent && fofs > en->ei.fofs)
- tmp_node = rb_next(parent);
- *next_ex = tmp_node ?
- rb_entry(tmp_node, struct extent_node, rb_node) : NULL;
-
- tmp_node = parent;
- if (parent && fofs < en->ei.fofs)
- tmp_node = rb_prev(parent);
- *prev_ex = tmp_node ?
- rb_entry(tmp_node, struct extent_node, rb_node) : NULL;
- return NULL;
-
-lookup_neighbors:
- if (fofs == en->ei.fofs) {
- /* lookup prev node for merging backward later */
- tmp_node = rb_prev(&en->rb_node);
- *prev_ex = tmp_node ?
- rb_entry(tmp_node, struct extent_node, rb_node) : NULL;
- }
- if (fofs == en->ei.fofs + en->ei.len - 1) {
- /* lookup next node for merging frontward later */
- tmp_node = rb_next(&en->rb_node);
- *next_ex = tmp_node ?
- rb_entry(tmp_node, struct extent_node, rb_node) : NULL;
- }
- return en;
-}
-
static struct extent_node *__try_merge_extent_node(struct inode *inode,
struct extent_tree *et, struct extent_info *ei,
struct extent_node *prev_ex,
@@ -391,17 +470,7 @@
goto do_insert;
}
- while (*p) {
- parent = *p;
- en = rb_entry(parent, struct extent_node, rb_node);
-
- if (ei->fofs < en->ei.fofs)
- p = &(*p)->rb_left;
- else if (ei->fofs >= en->ei.fofs + en->ei.len)
- p = &(*p)->rb_right;
- else
- f2fs_bug_on(sbi, 1);
- }
+ p = __lookup_rb_tree_for_insert(sbi, &et->root, &parent, ei->fofs);
do_insert:
en = __attach_extent_node(sbi, et, ei, parent, p);
if (!en)
@@ -417,7 +486,7 @@
return en;
}
-static unsigned int f2fs_update_extent_tree_range(struct inode *inode,
+static void f2fs_update_extent_tree_range(struct inode *inode,
pgoff_t fofs, block_t blkaddr, unsigned int len)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
@@ -430,7 +499,7 @@
unsigned int pos = (unsigned int)fofs;
if (!et)
- return false;
+ return;
trace_f2fs_update_extent_tree_range(inode, fofs, blkaddr, len);
@@ -438,7 +507,7 @@
if (is_inode_flag_set(inode, FI_NO_EXTENT)) {
write_unlock(&et->lock);
- return false;
+ return;
}
prev = et->largest;
@@ -451,8 +520,11 @@
__drop_largest_extent(inode, fofs, len);
/* 1. lookup first extent node in range [fofs, fofs + len - 1] */
- en = __lookup_extent_tree_ret(et, fofs, &prev_en, &next_en,
- &insert_p, &insert_parent);
+ en = (struct extent_node *)__lookup_rb_tree_ret(&et->root,
+ (struct rb_entry *)et->cached_en, fofs,
+ (struct rb_entry **)&prev_en,
+ (struct rb_entry **)&next_en,
+ &insert_p, &insert_parent, false);
if (!en)
en = next_en;
@@ -493,9 +565,8 @@
if (!next_en) {
struct rb_node *node = rb_next(&en->rb_node);
- next_en = node ?
- rb_entry(node, struct extent_node, rb_node)
- : NULL;
+ next_en = rb_entry_safe(node, struct extent_node,
+ rb_node);
}
if (parts)
@@ -536,8 +607,6 @@
__free_extent_tree(sbi, et);
write_unlock(&et->lock);
-
- return !__is_extent_same(&prev, &et->largest);
}
unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
@@ -553,7 +622,7 @@
if (!atomic_read(&sbi->total_zombie_tree))
goto free_node;
- if (!down_write_trylock(&sbi->extent_tree_lock))
+ if (!mutex_trylock(&sbi->extent_tree_lock))
goto out;
/* 1. remove unreferenced extent tree */
@@ -575,11 +644,11 @@
goto unlock_out;
cond_resched();
}
- up_write(&sbi->extent_tree_lock);
+ mutex_unlock(&sbi->extent_tree_lock);
free_node:
/* 2. remove LRU extent entries */
- if (!down_write_trylock(&sbi->extent_tree_lock))
+ if (!mutex_trylock(&sbi->extent_tree_lock))
goto out;
remained = nr_shrink - (node_cnt + tree_cnt);
@@ -609,7 +678,7 @@
spin_unlock(&sbi->extent_lock);
unlock_out:
- up_write(&sbi->extent_tree_lock);
+ mutex_unlock(&sbi->extent_tree_lock);
out:
trace_f2fs_shrink_extent_tree(sbi, node_cnt, tree_cnt);
@@ -656,10 +725,10 @@
if (inode->i_nlink && !is_bad_inode(inode) &&
atomic_read(&et->node_cnt)) {
- down_write(&sbi->extent_tree_lock);
+ mutex_lock(&sbi->extent_tree_lock);
list_add_tail(&et->list, &sbi->zombie_list);
atomic_inc(&sbi->total_zombie_tree);
- up_write(&sbi->extent_tree_lock);
+ mutex_unlock(&sbi->extent_tree_lock);
return;
}
@@ -667,12 +736,12 @@
node_cnt = f2fs_destroy_extent_node(inode);
/* delete extent tree entry in radix tree */
- down_write(&sbi->extent_tree_lock);
+ mutex_lock(&sbi->extent_tree_lock);
f2fs_bug_on(sbi, atomic_read(&et->node_cnt));
radix_tree_delete(&sbi->extent_tree_root, inode->i_ino);
kmem_cache_free(extent_tree_slab, et);
atomic_dec(&sbi->total_ext_tree);
- up_write(&sbi->extent_tree_lock);
+ mutex_unlock(&sbi->extent_tree_lock);
F2FS_I(inode)->extent_tree = NULL;
@@ -719,7 +788,7 @@
void init_extent_cache_info(struct f2fs_sb_info *sbi)
{
INIT_RADIX_TREE(&sbi->extent_tree_root, GFP_NOIO);
- init_rwsem(&sbi->extent_tree_lock);
+ mutex_init(&sbi->extent_tree_lock);
INIT_LIST_HEAD(&sbi->extent_list);
spin_lock_init(&sbi->extent_lock);
atomic_set(&sbi->total_ext_tree, 0);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 88e111a..a8434af 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -19,12 +19,17 @@
#include <linux/magic.h>
#include <linux/kobject.h>
#include <linux/sched.h>
+#include <linux/writeback.h>
+#include <linux/cred.h>
#include <linux/vmalloc.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
-#include <linux/fscrypto.h>
+#include <linux/quotaops.h>
#include <crypto/hash.h>
+#define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_F2FS_FS_ENCRYPTION)
+#include <linux/fscrypt.h>
+
#ifdef CONFIG_F2FS_CHECK_FS
#define f2fs_bug_on(sbi, condition) BUG_ON(condition)
#else
@@ -40,12 +45,16 @@
#ifdef CONFIG_F2FS_FAULT_INJECTION
enum {
FAULT_KMALLOC,
+ FAULT_KVMALLOC,
FAULT_PAGE_ALLOC,
+ FAULT_PAGE_GET,
+ FAULT_ALLOC_BIO,
FAULT_ALLOC_NID,
FAULT_ORPHAN,
FAULT_BLOCK,
FAULT_DIR_DEPTH,
FAULT_EVICT_INODE,
+ FAULT_TRUNCATE,
FAULT_IO,
FAULT_CHECKPOINT,
FAULT_MAX,
@@ -58,7 +67,7 @@
};
extern char *fault_name[FAULT_MAX];
-#define IS_FAULT_SET(fi, type) (fi->inject_type & (1 << (type)))
+#define IS_FAULT_SET(fi, type) ((fi)->inject_type & (1 << (type)))
#endif
/*
@@ -83,10 +92,16 @@
#define F2FS_MOUNT_FAULT_INJECTION 0x00010000
#define F2FS_MOUNT_ADAPTIVE 0x00020000
#define F2FS_MOUNT_LFS 0x00040000
+#define F2FS_MOUNT_USRQUOTA 0x00080000
+#define F2FS_MOUNT_GRPQUOTA 0x00100000
+#define F2FS_MOUNT_PRJQUOTA 0x00200000
+#define F2FS_MOUNT_QUOTA 0x00400000
+#define F2FS_MOUNT_INLINE_XATTR_SIZE 0x00800000
+#define F2FS_MOUNT_RESERVE_ROOT 0x01000000
-#define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option)
-#define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option)
-#define test_opt(sbi, option) (sbi->mount_opt.opt & F2FS_MOUNT_##option)
+#define clear_opt(sbi, option) ((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
+#define set_opt(sbi, option) ((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
+#define test_opt(sbi, option) ((sbi)->mount_opt.opt & F2FS_MOUNT_##option)
#define ver_after(a, b) (typecheck(unsigned long long, a) && \
typecheck(unsigned long long, b) && \
@@ -102,15 +117,28 @@
unsigned int opt;
};
-#define F2FS_FEATURE_ENCRYPT 0x0001
-#define F2FS_FEATURE_HMSMR 0x0002
+#define F2FS_FEATURE_ENCRYPT 0x0001
+#define F2FS_FEATURE_BLKZONED 0x0002
+#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
+#define F2FS_FEATURE_EXTRA_ATTR 0x0008
+#define F2FS_FEATURE_PRJQUOTA 0x0010
+#define F2FS_FEATURE_INODE_CHKSUM 0x0020
+#define F2FS_FEATURE_FLEXIBLE_INLINE_XATTR 0x0040
+#define F2FS_FEATURE_QUOTA_INO 0x0080
+#define F2FS_FEATURE_INODE_CRTIME 0x0100
#define F2FS_HAS_FEATURE(sb, mask) \
((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0)
#define F2FS_SET_FEATURE(sb, mask) \
- F2FS_SB(sb)->raw_super->feature |= cpu_to_le32(mask)
+ (F2FS_SB(sb)->raw_super->feature |= cpu_to_le32(mask))
#define F2FS_CLEAR_FEATURE(sb, mask) \
- F2FS_SB(sb)->raw_super->feature &= ~cpu_to_le32(mask)
+ (F2FS_SB(sb)->raw_super->feature &= ~cpu_to_le32(mask))
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
+#define F2FS_DEF_RESUID 0
+#define F2FS_DEF_RESGID 0
/*
* For checkpoint manager
@@ -120,19 +148,22 @@
SIT_BITMAP
};
-enum {
- CP_UMOUNT,
- CP_FASTBOOT,
- CP_SYNC,
- CP_RECOVERY,
- CP_DISCARD,
-};
+#define CP_UMOUNT 0x00000001
+#define CP_FASTBOOT 0x00000002
+#define CP_SYNC 0x00000004
+#define CP_RECOVERY 0x00000008
+#define CP_DISCARD 0x00000010
+#define CP_TRIMMED 0x00000020
-#define DEF_BATCHED_TRIM_SECTIONS 2
+#define DEF_BATCHED_TRIM_SECTIONS 2048
#define BATCHED_TRIM_SEGMENTS(sbi) \
- (SM_I(sbi)->trim_sections * (sbi)->segs_per_sec)
+ (GET_SEG_FROM_SEC(sbi, SM_I(sbi)->trim_sections))
#define BATCHED_TRIM_BLOCKS(sbi) \
(BATCHED_TRIM_SEGMENTS(sbi) << (sbi)->log_blocks_per_seg)
+#define MAX_DISCARD_BLOCKS(sbi) BLKS_PER_SEC(sbi)
+#define DEF_MAX_DISCARD_REQUEST 8 /* issue 8 discards per round */
+#define DEF_MIN_DISCARD_ISSUE_TIME 50 /* 50 ms, if exists */
+#define DEF_MAX_DISCARD_ISSUE_TIME 60000 /* 60 s, if no candidates */
#define DEF_CP_INTERVAL 60 /* 60 secs */
#define DEF_IDLE_INTERVAL 5 /* 5 secs */
@@ -141,7 +172,6 @@
__u64 trim_start;
__u64 trim_end;
__u64 trim_minlen;
- __u64 trimmed;
};
/*
@@ -160,12 +190,15 @@
ORPHAN_INO, /* for orphan ino list */
APPEND_INO, /* for append ino list */
UPDATE_INO, /* for update ino list */
+ TRANS_DIR_INO, /* for trasactions dir ino list */
+ FLUSH_INO, /* for multiple device flushing */
MAX_INO_ENTRY, /* max. list */
};
struct ino_entry {
- struct list_head list; /* list head */
- nid_t ino; /* inode number */
+ struct list_head list; /* list head */
+ nid_t ino; /* inode number */
+ unsigned int dirty_device; /* dirty device bitmap */
};
/* for the list of inodes to be GCed */
@@ -174,18 +207,88 @@
struct inode *inode; /* vfs inode pointer */
};
-/* for the list of blockaddresses to be discarded */
+/* for the bitmap indicate blocks to be discarded */
struct discard_entry {
struct list_head list; /* list head */
- block_t blkaddr; /* block address to be discarded */
- int len; /* # of consecutive blocks of the discard */
+ block_t start_blkaddr; /* start blockaddr of current segment */
+ unsigned char discard_map[SIT_VBLOCK_MAP_SIZE]; /* segment discard bitmap */
};
-struct bio_entry {
- struct list_head list;
- struct bio *bio;
- struct completion event;
- int error;
+/* default discard granularity of inner discard thread, unit: block count */
+#define DEFAULT_DISCARD_GRANULARITY 16
+
+/* max discard pend list number */
+#define MAX_PLIST_NUM 512
+#define plist_idx(blk_num) ((blk_num) >= MAX_PLIST_NUM ? \
+ (MAX_PLIST_NUM - 1) : (blk_num - 1))
+
+enum {
+ D_PREP,
+ D_SUBMIT,
+ D_DONE,
+};
+
+struct discard_info {
+ block_t lstart; /* logical start address */
+ block_t len; /* length */
+ block_t start; /* actual start address in dev */
+};
+
+struct discard_cmd {
+ struct rb_node rb_node; /* rb node located in rb-tree */
+ union {
+ struct {
+ block_t lstart; /* logical start address */
+ block_t len; /* length */
+ block_t start; /* actual start address in dev */
+ };
+ struct discard_info di; /* discard info */
+
+ };
+ struct list_head list; /* command list */
+ struct completion wait; /* compleation */
+ struct block_device *bdev; /* bdev */
+ unsigned short ref; /* reference count */
+ unsigned char state; /* state */
+ int error; /* bio error */
+};
+
+enum {
+ DPOLICY_BG,
+ DPOLICY_FORCE,
+ DPOLICY_FSTRIM,
+ DPOLICY_UMOUNT,
+ MAX_DPOLICY,
+};
+
+struct discard_policy {
+ int type; /* type of discard */
+ unsigned int min_interval; /* used for candidates exist */
+ unsigned int max_interval; /* used for candidates not exist */
+ unsigned int max_requests; /* # of discards issued per round */
+ unsigned int io_aware_gran; /* minimum granularity discard not be aware of I/O */
+ bool io_aware; /* issue discard in idle time */
+ bool sync; /* submit discard with REQ_SYNC flag */
+ unsigned int granularity; /* discard granularity */
+};
+
+struct discard_cmd_control {
+ struct task_struct *f2fs_issue_discard; /* discard thread */
+ struct list_head entry_list; /* 4KB discard entry list */
+ struct list_head pend_list[MAX_PLIST_NUM];/* store pending entries */
+ struct list_head wait_list; /* store on-flushing entries */
+ struct list_head fstrim_list; /* in-flight discard from fstrim */
+ wait_queue_head_t discard_wait_queue; /* waiting queue for wake-up */
+ unsigned int discard_wake; /* to wake up discard thread */
+ struct mutex cmd_lock;
+ unsigned int nr_discards; /* # of discards in the list */
+ unsigned int max_discards; /* max. discards to be issued */
+ unsigned int discard_granularity; /* discard granularity */
+ unsigned int undiscard_blks; /* # of undiscard blocks */
+ atomic_t issued_discard; /* # of issued discard */
+ atomic_t issing_discard; /* # of issing discard */
+ atomic_t discard_cmd_cnt; /* # of cached cmd count */
+ struct rb_root root; /* root of discard rb-tree */
};
/* for the list of fsync inodes, used only during recovery */
@@ -196,13 +299,13 @@
block_t last_dentry; /* block address locating the last dentry */
};
-#define nats_in_cursum(jnl) (le16_to_cpu(jnl->n_nats))
-#define sits_in_cursum(jnl) (le16_to_cpu(jnl->n_sits))
+#define nats_in_cursum(jnl) (le16_to_cpu((jnl)->n_nats))
+#define sits_in_cursum(jnl) (le16_to_cpu((jnl)->n_sits))
-#define nat_in_journal(jnl, i) (jnl->nat_j.entries[i].ne)
-#define nid_in_journal(jnl, i) (jnl->nat_j.entries[i].nid)
-#define sit_in_journal(jnl, i) (jnl->sit_j.entries[i].se)
-#define segno_in_journal(jnl, i) (jnl->sit_j.entries[i].segno)
+#define nat_in_journal(jnl, i) ((jnl)->nat_j.entries[i].ne)
+#define nid_in_journal(jnl, i) ((jnl)->nat_j.entries[i].nid)
+#define sit_in_journal(jnl, i) ((jnl)->sit_j.entries[i].se)
+#define segno_in_journal(jnl, i) ((jnl)->sit_j.entries[i].segno)
#define MAX_NAT_JENTRIES(jnl) (NAT_JOURNAL_ENTRIES - nats_in_cursum(jnl))
#define MAX_SIT_JENTRIES(jnl) (SIT_JOURNAL_ENTRIES - sits_in_cursum(jnl))
@@ -210,6 +313,7 @@
static inline int update_nats_in_cursum(struct f2fs_journal *journal, int i)
{
int before = nats_in_cursum(journal);
+
journal->n_nats = cpu_to_le16(before + i);
return before;
}
@@ -217,6 +321,7 @@
static inline int update_sits_in_cursum(struct f2fs_journal *journal, int i)
{
int before = sits_in_cursum(journal);
+
journal->n_sits = cpu_to_le16(before + i);
return before;
}
@@ -242,11 +347,20 @@
#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3)
#define F2FS_IOC_RELEASE_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 4)
#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5)
-#define F2FS_IOC_GARBAGE_COLLECT _IO(F2FS_IOCTL_MAGIC, 6)
+#define F2FS_IOC_GARBAGE_COLLECT _IOW(F2FS_IOCTL_MAGIC, 6, __u32)
#define F2FS_IOC_WRITE_CHECKPOINT _IO(F2FS_IOCTL_MAGIC, 7)
-#define F2FS_IOC_DEFRAGMENT _IO(F2FS_IOCTL_MAGIC, 8)
+#define F2FS_IOC_DEFRAGMENT _IOWR(F2FS_IOCTL_MAGIC, 8, \
+ struct f2fs_defragment)
#define F2FS_IOC_MOVE_RANGE _IOWR(F2FS_IOCTL_MAGIC, 9, \
struct f2fs_move_range)
+#define F2FS_IOC_FLUSH_DEVICE _IOW(F2FS_IOCTL_MAGIC, 10, \
+ struct f2fs_flush_device)
+#define F2FS_IOC_GARBAGE_COLLECT_RANGE _IOW(F2FS_IOCTL_MAGIC, 11, \
+ struct f2fs_gc_range)
+#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, __u32)
+#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
+#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, __u32)
+#define F2FS_IOC_PRECACHE_EXTENTS _IO(F2FS_IOCTL_MAGIC, 15)
#define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY
#define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY
@@ -271,6 +385,12 @@
#define F2FS_IOC32_GETVERSION FS_IOC32_GETVERSION
#endif
+struct f2fs_gc_range {
+ u32 sync;
+ u64 start;
+ u64 len;
+};
+
struct f2fs_defragment {
u64 start;
u64 len;
@@ -283,36 +403,70 @@
u64 len; /* size to move */
};
+struct f2fs_flush_device {
+ u32 dev_num; /* device number to flush */
+ u32 segments; /* # of segments to flush */
+};
+
+/* for inline stuff */
+#define DEF_INLINE_RESERVED_SIZE 1
+#define DEF_MIN_INLINE_SIZE 1
+static inline int get_extra_isize(struct inode *inode);
+static inline int get_inline_xattr_addrs(struct inode *inode);
+#define MAX_INLINE_DATA(inode) (sizeof(__le32) * \
+ (CUR_ADDRS_PER_INODE(inode) - \
+ get_inline_xattr_addrs(inode) - \
+ DEF_INLINE_RESERVED_SIZE))
+
+/* for inline dir */
+#define NR_INLINE_DENTRY(inode) (MAX_INLINE_DATA(inode) * BITS_PER_BYTE / \
+ ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
+ BITS_PER_BYTE + 1))
+#define INLINE_DENTRY_BITMAP_SIZE(inode) ((NR_INLINE_DENTRY(inode) + \
+ BITS_PER_BYTE - 1) / BITS_PER_BYTE)
+#define INLINE_RESERVED_SIZE(inode) (MAX_INLINE_DATA(inode) - \
+ ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
+ NR_INLINE_DENTRY(inode) + \
+ INLINE_DENTRY_BITMAP_SIZE(inode)))
+
/*
* For INODE and NODE manager
*/
/* for directory operations */
struct f2fs_dentry_ptr {
struct inode *inode;
- const void *bitmap;
+ void *bitmap;
struct f2fs_dir_entry *dentry;
__u8 (*filename)[F2FS_SLOT_LEN];
int max;
+ int nr_bitmap;
};
-static inline void make_dentry_ptr(struct inode *inode,
- struct f2fs_dentry_ptr *d, void *src, int type)
+static inline void make_dentry_ptr_block(struct inode *inode,
+ struct f2fs_dentry_ptr *d, struct f2fs_dentry_block *t)
{
d->inode = inode;
+ d->max = NR_DENTRY_IN_BLOCK;
+ d->nr_bitmap = SIZE_OF_DENTRY_BITMAP;
+ d->bitmap = &t->dentry_bitmap;
+ d->dentry = t->dentry;
+ d->filename = t->filename;
+}
- if (type == 1) {
- struct f2fs_dentry_block *t = (struct f2fs_dentry_block *)src;
- d->max = NR_DENTRY_IN_BLOCK;
- d->bitmap = &t->dentry_bitmap;
- d->dentry = t->dentry;
- d->filename = t->filename;
- } else {
- struct f2fs_inline_dentry *t = (struct f2fs_inline_dentry *)src;
- d->max = NR_INLINE_DENTRY;
- d->bitmap = &t->dentry_bitmap;
- d->dentry = t->dentry;
- d->filename = t->filename;
- }
+static inline void make_dentry_ptr_inline(struct inode *inode,
+ struct f2fs_dentry_ptr *d, void *t)
+{
+ int entry_cnt = NR_INLINE_DENTRY(inode);
+ int bitmap_size = INLINE_DENTRY_BITMAP_SIZE(inode);
+ int reserved_size = INLINE_RESERVED_SIZE(inode);
+
+ d->inode = inode;
+ d->max = entry_cnt;
+ d->nr_bitmap = bitmap_size;
+ d->bitmap = t;
+ d->dentry = t + bitmap_size + reserved_size;
+ d->filename = t + bitmap_size + reserved_size +
+ SIZE_OF_DIR_ENTRY * entry_cnt;
}
/*
@@ -344,16 +498,30 @@
/* number of extent info in extent cache we try to shrink */
#define EXTENT_CACHE_SHRINK_NUMBER 128
+struct rb_entry {
+ struct rb_node rb_node; /* rb node located in rb-tree */
+ unsigned int ofs; /* start offset of the entry */
+ unsigned int len; /* length of the entry */
+};
+
struct extent_info {
unsigned int fofs; /* start offset in a file */
- u32 blk; /* start block address of the extent */
unsigned int len; /* length of the extent */
+ u32 blk; /* start block address of the extent */
};
struct extent_node {
- struct rb_node rb_node; /* rb node located in rb-tree */
+ struct rb_node rb_node;
+ union {
+ struct {
+ unsigned int fofs;
+ unsigned int len;
+ u32 blk;
+ };
+ struct extent_info ei; /* extent info */
+
+ };
struct list_head list; /* node in global extent list of sbi */
- struct extent_info ei; /* extent info */
struct extent_tree *et; /* extent tree pointer */
};
@@ -384,15 +552,19 @@
unsigned int m_len;
unsigned int m_flags;
pgoff_t *m_next_pgofs; /* point next possible non-hole pgofs */
+ pgoff_t *m_next_extent; /* point to next possible extent */
+ int m_seg_type;
};
/* for flag in get_data_block */
-#define F2FS_GET_BLOCK_READ 0
-#define F2FS_GET_BLOCK_DIO 1
-#define F2FS_GET_BLOCK_FIEMAP 2
-#define F2FS_GET_BLOCK_BMAP 3
-#define F2FS_GET_BLOCK_PRE_DIO 4
-#define F2FS_GET_BLOCK_PRE_AIO 5
+enum {
+ F2FS_GET_BLOCK_DEFAULT,
+ F2FS_GET_BLOCK_FIEMAP,
+ F2FS_GET_BLOCK_BMAP,
+ F2FS_GET_BLOCK_PRE_DIO,
+ F2FS_GET_BLOCK_PRE_AIO,
+ F2FS_GET_BLOCK_PRECACHE,
+};
/*
* i_advise uses FADVISE_XXX_BIT. We can add additional hints later.
@@ -401,6 +573,7 @@
#define FADVISE_LOST_PINO_BIT 0x02
#define FADVISE_ENCRYPT_BIT 0x04
#define FADVISE_ENC_NAME_BIT 0x08
+#define FADVISE_KEEP_SIZE_BIT 0x10
#define file_is_cold(inode) is_file(inode, FADVISE_COLD_BIT)
#define file_wrong_pino(inode) is_file(inode, FADVISE_LOST_PINO_BIT)
@@ -413,6 +586,8 @@
#define file_clear_encrypt(inode) clear_file(inode, FADVISE_ENCRYPT_BIT)
#define file_enc_name(inode) is_file(inode, FADVISE_ENC_NAME_BIT)
#define file_set_enc_name(inode) set_file(inode, FADVISE_ENC_NAME_BIT)
+#define file_keep_isize(inode) is_file(inode, FADVISE_KEEP_SIZE_BIT)
+#define file_set_keep_isize(inode) set_file(inode, FADVISE_KEEP_SIZE_BIT)
#define DEF_DIR_LEVEL 0
@@ -421,7 +596,10 @@
unsigned long i_flags; /* keep an inode flags for ioctl */
unsigned char i_advise; /* use to give file attribute hints */
unsigned char i_dir_level; /* use for dentry level for large dir */
- unsigned int i_current_depth; /* use only in directory structure */
+ union {
+ unsigned int i_current_depth; /* only for directory depth */
+ unsigned short i_gc_failures; /* only for regular file */
+ };
unsigned int i_pino; /* parent inode number */
umode_t i_acl_mode; /* keep file acl mode temporarily */
@@ -432,16 +610,31 @@
f2fs_hash_t chash; /* hash value of given file name */
unsigned int clevel; /* maximum level of given file name */
struct task_struct *task; /* lookup and create consistency */
+ struct task_struct *cp_task; /* separate cp/wb IO stats*/
nid_t i_xattr_nid; /* node id that contains xattrs */
- unsigned long long xattr_ver; /* cp version of xattr modification */
loff_t last_disk_size; /* lastly written file size */
+#ifdef CONFIG_QUOTA
+ struct dquot *i_dquot[MAXQUOTAS];
+
+ /* quota space reservation, managed internally by quota code */
+ qsize_t i_reserved_quota;
+#endif
struct list_head dirty_list; /* dirty list for dirs and files */
struct list_head gdirty_list; /* linked in global dirty list */
+ struct list_head inmem_ilist; /* list for inmem inodes */
struct list_head inmem_pages; /* inmemory pages managed by f2fs */
+ struct task_struct *inmem_task; /* store inmemory task */
struct mutex inmem_lock; /* lock for inmemory pages */
struct extent_tree *extent_tree; /* cached extent_tree entry */
struct rw_semaphore dio_rwsem[2];/* avoid racing between dio and gc */
+ struct rw_semaphore i_mmap_sem;
+ struct rw_semaphore i_xattr_sem; /* avoid racing between reading and changing EAs */
+
+ int i_extra_isize; /* size of extra space located in i_addr */
+ kprojid_t i_projid; /* id for project quota */
+ int i_inline_xattr_size; /* inline xattr size */
+ struct timespec i_crtime; /* inode creation time */
};
static inline void get_extent_info(struct extent_info *ext,
@@ -468,11 +661,22 @@
ei->len = len;
}
-static inline bool __is_extent_same(struct extent_info *ei1,
- struct extent_info *ei2)
+static inline bool __is_discard_mergeable(struct discard_info *back,
+ struct discard_info *front)
{
- return (ei1->fofs == ei2->fofs && ei1->blk == ei2->blk &&
- ei1->len == ei2->len);
+ return back->lstart + back->len == front->lstart;
+}
+
+static inline bool __is_discard_back_mergeable(struct discard_info *cur,
+ struct discard_info *back)
+{
+ return __is_discard_mergeable(back, cur);
+}
+
+static inline bool __is_discard_front_mergeable(struct discard_info *cur,
+ struct discard_info *front)
+{
+ return __is_discard_mergeable(cur, front);
}
static inline bool __is_extent_mergeable(struct extent_info *back,
@@ -494,20 +698,29 @@
return __is_extent_mergeable(cur, front);
}
-extern void f2fs_mark_inode_dirty_sync(struct inode *);
+extern void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync);
static inline void __try_update_largest_extent(struct inode *inode,
struct extent_tree *et, struct extent_node *en)
{
if (en->ei.len > et->largest.len) {
et->largest = en->ei;
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, true);
}
}
+/*
+ * For free nid management
+ */
+enum nid_state {
+ FREE_NID, /* newly added to free nid list */
+ PREALLOC_NID, /* it is preallocated */
+ MAX_NID_STATE,
+};
+
struct f2fs_nm_info {
block_t nat_blkaddr; /* base disk address of NAT */
nid_t max_nid; /* maximum possible node ids */
- nid_t available_nids; /* maximum available node ids */
+ nid_t available_nids; /* # of available node ids */
nid_t next_scan_nid; /* the next nid to be scanned */
unsigned int ram_thresh; /* control the memory footprint */
unsigned int ra_nid_pages; /* # of nid pages to be readaheaded */
@@ -520,16 +733,28 @@
struct list_head nat_entries; /* cached nat entry list (clean) */
unsigned int nat_cnt; /* the # of cached nat entries */
unsigned int dirty_nat_cnt; /* total num of nat entries in set */
+ unsigned int nat_blocks; /* # of nat blocks */
/* free node ids management */
struct radix_tree_root free_nid_root;/* root of the free_nid cache */
- struct list_head free_nid_list; /* a list for free nids */
- spinlock_t free_nid_list_lock; /* protect free nid list */
- unsigned int fcnt; /* the number of free node id */
+ struct list_head free_nid_list; /* list for free nids excluding preallocated nids */
+ unsigned int nid_cnt[MAX_NID_STATE]; /* the number of free node id */
+ spinlock_t nid_list_lock; /* protect nid lists ops */
struct mutex build_lock; /* lock for build free nids */
+ unsigned char (*free_nid_bitmap)[NAT_ENTRY_BITMAP_SIZE];
+ unsigned char *nat_block_bitmap;
+ unsigned short *free_nid_count; /* free nid count of NAT block */
/* for checkpoint */
char *nat_bitmap; /* NAT bitmap pointer */
+
+ unsigned int nat_bits_blocks; /* # of nat bits blocks */
+ unsigned char *nat_bits; /* NAT bits blocks */
+ unsigned char *full_nat_bits; /* full NAT pages */
+ unsigned char *empty_nat_bits; /* empty NAT pages */
+#ifdef CONFIG_F2FS_CHECK_FS
+ char *nat_bitmap_mir; /* NAT bitmap mirror */
+#endif
int bitmap_size; /* bitmap size */
};
@@ -586,19 +811,20 @@
CURSEG_WARM_NODE, /* direct node blocks of normal files */
CURSEG_COLD_NODE, /* indirect node blocks */
NO_CHECK_TYPE,
- CURSEG_DIRECT_IO, /* to use for the direct IO path */
};
struct flush_cmd {
struct completion wait;
struct llist_node llnode;
+ nid_t ino;
int ret;
};
struct flush_cmd_control {
struct task_struct *f2fs_issue_flush; /* flush thread */
wait_queue_head_t flush_wait_queue; /* waiting queue for wake-up */
- atomic_t submit_flush; /* # of issued flushes */
+ atomic_t issued_flush; /* # of issued flushes */
+ atomic_t issing_flush; /* # of issing flushes */
struct llist_head issue_list; /* list for command issue */
struct llist_node *dispatch_list; /* list for command dispatch */
};
@@ -609,6 +835,8 @@
struct dirty_seglist_info *dirty_info; /* dirty segment information */
struct curseg_info *curseg_array; /* active segment information */
+ struct rw_semaphore curseg_lock; /* for preventing curseg change */
+
block_t seg0_blkaddr; /* block address of 0'th segment */
block_t main_blkaddr; /* start block address of main area */
block_t ssa_blkaddr; /* start block address of SSA area */
@@ -621,12 +849,6 @@
/* a threshold to reclaim prefree segments */
unsigned int rec_prefree_segments;
- /* for small discard management */
- struct list_head discard_list; /* 4KB discard list */
- struct list_head wait_list; /* linked with issued discard bio */
- int nr_discards; /* # of discards in the list */
- int max_discards; /* max. discards to be issued */
-
/* for batched trimming */
unsigned int trim_sections; /* # of sections to trim */
@@ -635,10 +857,14 @@
unsigned int ipu_policy; /* in-place-update policy */
unsigned int min_ipu_util; /* in-place-update threshold */
unsigned int min_fsync_blocks; /* threshold for fsync */
+ unsigned int min_hot_blocks; /* threshold for hot block allocation */
+ unsigned int min_ssr_sections; /* threshold to trigger SSR allocation */
/* for flush command control */
- struct flush_cmd_control *cmd_control_info;
+ struct flush_cmd_control *fcc_info;
+ /* for discard command control */
+ struct discard_cmd_control *dcc_info;
};
/*
@@ -650,13 +876,17 @@
* f2fs monitors the number of several block types such as on-writeback,
* dirty dentry blocks, dirty node blocks, and dirty meta blocks.
*/
+#define WB_DATA_TYPE(p) (__is_cp_guaranteed(p) ? F2FS_WB_CP_DATA : F2FS_WB_DATA)
enum count_type {
F2FS_DIRTY_DENTS,
F2FS_DIRTY_DATA,
+ F2FS_DIRTY_QDATA,
F2FS_DIRTY_NODES,
F2FS_DIRTY_META,
F2FS_INMEM_PAGES,
F2FS_DIRTY_IMETA,
+ F2FS_WB_CP_DATA,
+ F2FS_WB_DATA,
NR_COUNT_TYPE,
};
@@ -680,35 +910,104 @@
META_FLUSH,
INMEM, /* the below types are used by tracepoints only. */
INMEM_DROP,
+ INMEM_INVALIDATE,
INMEM_REVOKE,
IPU,
OPU,
};
+enum temp_type {
+ HOT = 0, /* must be zero for meta bio */
+ WARM,
+ COLD,
+ NR_TEMP_TYPE,
+};
+
+enum need_lock_type {
+ LOCK_REQ = 0,
+ LOCK_DONE,
+ LOCK_RETRY,
+};
+
+enum cp_reason_type {
+ CP_NO_NEEDED,
+ CP_NON_REGULAR,
+ CP_HARDLINK,
+ CP_SB_NEED_CP,
+ CP_WRONG_PINO,
+ CP_NO_SPC_ROLL,
+ CP_NODE_NEED_CP,
+ CP_FASTBOOT_MODE,
+ CP_SPEC_LOG_NUM,
+ CP_RECOVER_DIR,
+};
+
+enum iostat_type {
+ APP_DIRECT_IO, /* app direct IOs */
+ APP_BUFFERED_IO, /* app buffered IOs */
+ APP_WRITE_IO, /* app write IOs */
+ APP_MAPPED_IO, /* app mapped IOs */
+ FS_DATA_IO, /* data IOs from kworker/fsync/reclaimer */
+ FS_NODE_IO, /* node IOs from kworker/fsync/reclaimer */
+ FS_META_IO, /* meta IOs from kworker/reclaimer */
+ FS_GC_DATA_IO, /* data IOs from forground gc */
+ FS_GC_NODE_IO, /* node IOs from forground gc */
+ FS_CP_DATA_IO, /* data IOs from checkpoint */
+ FS_CP_NODE_IO, /* node IOs from checkpoint */
+ FS_CP_META_IO, /* meta IOs from checkpoint */
+ FS_DISCARD, /* discard */
+ NR_IO_TYPE,
+};
+
struct f2fs_io_info {
struct f2fs_sb_info *sbi; /* f2fs_sb_info pointer */
+ nid_t ino; /* inode number */
enum page_type type; /* contains DATA/NODE/META/META_FLUSH */
+ enum temp_type temp; /* contains HOT/WARM/COLD */
int op; /* contains REQ_OP_ */
- int op_flags; /* rq_flag_bits */
+ int op_flags; /* req_flag_bits */
block_t new_blkaddr; /* new block address to be written */
block_t old_blkaddr; /* old block address before Cow */
struct page *page; /* page to be written */
struct page *encrypted_page; /* encrypted page */
+ struct list_head list; /* serialize IOs */
+ bool submitted; /* indicate IO submission */
+ int need_lock; /* indicate we need to lock cp_rwsem */
+ bool in_list; /* indicate fio is in io_list */
+ enum iostat_type io_type; /* io type */
+ struct writeback_control *io_wbc; /* writeback control */
};
-#define is_read_io(rw) (rw == READ)
+#define is_read_io(rw) ((rw) == READ)
struct f2fs_bio_info {
struct f2fs_sb_info *sbi; /* f2fs superblock */
struct bio *bio; /* bios to merge */
sector_t last_block_in_bio; /* last block number */
struct f2fs_io_info fio; /* store buffered io info. */
struct rw_semaphore io_rwsem; /* blocking op for bio */
+ spinlock_t io_lock; /* serialize DATA/NODE IOs */
+ struct list_head io_list; /* track fios */
+};
+
+#define FDEV(i) (sbi->devs[i])
+#define RDEV(i) (raw_super->devs[i])
+struct f2fs_dev_info {
+ struct block_device *bdev;
+ char path[MAX_PATH_LEN];
+ unsigned int total_segments;
+ block_t start_blk;
+ block_t end_blk;
+#ifdef CONFIG_BLK_DEV_ZONED
+ unsigned int nr_blkz; /* Total number of zones */
+ u8 *blkz_type; /* Array of zones type */
+#endif
};
enum inode_type {
DIR_INODE, /* for dirty dir inode */
FILE_INODE, /* for dirty regular/symlink inode */
DIRTY_META, /* for all dirtied inode metadata */
+ ATOMIC_FILE, /* for all atomic files */
NR_INODE_TYPE,
};
@@ -736,10 +1035,6 @@
MAX_TIME,
};
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
-#define F2FS_KEY_DESC_PREFIX "f2fs:"
-#define F2FS_KEY_DESC_PREFIX_SIZE 5
-#endif
struct f2fs_sb_info {
struct super_block *sb; /* pointer to VFS super block */
struct proc_dir_entry *s_proc; /* proc entry */
@@ -747,10 +1042,11 @@
int valid_super_block; /* valid super block no */
unsigned long s_flag; /* flags for sbi */
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
- u8 key_prefix[F2FS_KEY_DESC_PREFIX_SIZE];
- u8 key_prefix_size;
+#ifdef CONFIG_BLK_DEV_ZONED
+ unsigned int blocks_per_blkz; /* F2FS blocks per zone */
+ unsigned int log_blocks_per_blkz; /* log2 F2FS blocks per zone */
#endif
+
/* for node-related operations */
struct f2fs_nm_info *nm_info; /* node manager */
struct inode *node_inode; /* cache node blocks */
@@ -759,9 +1055,11 @@
struct f2fs_sm_info *sm_info; /* segment manager */
/* for bio operations */
- struct f2fs_bio_info read_io; /* for read bios */
- struct f2fs_bio_info write_io[NR_PAGE_TYPE]; /* for write bios */
- struct mutex wio_mutex[NODE + 1]; /* bio ordering for NODE/DATA */
+ struct f2fs_bio_info *write_io[NR_PAGE_TYPE]; /* for write bios */
+ struct mutex wio_mutex[NR_PAGE_TYPE - 1][NR_TEMP_TYPE];
+ /* bio ordering for NODE/DATA */
+ int write_io_size_bits; /* Write IO size bits */
+ mempool_t *write_io_dummy; /* Dummy pages */
/* for checkpoint */
struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */
@@ -771,6 +1069,7 @@
struct mutex cp_mutex; /* checkpoint procedure lock */
struct rw_semaphore cp_rwsem; /* blocking FS operations */
struct rw_semaphore node_write; /* locking node writes */
+ struct rw_semaphore node_change; /* locking node change */
wait_queue_head_t cp_wait;
unsigned long last_time[MAX_TIME]; /* to store time in jiffies */
long interval_time[MAX_TIME]; /* to store thresholds */
@@ -786,7 +1085,7 @@
/* for extent tree cache */
struct radix_tree_root extent_tree_root;/* cache extent cache entries */
- struct rw_semaphore extent_tree_lock; /* locking extent radix tree */
+ struct mutex extent_tree_lock; /* locking extent radix tree */
struct list_head extent_list; /* lru list for shrinker */
spinlock_t extent_lock; /* locking extent lru list */
atomic_t total_ext_tree; /* extent tree count */
@@ -811,19 +1110,32 @@
loff_t max_file_blocks; /* max block index of file */
int active_logs; /* # of active logs */
int dir_level; /* directory level */
+ int inline_xattr_size; /* inline xattr size */
+ unsigned int trigger_ssr_threshold; /* threshold to trigger ssr */
+ int readdir_ra; /* readahead inode in readdir */
block_t user_block_count; /* # of user blocks */
block_t total_valid_block_count; /* # of valid blocks */
block_t discard_blks; /* discard command candidats */
block_t last_valid_block_count; /* for recovery */
+ block_t reserved_blocks; /* configurable reserved blocks */
+ block_t current_reserved_blocks; /* current reserved blocks */
+ block_t root_reserved_blocks; /* root reserved blocks */
+ kuid_t s_resuid; /* reserved blocks for uid */
+ kgid_t s_resgid; /* reserved blocks for gid */
+
+ unsigned int nquota_files; /* # of quota sysfile */
+
u32 s_next_generation; /* for NFS support */
- atomic_t nr_wb_bios; /* # of writeback bios */
/* # of pages, see count_type */
atomic_t nr_pages[NR_COUNT_TYPE];
/* # of allocated blocks */
struct percpu_counter alloc_valid_block_count;
+ /* writeback control */
+ atomic_t wb_sync_req; /* count # of WB_SYNC threads */
+
/* valid inode count */
struct percpu_counter total_valid_inode_count;
@@ -837,6 +1149,9 @@
/* threshold for converting bg victims for fg */
u64 fggc_threshold;
+ /* threshold for gc trials on pinned files */
+ u64 gc_pin_file_threshold;
+
/* maximum # of trials to find a victim segment for SSR and GC */
unsigned int max_victim_search;
@@ -856,18 +1171,30 @@
atomic_t inline_xattr; /* # of inline_xattr inodes */
atomic_t inline_inode; /* # of inline_data inodes */
atomic_t inline_dir; /* # of inline_dentry inodes */
+ atomic_t aw_cnt; /* # of atomic writes */
+ atomic_t vw_cnt; /* # of volatile writes */
+ atomic_t max_aw_cnt; /* max # of atomic writes */
+ atomic_t max_vw_cnt; /* max # of volatile writes */
int bg_gc; /* background gc calls */
unsigned int ndirty_inode[NR_INODE_TYPE]; /* # of dirty inodes */
#endif
- unsigned int last_victim[2]; /* last victim segment # */
spinlock_t stat_lock; /* lock for stat operations */
+ /* For app/fs IO statistics */
+ spinlock_t iostat_lock;
+ unsigned long long write_iostat[NR_IO_TYPE];
+ bool iostat_enable;
+
/* For sysfs suppport */
struct kobject s_kobj;
struct completion s_kobj_unregister;
/* For shrinker support */
struct list_head s_list;
+ int s_ndevs; /* number of devices */
+ struct f2fs_dev_info *devs; /* for device list */
+ unsigned int dirty_device; /* for checkpoint data flush */
+ spinlock_t dev_lock; /* protect dirty_device */
struct mutex umount_mutex;
unsigned int shrinker_run_no;
@@ -878,13 +1205,26 @@
/* Reference to checksum algorithm driver via cryptoapi */
struct crypto_shash *s_chksum_driver;
+ /* Precomputed FS UUID checksum for seeding other checksums */
+ __u32 s_chksum_seed;
+
/* For fault injection */
#ifdef CONFIG_F2FS_FAULT_INJECTION
struct f2fs_fault_info fault_info;
#endif
+
+#ifdef CONFIG_QUOTA
+ /* Names of quota files with journalled quota */
+ char *s_qf_names[MAXQUOTAS];
+ int s_jquota_fmt; /* Format of quota to use */
+#endif
};
#ifdef CONFIG_F2FS_FAULT_INJECTION
+#define f2fs_show_injection_info(type) \
+ printk("%sF2FS-fs : inject %s in %s of %pF\n", \
+ KERN_INFO, fault_name[type], \
+ __func__, __builtin_return_address(0))
static inline bool time_to_inject(struct f2fs_sb_info *sbi, int type)
{
struct f2fs_fault_info *ffi = &sbi->fault_info;
@@ -898,10 +1238,6 @@
atomic_inc(&ffi->inject_ops);
if (atomic_read(&ffi->inject_ops) >= ffi->inject_rate) {
atomic_set(&ffi->inject_ops, 0);
- printk("%sF2FS-fs : inject %s in %pF\n",
- KERN_INFO,
- fault_name[type],
- __builtin_return_address(0));
return true;
}
return false;
@@ -912,8 +1248,8 @@
* and the return value is in kbytes. s is of struct f2fs_sb_info.
*/
#define BD_PART_WRITTEN(s) \
-(((u64)part_stat_read(s->sb->s_bdev->bd_part, sectors[1]) - \
- s->sectors_written_start) >> 1)
+(((u64)part_stat_read((s)->sb->s_bdev->bd_part, sectors[1]) - \
+ (s)->sectors_written_start) >> 1)
static inline void f2fs_update_time(struct f2fs_sb_info *sbi, int type)
{
@@ -922,8 +1258,7 @@
static inline bool f2fs_time_over(struct f2fs_sb_info *sbi, int type)
{
- struct timespec ts = {sbi->interval_time[type], 0};
- unsigned long interval = timespec_to_jiffies(&ts);
+ unsigned long interval = sbi->interval_time[type] * HZ;
return time_after(jiffies, sbi->last_time[type] + interval);
}
@@ -943,24 +1278,31 @@
/*
* Inline functions
*/
+static inline u32 __f2fs_crc32(struct f2fs_sb_info *sbi, u32 crc,
+ const void *address, unsigned int length)
+{
+ struct {
+ struct shash_desc shash;
+ char ctx[4];
+ } desc;
+ int err;
+
+ BUG_ON(crypto_shash_descsize(sbi->s_chksum_driver) != sizeof(desc.ctx));
+
+ desc.shash.tfm = sbi->s_chksum_driver;
+ desc.shash.flags = 0;
+ *(u32 *)desc.ctx = crc;
+
+ err = crypto_shash_update(&desc.shash, address, length);
+ BUG_ON(err);
+
+ return *(u32 *)desc.ctx;
+}
+
static inline u32 f2fs_crc32(struct f2fs_sb_info *sbi, const void *address,
unsigned int length)
{
- SHASH_DESC_ON_STACK(shash, sbi->s_chksum_driver);
- u32 *ctx = (u32 *)shash_desc_ctx(shash);
- u32 retval;
- int err;
-
- shash->tfm = sbi->s_chksum_driver;
- shash->flags = 0;
- *ctx = F2FS_SUPER_MAGIC;
-
- err = crypto_shash_update(shash, address, length);
- BUG_ON(err);
-
- retval = *ctx;
- barrier_data(ctx);
- return retval;
+ return __f2fs_crc32(sbi, F2FS_SUPER_MAGIC, address, length);
}
static inline bool f2fs_crc_valid(struct f2fs_sb_info *sbi, __u32 blk_crc,
@@ -969,6 +1311,12 @@
return f2fs_crc32(sbi, buf, buf_size) == blk_crc;
}
+static inline u32 f2fs_chksum(struct f2fs_sb_info *sbi, u32 crc,
+ const void *address, unsigned int length)
+{
+ return __f2fs_crc32(sbi, crc, address, length);
+}
+
static inline struct f2fs_inode_info *F2FS_I(struct inode *inode)
{
return container_of(inode, struct f2fs_inode_info, vfs_inode);
@@ -1069,6 +1417,19 @@
return le64_to_cpu(cp->checkpoint_ver);
}
+static inline unsigned long f2fs_qf_ino(struct super_block *sb, int type)
+{
+ if (type < F2FS_MAX_QUOTAS)
+ return le32_to_cpu(F2FS_SB(sb)->raw_super->qf_ino[type]);
+ return 0;
+}
+
+static inline __u64 cur_cp_crc(struct f2fs_checkpoint *cp)
+{
+ size_t crc_offset = le32_to_cpu(cp->checksum_offset);
+ return le32_to_cpu(*((__le32 *)((unsigned char *)cp + crc_offset)));
+}
+
static inline bool __is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
{
unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
@@ -1092,9 +1453,11 @@
static inline void set_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f)
{
- spin_lock(&sbi->cp_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sbi->cp_lock, flags);
__set_ckpt_flags(F2FS_CKPT(sbi), f);
- spin_unlock(&sbi->cp_lock);
+ spin_unlock_irqrestore(&sbi->cp_lock, flags);
}
static inline void __clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
@@ -1108,16 +1471,34 @@
static inline void clear_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f)
{
- spin_lock(&sbi->cp_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sbi->cp_lock, flags);
__clear_ckpt_flags(F2FS_CKPT(sbi), f);
- spin_unlock(&sbi->cp_lock);
+ spin_unlock_irqrestore(&sbi->cp_lock, flags);
}
-static inline bool f2fs_discard_en(struct f2fs_sb_info *sbi)
+static inline void disable_nat_bits(struct f2fs_sb_info *sbi, bool lock)
{
- struct request_queue *q = bdev_get_queue(sbi->sb->s_bdev);
+ unsigned long flags;
- return blk_queue_discard(q);
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
+
+ if (lock)
+ spin_lock_irqsave(&sbi->cp_lock, flags);
+ __clear_ckpt_flags(F2FS_CKPT(sbi), CP_NAT_BITS_FLAG);
+ kfree(NM_I(sbi)->nat_bits);
+ NM_I(sbi)->nat_bits = NULL;
+ if (lock)
+ spin_unlock_irqrestore(&sbi->cp_lock, flags);
+}
+
+static inline bool enabled_nat_bits(struct f2fs_sb_info *sbi,
+ struct cp_control *cpc)
+{
+ bool set = is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG);
+
+ return (cpc) ? (cpc->reason & CP_UMOUNT) && set : set;
}
static inline void f2fs_lock_op(struct f2fs_sb_info *sbi)
@@ -1125,6 +1506,11 @@
down_read(&sbi->cp_rwsem);
}
+static inline int f2fs_trylock_op(struct f2fs_sb_info *sbi)
+{
+ return down_read_trylock(&sbi->cp_rwsem);
+}
+
static inline void f2fs_unlock_op(struct f2fs_sb_info *sbi)
{
up_read(&sbi->cp_rwsem);
@@ -1153,7 +1539,7 @@
static inline bool __remain_node_summaries(int reason)
{
- return (reason == CP_UMOUNT || reason == CP_FASTBOOT);
+ return (reason & (CP_UMOUNT | CP_FASTBOOT));
}
static inline bool __exist_node_summaries(struct f2fs_sb_info *sbi)
@@ -1174,17 +1560,14 @@
return 0;
}
-#define F2FS_DEFAULT_ALLOCATED_BLOCKS 1
-
/*
* Check whether the inode has blocks or not
*/
static inline int F2FS_HAS_BLOCKS(struct inode *inode)
{
- if (F2FS_I(inode)->i_xattr_nid)
- return inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS + 1;
- else
- return inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS;
+ block_t xattr_block = F2FS_I(inode)->i_xattr_nid ? 1 : 0;
+
+ return (inode->i_blocks >> F2FS_LOG_SECTORS_PER_BLOCK) > xattr_block;
}
static inline bool f2fs_has_xattr_block(unsigned int ofs)
@@ -1192,15 +1575,43 @@
return ofs == XATTR_NODE_OFFSET;
}
-static inline void f2fs_i_blocks_write(struct inode *, blkcnt_t, bool);
-static inline bool inc_valid_block_count(struct f2fs_sb_info *sbi,
+static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi,
+ struct inode *inode)
+{
+ if (!inode)
+ return true;
+ if (!test_opt(sbi, RESERVE_ROOT))
+ return false;
+ if (IS_NOQUOTA(inode))
+ return true;
+ if (capable(CAP_SYS_RESOURCE))
+ return true;
+ if (uid_eq(sbi->s_resuid, current_fsuid()))
+ return true;
+ if (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) &&
+ in_group_p(sbi->s_resgid))
+ return true;
+ return false;
+}
+
+static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
+static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
struct inode *inode, blkcnt_t *count)
{
- blkcnt_t diff;
+ blkcnt_t diff = 0, release = 0;
+ block_t avail_user_block_count;
+ int ret;
+
+ ret = dquot_reserve_block(inode, *count);
+ if (ret)
+ return ret;
#ifdef CONFIG_F2FS_FAULT_INJECTION
- if (time_to_inject(sbi, FAULT_BLOCK))
- return false;
+ if (time_to_inject(sbi, FAULT_BLOCK)) {
+ f2fs_show_injection_info(FAULT_BLOCK);
+ release = *count;
+ goto enospc;
+ }
#endif
/*
* let's increase this in prior to actual block count change in order
@@ -1210,39 +1621,61 @@
spin_lock(&sbi->stat_lock);
sbi->total_valid_block_count += (block_t)(*count);
- if (unlikely(sbi->total_valid_block_count > sbi->user_block_count)) {
- diff = sbi->total_valid_block_count - sbi->user_block_count;
+ avail_user_block_count = sbi->user_block_count -
+ sbi->current_reserved_blocks;
+
+ if (!__allow_reserved_blocks(sbi, inode))
+ avail_user_block_count -= sbi->root_reserved_blocks;
+
+ if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
+ diff = sbi->total_valid_block_count - avail_user_block_count;
+ if (diff > *count)
+ diff = *count;
*count -= diff;
- sbi->total_valid_block_count = sbi->user_block_count;
+ release = diff;
+ sbi->total_valid_block_count -= diff;
if (!*count) {
spin_unlock(&sbi->stat_lock);
percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
- return false;
+ goto enospc;
}
}
spin_unlock(&sbi->stat_lock);
- f2fs_i_blocks_write(inode, *count, true);
- return true;
+ if (unlikely(release))
+ dquot_release_reservation_block(inode, release);
+ f2fs_i_blocks_write(inode, *count, true, true);
+ return 0;
+
+enospc:
+ dquot_release_reservation_block(inode, release);
+ return -ENOSPC;
}
static inline void dec_valid_block_count(struct f2fs_sb_info *sbi,
struct inode *inode,
- blkcnt_t count)
+ block_t count)
{
+ blkcnt_t sectors = count << F2FS_LOG_SECTORS_PER_BLOCK;
+
spin_lock(&sbi->stat_lock);
f2fs_bug_on(sbi, sbi->total_valid_block_count < (block_t) count);
- f2fs_bug_on(sbi, inode->i_blocks < count);
+ f2fs_bug_on(sbi, inode->i_blocks < sectors);
sbi->total_valid_block_count -= (block_t)count;
+ if (sbi->reserved_blocks &&
+ sbi->current_reserved_blocks < sbi->reserved_blocks)
+ sbi->current_reserved_blocks = min(sbi->reserved_blocks,
+ sbi->current_reserved_blocks + count);
spin_unlock(&sbi->stat_lock);
- f2fs_i_blocks_write(inode, count, false);
+ f2fs_i_blocks_write(inode, count, false, true);
}
static inline void inc_page_count(struct f2fs_sb_info *sbi, int count_type)
{
atomic_inc(&sbi->nr_pages[count_type]);
- if (count_type == F2FS_DIRTY_DATA || count_type == F2FS_INMEM_PAGES)
+ if (count_type == F2FS_DIRTY_DATA || count_type == F2FS_INMEM_PAGES ||
+ count_type == F2FS_WB_CP_DATA || count_type == F2FS_WB_DATA)
return;
set_sbi_flag(sbi, SBI_IS_DIRTY);
@@ -1253,6 +1686,8 @@
atomic_inc(&F2FS_I(inode)->dirty_pages);
inc_page_count(F2FS_I_SB(inode), S_ISDIR(inode->i_mode) ?
F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA);
+ if (IS_NOQUOTA(inode))
+ inc_page_count(F2FS_I_SB(inode), F2FS_DIRTY_QDATA);
}
static inline void dec_page_count(struct f2fs_sb_info *sbi, int count_type)
@@ -1269,6 +1704,8 @@
atomic_dec(&F2FS_I(inode)->dirty_pages);
dec_page_count(F2FS_I_SB(inode), S_ISDIR(inode->i_mode) ?
F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA);
+ if (IS_NOQUOTA(inode))
+ dec_page_count(F2FS_I_SB(inode), F2FS_DIRTY_QDATA);
}
static inline s64 get_pages(struct f2fs_sb_info *sbi, int count_type)
@@ -1363,51 +1800,84 @@
return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum);
}
-static inline bool inc_valid_node_count(struct f2fs_sb_info *sbi,
- struct inode *inode)
+static inline int inc_valid_node_count(struct f2fs_sb_info *sbi,
+ struct inode *inode, bool is_inode)
{
block_t valid_block_count;
unsigned int valid_node_count;
+ bool quota = inode && !is_inode;
+
+ if (quota) {
+ int ret = dquot_reserve_block(inode, 1);
+ if (ret)
+ return ret;
+ }
+
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+ if (time_to_inject(sbi, FAULT_BLOCK)) {
+ f2fs_show_injection_info(FAULT_BLOCK);
+ goto enospc;
+ }
+#endif
spin_lock(&sbi->stat_lock);
- valid_block_count = sbi->total_valid_block_count + 1;
+ valid_block_count = sbi->total_valid_block_count +
+ sbi->current_reserved_blocks + 1;
+
+ if (!__allow_reserved_blocks(sbi, inode))
+ valid_block_count += sbi->root_reserved_blocks;
+
if (unlikely(valid_block_count > sbi->user_block_count)) {
spin_unlock(&sbi->stat_lock);
- return false;
+ goto enospc;
}
valid_node_count = sbi->total_valid_node_count + 1;
if (unlikely(valid_node_count > sbi->total_node_count)) {
spin_unlock(&sbi->stat_lock);
- return false;
+ goto enospc;
}
- if (inode)
- f2fs_i_blocks_write(inode, 1, true);
-
sbi->total_valid_node_count++;
sbi->total_valid_block_count++;
spin_unlock(&sbi->stat_lock);
+ if (inode) {
+ if (is_inode)
+ f2fs_mark_inode_dirty_sync(inode, true);
+ else
+ f2fs_i_blocks_write(inode, 1, true, true);
+ }
+
percpu_counter_inc(&sbi->alloc_valid_block_count);
- return true;
+ return 0;
+
+enospc:
+ if (quota)
+ dquot_release_reservation_block(inode, 1);
+ return -ENOSPC;
}
static inline void dec_valid_node_count(struct f2fs_sb_info *sbi,
- struct inode *inode)
+ struct inode *inode, bool is_inode)
{
spin_lock(&sbi->stat_lock);
f2fs_bug_on(sbi, !sbi->total_valid_block_count);
f2fs_bug_on(sbi, !sbi->total_valid_node_count);
- f2fs_bug_on(sbi, !inode->i_blocks);
+ f2fs_bug_on(sbi, !is_inode && !inode->i_blocks);
- f2fs_i_blocks_write(inode, 1, false);
sbi->total_valid_node_count--;
sbi->total_valid_block_count--;
+ if (sbi->reserved_blocks &&
+ sbi->current_reserved_blocks < sbi->reserved_blocks)
+ sbi->current_reserved_blocks++;
spin_unlock(&sbi->stat_lock);
+
+ if (!is_inode)
+ f2fs_i_blocks_write(inode, 1, false, true);
}
static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi)
@@ -1435,17 +1905,33 @@
{
#ifdef CONFIG_F2FS_FAULT_INJECTION
struct page *page = find_lock_page(mapping, index);
+
if (page)
return page;
- if (time_to_inject(F2FS_M_SB(mapping), FAULT_PAGE_ALLOC))
+ if (time_to_inject(F2FS_M_SB(mapping), FAULT_PAGE_ALLOC)) {
+ f2fs_show_injection_info(FAULT_PAGE_ALLOC);
return NULL;
+ }
#endif
if (!for_write)
return grab_cache_page(mapping, index);
return grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
}
+static inline struct page *f2fs_pagecache_get_page(
+ struct address_space *mapping, pgoff_t index,
+ int fgp_flags, gfp_t gfp_mask)
+{
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+ if (time_to_inject(F2FS_M_SB(mapping), FAULT_PAGE_GET)) {
+ f2fs_show_injection_info(FAULT_PAGE_GET);
+ return NULL;
+ }
+#endif
+ return pagecache_get_page(mapping, index, fgp_flags, gfp_mask);
+}
+
static inline void f2fs_copy_page(struct page *src, struct page *dst)
{
char *src_kaddr = kmap(src);
@@ -1495,15 +1981,25 @@
return entry;
}
-static inline struct bio *f2fs_bio_alloc(int npages)
+static inline struct bio *f2fs_bio_alloc(struct f2fs_sb_info *sbi,
+ int npages, bool no_fail)
{
struct bio *bio;
- /* No failure on bio allocation */
- bio = bio_alloc(GFP_NOIO, npages);
- if (!bio)
- bio = bio_alloc(GFP_NOIO | __GFP_NOFAIL, npages);
- return bio;
+ if (no_fail) {
+ /* No failure on bio allocation */
+ bio = bio_alloc(GFP_NOIO, npages);
+ if (!bio)
+ bio = bio_alloc(GFP_NOIO | __GFP_NOFAIL, npages);
+ return bio;
+ }
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+ if (time_to_inject(sbi, FAULT_ALLOC_BIO)) {
+ f2fs_show_injection_info(FAULT_ALLOC_BIO);
+ return NULL;
+ }
+#endif
+ return bio_alloc(GFP_KERNEL, npages);
}
static inline void f2fs_radix_tree_insert(struct radix_tree_root *root,
@@ -1518,22 +2014,42 @@
static inline bool IS_INODE(struct page *page)
{
struct f2fs_node *p = F2FS_NODE(page);
+
return RAW_IS_INODE(p);
}
+static inline int offset_in_addr(struct f2fs_inode *i)
+{
+ return (i->i_inline & F2FS_EXTRA_ATTR) ?
+ (le16_to_cpu(i->i_extra_isize) / sizeof(__le32)) : 0;
+}
+
static inline __le32 *blkaddr_in_node(struct f2fs_node *node)
{
return RAW_IS_INODE(node) ? node->i.i_addr : node->dn.addr;
}
-static inline block_t datablock_addr(struct page *node_page,
- unsigned int offset)
+static inline int f2fs_has_extra_attr(struct inode *inode);
+static inline block_t datablock_addr(struct inode *inode,
+ struct page *node_page, unsigned int offset)
{
struct f2fs_node *raw_node;
__le32 *addr_array;
+ int base = 0;
+ bool is_inode = IS_INODE(node_page);
+
raw_node = F2FS_NODE(node_page);
+
+ /* from GC path only */
+ if (is_inode) {
+ if (!inode)
+ base = offset_in_addr(&raw_node->i);
+ else if (f2fs_has_extra_attr(inode))
+ base = get_extra_isize(inode);
+ }
+
addr_array = blkaddr_in_node(raw_node);
- return le32_to_cpu(addr_array[offset]);
+ return le32_to_cpu(addr_array[base + offset]);
}
static inline int f2fs_test_bit(unsigned int nr, char *addr)
@@ -1596,6 +2112,20 @@
*addr ^= mask;
}
+#define F2FS_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
+#define F2FS_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL)
+#define F2FS_FL_INHERITED (FS_PROJINHERIT_FL)
+
+static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags)
+{
+ if (S_ISDIR(mode))
+ return flags;
+ else if (S_ISREG(mode))
+ return flags & F2FS_REG_FLMASK;
+ else
+ return flags & F2FS_OTHER_FLMASK;
+}
+
/* used for f2fs_inode_info->flags */
enum {
FI_NEW_INODE, /* indicate newly allocated inode */
@@ -1614,6 +2144,7 @@
FI_UPDATE_WRITE, /* inode has in-place-update data */
FI_NEED_IPU, /* used for ipu per file */
FI_ATOMIC_FILE, /* indicate atomic file */
+ FI_ATOMIC_COMMIT, /* indicate the state of atomical committing */
FI_VOLATILE_FILE, /* indicate volatile file */
FI_FIRST_BLOCK_WRITTEN, /* indicate #0 data block was written */
FI_DROP_CACHE, /* drop dirty page cache */
@@ -1621,6 +2152,11 @@
FI_INLINE_DOTS, /* indicate inline dot dentries */
FI_DO_DEFRAG, /* indicate defragment is running */
FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */
+ FI_NO_PREALLOC, /* indicate skipped preallocated blocks */
+ FI_HOT_DATA, /* indicate file is hot */
+ FI_EXTRA_ATTR, /* indicate file has extra attribute */
+ FI_PROJ_INHERIT, /* indicate file inherits projectid */
+ FI_PIN_FILE, /* indicate file should not be gced */
};
static inline void __mark_inode_dirty_flag(struct inode *inode,
@@ -1630,11 +2166,13 @@
case FI_INLINE_XATTR:
case FI_INLINE_DATA:
case FI_INLINE_DENTRY:
+ case FI_NEW_INODE:
if (set)
return;
case FI_DATA_EXIST:
case FI_INLINE_DOTS:
- f2fs_mark_inode_dirty_sync(inode);
+ case FI_PIN_FILE:
+ f2fs_mark_inode_dirty_sync(inode, true);
}
}
@@ -1661,7 +2199,7 @@
{
F2FS_I(inode)->i_acl_mode = mode;
set_inode_flag(inode, FI_ACL_MODE);
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, false);
}
static inline void f2fs_i_links_write(struct inode *inode, bool inc)
@@ -1670,18 +2208,26 @@
inc_nlink(inode);
else
drop_nlink(inode);
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, true);
}
static inline void f2fs_i_blocks_write(struct inode *inode,
- blkcnt_t diff, bool add)
+ block_t diff, bool add, bool claim)
{
bool clean = !is_inode_flag_set(inode, FI_DIRTY_INODE);
bool recover = is_inode_flag_set(inode, FI_AUTO_RECOVER);
- inode->i_blocks = add ? inode->i_blocks + diff :
- inode->i_blocks - diff;
- f2fs_mark_inode_dirty_sync(inode);
+ /* add = 1, claim = 1 should be dquot_reserve_block in pair */
+ if (add) {
+ if (claim)
+ dquot_claim_block(inode, diff);
+ else
+ dquot_alloc_block_nofail(inode, diff);
+ } else {
+ dquot_free_block(inode, diff);
+ }
+
+ f2fs_mark_inode_dirty_sync(inode, true);
if (clean || recover)
set_inode_flag(inode, FI_AUTO_RECOVER);
}
@@ -1695,34 +2241,34 @@
return;
i_size_write(inode, i_size);
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, true);
if (clean || recover)
set_inode_flag(inode, FI_AUTO_RECOVER);
}
-static inline bool f2fs_skip_inode_update(struct inode *inode)
-{
- if (!is_inode_flag_set(inode, FI_AUTO_RECOVER))
- return false;
- return F2FS_I(inode)->last_disk_size == i_size_read(inode);
-}
-
static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)
{
F2FS_I(inode)->i_current_depth = depth;
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, true);
+}
+
+static inline void f2fs_i_gc_failures_write(struct inode *inode,
+ unsigned int count)
+{
+ F2FS_I(inode)->i_gc_failures = count;
+ f2fs_mark_inode_dirty_sync(inode, true);
}
static inline void f2fs_i_xnid_write(struct inode *inode, nid_t xnid)
{
F2FS_I(inode)->i_xattr_nid = xnid;
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, true);
}
static inline void f2fs_i_pino_write(struct inode *inode, nid_t pino)
{
F2FS_I(inode)->i_pino = pino;
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, true);
}
static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)
@@ -1739,6 +2285,10 @@
set_bit(FI_DATA_EXIST, &fi->flags);
if (ri->i_inline & F2FS_INLINE_DOTS)
set_bit(FI_INLINE_DOTS, &fi->flags);
+ if (ri->i_inline & F2FS_EXTRA_ATTR)
+ set_bit(FI_EXTRA_ATTR, &fi->flags);
+ if (ri->i_inline & F2FS_PIN_FILE)
+ set_bit(FI_PIN_FILE, &fi->flags);
}
static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri)
@@ -1755,6 +2305,15 @@
ri->i_inline |= F2FS_DATA_EXIST;
if (is_inode_flag_set(inode, FI_INLINE_DOTS))
ri->i_inline |= F2FS_INLINE_DOTS;
+ if (is_inode_flag_set(inode, FI_EXTRA_ATTR))
+ ri->i_inline |= F2FS_EXTRA_ATTR;
+ if (is_inode_flag_set(inode, FI_PIN_FILE))
+ ri->i_inline |= F2FS_PIN_FILE;
+}
+
+static inline int f2fs_has_extra_attr(struct inode *inode)
+{
+ return is_inode_flag_set(inode, FI_EXTRA_ATTR);
}
static inline int f2fs_has_inline_xattr(struct inode *inode)
@@ -1764,24 +2323,20 @@
static inline unsigned int addrs_per_inode(struct inode *inode)
{
- if (f2fs_has_inline_xattr(inode))
- return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS;
- return DEF_ADDRS_PER_INODE;
+ return CUR_ADDRS_PER_INODE(inode) - get_inline_xattr_addrs(inode);
}
-static inline void *inline_xattr_addr(struct page *page)
+static inline void *inline_xattr_addr(struct inode *inode, struct page *page)
{
struct f2fs_inode *ri = F2FS_INODE(page);
+
return (void *)&(ri->i_addr[DEF_ADDRS_PER_INODE -
- F2FS_INLINE_XATTR_ADDRS]);
+ get_inline_xattr_addrs(inode)]);
}
static inline int inline_xattr_size(struct inode *inode)
{
- if (f2fs_has_inline_xattr(inode))
- return F2FS_INLINE_XATTR_ADDRS << 2;
- else
- return 0;
+ return get_inline_xattr_addrs(inode) * sizeof(__le32);
}
static inline int f2fs_has_inline_data(struct inode *inode)
@@ -1789,12 +2344,6 @@
return is_inode_flag_set(inode, FI_INLINE_DATA);
}
-static inline void f2fs_clear_inline_inode(struct inode *inode)
-{
- clear_inode_flag(inode, FI_INLINE_DATA);
- clear_inode_flag(inode, FI_DATA_EXIST);
-}
-
static inline int f2fs_exist_data(struct inode *inode)
{
return is_inode_flag_set(inode, FI_DATA_EXIST);
@@ -1805,11 +2354,21 @@
return is_inode_flag_set(inode, FI_INLINE_DOTS);
}
+static inline bool f2fs_is_pinned_file(struct inode *inode)
+{
+ return is_inode_flag_set(inode, FI_PIN_FILE);
+}
+
static inline bool f2fs_is_atomic_file(struct inode *inode)
{
return is_inode_flag_set(inode, FI_ATOMIC_FILE);
}
+static inline bool f2fs_is_commit_atomic_write(struct inode *inode)
+{
+ return is_inode_flag_set(inode, FI_ATOMIC_COMMIT);
+}
+
static inline bool f2fs_is_volatile_file(struct inode *inode)
{
return is_inode_flag_set(inode, FI_VOLATILE_FILE);
@@ -1825,10 +2384,12 @@
return is_inode_flag_set(inode, FI_DROP_CACHE);
}
-static inline void *inline_data_addr(struct page *page)
+static inline void *inline_data_addr(struct inode *inode, struct page *page)
{
struct f2fs_inode *ri = F2FS_INODE(page);
- return (void *)&(ri->i_addr[1]);
+ int extra_size = get_extra_isize(inode);
+
+ return (void *)&(ri->i_addr[extra_size + DEF_INLINE_RESERVED_SIZE]);
}
static inline int f2fs_has_inline_dentry(struct inode *inode)
@@ -1850,15 +2411,40 @@
static inline void set_file(struct inode *inode, int type)
{
F2FS_I(inode)->i_advise |= type;
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, true);
}
static inline void clear_file(struct inode *inode, int type)
{
F2FS_I(inode)->i_advise &= ~type;
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, true);
}
+static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync)
+{
+ bool ret;
+
+ if (dsync) {
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+ spin_lock(&sbi->inode_lock[DIRTY_META]);
+ ret = list_empty(&F2FS_I(inode)->gdirty_list);
+ spin_unlock(&sbi->inode_lock[DIRTY_META]);
+ return ret;
+ }
+ if (!is_inode_flag_set(inode, FI_AUTO_RECOVER) ||
+ file_keep_isize(inode) ||
+ i_size_read(inode) & PAGE_MASK)
+ return false;
+
+ down_read(&F2FS_I(inode)->i_sem);
+ ret = F2FS_I(inode)->last_disk_size == i_size_read(inode);
+ up_read(&F2FS_I(inode)->i_sem);
+
+ return ret;
+}
+
+#define sb_rdonly f2fs_readonly
static inline int f2fs_readonly(struct super_block *sb)
{
return sb->s_flags & MS_RDONLY;
@@ -1893,13 +2479,15 @@
size_t size, gfp_t flags)
{
#ifdef CONFIG_F2FS_FAULT_INJECTION
- if (time_to_inject(sbi, FAULT_KMALLOC))
+ if (time_to_inject(sbi, FAULT_KMALLOC)) {
+ f2fs_show_injection_info(FAULT_KMALLOC);
return NULL;
+ }
#endif
return kmalloc(size, flags);
}
-static inline void *f2fs_kvmalloc(size_t size, gfp_t flags)
+static inline void *kvmalloc(size_t size, gfp_t flags)
{
void *ret;
@@ -1909,7 +2497,7 @@
return ret;
}
-static inline void *f2fs_kvzalloc(size_t size, gfp_t flags)
+static inline void *kvzalloc(size_t size, gfp_t flags)
{
void *ret;
@@ -1919,42 +2507,129 @@
return ret;
}
+enum rw_hint {
+ WRITE_LIFE_NOT_SET = 0,
+ WRITE_LIFE_NONE = 1, /* RWH_WRITE_LIFE_NONE */
+ WRITE_LIFE_SHORT = 2, /* RWH_WRITE_LIFE_SHORT */
+ WRITE_LIFE_MEDIUM = 3, /* RWH_WRITE_LIFE_MEDIUM */
+ WRITE_LIFE_LONG = 4, /* RWH_WRITE_LIFE_LONG */
+ WRITE_LIFE_EXTREME = 5, /* RWH_WRITE_LIFE_EXTREME */
+};
+
+static inline int wbc_to_write_flags(struct writeback_control *wbc)
+{
+ if (wbc->sync_mode == WB_SYNC_ALL)
+ return REQ_SYNC;
+ else if (wbc->for_kupdate || wbc->for_background)
+ return 0;
+
+ return 0;
+}
+
+static inline void *f2fs_kzalloc(struct f2fs_sb_info *sbi,
+ size_t size, gfp_t flags)
+{
+ return f2fs_kmalloc(sbi, size, flags | __GFP_ZERO);
+}
+
+static inline void *f2fs_kvmalloc(struct f2fs_sb_info *sbi,
+ size_t size, gfp_t flags)
+{
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+ if (time_to_inject(sbi, FAULT_KVMALLOC)) {
+ f2fs_show_injection_info(FAULT_KVMALLOC);
+ return NULL;
+ }
+#endif
+ return kvmalloc(size, flags);
+}
+
+static inline void *f2fs_kvzalloc(struct f2fs_sb_info *sbi,
+ size_t size, gfp_t flags)
+{
+ return f2fs_kvmalloc(sbi, size, flags | __GFP_ZERO);
+}
+
+static inline int get_extra_isize(struct inode *inode)
+{
+ return F2FS_I(inode)->i_extra_isize / sizeof(__le32);
+}
+
+static inline int get_inline_xattr_addrs(struct inode *inode)
+{
+ return F2FS_I(inode)->i_inline_xattr_size;
+}
+
#define get_inode_mode(i) \
((is_inode_flag_set(i, FI_ACL_MODE)) ? \
(F2FS_I(i)->i_acl_mode) : ((i)->i_mode))
-/* get offset of first page in next direct node */
-#define PGOFS_OF_NEXT_DNODE(pgofs, inode) \
- ((pgofs < ADDRS_PER_INODE(inode)) ? ADDRS_PER_INODE(inode) : \
- (pgofs - ADDRS_PER_INODE(inode) + ADDRS_PER_BLOCK) / \
- ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(inode))
+#define F2FS_TOTAL_EXTRA_ATTR_SIZE \
+ (offsetof(struct f2fs_inode, i_extra_end) - \
+ offsetof(struct f2fs_inode, i_extra_isize)) \
+
+#define F2FS_OLD_ATTRIBUTE_SIZE (offsetof(struct f2fs_inode, i_addr))
+#define F2FS_FITS_IN_INODE(f2fs_inode, extra_isize, field) \
+ ((offsetof(typeof(*f2fs_inode), field) + \
+ sizeof((f2fs_inode)->field)) \
+ <= (F2FS_OLD_ATTRIBUTE_SIZE + extra_isize)) \
+
+static inline void f2fs_reset_iostat(struct f2fs_sb_info *sbi)
+{
+ int i;
+
+ spin_lock(&sbi->iostat_lock);
+ for (i = 0; i < NR_IO_TYPE; i++)
+ sbi->write_iostat[i] = 0;
+ spin_unlock(&sbi->iostat_lock);
+}
+
+static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi,
+ enum iostat_type type, unsigned long long io_bytes)
+{
+ if (!sbi->iostat_enable)
+ return;
+ spin_lock(&sbi->iostat_lock);
+ sbi->write_iostat[type] += io_bytes;
+
+ if (type == APP_WRITE_IO || type == APP_DIRECT_IO)
+ sbi->write_iostat[APP_BUFFERED_IO] =
+ sbi->write_iostat[APP_WRITE_IO] -
+ sbi->write_iostat[APP_DIRECT_IO];
+ spin_unlock(&sbi->iostat_lock);
+}
/*
* file.c
*/
-int f2fs_sync_file(struct file *, loff_t, loff_t, int);
-void truncate_data_blocks(struct dnode_of_data *);
-int truncate_blocks(struct inode *, u64, bool);
-int f2fs_truncate(struct inode *);
-int f2fs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
-int f2fs_setattr(struct dentry *, struct iattr *);
-int truncate_hole(struct inode *, pgoff_t, pgoff_t);
-int truncate_data_blocks_range(struct dnode_of_data *, int);
-long f2fs_ioctl(struct file *, unsigned int, unsigned long);
-long f2fs_compat_ioctl(struct file *, unsigned int, unsigned long);
+int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync);
+void truncate_data_blocks(struct dnode_of_data *dn);
+int truncate_blocks(struct inode *inode, u64 from, bool lock);
+int f2fs_truncate(struct inode *inode);
+int f2fs_getattr(struct vfsmount *mnt, struct dentry *dentry,
+ struct kstat *stat);
+int f2fs_setattr(struct dentry *dentry, struct iattr *attr);
+int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);
+void truncate_data_blocks_range(struct dnode_of_data *dn, int count);
+int f2fs_precache_extents(struct inode *inode);
+long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+int f2fs_pin_file_control(struct inode *inode, bool inc);
/*
* inode.c
*/
-void f2fs_set_inode_flags(struct inode *);
-struct inode *f2fs_iget(struct super_block *, unsigned long);
-struct inode *f2fs_iget_retry(struct super_block *, unsigned long);
-int try_to_free_nats(struct f2fs_sb_info *, int);
-int update_inode(struct inode *, struct page *);
-int update_inode_page(struct inode *);
-int f2fs_write_inode(struct inode *, struct writeback_control *);
-void f2fs_evict_inode(struct inode *);
-void handle_failed_inode(struct inode *);
+void f2fs_set_inode_flags(struct inode *inode);
+bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page);
+void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page);
+struct inode *f2fs_iget(struct super_block *sb, unsigned long ino);
+struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino);
+int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink);
+void update_inode(struct inode *inode, struct page *node_page);
+void update_inode_page(struct inode *inode);
+int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc);
+void f2fs_evict_inode(struct inode *inode);
+void handle_failed_inode(struct inode *inode);
/*
* namei.c
@@ -1964,40 +2639,45 @@
/*
* dir.c
*/
-void set_de_type(struct f2fs_dir_entry *, umode_t);
-unsigned char get_de_type(struct f2fs_dir_entry *);
-struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *,
- f2fs_hash_t, int *, struct f2fs_dentry_ptr *);
-bool f2fs_fill_dentries(struct dir_context *, struct f2fs_dentry_ptr *,
- unsigned int, struct fscrypt_str *);
-void do_make_empty_dir(struct inode *, struct inode *,
- struct f2fs_dentry_ptr *);
-struct page *init_inode_metadata(struct inode *, struct inode *,
- const struct qstr *, const struct qstr *, struct page *);
-void update_parent_metadata(struct inode *, struct inode *, unsigned int);
-int room_for_filename(const void *, int, int);
-void f2fs_drop_nlink(struct inode *, struct inode *);
-struct f2fs_dir_entry *__f2fs_find_entry(struct inode *, struct fscrypt_name *,
- struct page **);
-struct f2fs_dir_entry *f2fs_find_entry(struct inode *, const struct qstr *,
- struct page **);
-struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **);
-ino_t f2fs_inode_by_name(struct inode *, const struct qstr *, struct page **);
-void f2fs_set_link(struct inode *, struct f2fs_dir_entry *,
- struct page *, struct inode *);
-int update_dent_inode(struct inode *, struct inode *, const struct qstr *);
-void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *,
- const struct qstr *, f2fs_hash_t , unsigned int);
-int f2fs_add_regular_entry(struct inode *, const struct qstr *,
- const struct qstr *, struct inode *, nid_t, umode_t);
-int __f2fs_do_add_link(struct inode *, struct fscrypt_name*, struct inode *,
- nid_t, umode_t);
-int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *, nid_t,
- umode_t);
-void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *,
- struct inode *);
-int f2fs_do_tmpfile(struct inode *, struct inode *);
-bool f2fs_empty_dir(struct inode *);
+void set_de_type(struct f2fs_dir_entry *de, umode_t mode);
+unsigned char get_de_type(struct f2fs_dir_entry *de);
+struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname,
+ f2fs_hash_t namehash, int *max_slots,
+ struct f2fs_dentry_ptr *d);
+int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
+ unsigned int start_pos, struct fscrypt_str *fstr);
+void do_make_empty_dir(struct inode *inode, struct inode *parent,
+ struct f2fs_dentry_ptr *d);
+struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
+ const struct qstr *new_name,
+ const struct qstr *orig_name, struct page *dpage);
+void update_parent_metadata(struct inode *dir, struct inode *inode,
+ unsigned int current_depth);
+int room_for_filename(const void *bitmap, int slots, int max_slots);
+void f2fs_drop_nlink(struct inode *dir, struct inode *inode);
+struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir,
+ struct fscrypt_name *fname, struct page **res_page);
+struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
+ const struct qstr *child, struct page **res_page);
+struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p);
+ino_t f2fs_inode_by_name(struct inode *dir, const struct qstr *qstr,
+ struct page **page);
+void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
+ struct page *page, struct inode *inode);
+void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d,
+ const struct qstr *name, f2fs_hash_t name_hash,
+ unsigned int bit_pos);
+int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
+ const struct qstr *orig_name,
+ struct inode *inode, nid_t ino, umode_t mode);
+int __f2fs_do_add_link(struct inode *dir, struct fscrypt_name *fname,
+ struct inode *inode, nid_t ino, umode_t mode);
+int __f2fs_add_link(struct inode *dir, const struct qstr *name,
+ struct inode *inode, nid_t ino, umode_t mode);
+void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
+ struct inode *dir, struct inode *inode);
+int f2fs_do_tmpfile(struct inode *inode, struct inode *dir);
+bool f2fs_empty_dir(struct inode *dir);
static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
{
@@ -2008,12 +2688,14 @@
/*
* super.c
*/
-int f2fs_inode_dirtied(struct inode *);
-void f2fs_inode_synced(struct inode *);
-int f2fs_commit_super(struct f2fs_sb_info *, bool);
-int f2fs_sync_fs(struct super_block *, int);
+int f2fs_inode_dirtied(struct inode *inode, bool sync);
+void f2fs_inode_synced(struct inode *inode);
+int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly);
+void f2fs_quota_off_umount(struct super_block *sb);
+int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover);
+int f2fs_sync_fs(struct super_block *sb, int sync);
extern __printf(3, 4)
-void f2fs_msg(struct super_block *, const char *, const char *, ...);
+void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...);
int sanity_check_ckpt(struct f2fs_sb_info *sbi);
/*
@@ -2028,160 +2710,200 @@
struct dnode_of_data;
struct node_info;
-bool available_free_memory(struct f2fs_sb_info *, int);
-int need_dentry_mark(struct f2fs_sb_info *, nid_t);
-bool is_checkpointed_node(struct f2fs_sb_info *, nid_t);
-bool need_inode_block_update(struct f2fs_sb_info *, nid_t);
-void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
-pgoff_t get_next_page_offset(struct dnode_of_data *, pgoff_t);
-int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
-int truncate_inode_blocks(struct inode *, pgoff_t);
-int truncate_xattr_node(struct inode *, struct page *);
-int wait_on_node_pages_writeback(struct f2fs_sb_info *, nid_t);
-int remove_inode_page(struct inode *);
-struct page *new_inode_page(struct inode *);
-struct page *new_node_page(struct dnode_of_data *, unsigned int, struct page *);
-void ra_node_page(struct f2fs_sb_info *, nid_t);
-struct page *get_node_page(struct f2fs_sb_info *, pgoff_t);
-struct page *get_node_page_ra(struct page *, int);
-void move_node_page(struct page *, int);
-int fsync_node_pages(struct f2fs_sb_info *, struct inode *,
- struct writeback_control *, bool);
-int sync_node_pages(struct f2fs_sb_info *, struct writeback_control *);
-void build_free_nids(struct f2fs_sb_info *);
-bool alloc_nid(struct f2fs_sb_info *, nid_t *);
-void alloc_nid_done(struct f2fs_sb_info *, nid_t);
-void alloc_nid_failed(struct f2fs_sb_info *, nid_t);
-int try_to_free_nids(struct f2fs_sb_info *, int);
-void recover_inline_xattr(struct inode *, struct page *);
-void recover_xattr_data(struct inode *, struct page *, block_t);
-int recover_inode_page(struct f2fs_sb_info *, struct page *);
-int restore_node_summary(struct f2fs_sb_info *, unsigned int,
- struct f2fs_summary_block *);
-void flush_nat_entries(struct f2fs_sb_info *);
-int build_node_manager(struct f2fs_sb_info *);
-void destroy_node_manager(struct f2fs_sb_info *);
+bool available_free_memory(struct f2fs_sb_info *sbi, int type);
+int need_dentry_mark(struct f2fs_sb_info *sbi, nid_t nid);
+bool is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid);
+bool need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino);
+void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni);
+pgoff_t get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs);
+int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode);
+int truncate_inode_blocks(struct inode *inode, pgoff_t from);
+int truncate_xattr_node(struct inode *inode);
+int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino);
+int remove_inode_page(struct inode *inode);
+struct page *new_inode_page(struct inode *inode);
+struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs);
+void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid);
+struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid);
+struct page *get_node_page_ra(struct page *parent, int start);
+void move_node_page(struct page *node_page, int gc_type);
+int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
+ struct writeback_control *wbc, bool atomic);
+int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc,
+ bool do_balance, enum iostat_type io_type);
+void build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount);
+bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid);
+void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid);
+void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid);
+int try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink);
+void recover_inline_xattr(struct inode *inode, struct page *page);
+int recover_xattr_data(struct inode *inode, struct page *page);
+int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page);
+void restore_node_summary(struct f2fs_sb_info *sbi,
+ unsigned int segno, struct f2fs_summary_block *sum);
+void flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc);
+int build_node_manager(struct f2fs_sb_info *sbi);
+void destroy_node_manager(struct f2fs_sb_info *sbi);
int __init create_node_manager_caches(void);
void destroy_node_manager_caches(void);
/*
* segment.c
*/
-void register_inmem_page(struct inode *, struct page *);
-void drop_inmem_pages(struct inode *);
-int commit_inmem_pages(struct inode *);
-void f2fs_balance_fs(struct f2fs_sb_info *, bool);
-void f2fs_balance_fs_bg(struct f2fs_sb_info *);
-int f2fs_issue_flush(struct f2fs_sb_info *);
-int create_flush_cmd_control(struct f2fs_sb_info *);
-void destroy_flush_cmd_control(struct f2fs_sb_info *);
-void invalidate_blocks(struct f2fs_sb_info *, block_t);
-bool is_checkpointed_data(struct f2fs_sb_info *, block_t);
-void refresh_sit_entry(struct f2fs_sb_info *, block_t, block_t);
-void f2fs_wait_all_discard_bio(struct f2fs_sb_info *);
-void clear_prefree_segments(struct f2fs_sb_info *, struct cp_control *);
-void release_discard_addrs(struct f2fs_sb_info *);
-int npages_for_summary_flush(struct f2fs_sb_info *, bool);
-void allocate_new_segments(struct f2fs_sb_info *);
-int f2fs_trim_fs(struct f2fs_sb_info *, struct fstrim_range *);
-struct page *get_sum_page(struct f2fs_sb_info *, unsigned int);
-void update_meta_page(struct f2fs_sb_info *, void *, block_t);
-void write_meta_page(struct f2fs_sb_info *, struct page *);
-void write_node_page(unsigned int, struct f2fs_io_info *);
-void write_data_page(struct dnode_of_data *, struct f2fs_io_info *);
-void rewrite_data_page(struct f2fs_io_info *);
-void __f2fs_replace_block(struct f2fs_sb_info *, struct f2fs_summary *,
- block_t, block_t, bool, bool);
-void f2fs_replace_block(struct f2fs_sb_info *, struct dnode_of_data *,
- block_t, block_t, unsigned char, bool, bool);
-void allocate_data_block(struct f2fs_sb_info *, struct page *,
- block_t, block_t *, struct f2fs_summary *, int);
-void f2fs_wait_on_page_writeback(struct page *, enum page_type, bool);
-void f2fs_wait_on_encrypted_page_writeback(struct f2fs_sb_info *, block_t);
-void write_data_summaries(struct f2fs_sb_info *, block_t);
-void write_node_summaries(struct f2fs_sb_info *, block_t);
-int lookup_journal_in_cursum(struct f2fs_journal *, int, unsigned int, int);
-void flush_sit_entries(struct f2fs_sb_info *, struct cp_control *);
-int build_segment_manager(struct f2fs_sb_info *);
-void destroy_segment_manager(struct f2fs_sb_info *);
+bool need_SSR(struct f2fs_sb_info *sbi);
+void register_inmem_page(struct inode *inode, struct page *page);
+void drop_inmem_pages_all(struct f2fs_sb_info *sbi);
+void drop_inmem_pages(struct inode *inode);
+void drop_inmem_page(struct inode *inode, struct page *page);
+int commit_inmem_pages(struct inode *inode);
+void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need);
+void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi);
+int f2fs_issue_flush(struct f2fs_sb_info *sbi, nid_t ino);
+int create_flush_cmd_control(struct f2fs_sb_info *sbi);
+int f2fs_flush_device_cache(struct f2fs_sb_info *sbi);
+void destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free);
+void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr);
+bool is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr);
+void init_discard_policy(struct discard_policy *dpolicy, int discard_type,
+ unsigned int granularity);
+void drop_discard_cmd(struct f2fs_sb_info *sbi);
+void stop_discard_thread(struct f2fs_sb_info *sbi);
+bool f2fs_wait_discard_bios(struct f2fs_sb_info *sbi);
+void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc);
+void release_discard_addrs(struct f2fs_sb_info *sbi);
+int npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra);
+void allocate_new_segments(struct f2fs_sb_info *sbi);
+int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range);
+bool exist_trim_candidates(struct f2fs_sb_info *sbi, struct cp_control *cpc);
+struct page *get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno);
+void update_meta_page(struct f2fs_sb_info *sbi, void *src, block_t blk_addr);
+void write_meta_page(struct f2fs_sb_info *sbi, struct page *page,
+ enum iostat_type io_type);
+void write_node_page(unsigned int nid, struct f2fs_io_info *fio);
+void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio);
+int rewrite_data_page(struct f2fs_io_info *fio);
+void __f2fs_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
+ block_t old_blkaddr, block_t new_blkaddr,
+ bool recover_curseg, bool recover_newaddr);
+void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
+ block_t old_addr, block_t new_addr,
+ unsigned char version, bool recover_curseg,
+ bool recover_newaddr);
+void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
+ block_t old_blkaddr, block_t *new_blkaddr,
+ struct f2fs_summary *sum, int type,
+ struct f2fs_io_info *fio, bool add_list);
+void f2fs_wait_on_page_writeback(struct page *page,
+ enum page_type type, bool ordered);
+void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr);
+void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk);
+void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk);
+int lookup_journal_in_cursum(struct f2fs_journal *journal, int type,
+ unsigned int val, int alloc);
+void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc);
+int build_segment_manager(struct f2fs_sb_info *sbi);
+void destroy_segment_manager(struct f2fs_sb_info *sbi);
int __init create_segment_manager_caches(void);
void destroy_segment_manager_caches(void);
+int rw_hint_to_seg_type(enum rw_hint hint);
/*
* checkpoint.c
*/
-void f2fs_stop_checkpoint(struct f2fs_sb_info *, bool);
-struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
-struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t);
-struct page *get_tmp_page(struct f2fs_sb_info *, pgoff_t);
-bool is_valid_blkaddr(struct f2fs_sb_info *, block_t, int);
-int ra_meta_pages(struct f2fs_sb_info *, block_t, int, int, bool);
-void ra_meta_pages_cond(struct f2fs_sb_info *, pgoff_t);
-long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
-void add_ino_entry(struct f2fs_sb_info *, nid_t, int type);
-void remove_ino_entry(struct f2fs_sb_info *, nid_t, int type);
-void release_ino_entry(struct f2fs_sb_info *, bool);
-bool exist_written_data(struct f2fs_sb_info *, nid_t, int);
-int f2fs_sync_inode_meta(struct f2fs_sb_info *);
-int acquire_orphan_inode(struct f2fs_sb_info *);
-void release_orphan_inode(struct f2fs_sb_info *);
-void add_orphan_inode(struct inode *);
-void remove_orphan_inode(struct f2fs_sb_info *, nid_t);
-int recover_orphan_inodes(struct f2fs_sb_info *);
-int get_valid_checkpoint(struct f2fs_sb_info *);
-void update_dirty_page(struct inode *, struct page *);
-void remove_dirty_inode(struct inode *);
-int sync_dirty_inodes(struct f2fs_sb_info *, enum inode_type);
-int write_checkpoint(struct f2fs_sb_info *, struct cp_control *);
-void init_ino_entry_info(struct f2fs_sb_info *);
+void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io);
+struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
+struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
+struct page *get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index);
+bool is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type);
+int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
+ int type, bool sync);
+void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index);
+long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
+ long nr_to_write, enum iostat_type io_type);
+void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type);
+void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type);
+void release_ino_entry(struct f2fs_sb_info *sbi, bool all);
+bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode);
+void set_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
+ unsigned int devidx, int type);
+bool is_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
+ unsigned int devidx, int type);
+int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi);
+int acquire_orphan_inode(struct f2fs_sb_info *sbi);
+void release_orphan_inode(struct f2fs_sb_info *sbi);
+void add_orphan_inode(struct inode *inode);
+void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino);
+int recover_orphan_inodes(struct f2fs_sb_info *sbi);
+int get_valid_checkpoint(struct f2fs_sb_info *sbi);
+void update_dirty_page(struct inode *inode, struct page *page);
+void remove_dirty_inode(struct inode *inode);
+int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type);
+int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc);
+void init_ino_entry_info(struct f2fs_sb_info *sbi);
int __init create_checkpoint_caches(void);
void destroy_checkpoint_caches(void);
/*
* data.c
*/
-void f2fs_submit_merged_bio(struct f2fs_sb_info *, enum page_type, int);
-void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *, struct inode *,
- struct page *, nid_t, enum page_type, int);
-void f2fs_flush_merged_bios(struct f2fs_sb_info *);
-int f2fs_submit_page_bio(struct f2fs_io_info *);
-void f2fs_submit_page_mbio(struct f2fs_io_info *);
-void set_data_blkaddr(struct dnode_of_data *);
-void f2fs_update_data_blkaddr(struct dnode_of_data *, block_t);
-int reserve_new_blocks(struct dnode_of_data *, blkcnt_t);
-int reserve_new_block(struct dnode_of_data *);
-int f2fs_get_block(struct dnode_of_data *, pgoff_t);
-ssize_t f2fs_preallocate_blocks(struct kiocb *, struct iov_iter *);
-int f2fs_reserve_block(struct dnode_of_data *, pgoff_t);
-struct page *get_read_data_page(struct inode *, pgoff_t, int, bool);
-struct page *find_data_page(struct inode *, pgoff_t);
-struct page *get_lock_data_page(struct inode *, pgoff_t, bool);
-struct page *get_new_data_page(struct inode *, struct page *, pgoff_t, bool);
-int do_write_data_page(struct f2fs_io_info *);
-int f2fs_map_blocks(struct inode *, struct f2fs_map_blocks *, int, int);
-int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *, u64, u64);
-void f2fs_set_page_dirty_nobuffers(struct page *);
-void f2fs_invalidate_page(struct page *, unsigned int, unsigned int);
-int f2fs_release_page(struct page *, gfp_t);
+void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type);
+void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi,
+ struct inode *inode, nid_t ino, pgoff_t idx,
+ enum page_type type);
+void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi);
+int f2fs_submit_page_bio(struct f2fs_io_info *fio);
+int f2fs_submit_page_write(struct f2fs_io_info *fio);
+struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi,
+ block_t blk_addr, struct bio *bio);
+int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr);
+void set_data_blkaddr(struct dnode_of_data *dn);
+void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr);
+int reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count);
+int reserve_new_block(struct dnode_of_data *dn);
+int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index);
+int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from);
+int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index);
+struct page *get_read_data_page(struct inode *inode, pgoff_t index,
+ int op_flags, bool for_write);
+struct page *find_data_page(struct inode *inode, pgoff_t index);
+struct page *get_lock_data_page(struct inode *inode, pgoff_t index,
+ bool for_write);
+struct page *get_new_data_page(struct inode *inode,
+ struct page *ipage, pgoff_t index, bool new_i_size);
+int do_write_data_page(struct f2fs_io_info *fio);
+int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
+ int create, int flag);
+int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+ u64 start, u64 len);
+bool should_update_inplace(struct inode *inode, struct f2fs_io_info *fio);
+bool should_update_outplace(struct inode *inode, struct f2fs_io_info *fio);
+void f2fs_set_page_dirty_nobuffers(struct page *page);
+int __f2fs_write_data_pages(struct address_space *mapping,
+ struct writeback_control *wbc,
+ enum iostat_type io_type);
+void f2fs_invalidate_page(struct page *page, unsigned int offset,
+ unsigned int length);
+int f2fs_release_page(struct page *page, gfp_t wait);
#ifdef CONFIG_MIGRATION
-int f2fs_migrate_page(struct address_space *, struct page *, struct page *,
- enum migrate_mode);
+int f2fs_migrate_page(struct address_space *mapping, struct page *newpage,
+ struct page *page, enum migrate_mode mode);
#endif
/*
* gc.c
*/
-int start_gc_thread(struct f2fs_sb_info *);
-void stop_gc_thread(struct f2fs_sb_info *);
-block_t start_bidx_of_node(unsigned int, struct inode *);
-int f2fs_gc(struct f2fs_sb_info *, bool);
-void build_gc_manager(struct f2fs_sb_info *);
+int start_gc_thread(struct f2fs_sb_info *sbi);
+void stop_gc_thread(struct f2fs_sb_info *sbi);
+block_t start_bidx_of_node(unsigned int node_ofs, struct inode *inode);
+int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background,
+ unsigned int segno);
+void build_gc_manager(struct f2fs_sb_info *sbi);
/*
* recovery.c
*/
-int recover_fsync_data(struct f2fs_sb_info *, bool);
-bool space_for_roll_forward(struct f2fs_sb_info *);
+int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only);
+bool space_for_roll_forward(struct f2fs_sb_info *sbi);
/*
* debug.c
@@ -2195,13 +2917,20 @@
unsigned long long hit_largest, hit_cached, hit_rbtree;
unsigned long long hit_total, total_ext;
int ext_tree, zombie_tree, ext_node;
- int ndirty_node, ndirty_dent, ndirty_meta, ndirty_data, ndirty_imeta;
+ int ndirty_node, ndirty_dent, ndirty_meta, ndirty_imeta;
+ int ndirty_data, ndirty_qdata;
int inmem_pages;
- unsigned int ndirty_dirs, ndirty_files, ndirty_all;
- int nats, dirty_nats, sits, dirty_sits, fnids;
+ unsigned int ndirty_dirs, ndirty_files, nquota_files, ndirty_all;
+ int nats, dirty_nats, sits, dirty_sits;
+ int free_nids, avail_nids, alloc_nids;
int total_count, utilization;
- int bg_gc, wb_bios;
- int inline_xattr, inline_inode, inline_dir, orphans;
+ int bg_gc, nr_wb_cp_data, nr_wb_data;
+ int nr_flushing, nr_flushed, flush_list_empty;
+ int nr_discarding, nr_discarded;
+ int nr_discard_cmd;
+ unsigned int undiscard_blks;
+ int inline_xattr, inline_inode, inline_dir, append, update, orphans;
+ int aw_cnt, max_aw_cnt, vw_cnt, max_vw_cnt;
unsigned int valid_count, valid_node_count, valid_inode_count, discard_blks;
unsigned int bimodal, avg_vblocks;
int util_free, util_valid, util_invalid;
@@ -2273,11 +3002,33 @@
((sbi)->block_count[(curseg)->alloc_type]++)
#define stat_inc_inplace_blocks(sbi) \
(atomic_inc(&(sbi)->inplace_count))
+#define stat_inc_atomic_write(inode) \
+ (atomic_inc(&F2FS_I_SB(inode)->aw_cnt))
+#define stat_dec_atomic_write(inode) \
+ (atomic_dec(&F2FS_I_SB(inode)->aw_cnt))
+#define stat_update_max_atomic_write(inode) \
+ do { \
+ int cur = atomic_read(&F2FS_I_SB(inode)->aw_cnt); \
+ int max = atomic_read(&F2FS_I_SB(inode)->max_aw_cnt); \
+ if (cur > max) \
+ atomic_set(&F2FS_I_SB(inode)->max_aw_cnt, cur); \
+ } while (0)
+#define stat_inc_volatile_write(inode) \
+ (atomic_inc(&F2FS_I_SB(inode)->vw_cnt))
+#define stat_dec_volatile_write(inode) \
+ (atomic_dec(&F2FS_I_SB(inode)->vw_cnt))
+#define stat_update_max_volatile_write(inode) \
+ do { \
+ int cur = atomic_read(&F2FS_I_SB(inode)->vw_cnt); \
+ int max = atomic_read(&F2FS_I_SB(inode)->max_vw_cnt); \
+ if (cur > max) \
+ atomic_set(&F2FS_I_SB(inode)->max_vw_cnt, cur); \
+ } while (0)
#define stat_inc_seg_count(sbi, type, gc_type) \
do { \
struct f2fs_stat_info *si = F2FS_STAT(sbi); \
- (si)->tot_segs++; \
- if (type == SUM_TYPE_DATA) { \
+ si->tot_segs++; \
+ if ((type) == SUM_TYPE_DATA) { \
si->data_segs++; \
si->bg_data_segs += (gc_type == BG_GC) ? 1 : 0; \
} else { \
@@ -2287,14 +3038,14 @@
} while (0)
#define stat_inc_tot_blk_count(si, blks) \
- (si->tot_blks += (blks))
+ ((si)->tot_blks += (blks))
#define stat_inc_data_blk_count(sbi, blks, gc_type) \
do { \
struct f2fs_stat_info *si = F2FS_STAT(sbi); \
stat_inc_tot_blk_count(si, blks); \
si->data_blks += (blks); \
- si->bg_data_blks += (gc_type == BG_GC) ? (blks) : 0; \
+ si->bg_data_blks += ((gc_type) == BG_GC) ? (blks) : 0; \
} while (0)
#define stat_inc_node_blk_count(sbi, blks, gc_type) \
@@ -2302,37 +3053,43 @@
struct f2fs_stat_info *si = F2FS_STAT(sbi); \
stat_inc_tot_blk_count(si, blks); \
si->node_blks += (blks); \
- si->bg_node_blks += (gc_type == BG_GC) ? (blks) : 0; \
+ si->bg_node_blks += ((gc_type) == BG_GC) ? (blks) : 0; \
} while (0)
-int f2fs_build_stats(struct f2fs_sb_info *);
-void f2fs_destroy_stats(struct f2fs_sb_info *);
+int f2fs_build_stats(struct f2fs_sb_info *sbi);
+void f2fs_destroy_stats(struct f2fs_sb_info *sbi);
int __init f2fs_create_root_stats(void);
void f2fs_destroy_root_stats(void);
#else
-#define stat_inc_cp_count(si)
-#define stat_inc_bg_cp_count(si)
-#define stat_inc_call_count(si)
-#define stat_inc_bggc_count(si)
-#define stat_inc_dirty_inode(sbi, type)
-#define stat_dec_dirty_inode(sbi, type)
-#define stat_inc_total_hit(sb)
-#define stat_inc_rbtree_node_hit(sb)
-#define stat_inc_largest_node_hit(sbi)
-#define stat_inc_cached_node_hit(sbi)
-#define stat_inc_inline_xattr(inode)
-#define stat_dec_inline_xattr(inode)
-#define stat_inc_inline_inode(inode)
-#define stat_dec_inline_inode(inode)
-#define stat_inc_inline_dir(inode)
-#define stat_dec_inline_dir(inode)
-#define stat_inc_seg_type(sbi, curseg)
-#define stat_inc_block_count(sbi, curseg)
-#define stat_inc_inplace_blocks(sbi)
-#define stat_inc_seg_count(sbi, type, gc_type)
-#define stat_inc_tot_blk_count(si, blks)
-#define stat_inc_data_blk_count(sbi, blks, gc_type)
-#define stat_inc_node_blk_count(sbi, blks, gc_type)
+#define stat_inc_cp_count(si) do { } while (0)
+#define stat_inc_bg_cp_count(si) do { } while (0)
+#define stat_inc_call_count(si) do { } while (0)
+#define stat_inc_bggc_count(si) do { } while (0)
+#define stat_inc_dirty_inode(sbi, type) do { } while (0)
+#define stat_dec_dirty_inode(sbi, type) do { } while (0)
+#define stat_inc_total_hit(sb) do { } while (0)
+#define stat_inc_rbtree_node_hit(sb) do { } while (0)
+#define stat_inc_largest_node_hit(sbi) do { } while (0)
+#define stat_inc_cached_node_hit(sbi) do { } while (0)
+#define stat_inc_inline_xattr(inode) do { } while (0)
+#define stat_dec_inline_xattr(inode) do { } while (0)
+#define stat_inc_inline_inode(inode) do { } while (0)
+#define stat_dec_inline_inode(inode) do { } while (0)
+#define stat_inc_inline_dir(inode) do { } while (0)
+#define stat_dec_inline_dir(inode) do { } while (0)
+#define stat_inc_atomic_write(inode) do { } while (0)
+#define stat_dec_atomic_write(inode) do { } while (0)
+#define stat_update_max_atomic_write(inode) do { } while (0)
+#define stat_inc_volatile_write(inode) do { } while (0)
+#define stat_dec_volatile_write(inode) do { } while (0)
+#define stat_update_max_volatile_write(inode) do { } while (0)
+#define stat_inc_seg_type(sbi, curseg) do { } while (0)
+#define stat_inc_block_count(sbi, curseg) do { } while (0)
+#define stat_inc_inplace_blocks(sbi) do { } while (0)
+#define stat_inc_seg_count(sbi, type, gc_type) do { } while (0)
+#define stat_inc_tot_blk_count(si, blks) do { } while (0)
+#define stat_inc_data_blk_count(sbi, blks, gc_type) do { } while (0)
+#define stat_inc_node_blk_count(sbi, blks, gc_type) do { } while (0)
static inline int f2fs_build_stats(struct f2fs_sb_info *sbi) { return 0; }
static inline void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { }
@@ -2355,53 +3112,79 @@
/*
* inline.c
*/
-bool f2fs_may_inline_data(struct inode *);
-bool f2fs_may_inline_dentry(struct inode *);
-void read_inline_data(struct page *, struct page *);
-bool truncate_inline_inode(struct page *, u64);
-int f2fs_read_inline_data(struct inode *, struct page *);
-int f2fs_convert_inline_page(struct dnode_of_data *, struct page *);
-int f2fs_convert_inline_inode(struct inode *);
-int f2fs_write_inline_data(struct inode *, struct page *);
-bool recover_inline_data(struct inode *, struct page *);
-struct f2fs_dir_entry *find_in_inline_dir(struct inode *,
- struct fscrypt_name *, struct page **);
-int make_empty_inline_dir(struct inode *inode, struct inode *, struct page *);
-int f2fs_add_inline_entry(struct inode *, const struct qstr *,
- const struct qstr *, struct inode *, nid_t, umode_t);
-void f2fs_delete_inline_entry(struct f2fs_dir_entry *, struct page *,
- struct inode *, struct inode *);
-bool f2fs_empty_inline_dir(struct inode *);
-int f2fs_read_inline_dir(struct file *, struct dir_context *,
- struct fscrypt_str *);
-int f2fs_inline_data_fiemap(struct inode *,
- struct fiemap_extent_info *, __u64, __u64);
+bool f2fs_may_inline_data(struct inode *inode);
+bool f2fs_may_inline_dentry(struct inode *inode);
+void read_inline_data(struct page *page, struct page *ipage);
+void truncate_inline_inode(struct inode *inode, struct page *ipage, u64 from);
+int f2fs_read_inline_data(struct inode *inode, struct page *page);
+int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page);
+int f2fs_convert_inline_inode(struct inode *inode);
+int f2fs_write_inline_data(struct inode *inode, struct page *page);
+bool recover_inline_data(struct inode *inode, struct page *npage);
+struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
+ struct fscrypt_name *fname, struct page **res_page);
+int make_empty_inline_dir(struct inode *inode, struct inode *parent,
+ struct page *ipage);
+int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name,
+ const struct qstr *orig_name,
+ struct inode *inode, nid_t ino, umode_t mode);
+void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page,
+ struct inode *dir, struct inode *inode);
+bool f2fs_empty_inline_dir(struct inode *dir);
+int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx,
+ struct fscrypt_str *fstr);
+int f2fs_inline_data_fiemap(struct inode *inode,
+ struct fiemap_extent_info *fieinfo,
+ __u64 start, __u64 len);
/*
* shrinker.c
*/
-unsigned long f2fs_shrink_count(struct shrinker *, struct shrink_control *);
-unsigned long f2fs_shrink_scan(struct shrinker *, struct shrink_control *);
-void f2fs_join_shrinker(struct f2fs_sb_info *);
-void f2fs_leave_shrinker(struct f2fs_sb_info *);
+unsigned long f2fs_shrink_count(struct shrinker *shrink,
+ struct shrink_control *sc);
+unsigned long f2fs_shrink_scan(struct shrinker *shrink,
+ struct shrink_control *sc);
+void f2fs_join_shrinker(struct f2fs_sb_info *sbi);
+void f2fs_leave_shrinker(struct f2fs_sb_info *sbi);
/*
* extent_cache.c
*/
-unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *, int);
-bool f2fs_init_extent_tree(struct inode *, struct f2fs_extent *);
-void f2fs_drop_extent_tree(struct inode *);
-unsigned int f2fs_destroy_extent_node(struct inode *);
-void f2fs_destroy_extent_tree(struct inode *);
-bool f2fs_lookup_extent_cache(struct inode *, pgoff_t, struct extent_info *);
-void f2fs_update_extent_cache(struct dnode_of_data *);
+struct rb_entry *__lookup_rb_tree(struct rb_root *root,
+ struct rb_entry *cached_re, unsigned int ofs);
+struct rb_node **__lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi,
+ struct rb_root *root, struct rb_node **parent,
+ unsigned int ofs);
+struct rb_entry *__lookup_rb_tree_ret(struct rb_root *root,
+ struct rb_entry *cached_re, unsigned int ofs,
+ struct rb_entry **prev_entry, struct rb_entry **next_entry,
+ struct rb_node ***insert_p, struct rb_node **insert_parent,
+ bool force);
+bool __check_rb_tree_consistence(struct f2fs_sb_info *sbi,
+ struct rb_root *root);
+unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink);
+bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext);
+void f2fs_drop_extent_tree(struct inode *inode);
+unsigned int f2fs_destroy_extent_node(struct inode *inode);
+void f2fs_destroy_extent_tree(struct inode *inode);
+bool f2fs_lookup_extent_cache(struct inode *inode, pgoff_t pgofs,
+ struct extent_info *ei);
+void f2fs_update_extent_cache(struct dnode_of_data *dn);
void f2fs_update_extent_cache_range(struct dnode_of_data *dn,
- pgoff_t, block_t, unsigned int);
-void init_extent_cache_info(struct f2fs_sb_info *);
+ pgoff_t fofs, block_t blkaddr, unsigned int len);
+void init_extent_cache_info(struct f2fs_sb_info *sbi);
int __init create_extent_cache(void);
void destroy_extent_cache(void);
/*
+ * sysfs.c
+ */
+int __init f2fs_init_sysfs(void);
+void f2fs_exit_sysfs(void);
+int f2fs_register_sysfs(struct f2fs_sb_info *sbi);
+void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi);
+
+/*
* crypto support
*/
static inline bool f2fs_encrypted_inode(struct inode *inode)
@@ -2409,10 +3192,16 @@
return file_is_encrypt(inode);
}
+static inline bool f2fs_encrypted_file(struct inode *inode)
+{
+ return f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode);
+}
+
static inline void f2fs_set_encrypted_inode(struct inode *inode)
{
#ifdef CONFIG_F2FS_FS_ENCRYPTION
file_set_encrypt(inode);
+ inode->i_flags |= S_ENCRYPTED;
#endif
}
@@ -2426,9 +3215,60 @@
return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_ENCRYPT);
}
-static inline int f2fs_sb_mounted_hmsmr(struct super_block *sb)
+static inline int f2fs_sb_mounted_blkzoned(struct super_block *sb)
{
- return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_HMSMR);
+ return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_BLKZONED);
+}
+
+static inline int f2fs_sb_has_extra_attr(struct super_block *sb)
+{
+ return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_EXTRA_ATTR);
+}
+
+static inline int f2fs_sb_has_project_quota(struct super_block *sb)
+{
+ return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_PRJQUOTA);
+}
+
+static inline int f2fs_sb_has_inode_chksum(struct super_block *sb)
+{
+ return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_INODE_CHKSUM);
+}
+
+static inline int f2fs_sb_has_flexible_inline_xattr(struct super_block *sb)
+{
+ return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_FLEXIBLE_INLINE_XATTR);
+}
+
+static inline int f2fs_sb_has_quota_ino(struct super_block *sb)
+{
+ return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_QUOTA_INO);
+}
+
+static inline int f2fs_sb_has_inode_crtime(struct super_block *sb)
+{
+ return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_INODE_CRTIME);
+}
+
+#ifdef CONFIG_BLK_DEV_ZONED
+static inline int get_blkz_type(struct f2fs_sb_info *sbi,
+ struct block_device *bdev, block_t blkaddr)
+{
+ unsigned int zno = blkaddr >> sbi->log_blocks_per_blkz;
+ int i;
+
+ for (i = 0; i < sbi->s_ndevs; i++)
+ if (FDEV(i).bdev == bdev)
+ return FDEV(i).blkz_type[zno];
+ return -EINVAL;
+}
+#endif
+
+static inline bool f2fs_discard_en(struct f2fs_sb_info *sbi)
+{
+ struct request_queue *q = bdev_get_queue(sbi->sb->s_bdev);
+
+ return blk_queue_discard(q) || f2fs_sb_mounted_blkzoned(sbi->sb);
}
static inline void set_opt_mode(struct f2fs_sb_info *sbi, unsigned int mt)
@@ -2457,28 +3297,4 @@
#endif
}
-#ifndef CONFIG_F2FS_FS_ENCRYPTION
-#define fscrypt_set_d_op(i)
-#define fscrypt_get_ctx fscrypt_notsupp_get_ctx
-#define fscrypt_release_ctx fscrypt_notsupp_release_ctx
-#define fscrypt_encrypt_page fscrypt_notsupp_encrypt_page
-#define fscrypt_decrypt_page fscrypt_notsupp_decrypt_page
-#define fscrypt_decrypt_bio_pages fscrypt_notsupp_decrypt_bio_pages
-#define fscrypt_pullback_bio_page fscrypt_notsupp_pullback_bio_page
-#define fscrypt_restore_control_page fscrypt_notsupp_restore_control_page
-#define fscrypt_zeroout_range fscrypt_notsupp_zeroout_range
-#define fscrypt_process_policy fscrypt_notsupp_process_policy
-#define fscrypt_get_policy fscrypt_notsupp_get_policy
-#define fscrypt_has_permitted_context fscrypt_notsupp_has_permitted_context
-#define fscrypt_inherit_context fscrypt_notsupp_inherit_context
-#define fscrypt_get_encryption_info fscrypt_notsupp_get_encryption_info
-#define fscrypt_put_encryption_info fscrypt_notsupp_put_encryption_info
-#define fscrypt_setup_filename fscrypt_notsupp_setup_filename
-#define fscrypt_free_filename fscrypt_notsupp_free_filename
-#define fscrypt_fname_encrypted_size fscrypt_notsupp_fname_encrypted_size
-#define fscrypt_fname_alloc_buffer fscrypt_notsupp_fname_alloc_buffer
-#define fscrypt_fname_free_buffer fscrypt_notsupp_fname_free_buffer
-#define fscrypt_fname_disk_to_usr fscrypt_notsupp_fname_disk_to_usr
-#define fscrypt_fname_usr_to_disk fscrypt_notsupp_fname_usr_to_disk
-#endif
#endif
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 801111e..b926df7 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -20,6 +20,7 @@
#include <linux/uaccess.h>
#include <linux/mount.h>
#include <linux/pagevec.h>
+#include <linux/uio.h>
#include <linux/uuid.h>
#include <linux/file.h>
@@ -32,6 +33,19 @@
#include "trace.h"
#include <trace/events/f2fs.h>
+static int f2fs_filemap_fault(struct vm_area_struct *vma,
+ struct vm_fault *vmf)
+{
+ struct inode *inode = file_inode(vma->vm_file);
+ int err;
+
+ down_read(&F2FS_I(inode)->i_mmap_sem);
+ err = filemap_fault(vma, vmf);
+ up_read(&F2FS_I(inode)->i_mmap_sem);
+
+ return err;
+}
+
static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
struct vm_fault *vmf)
{
@@ -41,6 +55,11 @@
struct dnode_of_data dn;
int err;
+ if (unlikely(f2fs_cp_error(sbi))) {
+ err = -EIO;
+ goto err;
+ }
+
sb_start_pagefault(inode->i_sb);
f2fs_bug_on(sbi, f2fs_has_inline_data(inode));
@@ -59,13 +78,14 @@
f2fs_balance_fs(sbi, dn.node_changed);
file_update_time(vma->vm_file);
+ down_read(&F2FS_I(inode)->i_mmap_sem);
lock_page(page);
if (unlikely(page->mapping != inode->i_mapping ||
page_offset(page) > i_size_read(inode) ||
!PageUptodate(page))) {
unlock_page(page);
err = -EFAULT;
- goto out;
+ goto out_sem;
}
/*
@@ -85,25 +105,28 @@
if (!PageUptodate(page))
SetPageUptodate(page);
+ f2fs_update_iostat(sbi, APP_MAPPED_IO, F2FS_BLKSIZE);
+
trace_f2fs_vm_page_mkwrite(page, DATA);
mapped:
/* fill the page */
f2fs_wait_on_page_writeback(page, DATA, false);
/* wait for GCed encrypted page writeback */
- if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
- f2fs_wait_on_encrypted_page_writeback(sbi, dn.data_blkaddr);
+ if (f2fs_encrypted_file(inode))
+ f2fs_wait_on_block_writeback(sbi, dn.data_blkaddr);
- /* if gced page is attached, don't write to cold segment */
- clear_cold_data(page);
+out_sem:
+ up_read(&F2FS_I(inode)->i_mmap_sem);
out:
sb_end_pagefault(inode->i_sb);
f2fs_update_time(sbi, REQ_TIME);
+err:
return block_page_mkwrite_return(err);
}
static const struct vm_operations_struct f2fs_file_vm_ops = {
- .fault = filemap_fault,
+ .fault = f2fs_filemap_fault,
.map_pages = filemap_map_pages,
.page_mkwrite = f2fs_vm_page_mkwrite,
};
@@ -118,39 +141,37 @@
if (!dentry)
return 0;
- if (update_dent_inode(inode, inode, &dentry->d_name)) {
- dput(dentry);
- return 0;
- }
-
*pino = parent_ino(dentry);
dput(dentry);
return 1;
}
-static inline bool need_do_checkpoint(struct inode *inode)
+static inline enum cp_reason_type need_do_checkpoint(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- bool need_cp = false;
+ enum cp_reason_type cp_reason = CP_NO_NEEDED;
- if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1)
- need_cp = true;
+ if (!S_ISREG(inode->i_mode))
+ cp_reason = CP_NON_REGULAR;
+ else if (inode->i_nlink != 1)
+ cp_reason = CP_HARDLINK;
else if (is_sbi_flag_set(sbi, SBI_NEED_CP))
- need_cp = true;
+ cp_reason = CP_SB_NEED_CP;
else if (file_wrong_pino(inode))
- need_cp = true;
+ cp_reason = CP_WRONG_PINO;
else if (!space_for_roll_forward(sbi))
- need_cp = true;
+ cp_reason = CP_NO_SPC_ROLL;
else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino))
- need_cp = true;
- else if (F2FS_I(inode)->xattr_ver == cur_cp_version(F2FS_CKPT(sbi)))
- need_cp = true;
+ cp_reason = CP_NODE_NEED_CP;
else if (test_opt(sbi, FASTBOOT))
- need_cp = true;
+ cp_reason = CP_FASTBOOT_MODE;
else if (sbi->active_logs == 2)
- need_cp = true;
+ cp_reason = CP_SPEC_LOG_NUM;
+ else if (need_dentry_mark(sbi, inode->i_ino) &&
+ exist_written_data(sbi, F2FS_I(inode)->i_pino, TRANS_DIR_INO))
+ cp_reason = CP_RECOVER_DIR;
- return need_cp;
+ return cp_reason;
}
static bool need_inode_page_update(struct f2fs_sb_info *sbi, nid_t ino)
@@ -170,7 +191,6 @@
nid_t pino;
down_write(&fi->i_sem);
- fi->xattr_ver = 0;
if (file_wrong_pino(inode) && inode->i_nlink == 1 &&
get_parent_ino(inode, &pino)) {
f2fs_i_pino_write(inode, pino);
@@ -186,7 +206,7 @@
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
nid_t ino = inode->i_ino;
int ret = 0;
- bool need_cp = false;
+ enum cp_reason_type cp_reason = 0;
struct writeback_control wbc = {
.sync_mode = WB_SYNC_ALL,
.nr_to_write = LONG_MAX,
@@ -205,12 +225,12 @@
clear_inode_flag(inode, FI_NEED_IPU);
if (ret) {
- trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
+ trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
return ret;
}
/* if the inode is dirty, let's recover all the time */
- if (!datasync && !f2fs_skip_inode_update(inode)) {
+ if (!f2fs_skip_inode_update(inode, datasync)) {
f2fs_write_inode(inode, NULL);
goto go_write;
}
@@ -236,10 +256,10 @@
* sudden-power-off.
*/
down_read(&F2FS_I(inode)->i_sem);
- need_cp = need_do_checkpoint(inode);
+ cp_reason = need_do_checkpoint(inode);
up_read(&F2FS_I(inode)->i_sem);
- if (need_cp) {
+ if (cp_reason) {
/* all the dirty node pages should be flushed for POR */
ret = f2fs_sync_fs(inode->i_sb, 1);
@@ -264,31 +284,47 @@
}
if (need_inode_block_update(sbi, ino)) {
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, true);
f2fs_write_inode(inode, NULL);
goto sync_nodes;
}
- ret = wait_on_node_pages_writeback(sbi, ino);
- if (ret)
- goto out;
+ /*
+ * If it's atomic_write, it's just fine to keep write ordering. So
+ * here we don't need to wait for node write completion, since we use
+ * node chain which serializes node blocks. If one of node writes are
+ * reordered, we can see simply broken chain, resulting in stopping
+ * roll-forward recovery. It means we'll recover all or none node blocks
+ * given fsync mark.
+ */
+ if (!atomic) {
+ ret = wait_on_node_pages_writeback(sbi, ino);
+ if (ret)
+ goto out;
+ }
/* once recovery info is written, don't need to tack this */
remove_ino_entry(sbi, ino, APPEND_INO);
clear_inode_flag(inode, FI_APPEND_WRITE);
flush_out:
- remove_ino_entry(sbi, ino, UPDATE_INO);
- clear_inode_flag(inode, FI_UPDATE_WRITE);
- ret = f2fs_issue_flush(sbi);
+ if (!atomic)
+ ret = f2fs_issue_flush(sbi, inode->i_ino);
+ if (!ret) {
+ remove_ino_entry(sbi, ino, UPDATE_INO);
+ clear_inode_flag(inode, FI_UPDATE_WRITE);
+ remove_ino_entry(sbi, ino, FLUSH_INO);
+ }
f2fs_update_time(sbi, REQ_TIME);
out:
- trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
+ trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
f2fs_trace_ios(NULL, 1);
return ret;
}
int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
{
+ if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(file)))))
+ return -EIO;
return f2fs_do_sync_file(file, start, end, datasync, false);
}
@@ -376,7 +412,8 @@
dn.ofs_in_node++, pgofs++,
data_ofs = (loff_t)pgofs << PAGE_SHIFT) {
block_t blkaddr;
- blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
+ blkaddr = datablock_addr(dn.inode,
+ dn.node_page, dn.ofs_in_node);
if (__found_offset(blkaddr, dirty, pgofs, whence)) {
f2fs_put_dnode(&dn);
@@ -424,13 +461,8 @@
struct inode *inode = file_inode(file);
int err;
- if (f2fs_encrypted_inode(inode)) {
- err = fscrypt_get_encryption_info(inode);
- if (err)
- return 0;
- if (!f2fs_encrypted_inode(inode))
- return -ENOKEY;
- }
+ if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
+ return -EIO;
/* we don't need to use inline_data strictly */
err = f2fs_convert_inline_inode(inode);
@@ -444,35 +476,26 @@
static int f2fs_file_open(struct inode *inode, struct file *filp)
{
- int ret = generic_file_open(inode, filp);
- struct dentry *dir;
+ int err = fscrypt_file_open(inode, filp);
- if (!ret && f2fs_encrypted_inode(inode)) {
- ret = fscrypt_get_encryption_info(inode);
- if (ret)
- return -EACCES;
- if (!fscrypt_has_encryption_key(inode))
- return -ENOKEY;
- }
- dir = dget_parent(file_dentry(filp));
- if (f2fs_encrypted_inode(d_inode(dir)) &&
- !fscrypt_has_permitted_context(d_inode(dir), inode)) {
- dput(dir);
- return -EPERM;
- }
- dput(dir);
- return ret;
+ if (err)
+ return err;
+ return dquot_file_open(inode, filp);
}
-int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
+void truncate_data_blocks_range(struct dnode_of_data *dn, int count)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
struct f2fs_node *raw_node;
int nr_free = 0, ofs = dn->ofs_in_node, len = count;
__le32 *addr;
+ int base = 0;
+
+ if (IS_INODE(dn->node_page) && f2fs_has_extra_attr(dn->inode))
+ base = get_extra_isize(dn->inode);
raw_node = F2FS_NODE(dn->node_page);
- addr = blkaddr_in_node(raw_node) + ofs;
+ addr = blkaddr_in_node(raw_node) + base + ofs;
for (; count > 0; count--, addr++, dn->ofs_in_node++) {
block_t blkaddr = le32_to_cpu(*addr);
@@ -503,7 +526,6 @@
f2fs_update_time(sbi, REQ_TIME);
trace_f2fs_truncate_data_blocks_range(dn->inode, dn->nid,
dn->ofs_in_node, nr_free);
- return nr_free;
}
void truncate_data_blocks(struct dnode_of_data *dn)
@@ -532,12 +554,14 @@
page = get_lock_data_page(inode, index, true);
if (IS_ERR(page))
- return 0;
+ return PTR_ERR(page) == -ENOENT ? 0 : PTR_ERR(page);
truncate_out:
f2fs_wait_on_page_writeback(page, DATA, true);
zero_user(page, offset, PAGE_SIZE - offset);
- if (!cache_only || !f2fs_encrypted_inode(inode) ||
- !S_ISREG(inode->i_mode))
+
+ /* An encrypted inode should have a key and truncate the last page. */
+ f2fs_bug_on(F2FS_I_SB(inode), cache_only && f2fs_encrypted_inode(inode));
+ if (!cache_only)
set_page_dirty(page);
f2fs_put_page(page, 1);
return 0;
@@ -570,8 +594,7 @@
}
if (f2fs_has_inline_data(inode)) {
- if (truncate_inline_inode(ipage, from))
- set_page_dirty(ipage);
+ truncate_inline_inode(inode, ipage, from);
f2fs_put_page(ipage, 1);
truncate_page = true;
goto out;
@@ -614,12 +637,21 @@
{
int err;
+ if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
+ return -EIO;
+
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return 0;
trace_f2fs_truncate(inode);
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+ if (time_to_inject(F2FS_I_SB(inode), FAULT_TRUNCATE)) {
+ f2fs_show_injection_info(FAULT_TRUNCATE);
+ return -EIO;
+ }
+#endif
/* we should check inline_data size */
if (!f2fs_may_inline_data(inode)) {
err = f2fs_convert_inline_inode(inode);
@@ -632,16 +664,52 @@
return err;
inode->i_mtime = inode->i_ctime = current_time(inode);
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, false);
return 0;
}
int f2fs_getattr(struct vfsmount *mnt,
- struct dentry *dentry, struct kstat *stat)
+ struct dentry *dentry, struct kstat *stat)
{
struct inode *inode = d_inode(dentry);
+#if 0
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ struct f2fs_inode *ri;
+ unsigned int flags;
+
+ if (f2fs_has_extra_attr(inode) &&
+ f2fs_sb_has_inode_crtime(inode->i_sb) &&
+ F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_crtime)) {
+ stat->result_mask |= STATX_BTIME;
+ stat->btime.tv_sec = fi->i_crtime.tv_sec;
+ stat->btime.tv_nsec = fi->i_crtime.tv_nsec;
+ }
+
+ flags = fi->i_flags & (FS_FL_USER_VISIBLE | FS_PROJINHERIT_FL);
+ if (flags & FS_APPEND_FL)
+ stat->attributes |= STATX_ATTR_APPEND;
+ if (flags & FS_COMPR_FL)
+ stat->attributes |= STATX_ATTR_COMPRESSED;
+ if (f2fs_encrypted_inode(inode))
+ stat->attributes |= STATX_ATTR_ENCRYPTED;
+ if (flags & FS_IMMUTABLE_FL)
+ stat->attributes |= STATX_ATTR_IMMUTABLE;
+ if (flags & FS_NODUMP_FL)
+ stat->attributes |= STATX_ATTR_NODUMP;
+
+ stat->attributes_mask |= (STATX_ATTR_APPEND |
+ STATX_ATTR_COMPRESSED |
+ STATX_ATTR_ENCRYPTED |
+ STATX_ATTR_IMMUTABLE |
+ STATX_ATTR_NODUMP);
+#endif
generic_fillattr(inode, stat);
- stat->blocks <<= 3;
+
+ /* we need to show initial sectors used for inline_data/dentries */
+ if ((S_ISREG(inode->i_mode) && f2fs_has_inline_data(inode)) ||
+ f2fs_has_inline_dentry(inode))
+ stat->blocks += (stat->size + 511) >> 9;
+
return 0;
}
@@ -679,28 +747,49 @@
{
struct inode *inode = d_inode(dentry);
int err;
+ bool size_changed = false;
+
+ if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
+ return -EIO;
err = setattr_prepare(dentry, attr);
if (err)
return err;
- if (attr->ia_valid & ATTR_SIZE) {
- if (f2fs_encrypted_inode(inode) &&
- fscrypt_get_encryption_info(inode))
- return -EACCES;
+ err = fscrypt_prepare_setattr(dentry, attr);
+ if (err)
+ return err;
+ if (is_quota_modification(inode, attr)) {
+ err = dquot_initialize(inode);
+ if (err)
+ return err;
+ }
+ if ((attr->ia_valid & ATTR_UID &&
+ !uid_eq(attr->ia_uid, inode->i_uid)) ||
+ (attr->ia_valid & ATTR_GID &&
+ !gid_eq(attr->ia_gid, inode->i_gid))) {
+ err = dquot_transfer(inode, attr);
+ if (err)
+ return err;
+ }
+
+ if (attr->ia_valid & ATTR_SIZE) {
if (attr->ia_size <= i_size_read(inode)) {
+ down_write(&F2FS_I(inode)->i_mmap_sem);
truncate_setsize(inode, attr->ia_size);
err = f2fs_truncate(inode);
+ up_write(&F2FS_I(inode)->i_mmap_sem);
if (err)
return err;
- f2fs_balance_fs(F2FS_I_SB(inode), true);
} else {
/*
* do not trim all blocks after i_size if target size is
* larger than i_size.
*/
+ down_write(&F2FS_I(inode)->i_mmap_sem);
truncate_setsize(inode, attr->ia_size);
+ up_write(&F2FS_I(inode)->i_mmap_sem);
/* should convert inline inode here */
if (!f2fs_may_inline_data(inode)) {
@@ -710,6 +799,12 @@
}
inode->i_mtime = inode->i_ctime = current_time(inode);
}
+
+ down_write(&F2FS_I(inode)->i_sem);
+ F2FS_I(inode)->last_disk_size = i_size_read(inode);
+ up_write(&F2FS_I(inode)->i_sem);
+
+ size_changed = true;
}
__setattr_copy(inode, attr);
@@ -722,7 +817,12 @@
}
}
- f2fs_mark_inode_dirty_sync(inode);
+ /* file size may changed here */
+ f2fs_mark_inode_dirty_sync(inode, size_changed);
+
+ /* inode change will produce dirty node pages flushed by checkpoint */
+ f2fs_balance_fs(F2FS_I_SB(inode), true);
+
return err;
}
@@ -774,7 +874,7 @@
err = get_dnode_of_data(&dn, pg_start, LOOKUP_NODE);
if (err) {
if (err == -ENOENT) {
- pg_start++;
+ pg_start = get_next_page_offset(&dn, pg_start);
continue;
}
return err;
@@ -836,12 +936,14 @@
blk_start = (loff_t)pg_start << PAGE_SHIFT;
blk_end = (loff_t)pg_end << PAGE_SHIFT;
+ down_write(&F2FS_I(inode)->i_mmap_sem);
truncate_inode_pages_range(mapping, blk_start,
blk_end - 1);
f2fs_lock_op(sbi);
ret = truncate_hole(inode, pg_start, pg_end);
f2fs_unlock_op(sbi);
+ up_write(&F2FS_I(inode)->i_mmap_sem);
}
}
@@ -872,7 +974,8 @@
done = min((pgoff_t)ADDRS_PER_PAGE(dn.node_page, inode) -
dn.ofs_in_node, len);
for (i = 0; i < done; i++, blkaddr++, do_replace++, dn.ofs_in_node++) {
- *blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
+ *blkaddr = datablock_addr(dn.inode,
+ dn.node_page, dn.ofs_in_node);
if (!is_checkpointed_data(sbi, *blkaddr)) {
if (test_opt(sbi, LFS)) {
@@ -948,15 +1051,15 @@
ADDRS_PER_PAGE(dn.node_page, dst_inode) -
dn.ofs_in_node, len - i);
do {
- dn.data_blkaddr = datablock_addr(dn.node_page,
- dn.ofs_in_node);
+ dn.data_blkaddr = datablock_addr(dn.inode,
+ dn.node_page, dn.ofs_in_node);
truncate_data_blocks_range(&dn, 1);
if (do_replace[i]) {
f2fs_i_blocks_write(src_inode,
- 1, false);
+ 1, false, false);
f2fs_i_blocks_write(dst_inode,
- 1, true);
+ 1, true, false);
f2fs_replace_block(sbi, &dn, dn.data_blkaddr,
blkaddr[i], ni.version, true, false);
@@ -1008,11 +1111,13 @@
while (len) {
olen = min((pgoff_t)4 * ADDRS_PER_BLOCK, len);
- src_blkaddr = f2fs_kvzalloc(sizeof(block_t) * olen, GFP_KERNEL);
+ src_blkaddr = f2fs_kvzalloc(F2FS_I_SB(src_inode),
+ sizeof(block_t) * olen, GFP_KERNEL);
if (!src_blkaddr)
return -ENOMEM;
- do_replace = f2fs_kvzalloc(sizeof(int) * olen, GFP_KERNEL);
+ do_replace = f2fs_kvzalloc(F2FS_I_SB(src_inode),
+ sizeof(int) * olen, GFP_KERNEL);
if (!do_replace) {
kvfree(src_blkaddr);
return -ENOMEM;
@@ -1080,16 +1185,20 @@
pg_start = offset >> PAGE_SHIFT;
pg_end = (offset + len) >> PAGE_SHIFT;
+ /* avoid gc operation during block exchange */
+ down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
+
+ down_write(&F2FS_I(inode)->i_mmap_sem);
/* write out all dirty pages from offset */
ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
if (ret)
- return ret;
+ goto out_unlock;
truncate_pagecache(inode, offset);
ret = f2fs_do_collapse(inode, pg_start, pg_end);
if (ret)
- return ret;
+ goto out_unlock;
/* write out all moved pages, if possible */
filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
@@ -1101,7 +1210,9 @@
ret = truncate_blocks(inode, new_size, true);
if (!ret)
f2fs_i_size_write(inode, new_size);
-
+out_unlock:
+ up_write(&F2FS_I(inode)->i_mmap_sem);
+ up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
return ret;
}
@@ -1115,7 +1226,8 @@
int ret;
for (; index < end; index++, dn->ofs_in_node++) {
- if (datablock_addr(dn->node_page, dn->ofs_in_node) == NULL_ADDR)
+ if (datablock_addr(dn->inode, dn->node_page,
+ dn->ofs_in_node) == NULL_ADDR)
count++;
}
@@ -1126,8 +1238,8 @@
dn->ofs_in_node = ofs_in_node;
for (index = start; index < end; index++, dn->ofs_in_node++) {
- dn->data_blkaddr =
- datablock_addr(dn->node_page, dn->ofs_in_node);
+ dn->data_blkaddr = datablock_addr(dn->inode,
+ dn->node_page, dn->ofs_in_node);
/*
* reserve_new_blocks will not guarantee entire block
* allocation.
@@ -1166,9 +1278,10 @@
if (ret)
return ret;
+ down_write(&F2FS_I(inode)->i_mmap_sem);
ret = filemap_write_and_wait_range(mapping, offset, offset + len - 1);
if (ret)
- return ret;
+ goto out_sem;
truncate_pagecache_range(inode, offset, offset + len - 1);
@@ -1182,17 +1295,15 @@
ret = fill_zero(inode, pg_start, off_start,
off_end - off_start);
if (ret)
- return ret;
+ goto out_sem;
- if (offset + len > new_size)
- new_size = offset + len;
new_size = max_t(loff_t, new_size, offset + len);
} else {
if (off_start) {
ret = fill_zero(inode, pg_start++, off_start,
PAGE_SIZE - off_start);
if (ret)
- return ret;
+ goto out_sem;
new_size = max_t(loff_t, new_size,
(loff_t)pg_start << PAGE_SHIFT);
@@ -1218,6 +1329,9 @@
ret = f2fs_do_zero_range(&dn, index, end);
f2fs_put_dnode(&dn);
f2fs_unlock_op(sbi);
+
+ f2fs_balance_fs(sbi, dn.node_changed);
+
if (ret)
goto out;
@@ -1238,6 +1352,8 @@
out:
if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size)
f2fs_i_size_write(inode, new_size);
+out_sem:
+ up_write(&F2FS_I(inode)->i_mmap_sem);
return ret;
}
@@ -1250,8 +1366,9 @@
int ret = 0;
new_size = i_size_read(inode) + len;
- if (new_size > inode->i_sb->s_maxbytes)
- return -EFBIG;
+ ret = inode_newsize_ok(inode, new_size);
+ if (ret)
+ return ret;
if (offset >= i_size_read(inode))
return -EINVAL;
@@ -1266,14 +1383,18 @@
f2fs_balance_fs(sbi, true);
+ /* avoid gc operation during block exchange */
+ down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
+
+ down_write(&F2FS_I(inode)->i_mmap_sem);
ret = truncate_blocks(inode, i_size_read(inode), true);
if (ret)
- return ret;
+ goto out;
/* write out all dirty pages from offset */
ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
if (ret)
- return ret;
+ goto out;
truncate_pagecache(inode, offset);
@@ -1302,6 +1423,9 @@
if (!ret)
f2fs_i_size_write(inode, new_size);
+out:
+ up_write(&F2FS_I(inode)->i_mmap_sem);
+ up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
return ret;
}
@@ -1309,19 +1433,20 @@
loff_t len, int mode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- struct f2fs_map_blocks map = { .m_next_pgofs = NULL };
+ struct f2fs_map_blocks map = { .m_next_pgofs = NULL,
+ .m_next_extent = NULL, .m_seg_type = NO_CHECK_TYPE };
pgoff_t pg_end;
loff_t new_size = i_size_read(inode);
loff_t off_end;
- int ret;
+ int err;
- ret = inode_newsize_ok(inode, (len + offset));
- if (ret)
- return ret;
+ err = inode_newsize_ok(inode, (len + offset));
+ if (err)
+ return err;
- ret = f2fs_convert_inline_inode(inode);
- if (ret)
- return ret;
+ err = f2fs_convert_inline_inode(inode);
+ if (err)
+ return err;
f2fs_balance_fs(sbi, true);
@@ -1333,12 +1458,12 @@
if (off_end)
map.m_len++;
- ret = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO);
- if (ret) {
+ err = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO);
+ if (err) {
pgoff_t last_off;
if (!map.m_len)
- return ret;
+ return err;
last_off = map.m_lblk + map.m_len - 1;
@@ -1349,10 +1474,14 @@
new_size = ((loff_t)pg_end << PAGE_SHIFT) + off_end;
}
- if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size)
- f2fs_i_size_write(inode, new_size);
+ if (new_size > i_size_read(inode)) {
+ if (mode & FALLOC_FL_KEEP_SIZE)
+ file_set_keep_isize(inode);
+ else
+ f2fs_i_size_write(inode, new_size);
+ }
- return ret;
+ return err;
}
static long f2fs_fallocate(struct file *file, int mode,
@@ -1361,6 +1490,9 @@
struct inode *inode = file_inode(file);
long ret = 0;
+ if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
+ return -EIO;
+
/* f2fs only support ->fallocate for regular file */
if (!S_ISREG(inode->i_mode))
return -EINVAL;
@@ -1393,7 +1525,7 @@
if (!ret) {
inode->i_mtime = inode->i_ctime = current_time(inode);
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, false);
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
}
@@ -1419,6 +1551,7 @@
drop_inmem_pages(inode);
if (f2fs_is_volatile_file(inode)) {
clear_inode_flag(inode, FI_VOLATILE_FILE);
+ stat_dec_volatile_write(inode);
set_inode_flag(inode, FI_DROP_CACHE);
filemap_fdatawrite(inode->i_mapping);
clear_inode_flag(inode, FI_DROP_CACHE);
@@ -1426,17 +1559,20 @@
return 0;
}
-#define F2FS_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
-#define F2FS_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL)
-
-static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags)
+static int f2fs_file_flush(struct file *file, fl_owner_t id)
{
- if (S_ISDIR(mode))
- return flags;
- else if (S_ISREG(mode))
- return flags & F2FS_REG_FLMASK;
- else
- return flags & F2FS_OTHER_FLMASK;
+ struct inode *inode = file_inode(file);
+
+ /*
+ * If the process doing a transaction is crashed, we should do
+ * roll-back. Otherwise, other reader/write can see corrupted database
+ * until all the writers close its file. Since this should be done
+ * before dropping file lock, it needs to do in ->flush.
+ */
+ if (f2fs_is_atomic_file(inode) &&
+ F2FS_I(inode)->inmem_task == current)
+ drop_inmem_pages(inode);
+ return 0;
}
static int f2fs_ioc_getflags(struct file *filp, unsigned long arg)
@@ -1465,28 +1601,34 @@
if (ret)
return ret;
- flags = f2fs_mask_flags(inode->i_mode, flags);
-
inode_lock(inode);
+ /* Is it quota file? Do not allow user to mess with it */
+ if (IS_NOQUOTA(inode)) {
+ ret = -EPERM;
+ goto unlock_out;
+ }
+
+ flags = f2fs_mask_flags(inode->i_mode, flags);
+
oldflags = fi->i_flags;
if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
if (!capable(CAP_LINUX_IMMUTABLE)) {
- inode_unlock(inode);
ret = -EPERM;
- goto out;
+ goto unlock_out;
}
}
flags = flags & FS_FL_USER_MODIFIABLE;
flags |= oldflags & ~FS_FL_USER_MODIFIABLE;
fi->i_flags = flags;
- inode_unlock(inode);
inode->i_ctime = current_time(inode);
f2fs_set_inode_flags(inode);
-out:
+ f2fs_mark_inode_dirty_sync(inode, false);
+unlock_out:
+ inode_unlock(inode);
mnt_drop_write_file(filp);
return ret;
}
@@ -1506,6 +1648,9 @@
if (!inode_owner_or_capable(inode))
return -EACCES;
+ if (!S_ISREG(inode->i_mode))
+ return -EINVAL;
+
ret = mnt_want_write_file(filp);
if (ret)
return ret;
@@ -1520,17 +1665,26 @@
goto out;
set_inode_flag(inode, FI_ATOMIC_FILE);
+ set_inode_flag(inode, FI_HOT_DATA);
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
if (!get_dirty_pages(inode))
- goto out;
+ goto inc_stat;
f2fs_msg(F2FS_I_SB(inode)->sb, KERN_WARNING,
"Unexpected flush for atomic writes: ino=%lu, npages=%u",
inode->i_ino, get_dirty_pages(inode));
ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
- if (ret)
+ if (ret) {
clear_inode_flag(inode, FI_ATOMIC_FILE);
+ clear_inode_flag(inode, FI_HOT_DATA);
+ goto out;
+ }
+
+inc_stat:
+ F2FS_I(inode)->inmem_task = current;
+ stat_inc_atomic_write(inode);
+ stat_update_max_atomic_write(inode);
out:
inode_unlock(inode);
mnt_drop_write_file(filp);
@@ -1555,15 +1709,19 @@
goto err_out;
if (f2fs_is_atomic_file(inode)) {
- clear_inode_flag(inode, FI_ATOMIC_FILE);
ret = commit_inmem_pages(inode);
- if (ret) {
- set_inode_flag(inode, FI_ATOMIC_FILE);
+ if (ret)
goto err_out;
- }
- }
- ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
+ ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
+ if (!ret) {
+ clear_inode_flag(inode, FI_ATOMIC_FILE);
+ clear_inode_flag(inode, FI_HOT_DATA);
+ stat_dec_atomic_write(inode);
+ }
+ } else {
+ ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false);
+ }
err_out:
inode_unlock(inode);
mnt_drop_write_file(filp);
@@ -1578,6 +1736,9 @@
if (!inode_owner_or_capable(inode))
return -EACCES;
+ if (!S_ISREG(inode->i_mode))
+ return -EINVAL;
+
ret = mnt_want_write_file(filp);
if (ret)
return ret;
@@ -1591,6 +1752,9 @@
if (ret)
goto out;
+ stat_inc_volatile_write(inode);
+ stat_update_max_volatile_write(inode);
+
set_inode_flag(inode, FI_VOLATILE_FILE);
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
out:
@@ -1646,6 +1810,7 @@
drop_inmem_pages(inode);
if (f2fs_is_volatile_file(inode)) {
clear_inode_flag(inode, FI_VOLATILE_FILE);
+ stat_dec_volatile_write(inode);
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
}
@@ -1677,27 +1842,40 @@
switch (in) {
case F2FS_GOING_DOWN_FULLSYNC:
sb = freeze_bdev(sb->s_bdev);
- if (sb && !IS_ERR(sb)) {
+ if (IS_ERR(sb)) {
+ ret = PTR_ERR(sb);
+ goto out;
+ }
+ if (sb) {
f2fs_stop_checkpoint(sbi, false);
thaw_bdev(sb->s_bdev, sb);
}
break;
case F2FS_GOING_DOWN_METASYNC:
/* do checkpoint only */
- f2fs_sync_fs(sb, 1);
+ ret = f2fs_sync_fs(sb, 1);
+ if (ret)
+ goto out;
f2fs_stop_checkpoint(sbi, false);
break;
case F2FS_GOING_DOWN_NOSYNC:
f2fs_stop_checkpoint(sbi, false);
break;
case F2FS_GOING_DOWN_METAFLUSH:
- sync_meta_pages(sbi, META, LONG_MAX);
+ sync_meta_pages(sbi, META, LONG_MAX, FS_META_IO);
f2fs_stop_checkpoint(sbi, false);
break;
default:
ret = -EINVAL;
goto out;
}
+
+ stop_gc_thread(sbi);
+ stop_discard_thread(sbi);
+
+ drop_discard_cmd(sbi);
+ clear_opt(sbi, DISCARD);
+
f2fs_update_time(sbi, REQ_TIME);
out:
mnt_drop_write_file(filp);
@@ -1752,31 +1930,21 @@
static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg)
{
- struct fscrypt_policy policy;
struct inode *inode = file_inode(filp);
- if (copy_from_user(&policy, (struct fscrypt_policy __user *)arg,
- sizeof(policy)))
- return -EFAULT;
+ if (!f2fs_sb_has_crypto(inode->i_sb))
+ return -EOPNOTSUPP;
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
- return fscrypt_process_policy(filp, &policy);
+ return fscrypt_ioctl_set_policy(filp, (const void __user *)arg);
}
static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)
{
- struct fscrypt_policy policy;
- struct inode *inode = file_inode(filp);
- int err;
-
- err = fscrypt_get_policy(inode, &policy);
- if (err)
- return err;
-
- if (copy_to_user((struct fscrypt_policy __user *)arg, &policy, sizeof(policy)))
- return -EFAULT;
- return 0;
+ if (!f2fs_sb_has_crypto(file_inode(filp)->i_sb))
+ return -EOPNOTSUPP;
+ return fscrypt_ioctl_get_policy(filp, (void __user *)arg);
}
static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg)
@@ -1842,7 +2010,51 @@
mutex_lock(&sbi->gc_mutex);
}
- ret = f2fs_gc(sbi, sync);
+ ret = f2fs_gc(sbi, sync, true, NULL_SEGNO);
+out:
+ mnt_drop_write_file(filp);
+ return ret;
+}
+
+static int f2fs_ioc_gc_range(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct f2fs_gc_range range;
+ u64 end;
+ int ret;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&range, (struct f2fs_gc_range __user *)arg,
+ sizeof(range)))
+ return -EFAULT;
+
+ if (f2fs_readonly(sbi->sb))
+ return -EROFS;
+
+ ret = mnt_want_write_file(filp);
+ if (ret)
+ return ret;
+
+ end = range.start + range.len;
+ if (range.start < MAIN_BLKADDR(sbi) || end >= MAX_BLKADDR(sbi))
+ return -EINVAL;
+do_more:
+ if (!range.sync) {
+ if (!mutex_trylock(&sbi->gc_mutex)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ } else {
+ mutex_lock(&sbi->gc_mutex);
+ }
+
+ ret = f2fs_gc(sbi, range.sync, true, GET_SEGNO(sbi, range.start));
+ range.start += sbi->blocks_per_seg;
+ if (range.start <= end)
+ goto do_more;
out:
mnt_drop_write_file(filp);
return ret;
@@ -1875,18 +2087,18 @@
struct f2fs_defragment *range)
{
struct inode *inode = file_inode(filp);
- struct f2fs_map_blocks map = { .m_next_pgofs = NULL };
- struct extent_info ei;
- pgoff_t pg_start, pg_end;
+ struct f2fs_map_blocks map = { .m_next_extent = NULL,
+ .m_seg_type = NO_CHECK_TYPE };
+ struct extent_info ei = {0,0,0};
+ pgoff_t pg_start, pg_end, next_pgofs;
unsigned int blk_per_seg = sbi->blocks_per_seg;
unsigned int total = 0, sec_num;
- unsigned int pages_per_sec = sbi->segs_per_sec * blk_per_seg;
block_t blk_end = 0;
bool fragmented = false;
int err;
/* if in-place-update policy is enabled, don't waste time here */
- if (need_inplace_update(inode))
+ if (should_update_inplace(inode, NULL))
return -EINVAL;
pg_start = range->start >> PAGE_SHIFT;
@@ -1912,6 +2124,7 @@
}
map.m_lblk = pg_start;
+ map.m_next_pgofs = &next_pgofs;
/*
* lookup mapping info in dnode page cache, skip defragmenting if all
@@ -1920,19 +2133,21 @@
*/
while (map.m_lblk < pg_end) {
map.m_len = pg_end - map.m_lblk;
- err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_READ);
+ err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT);
if (err)
goto out;
if (!(map.m_flags & F2FS_MAP_FLAGS)) {
- map.m_lblk++;
+ map.m_lblk = next_pgofs;
continue;
}
- if (blk_end && blk_end != map.m_pblk) {
+ if (blk_end && blk_end != map.m_pblk)
fragmented = true;
- break;
- }
+
+ /* record total count of block that we're going to move */
+ total += map.m_len;
+
blk_end = map.m_pblk + map.m_len;
map.m_lblk += map.m_len;
@@ -1941,10 +2156,7 @@
if (!fragmented)
goto out;
- map.m_lblk = pg_start;
- map.m_len = pg_end - pg_start;
-
- sec_num = (map.m_len + pages_per_sec - 1) / pages_per_sec;
+ sec_num = (total + BLKS_PER_SEC(sbi) - 1) / BLKS_PER_SEC(sbi);
/*
* make sure there are enough free section for LFS allocation, this can
@@ -1956,18 +2168,22 @@
goto out;
}
+ map.m_lblk = pg_start;
+ map.m_len = pg_end - pg_start;
+ total = 0;
+
while (map.m_lblk < pg_end) {
pgoff_t idx;
int cnt = 0;
do_map:
map.m_len = pg_end - map.m_lblk;
- err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_READ);
+ err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT);
if (err)
goto clear_out;
if (!(map.m_flags & F2FS_MAP_FLAGS)) {
- map.m_lblk++;
+ map.m_lblk = next_pgofs;
continue;
}
@@ -2021,42 +2237,40 @@
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (!S_ISREG(inode->i_mode))
+ if (!S_ISREG(inode->i_mode) || f2fs_is_atomic_file(inode))
+ return -EINVAL;
+
+ if (f2fs_readonly(sbi->sb))
+ return -EROFS;
+
+ if (copy_from_user(&range, (struct f2fs_defragment __user *)arg,
+ sizeof(range)))
+ return -EFAULT;
+
+ /* verify alignment of offset & size */
+ if (range.start & (F2FS_BLKSIZE - 1) || range.len & (F2FS_BLKSIZE - 1))
+ return -EINVAL;
+
+ if (unlikely((range.start + range.len) >> PAGE_SHIFT >
+ sbi->max_file_blocks))
return -EINVAL;
err = mnt_want_write_file(filp);
if (err)
return err;
- if (f2fs_readonly(sbi->sb)) {
- err = -EROFS;
- goto out;
- }
-
- if (copy_from_user(&range, (struct f2fs_defragment __user *)arg,
- sizeof(range))) {
- err = -EFAULT;
- goto out;
- }
-
- /* verify alignment of offset & size */
- if (range.start & (F2FS_BLKSIZE - 1) ||
- range.len & (F2FS_BLKSIZE - 1)) {
- err = -EINVAL;
- goto out;
- }
-
err = f2fs_defragment_range(sbi, filp, &range);
+ mnt_drop_write_file(filp);
+
f2fs_update_time(sbi, REQ_TIME);
if (err < 0)
- goto out;
+ return err;
if (copy_to_user((struct f2fs_defragment __user *)arg, &range,
sizeof(range)))
- err = -EFAULT;
-out:
- mnt_drop_write_file(filp);
- return err;
+ return -EFAULT;
+
+ return 0;
}
static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
@@ -2090,9 +2304,13 @@
}
inode_lock(src);
+ down_write(&F2FS_I(src)->dio_rwsem[WRITE]);
if (src != dst) {
- if (!inode_trylock(dst)) {
- ret = -EBUSY;
+ ret = -EBUSY;
+ if (!inode_trylock(dst))
+ goto out;
+ if (!down_write_trylock(&F2FS_I(dst)->dio_rwsem[WRITE])) {
+ inode_unlock(dst);
goto out;
}
}
@@ -2152,9 +2370,12 @@
}
f2fs_unlock_op(sbi);
out_unlock:
- if (src != dst)
+ if (src != dst) {
+ up_write(&F2FS_I(dst)->dio_rwsem[WRITE]);
inode_unlock(dst);
+ }
out:
+ up_write(&F2FS_I(src)->dio_rwsem[WRITE]);
inode_unlock(src);
return ret;
}
@@ -2190,6 +2411,8 @@
range.pos_out, range.len);
mnt_drop_write_file(filp);
+ if (err)
+ goto err_out;
if (copy_to_user((struct f2fs_move_range __user *)arg,
&range, sizeof(range)))
@@ -2199,8 +2422,203 @@
return err;
}
+static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct sit_info *sm = SIT_I(sbi);
+ unsigned int start_segno = 0, end_segno = 0;
+ unsigned int dev_start_segno = 0, dev_end_segno = 0;
+ struct f2fs_flush_device range;
+ int ret;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (f2fs_readonly(sbi->sb))
+ return -EROFS;
+
+ if (copy_from_user(&range, (struct f2fs_flush_device __user *)arg,
+ sizeof(range)))
+ return -EFAULT;
+
+ if (sbi->s_ndevs <= 1 || sbi->s_ndevs - 1 <= range.dev_num ||
+ sbi->segs_per_sec != 1) {
+ f2fs_msg(sbi->sb, KERN_WARNING,
+ "Can't flush %u in %d for segs_per_sec %u != 1\n",
+ range.dev_num, sbi->s_ndevs,
+ sbi->segs_per_sec);
+ return -EINVAL;
+ }
+
+ ret = mnt_want_write_file(filp);
+ if (ret)
+ return ret;
+
+ if (range.dev_num != 0)
+ dev_start_segno = GET_SEGNO(sbi, FDEV(range.dev_num).start_blk);
+ dev_end_segno = GET_SEGNO(sbi, FDEV(range.dev_num).end_blk);
+
+ start_segno = sm->last_victim[FLUSH_DEVICE];
+ if (start_segno < dev_start_segno || start_segno >= dev_end_segno)
+ start_segno = dev_start_segno;
+ end_segno = min(start_segno + range.segments, dev_end_segno);
+
+ while (start_segno < end_segno) {
+ if (!mutex_trylock(&sbi->gc_mutex)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ sm->last_victim[GC_CB] = end_segno + 1;
+ sm->last_victim[GC_GREEDY] = end_segno + 1;
+ sm->last_victim[ALLOC_NEXT] = end_segno + 1;
+ ret = f2fs_gc(sbi, true, true, start_segno);
+ if (ret == -EAGAIN)
+ ret = 0;
+ else if (ret < 0)
+ break;
+ start_segno++;
+ }
+out:
+ mnt_drop_write_file(filp);
+ return ret;
+}
+
+static int f2fs_ioc_get_features(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ u32 sb_feature = le32_to_cpu(F2FS_I_SB(inode)->raw_super->feature);
+
+ /* Must validate to set it with SQLite behavior in Android. */
+ sb_feature |= F2FS_FEATURE_ATOMIC_WRITE;
+
+ return put_user(sb_feature, (u32 __user *)arg);
+}
+
+int f2fs_pin_file_control(struct inode *inode, bool inc)
+{
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+ /* Use i_gc_failures for normal file as a risk signal. */
+ if (inc)
+ f2fs_i_gc_failures_write(inode, fi->i_gc_failures + 1);
+
+ if (fi->i_gc_failures > sbi->gc_pin_file_threshold) {
+ f2fs_msg(sbi->sb, KERN_WARNING,
+ "%s: Enable GC = ino %lx after %x GC trials\n",
+ __func__, inode->i_ino, fi->i_gc_failures);
+ clear_inode_flag(inode, FI_PIN_FILE);
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ __u32 pin;
+ int ret = 0;
+
+ if (!inode_owner_or_capable(inode))
+ return -EACCES;
+
+ if (get_user(pin, (__u32 __user *)arg))
+ return -EFAULT;
+
+ if (!S_ISREG(inode->i_mode))
+ return -EINVAL;
+
+ if (f2fs_readonly(F2FS_I_SB(inode)->sb))
+ return -EROFS;
+
+ ret = mnt_want_write_file(filp);
+ if (ret)
+ return ret;
+
+ inode_lock(inode);
+
+ if (should_update_outplace(inode, NULL)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!pin) {
+ clear_inode_flag(inode, FI_PIN_FILE);
+ F2FS_I(inode)->i_gc_failures = 1;
+ goto done;
+ }
+
+ if (f2fs_pin_file_control(inode, false)) {
+ ret = -EAGAIN;
+ goto out;
+ }
+ ret = f2fs_convert_inline_inode(inode);
+ if (ret)
+ goto out;
+
+ set_inode_flag(inode, FI_PIN_FILE);
+ ret = F2FS_I(inode)->i_gc_failures;
+done:
+ f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
+out:
+ inode_unlock(inode);
+ mnt_drop_write_file(filp);
+ return ret;
+}
+
+static int f2fs_ioc_get_pin_file(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ __u32 pin = 0;
+
+ if (is_inode_flag_set(inode, FI_PIN_FILE))
+ pin = F2FS_I(inode)->i_gc_failures;
+ return put_user(pin, (u32 __user *)arg);
+}
+
+int f2fs_precache_extents(struct inode *inode)
+{
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ struct f2fs_map_blocks map;
+ pgoff_t m_next_extent;
+ loff_t end;
+ int err;
+
+ if (is_inode_flag_set(inode, FI_NO_EXTENT))
+ return -EOPNOTSUPP;
+
+ map.m_lblk = 0;
+ map.m_next_pgofs = NULL;
+ map.m_next_extent = &m_next_extent;
+ map.m_seg_type = NO_CHECK_TYPE;
+ end = F2FS_I_SB(inode)->max_file_blocks;
+
+ while (map.m_lblk < end) {
+ map.m_len = end - map.m_lblk;
+
+ down_write(&fi->dio_rwsem[WRITE]);
+ err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_PRECACHE);
+ up_write(&fi->dio_rwsem[WRITE]);
+ if (err)
+ return err;
+
+ map.m_lblk = m_next_extent;
+ }
+
+ return err;
+}
+
+static int f2fs_ioc_precache_extents(struct file *filp, unsigned long arg)
+{
+ return f2fs_precache_extents(file_inode(filp));
+}
+
long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
+ if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp)))))
+ return -EIO;
+
switch (cmd) {
case F2FS_IOC_GETFLAGS:
return f2fs_ioc_getflags(filp, arg);
@@ -2230,12 +2648,24 @@
return f2fs_ioc_get_encryption_pwsalt(filp, arg);
case F2FS_IOC_GARBAGE_COLLECT:
return f2fs_ioc_gc(filp, arg);
+ case F2FS_IOC_GARBAGE_COLLECT_RANGE:
+ return f2fs_ioc_gc_range(filp, arg);
case F2FS_IOC_WRITE_CHECKPOINT:
return f2fs_ioc_write_checkpoint(filp, arg);
case F2FS_IOC_DEFRAGMENT:
return f2fs_ioc_defragment(filp, arg);
case F2FS_IOC_MOVE_RANGE:
return f2fs_ioc_move_range(filp, arg);
+ case F2FS_IOC_FLUSH_DEVICE:
+ return f2fs_ioc_flush_device(filp, arg);
+ case F2FS_IOC_GET_FEATURES:
+ return f2fs_ioc_get_features(filp, arg);
+ case F2FS_IOC_GET_PIN_FILE:
+ return f2fs_ioc_get_pin_file(filp, arg);
+ case F2FS_IOC_SET_PIN_FILE:
+ return f2fs_ioc_set_pin_file(filp, arg);
+ case F2FS_IOC_PRECACHE_EXTENTS:
+ return f2fs_ioc_precache_extents(filp, arg);
default:
return -ENOTTY;
}
@@ -2248,20 +2678,30 @@
struct blk_plug plug;
ssize_t ret;
- if (f2fs_encrypted_inode(inode) &&
- !fscrypt_has_encryption_key(inode) &&
- fscrypt_get_encryption_info(inode))
- return -EACCES;
+ if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
+ return -EIO;
inode_lock(inode);
ret = generic_write_checks(iocb, from);
if (ret > 0) {
- ret = f2fs_preallocate_blocks(iocb, from);
- if (!ret) {
- blk_start_plug(&plug);
- ret = __generic_file_write_iter(iocb, from);
- blk_finish_plug(&plug);
+ int err;
+
+ if (iov_iter_fault_in_readable(from, iov_iter_count(from)))
+ set_inode_flag(inode, FI_NO_PREALLOC);
+
+ err = f2fs_preallocate_blocks(iocb, from);
+ if (err) {
+ clear_inode_flag(inode, FI_NO_PREALLOC);
+ inode_unlock(inode);
+ return err;
}
+ blk_start_plug(&plug);
+ ret = __generic_file_write_iter(iocb, from);
+ blk_finish_plug(&plug);
+ clear_inode_flag(inode, FI_NO_PREALLOC);
+
+ if (ret > 0)
+ f2fs_update_iostat(F2FS_I_SB(inode), APP_WRITE_IO, ret);
}
inode_unlock(inode);
@@ -2293,10 +2733,15 @@
case F2FS_IOC_GET_ENCRYPTION_PWSALT:
case F2FS_IOC_GET_ENCRYPTION_POLICY:
case F2FS_IOC_GARBAGE_COLLECT:
+ case F2FS_IOC_GARBAGE_COLLECT_RANGE:
case F2FS_IOC_WRITE_CHECKPOINT:
case F2FS_IOC_DEFRAGMENT:
- break;
case F2FS_IOC_MOVE_RANGE:
+ case F2FS_IOC_FLUSH_DEVICE:
+ case F2FS_IOC_GET_FEATURES:
+ case F2FS_IOC_GET_PIN_FILE:
+ case F2FS_IOC_SET_PIN_FILE:
+ case F2FS_IOC_PRECACHE_EXTENTS:
break;
default:
return -ENOIOCTLCMD;
@@ -2312,6 +2757,7 @@
.open = f2fs_file_open,
.release = f2fs_release_file,
.mmap = f2fs_file_mmap,
+ .flush = f2fs_file_flush,
.fsync = f2fs_sync_file,
.fallocate = f2fs_fallocate,
.unlocked_ioctl = f2fs_ioctl,
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 34a69e7..3b26aa1 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -28,17 +28,23 @@
struct f2fs_sb_info *sbi = data;
struct f2fs_gc_kthread *gc_th = sbi->gc_thread;
wait_queue_head_t *wq = &sbi->gc_thread->gc_wait_queue_head;
- long wait_ms;
+ unsigned int wait_ms;
wait_ms = gc_th->min_sleep_time;
+ set_freezable();
do {
+ wait_event_interruptible_timeout(*wq,
+ kthread_should_stop() || freezing(current) ||
+ gc_th->gc_wake,
+ msecs_to_jiffies(wait_ms));
+
+ /* give it a try one time */
+ if (gc_th->gc_wake)
+ gc_th->gc_wake = 0;
+
if (try_to_freeze())
continue;
- else
- wait_event_interruptible_timeout(*wq,
- kthread_should_stop(),
- msecs_to_jiffies(wait_ms));
if (kthread_should_stop())
break;
@@ -48,10 +54,15 @@
}
#ifdef CONFIG_F2FS_FAULT_INJECTION
- if (time_to_inject(sbi, FAULT_CHECKPOINT))
+ if (time_to_inject(sbi, FAULT_CHECKPOINT)) {
+ f2fs_show_injection_info(FAULT_CHECKPOINT);
f2fs_stop_checkpoint(sbi, false);
+ }
#endif
+ if (!sb_start_write_trylock(sbi->sb))
+ continue;
+
/*
* [GC triggering condition]
* 0. GC is not conducted currently.
@@ -66,23 +77,28 @@
* So, I'd like to wait some time to collect dirty segments.
*/
if (!mutex_trylock(&sbi->gc_mutex))
- continue;
+ goto next;
+
+ if (gc_th->gc_urgent) {
+ wait_ms = gc_th->urgent_sleep_time;
+ goto do_gc;
+ }
if (!is_idle(sbi)) {
increase_sleep_time(gc_th, &wait_ms);
mutex_unlock(&sbi->gc_mutex);
- continue;
+ goto next;
}
if (has_enough_invalid_blocks(sbi))
decrease_sleep_time(gc_th, &wait_ms);
else
increase_sleep_time(gc_th, &wait_ms);
-
+do_gc:
stat_inc_bggc_count(sbi);
/* if return value is not zero, no victim was selected */
- if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC)))
+ if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true, NULL_SEGNO))
wait_ms = gc_th->no_gc_sleep_time;
trace_f2fs_background_gc(sbi->sb, wait_ms,
@@ -90,6 +106,8 @@
/* balancing f2fs's metadata periodically */
f2fs_balance_fs_bg(sbi);
+next:
+ sb_end_write(sbi->sb);
} while (!kthread_should_stop());
return 0;
@@ -107,11 +125,14 @@
goto out;
}
+ gc_th->urgent_sleep_time = DEF_GC_THREAD_URGENT_SLEEP_TIME;
gc_th->min_sleep_time = DEF_GC_THREAD_MIN_SLEEP_TIME;
gc_th->max_sleep_time = DEF_GC_THREAD_MAX_SLEEP_TIME;
gc_th->no_gc_sleep_time = DEF_GC_THREAD_NOGC_SLEEP_TIME;
gc_th->gc_idle = 0;
+ gc_th->gc_urgent = 0;
+ gc_th->gc_wake= 0;
sbi->gc_thread = gc_th;
init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head);
@@ -170,7 +191,11 @@
if (gc_type != FG_GC && p->max_search > sbi->max_victim_search)
p->max_search = sbi->max_victim_search;
- p->offset = sbi->last_victim[p->gc_mode];
+ /* let's select beginning hot/small space first */
+ if (type == CURSEG_HOT_DATA || IS_NODESEG(type))
+ p->offset = 0;
+ else
+ p->offset = SIT_I(sbi)->last_victim[p->gc_mode];
}
static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
@@ -180,7 +205,7 @@
if (p->alloc_mode == SSR)
return sbi->blocks_per_seg;
if (p->gc_mode == GC_GREEDY)
- return sbi->blocks_per_seg * p->ofs_unit;
+ return 2 * sbi->blocks_per_seg * p->ofs_unit;
else if (p->gc_mode == GC_CB)
return UINT_MAX;
else /* No other gc_mode */
@@ -205,7 +230,7 @@
continue;
clear_bit(secno, dirty_i->victim_secmap);
- return secno * sbi->segs_per_sec;
+ return GET_SEG_FROM_SEC(sbi, secno);
}
return NULL_SEGNO;
}
@@ -213,8 +238,8 @@
static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno)
{
struct sit_info *sit_i = SIT_I(sbi);
- unsigned int secno = GET_SECNO(sbi, segno);
- unsigned int start = secno * sbi->segs_per_sec;
+ unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
+ unsigned int start = GET_SEG_FROM_SEC(sbi, secno);
unsigned long long mtime = 0;
unsigned int vblocks;
unsigned char age = 0;
@@ -223,7 +248,7 @@
for (i = 0; i < sbi->segs_per_sec; i++)
mtime += get_seg_entry(sbi, start + i)->mtime;
- vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec);
+ vblocks = get_valid_blocks(sbi, segno, true);
mtime = div_u64(mtime, sbi->segs_per_sec);
vblocks = div_u64(vblocks, sbi->segs_per_sec);
@@ -250,7 +275,7 @@
/* alloc_mode == LFS */
if (p->gc_mode == GC_GREEDY)
- return get_valid_blocks(sbi, segno, sbi->segs_per_sec);
+ return get_valid_blocks(sbi, segno, true);
else
return get_cb_cost(sbi, segno);
}
@@ -279,6 +304,7 @@
unsigned int *result, int gc_type, int type, char alloc_mode)
{
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+ struct sit_info *sm = SIT_I(sbi);
struct victim_sel_policy p;
unsigned int secno, last_victim;
unsigned int last_segment = MAIN_SEGS(sbi);
@@ -292,10 +318,18 @@
p.min_segno = NULL_SEGNO;
p.min_cost = get_max_cost(sbi, &p);
+ if (*result != NULL_SEGNO) {
+ if (IS_DATASEG(get_seg_entry(sbi, *result)->type) &&
+ get_valid_blocks(sbi, *result, false) &&
+ !sec_usage_check(sbi, GET_SEC_FROM_SEG(sbi, *result)))
+ p.min_segno = *result;
+ goto out;
+ }
+
if (p.max_search == 0)
goto out;
- last_victim = sbi->last_victim[p.gc_mode];
+ last_victim = sm->last_victim[p.gc_mode];
if (p.alloc_mode == LFS && gc_type == FG_GC) {
p.min_segno = check_bg_victims(sbi);
if (p.min_segno != NULL_SEGNO)
@@ -308,9 +342,10 @@
segno = find_next_bit(p.dirty_segmap, last_segment, p.offset);
if (segno >= last_segment) {
- if (sbi->last_victim[p.gc_mode]) {
- last_segment = sbi->last_victim[p.gc_mode];
- sbi->last_victim[p.gc_mode] = 0;
+ if (sm->last_victim[p.gc_mode]) {
+ last_segment =
+ sm->last_victim[p.gc_mode];
+ sm->last_victim[p.gc_mode] = 0;
p.offset = 0;
continue;
}
@@ -327,7 +362,7 @@
nsearched++;
}
- secno = GET_SECNO(sbi, segno);
+ secno = GET_SEC_FROM_SEG(sbi, segno);
if (sec_usage_check(sbi, secno))
goto next;
@@ -345,17 +380,18 @@
}
next:
if (nsearched >= p.max_search) {
- if (!sbi->last_victim[p.gc_mode] && segno <= last_victim)
- sbi->last_victim[p.gc_mode] = last_victim + 1;
+ if (!sm->last_victim[p.gc_mode] && segno <= last_victim)
+ sm->last_victim[p.gc_mode] = last_victim + 1;
else
- sbi->last_victim[p.gc_mode] = segno + 1;
+ sm->last_victim[p.gc_mode] = segno + 1;
+ sm->last_victim[p.gc_mode] %= MAIN_SEGS(sbi);
break;
}
}
if (p.min_segno != NULL_SEGNO) {
got_it:
if (p.alloc_mode == LFS) {
- secno = GET_SECNO(sbi, p.min_segno);
+ secno = GET_SEC_FROM_SEG(sbi, p.min_segno);
if (gc_type == FG_GC)
sbi->cur_victim_sec = secno;
else
@@ -420,10 +456,10 @@
struct seg_entry *sentry;
int ret;
- mutex_lock(&sit_i->sentry_lock);
+ down_read(&sit_i->sentry_lock);
sentry = get_seg_entry(sbi, segno);
ret = f2fs_test_bit(offset, sentry->cur_valid_map);
- mutex_unlock(&sit_i->sentry_lock);
+ up_read(&sit_i->sentry_lock);
return ret;
}
@@ -538,12 +574,14 @@
get_node_info(sbi, nid, dni);
if (sum->version != dni->version) {
- f2fs_put_page(node_page, 1);
- return false;
+ f2fs_msg(sbi->sb, KERN_WARNING,
+ "%s: valid data with mismatched node version.",
+ __func__);
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
}
*nofs = ofs_of_node(node_page);
- source_blkaddr = datablock_addr(node_page, ofs_in_node);
+ source_blkaddr = datablock_addr(NULL, node_page, ofs_in_node);
f2fs_put_page(node_page, 1);
if (source_blkaddr != blkaddr)
@@ -551,14 +589,22 @@
return true;
}
-static void move_encrypted_block(struct inode *inode, block_t bidx)
+/*
+ * Move data block via META_MAPPING while keeping locked data page.
+ * This can be used to move blocks, aka LBAs, directly on disk.
+ */
+static void move_data_block(struct inode *inode, block_t bidx,
+ unsigned int segno, int off)
{
struct f2fs_io_info fio = {
.sbi = F2FS_I_SB(inode),
+ .ino = inode->i_ino,
.type = DATA,
+ .temp = COLD,
.op = REQ_OP_READ,
- .op_flags = READ_SYNC,
+ .op_flags = 0,
.encrypted_page = NULL,
+ .in_list = false,
};
struct dnode_of_data dn;
struct f2fs_summary sum;
@@ -572,6 +618,17 @@
if (!page)
return;
+ if (!check_valid_map(F2FS_I_SB(inode), segno, off))
+ goto out;
+
+ if (f2fs_is_atomic_file(inode))
+ goto out;
+
+ if (f2fs_is_pinned_file(inode)) {
+ f2fs_pin_file_control(inode, true);
+ goto out;
+ }
+
set_new_dnode(&dn, inode, NULL, NULL, 0);
err = get_dnode_of_data(&dn, bidx, LOOKUP_NODE);
if (err)
@@ -596,10 +653,10 @@
fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr;
allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
- &sum, CURSEG_COLD_DATA);
+ &sum, CURSEG_COLD_DATA, NULL, false);
- fio.encrypted_page = pagecache_get_page(META_MAPPING(fio.sbi), newaddr,
- FGP_LOCK | FGP_CREAT, GFP_NOFS);
+ fio.encrypted_page = f2fs_pagecache_get_page(META_MAPPING(fio.sbi),
+ newaddr, FGP_LOCK | FGP_CREAT, GFP_NOFS);
if (!fio.encrypted_page) {
err = -ENOMEM;
goto recover_block;
@@ -632,9 +689,16 @@
f2fs_wait_on_page_writeback(dn.node_page, NODE, true);
fio.op = REQ_OP_WRITE;
- fio.op_flags = WRITE_SYNC;
+ fio.op_flags = REQ_SYNC;
fio.new_blkaddr = newaddr;
- f2fs_submit_page_mbio(&fio);
+ err = f2fs_submit_page_write(&fio);
+ if (err) {
+ if (PageWriteback(fio.encrypted_page))
+ end_page_writeback(fio.encrypted_page);
+ goto put_page_out;
+ }
+
+ f2fs_update_iostat(fio.sbi, FS_GC_DATA_IO, F2FS_BLKSIZE);
f2fs_update_data_blkaddr(&dn, newaddr);
set_inode_flag(inode, FI_APPEND_WRITE);
@@ -652,7 +716,8 @@
f2fs_put_page(page, 1);
}
-static void move_data_page(struct inode *inode, block_t bidx, int gc_type)
+static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
+ unsigned int segno, int off)
{
struct page *page;
@@ -660,6 +725,17 @@
if (IS_ERR(page))
return;
+ if (!check_valid_map(F2FS_I_SB(inode), segno, off))
+ goto out;
+
+ if (f2fs_is_atomic_file(inode))
+ goto out;
+ if (f2fs_is_pinned_file(inode)) {
+ if (gc_type == FG_GC)
+ f2fs_pin_file_control(inode, true);
+ goto out;
+ }
+
if (gc_type == BG_GC) {
if (PageWriteback(page))
goto out;
@@ -668,11 +744,16 @@
} else {
struct f2fs_io_info fio = {
.sbi = F2FS_I_SB(inode),
+ .ino = inode->i_ino,
.type = DATA,
+ .temp = COLD,
.op = REQ_OP_WRITE,
- .op_flags = WRITE_SYNC,
+ .op_flags = REQ_SYNC,
+ .old_blkaddr = NULL_ADDR,
.page = page,
.encrypted_page = NULL,
+ .need_lock = LOCK_REQ,
+ .io_type = FS_GC_DATA_IO,
};
bool is_dirty = PageDirty(page);
int err;
@@ -680,8 +761,10 @@
retry:
set_page_dirty(page);
f2fs_wait_on_page_writeback(page, DATA, true);
- if (clear_page_dirty_for_io(page))
+ if (clear_page_dirty_for_io(page)) {
inode_dec_dirty_pages(inode);
+ remove_dirty_inode(inode);
+ }
set_cold_data(page);
@@ -690,8 +773,6 @@
congestion_wait(BLK_RW_ASYNC, HZ/50);
goto retry;
}
-
- clear_cold_data(page);
}
out:
f2fs_put_page(page, 1);
@@ -761,16 +842,22 @@
continue;
/* if encrypted inode, let's go phase 3 */
- if (f2fs_encrypted_inode(inode) &&
- S_ISREG(inode->i_mode)) {
+ if (f2fs_encrypted_file(inode)) {
add_gc_inode(gc_list, inode);
continue;
}
+ if (!down_write_trylock(
+ &F2FS_I(inode)->dio_rwsem[WRITE])) {
+ iput(inode);
+ continue;
+ }
+
start_bidx = start_bidx_of_node(nofs, inode);
data_page = get_read_data_page(inode,
start_bidx + ofs_in_node, REQ_RAHEAD,
true);
+ up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
if (IS_ERR(data_page)) {
iput(inode);
continue;
@@ -796,14 +883,18 @@
continue;
}
locked = true;
+
+ /* wait for all inflight aio data */
+ inode_dio_wait(inode);
}
start_bidx = start_bidx_of_node(nofs, inode)
+ ofs_in_node;
- if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
- move_encrypted_block(inode, start_bidx);
+ if (f2fs_encrypted_file(inode))
+ move_data_block(inode, start_bidx, segno, off);
else
- move_data_page(inode, start_bidx, gc_type);
+ move_data_page(inode, start_bidx, gc_type,
+ segno, off);
if (locked) {
up_write(&fi->dio_rwsem[WRITE]);
@@ -824,10 +915,10 @@
struct sit_info *sit_i = SIT_I(sbi);
int ret;
- mutex_lock(&sit_i->sentry_lock);
+ down_write(&sit_i->sentry_lock);
ret = DIRTY_I(sbi)->v_ops->get_victim(sbi, victim, gc_type,
NO_CHECK_TYPE, LFS);
- mutex_unlock(&sit_i->sentry_lock);
+ up_write(&sit_i->sentry_lock);
return ret;
}
@@ -840,7 +931,7 @@
struct blk_plug plug;
unsigned int segno = start_segno;
unsigned int end_segno = start_segno + sbi->segs_per_sec;
- int sec_freed = 0;
+ int seg_freed = 0;
unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ?
SUM_TYPE_DATA : SUM_TYPE_NODE;
@@ -864,7 +955,7 @@
GET_SUM_BLOCK(sbi, segno));
f2fs_put_page(sum_page, 0);
- if (get_valid_blocks(sbi, segno, 1) == 0 ||
+ if (get_valid_blocks(sbi, segno, false) == 0 ||
!PageUptodate(sum_page) ||
unlikely(f2fs_cp_error(sbi)))
goto next;
@@ -875,11 +966,10 @@
/*
* this is to avoid deadlock:
* - lock_page(sum_page) - f2fs_replace_block
- * - check_valid_map() - mutex_lock(sentry_lock)
- * - mutex_lock(sentry_lock) - change_curseg()
+ * - check_valid_map() - down_write(sentry_lock)
+ * - down_read(sentry_lock) - change_curseg()
* - lock_page(sum_page)
*/
-
if (type == SUM_TYPE_NODE)
gc_node_segment(sbi, sum->entries, segno, gc_type);
else
@@ -887,87 +977,113 @@
gc_type);
stat_inc_seg_count(sbi, type, gc_type);
+
+ if (gc_type == FG_GC &&
+ get_valid_blocks(sbi, segno, false) == 0)
+ seg_freed++;
next:
f2fs_put_page(sum_page, 0);
}
if (gc_type == FG_GC)
- f2fs_submit_merged_bio(sbi,
- (type == SUM_TYPE_NODE) ? NODE : DATA, WRITE);
+ f2fs_submit_merged_write(sbi,
+ (type == SUM_TYPE_NODE) ? NODE : DATA);
blk_finish_plug(&plug);
- if (gc_type == FG_GC &&
- get_valid_blocks(sbi, start_segno, sbi->segs_per_sec) == 0)
- sec_freed = 1;
-
stat_inc_call_count(sbi->stat_info);
- return sec_freed;
+ return seg_freed;
}
-int f2fs_gc(struct f2fs_sb_info *sbi, bool sync)
+int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
+ bool background, unsigned int segno)
{
- unsigned int segno;
int gc_type = sync ? FG_GC : BG_GC;
- int sec_freed = 0;
- int ret = -EINVAL;
+ int sec_freed = 0, seg_freed = 0, total_freed = 0;
+ int ret = 0;
struct cp_control cpc;
+ unsigned int init_segno = segno;
struct gc_inode_list gc_list = {
.ilist = LIST_HEAD_INIT(gc_list.ilist),
.iroot = RADIX_TREE_INIT(GFP_NOFS),
};
+ trace_f2fs_gc_begin(sbi->sb, sync, background,
+ get_pages(sbi, F2FS_DIRTY_NODES),
+ get_pages(sbi, F2FS_DIRTY_DENTS),
+ get_pages(sbi, F2FS_DIRTY_IMETA),
+ free_sections(sbi),
+ free_segments(sbi),
+ reserved_segments(sbi),
+ prefree_segments(sbi));
+
cpc.reason = __get_cp_reason(sbi);
gc_more:
- segno = NULL_SEGNO;
-
- if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE)))
+ if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE))) {
+ ret = -EINVAL;
goto stop;
+ }
if (unlikely(f2fs_cp_error(sbi))) {
ret = -EIO;
goto stop;
}
- if (gc_type == BG_GC && has_not_enough_free_secs(sbi, sec_freed, 0)) {
- gc_type = FG_GC;
+ if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0, 0)) {
/*
- * If there is no victim and no prefree segment but still not
- * enough free sections, we should flush dent/node blocks and do
- * garbage collections.
+ * For example, if there are many prefree_segments below given
+ * threshold, we can make them free by checkpoint. Then, we
+ * secure free segments which doesn't need fggc any more.
*/
- if (__get_victim(sbi, &segno, gc_type) ||
- prefree_segments(sbi)) {
- ret = write_checkpoint(sbi, &cpc);
- if (ret)
- goto stop;
- segno = NULL_SEGNO;
- } else if (has_not_enough_free_secs(sbi, 0, 0)) {
+ if (prefree_segments(sbi)) {
ret = write_checkpoint(sbi, &cpc);
if (ret)
goto stop;
}
+ if (has_not_enough_free_secs(sbi, 0, 0))
+ gc_type = FG_GC;
}
- if (segno == NULL_SEGNO && !__get_victim(sbi, &segno, gc_type))
+ /* f2fs_balance_fs doesn't need to do BG_GC in critical path. */
+ if (gc_type == BG_GC && !background) {
+ ret = -EINVAL;
goto stop;
- ret = 0;
+ }
+ if (!__get_victim(sbi, &segno, gc_type)) {
+ ret = -ENODATA;
+ goto stop;
+ }
- if (do_garbage_collect(sbi, segno, &gc_list, gc_type) &&
- gc_type == FG_GC)
+ seg_freed = do_garbage_collect(sbi, segno, &gc_list, gc_type);
+ if (gc_type == FG_GC && seg_freed == sbi->segs_per_sec)
sec_freed++;
+ total_freed += seg_freed;
if (gc_type == FG_GC)
sbi->cur_victim_sec = NULL_SEGNO;
if (!sync) {
- if (has_not_enough_free_secs(sbi, sec_freed, 0))
+ if (has_not_enough_free_secs(sbi, sec_freed, 0)) {
+ segno = NULL_SEGNO;
goto gc_more;
+ }
if (gc_type == FG_GC)
ret = write_checkpoint(sbi, &cpc);
}
stop:
+ SIT_I(sbi)->last_victim[ALLOC_NEXT] = 0;
+ SIT_I(sbi)->last_victim[FLUSH_DEVICE] = init_segno;
+
+ trace_f2fs_gc_end(sbi->sb, ret, total_freed, sec_freed,
+ get_pages(sbi, F2FS_DIRTY_NODES),
+ get_pages(sbi, F2FS_DIRTY_DENTS),
+ get_pages(sbi, F2FS_DIRTY_IMETA),
+ free_sections(sbi),
+ free_segments(sbi),
+ reserved_segments(sbi),
+ prefree_segments(sbi));
+
mutex_unlock(&sbi->gc_mutex);
put_gc_inode(&gc_list);
@@ -979,7 +1095,7 @@
void build_gc_manager(struct f2fs_sb_info *sbi)
{
- u64 main_count, resv_count, ovp_count, blocks_per_sec;
+ u64 main_count, resv_count, ovp_count;
DIRTY_I(sbi)->v_ops = &default_v_ops;
@@ -987,8 +1103,13 @@
main_count = SM_I(sbi)->main_segments << sbi->log_blocks_per_seg;
resv_count = SM_I(sbi)->reserved_segments << sbi->log_blocks_per_seg;
ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
- blocks_per_sec = sbi->blocks_per_seg * sbi->segs_per_sec;
- sbi->fggc_threshold = div_u64((main_count - ovp_count) * blocks_per_sec,
- (main_count - resv_count));
+ sbi->fggc_threshold = div64_u64((main_count - ovp_count) *
+ BLKS_PER_SEC(sbi), (main_count - resv_count));
+ sbi->gc_pin_file_threshold = DEF_GC_FAILED_PINNED_FILES;
+
+ /* give warm/cold data area from slower device */
+ if (sbi->s_ndevs && sbi->segs_per_sec == 1)
+ SIT_I(sbi)->last_victim[ALLOC_NEXT] =
+ GET_SEGNO(sbi, FDEV(0).end_blk) + 1;
}
diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h
index a993967..b0045d4 100644
--- a/fs/f2fs/gc.h
+++ b/fs/f2fs/gc.h
@@ -13,12 +13,15 @@
* whether IO subsystem is idle
* or not
*/
+#define DEF_GC_THREAD_URGENT_SLEEP_TIME 500 /* 500 ms */
#define DEF_GC_THREAD_MIN_SLEEP_TIME 30000 /* milliseconds */
#define DEF_GC_THREAD_MAX_SLEEP_TIME 60000
#define DEF_GC_THREAD_NOGC_SLEEP_TIME 300000 /* wait 5 min */
#define LIMIT_INVALID_BLOCK 40 /* percentage over total user space */
#define LIMIT_FREE_BLOCK 40 /* percentage over invalid + free space */
+#define DEF_GC_FAILED_PINNED_FILES 2048
+
/* Search max. number of dirty segments to select a victim segment */
#define DEF_MAX_VICTIM_SEARCH 4096 /* covers 8GB */
@@ -27,12 +30,15 @@
wait_queue_head_t gc_wait_queue_head;
/* for gc sleep time */
+ unsigned int urgent_sleep_time;
unsigned int min_sleep_time;
unsigned int max_sleep_time;
unsigned int no_gc_sleep_time;
/* for changing gc mode */
unsigned int gc_idle;
+ unsigned int gc_urgent;
+ unsigned int gc_wake;
};
struct gc_inode_list {
@@ -65,25 +71,32 @@
}
static inline void increase_sleep_time(struct f2fs_gc_kthread *gc_th,
- long *wait)
+ unsigned int *wait)
{
+ unsigned int min_time = gc_th->min_sleep_time;
+ unsigned int max_time = gc_th->max_sleep_time;
+
if (*wait == gc_th->no_gc_sleep_time)
return;
- *wait += gc_th->min_sleep_time;
- if (*wait > gc_th->max_sleep_time)
- *wait = gc_th->max_sleep_time;
+ if ((long long)*wait + (long long)min_time > (long long)max_time)
+ *wait = max_time;
+ else
+ *wait += min_time;
}
static inline void decrease_sleep_time(struct f2fs_gc_kthread *gc_th,
- long *wait)
+ unsigned int *wait)
{
+ unsigned int min_time = gc_th->min_sleep_time;
+
if (*wait == gc_th->no_gc_sleep_time)
*wait = gc_th->max_sleep_time;
- *wait -= gc_th->min_sleep_time;
- if (*wait <= gc_th->min_sleep_time)
- *wait = gc_th->min_sleep_time;
+ if ((long long)*wait - (long long)min_time < (long long)min_time)
+ *wait = min_time;
+ else
+ *wait -= min_time;
}
static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi)
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index e14edc9..364114a 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -23,10 +23,10 @@
if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode))
return false;
- if (i_size_read(inode) > MAX_INLINE_DATA)
+ if (i_size_read(inode) > MAX_INLINE_DATA(inode))
return false;
- if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
+ if (f2fs_encrypted_file(inode))
return false;
return true;
@@ -45,6 +45,7 @@
void read_inline_data(struct page *page, struct page *ipage)
{
+ struct inode *inode = page->mapping->host;
void *src_addr, *dst_addr;
if (PageUptodate(page))
@@ -52,31 +53,33 @@
f2fs_bug_on(F2FS_P_SB(page), page->index);
- zero_user_segment(page, MAX_INLINE_DATA, PAGE_SIZE);
+ zero_user_segment(page, MAX_INLINE_DATA(inode), PAGE_SIZE);
/* Copy the whole inline data block */
- src_addr = inline_data_addr(ipage);
+ src_addr = inline_data_addr(inode, ipage);
dst_addr = kmap_atomic(page);
- memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
+ memcpy(dst_addr, src_addr, MAX_INLINE_DATA(inode));
flush_dcache_page(page);
kunmap_atomic(dst_addr);
if (!PageUptodate(page))
SetPageUptodate(page);
}
-bool truncate_inline_inode(struct page *ipage, u64 from)
+void truncate_inline_inode(struct inode *inode, struct page *ipage, u64 from)
{
void *addr;
- if (from >= MAX_INLINE_DATA)
- return false;
+ if (from >= MAX_INLINE_DATA(inode))
+ return;
- addr = inline_data_addr(ipage);
+ addr = inline_data_addr(inode, ipage);
f2fs_wait_on_page_writeback(ipage, NODE, true);
- memset(addr + from, 0, MAX_INLINE_DATA - from);
+ memset(addr + from, 0, MAX_INLINE_DATA(inode) - from);
set_page_dirty(ipage);
- return true;
+
+ if (from == 0)
+ clear_inode_flag(inode, FI_DATA_EXIST);
}
int f2fs_read_inline_data(struct inode *inode, struct page *page)
@@ -127,11 +130,13 @@
{
struct f2fs_io_info fio = {
.sbi = F2FS_I_SB(dn->inode),
+ .ino = dn->inode->i_ino,
.type = DATA,
.op = REQ_OP_WRITE,
- .op_flags = WRITE_SYNC | REQ_PRIO,
+ .op_flags = REQ_SYNC | REQ_PRIO,
.page = page,
.encrypted_page = NULL,
+ .io_type = FS_DATA_IO,
};
int dirty, err;
@@ -153,20 +158,23 @@
/* write data page to try to make data consistent */
set_page_writeback(page);
fio.old_blkaddr = dn->data_blkaddr;
+ set_inode_flag(dn->inode, FI_HOT_DATA);
write_data_page(dn, &fio);
f2fs_wait_on_page_writeback(page, DATA, true);
- if (dirty)
+ if (dirty) {
inode_dec_dirty_pages(dn->inode);
+ remove_dirty_inode(dn->inode);
+ }
/* this converted inline_data should be recovered. */
set_inode_flag(dn->inode, FI_APPEND_WRITE);
/* clear inline data and flag after data writeback */
- truncate_inline_inode(dn->inode_page, 0);
+ truncate_inline_inode(dn->inode, dn->inode_page, 0);
clear_inline_node(dn->inode_page);
clear_out:
stat_dec_inline_inode(dn->inode);
- f2fs_clear_inline_inode(dn->inode);
+ clear_inode_flag(dn->inode, FI_INLINE_DATA);
f2fs_put_dnode(dn);
return 0;
}
@@ -213,6 +221,8 @@
{
void *src_addr, *dst_addr;
struct dnode_of_data dn;
+ struct address_space *mapping = page_mapping(page);
+ unsigned long flags;
int err;
set_new_dnode(&dn, inode, NULL, NULL, 0);
@@ -229,11 +239,16 @@
f2fs_wait_on_page_writeback(dn.inode_page, NODE, true);
src_addr = kmap_atomic(page);
- dst_addr = inline_data_addr(dn.inode_page);
- memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
+ dst_addr = inline_data_addr(inode, dn.inode_page);
+ memcpy(dst_addr, src_addr, MAX_INLINE_DATA(inode));
kunmap_atomic(src_addr);
set_page_dirty(dn.inode_page);
+ spin_lock_irqsave(&mapping->tree_lock, flags);
+ radix_tree_tag_clear(&mapping->page_tree, page_index(page),
+ PAGECACHE_TAG_DIRTY);
+ spin_unlock_irqrestore(&mapping->tree_lock, flags);
+
set_inode_flag(inode, FI_APPEND_WRITE);
set_inode_flag(inode, FI_DATA_EXIST);
@@ -268,9 +283,9 @@
f2fs_wait_on_page_writeback(ipage, NODE, true);
- src_addr = inline_data_addr(npage);
- dst_addr = inline_data_addr(ipage);
- memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
+ src_addr = inline_data_addr(inode, npage);
+ dst_addr = inline_data_addr(inode, ipage);
+ memcpy(dst_addr, src_addr, MAX_INLINE_DATA(inode));
set_inode_flag(inode, FI_INLINE_DATA);
set_inode_flag(inode, FI_DATA_EXIST);
@@ -283,9 +298,8 @@
if (f2fs_has_inline_data(inode)) {
ipage = get_node_page(sbi, inode->i_ino);
f2fs_bug_on(sbi, IS_ERR(ipage));
- if (!truncate_inline_inode(ipage, 0))
- return false;
- f2fs_clear_inline_inode(inode);
+ truncate_inline_inode(inode, ipage, 0);
+ clear_inode_flag(inode, FI_INLINE_DATA);
f2fs_put_page(ipage, 1);
} else if (ri && (ri->i_inline & F2FS_INLINE_DATA)) {
if (truncate_blocks(inode, 0, false))
@@ -299,11 +313,11 @@
struct fscrypt_name *fname, struct page **res_page)
{
struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
- struct f2fs_inline_dentry *inline_dentry;
struct qstr name = FSTR_TO_QSTR(&fname->disk_name);
struct f2fs_dir_entry *de;
struct f2fs_dentry_ptr d;
struct page *ipage;
+ void *inline_dentry;
f2fs_hash_t namehash;
ipage = get_node_page(sbi, dir->i_ino);
@@ -314,9 +328,9 @@
namehash = f2fs_dentry_hash(&name, fname);
- inline_dentry = inline_data_addr(ipage);
+ inline_dentry = inline_data_addr(dir, ipage);
- make_dentry_ptr(NULL, &d, (void *)inline_dentry, 2);
+ make_dentry_ptr_inline(dir, &d, inline_dentry);
de = find_target_dentry(fname, namehash, NULL, &d);
unlock_page(ipage);
if (de)
@@ -330,19 +344,19 @@
int make_empty_inline_dir(struct inode *inode, struct inode *parent,
struct page *ipage)
{
- struct f2fs_inline_dentry *dentry_blk;
struct f2fs_dentry_ptr d;
+ void *inline_dentry;
- dentry_blk = inline_data_addr(ipage);
+ inline_dentry = inline_data_addr(inode, ipage);
- make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2);
+ make_dentry_ptr_inline(inode, &d, inline_dentry);
do_make_empty_dir(inode, parent, &d);
set_page_dirty(ipage);
/* update i_size to MAX_INLINE_DATA */
- if (i_size_read(inode) < MAX_INLINE_DATA)
- f2fs_i_size_write(inode, MAX_INLINE_DATA);
+ if (i_size_read(inode) < MAX_INLINE_DATA(inode))
+ f2fs_i_size_write(inode, MAX_INLINE_DATA(inode));
return 0;
}
@@ -351,11 +365,12 @@
* release ipage in this function.
*/
static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage,
- struct f2fs_inline_dentry *inline_dentry)
+ void *inline_dentry)
{
struct page *page;
struct dnode_of_data dn;
struct f2fs_dentry_block *dentry_blk;
+ struct f2fs_dentry_ptr src, dst;
int err;
page = f2fs_grab_cache_page(dir->i_mapping, 0, false);
@@ -370,25 +385,24 @@
goto out;
f2fs_wait_on_page_writeback(page, DATA, true);
- zero_user_segment(page, MAX_INLINE_DATA, PAGE_SIZE);
+ zero_user_segment(page, MAX_INLINE_DATA(dir), PAGE_SIZE);
dentry_blk = kmap_atomic(page);
+ make_dentry_ptr_inline(dir, &src, inline_dentry);
+ make_dentry_ptr_block(dir, &dst, dentry_blk);
+
/* copy data from inline dentry block to new dentry block */
- memcpy(dentry_blk->dentry_bitmap, inline_dentry->dentry_bitmap,
- INLINE_DENTRY_BITMAP_SIZE);
- memset(dentry_blk->dentry_bitmap + INLINE_DENTRY_BITMAP_SIZE, 0,
- SIZE_OF_DENTRY_BITMAP - INLINE_DENTRY_BITMAP_SIZE);
+ memcpy(dst.bitmap, src.bitmap, src.nr_bitmap);
+ memset(dst.bitmap + src.nr_bitmap, 0, dst.nr_bitmap - src.nr_bitmap);
/*
* we do not need to zero out remainder part of dentry and filename
* field, since we have used bitmap for marking the usage status of
* them, besides, we can also ignore copying/zeroing reserved space
* of dentry block, because them haven't been used so far.
*/
- memcpy(dentry_blk->dentry, inline_dentry->dentry,
- sizeof(struct f2fs_dir_entry) * NR_INLINE_DENTRY);
- memcpy(dentry_blk->filename, inline_dentry->filename,
- NR_INLINE_DENTRY * F2FS_SLOT_LEN);
+ memcpy(dst.dentry, src.dentry, SIZE_OF_DIR_ENTRY * src.max);
+ memcpy(dst.filename, src.filename, src.max * F2FS_SLOT_LEN);
kunmap_atomic(dentry_blk);
if (!PageUptodate(page))
@@ -396,7 +410,7 @@
set_page_dirty(page);
/* clear inline dir and flag after data writeback */
- truncate_inline_inode(ipage, 0);
+ truncate_inline_inode(dir, ipage, 0);
stat_dec_inline_dir(dir);
clear_inode_flag(dir, FI_INLINE_DENTRY);
@@ -409,14 +423,13 @@
return err;
}
-static int f2fs_add_inline_entries(struct inode *dir,
- struct f2fs_inline_dentry *inline_dentry)
+static int f2fs_add_inline_entries(struct inode *dir, void *inline_dentry)
{
struct f2fs_dentry_ptr d;
unsigned long bit_pos = 0;
int err = 0;
- make_dentry_ptr(NULL, &d, (void *)inline_dentry, 2);
+ make_dentry_ptr_inline(dir, &d, inline_dentry);
while (bit_pos < d.max) {
struct f2fs_dir_entry *de;
@@ -437,7 +450,7 @@
}
new_name.name = d.filename[bit_pos];
- new_name.len = de->name_len;
+ new_name.len = le16_to_cpu(de->name_len);
ino = le32_to_cpu(de->ino);
fake_mode = get_de_type(de) << S_SHIFT;
@@ -458,20 +471,20 @@
}
static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage,
- struct f2fs_inline_dentry *inline_dentry)
+ void *inline_dentry)
{
- struct f2fs_inline_dentry *backup_dentry;
+ void *backup_dentry;
int err;
backup_dentry = f2fs_kmalloc(F2FS_I_SB(dir),
- sizeof(struct f2fs_inline_dentry), GFP_F2FS_ZERO);
+ MAX_INLINE_DATA(dir), GFP_F2FS_ZERO);
if (!backup_dentry) {
f2fs_put_page(ipage, 1);
return -ENOMEM;
}
- memcpy(backup_dentry, inline_dentry, MAX_INLINE_DATA);
- truncate_inline_inode(ipage, 0);
+ memcpy(backup_dentry, inline_dentry, MAX_INLINE_DATA(dir));
+ truncate_inline_inode(dir, ipage, 0);
unlock_page(ipage);
@@ -487,9 +500,9 @@
return 0;
recover:
lock_page(ipage);
- memcpy(inline_dentry, backup_dentry, MAX_INLINE_DATA);
+ memcpy(inline_dentry, backup_dentry, MAX_INLINE_DATA(dir));
f2fs_i_depth_write(dir, 0);
- f2fs_i_size_write(dir, MAX_INLINE_DATA);
+ f2fs_i_size_write(dir, MAX_INLINE_DATA(dir));
set_page_dirty(ipage);
f2fs_put_page(ipage, 1);
@@ -498,7 +511,7 @@
}
static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
- struct f2fs_inline_dentry *inline_dentry)
+ void *inline_dentry)
{
if (!F2FS_I(dir)->i_dir_level)
return f2fs_move_inline_dirents(dir, ipage, inline_dentry);
@@ -514,7 +527,7 @@
struct page *ipage;
unsigned int bit_pos;
f2fs_hash_t name_hash;
- struct f2fs_inline_dentry *dentry_blk = NULL;
+ void *inline_dentry = NULL;
struct f2fs_dentry_ptr d;
int slots = GET_DENTRY_SLOTS(new_name->len);
struct page *page = NULL;
@@ -524,11 +537,12 @@
if (IS_ERR(ipage))
return PTR_ERR(ipage);
- dentry_blk = inline_data_addr(ipage);
- bit_pos = room_for_filename(&dentry_blk->dentry_bitmap,
- slots, NR_INLINE_DENTRY);
- if (bit_pos >= NR_INLINE_DENTRY) {
- err = f2fs_convert_inline_dir(dir, ipage, dentry_blk);
+ inline_dentry = inline_data_addr(dir, ipage);
+ make_dentry_ptr_inline(dir, &d, inline_dentry);
+
+ bit_pos = room_for_filename(d.bitmap, slots, d.max);
+ if (bit_pos >= d.max) {
+ err = f2fs_convert_inline_dir(dir, ipage, inline_dentry);
if (err)
return err;
err = -EAGAIN;
@@ -543,14 +557,11 @@
err = PTR_ERR(page);
goto fail;
}
- if (f2fs_encrypted_inode(dir))
- file_set_enc_name(inode);
}
f2fs_wait_on_page_writeback(ipage, NODE, true);
name_hash = f2fs_dentry_hash(new_name, NULL);
- make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2);
f2fs_update_dentry(ino, mode, &d, new_name, name_hash, bit_pos);
set_page_dirty(ipage);
@@ -573,7 +584,8 @@
void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page,
struct inode *dir, struct inode *inode)
{
- struct f2fs_inline_dentry *inline_dentry;
+ struct f2fs_dentry_ptr d;
+ void *inline_dentry;
int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len));
unsigned int bit_pos;
int i;
@@ -581,17 +593,18 @@
lock_page(page);
f2fs_wait_on_page_writeback(page, NODE, true);
- inline_dentry = inline_data_addr(page);
- bit_pos = dentry - inline_dentry->dentry;
+ inline_dentry = inline_data_addr(dir, page);
+ make_dentry_ptr_inline(dir, &d, inline_dentry);
+
+ bit_pos = dentry - d.dentry;
for (i = 0; i < slots; i++)
- __clear_bit_le(bit_pos + i,
- &inline_dentry->dentry_bitmap);
+ __clear_bit_le(bit_pos + i, d.bitmap);
set_page_dirty(page);
f2fs_put_page(page, 1);
dir->i_ctime = dir->i_mtime = current_time(dir);
- f2fs_mark_inode_dirty_sync(dir);
+ f2fs_mark_inode_dirty_sync(dir, false);
if (inode)
f2fs_drop_nlink(dir, inode);
@@ -602,20 +615,21 @@
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
struct page *ipage;
unsigned int bit_pos = 2;
- struct f2fs_inline_dentry *dentry_blk;
+ void *inline_dentry;
+ struct f2fs_dentry_ptr d;
ipage = get_node_page(sbi, dir->i_ino);
if (IS_ERR(ipage))
return false;
- dentry_blk = inline_data_addr(ipage);
- bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
- NR_INLINE_DENTRY,
- bit_pos);
+ inline_dentry = inline_data_addr(dir, ipage);
+ make_dentry_ptr_inline(dir, &d, inline_dentry);
+
+ bit_pos = find_next_bit_le(d.bitmap, d.max, bit_pos);
f2fs_put_page(ipage, 1);
- if (bit_pos < NR_INLINE_DENTRY)
+ if (bit_pos < d.max)
return false;
return true;
@@ -625,26 +639,30 @@
struct fscrypt_str *fstr)
{
struct inode *inode = file_inode(file);
- struct f2fs_inline_dentry *inline_dentry = NULL;
struct page *ipage = NULL;
struct f2fs_dentry_ptr d;
+ void *inline_dentry = NULL;
+ int err;
- if (ctx->pos == NR_INLINE_DENTRY)
+ make_dentry_ptr_inline(inode, &d, inline_dentry);
+
+ if (ctx->pos == d.max)
return 0;
ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
if (IS_ERR(ipage))
return PTR_ERR(ipage);
- inline_dentry = inline_data_addr(ipage);
+ inline_dentry = inline_data_addr(inode, ipage);
- make_dentry_ptr(inode, &d, (void *)inline_dentry, 2);
+ make_dentry_ptr_inline(inode, &d, inline_dentry);
- if (!f2fs_fill_dentries(ctx, &d, 0, fstr))
- ctx->pos = NR_INLINE_DENTRY;
+ err = f2fs_fill_dentries(ctx, &d, 0, fstr);
+ if (!err)
+ ctx->pos = d.max;
f2fs_put_page(ipage, 1);
- return 0;
+ return err < 0 ? err : 0;
}
int f2fs_inline_data_fiemap(struct inode *inode,
@@ -666,7 +684,7 @@
goto out;
}
- ilen = min_t(size_t, MAX_INLINE_DATA, i_size_read(inode));
+ ilen = min_t(size_t, MAX_INLINE_DATA(inode), i_size_read(inode));
if (start >= ilen)
goto out;
if (start + len < ilen)
@@ -675,7 +693,8 @@
get_node_info(F2FS_I_SB(inode), inode->i_ino, &ni);
byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits;
- byteaddr += (char *)inline_data_addr(ipage) - (char *)F2FS_INODE(ipage);
+ byteaddr += (char *)inline_data_addr(inode, ipage) -
+ (char *)F2FS_INODE(ipage);
err = fiemap_fill_next_extent(fieinfo, start, byteaddr, ilen, flags);
out:
f2fs_put_page(ipage, 1);
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index d736989..89c838b 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -16,13 +16,18 @@
#include "f2fs.h"
#include "node.h"
+#include "segment.h"
#include <trace/events/f2fs.h>
-void f2fs_mark_inode_dirty_sync(struct inode *inode)
+void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync)
{
- if (f2fs_inode_dirtied(inode))
+ if (is_inode_flag_set(inode, FI_NEW_INODE))
return;
+
+ if (f2fs_inode_dirtied(inode, sync))
+ return;
+
mark_inode_dirty_sync(inode);
}
@@ -41,27 +46,31 @@
new_fl |= S_NOATIME;
if (flags & FS_DIRSYNC_FL)
new_fl |= S_DIRSYNC;
+ if (f2fs_encrypted_inode(inode))
+ new_fl |= S_ENCRYPTED;
inode_set_flags(inode, new_fl,
- S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
- f2fs_mark_inode_dirty_sync(inode);
+ S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|
+ S_ENCRYPTED);
}
static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
{
+ int extra_size = get_extra_isize(inode);
+
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
- if (ri->i_addr[0])
- inode->i_rdev =
- old_decode_dev(le32_to_cpu(ri->i_addr[0]));
+ if (ri->i_addr[extra_size])
+ inode->i_rdev = old_decode_dev(
+ le32_to_cpu(ri->i_addr[extra_size]));
else
- inode->i_rdev =
- new_decode_dev(le32_to_cpu(ri->i_addr[1]));
+ inode->i_rdev = new_decode_dev(
+ le32_to_cpu(ri->i_addr[extra_size + 1]));
}
}
static bool __written_first_block(struct f2fs_inode *ri)
{
- block_t addr = le32_to_cpu(ri->i_addr[0]);
+ block_t addr = le32_to_cpu(ri->i_addr[offset_in_addr(ri)]);
if (addr != NEW_ADDR && addr != NULL_ADDR)
return true;
@@ -70,25 +79,27 @@
static void __set_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
{
+ int extra_size = get_extra_isize(inode);
+
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
if (old_valid_dev(inode->i_rdev)) {
- ri->i_addr[0] =
+ ri->i_addr[extra_size] =
cpu_to_le32(old_encode_dev(inode->i_rdev));
- ri->i_addr[1] = 0;
+ ri->i_addr[extra_size + 1] = 0;
} else {
- ri->i_addr[0] = 0;
- ri->i_addr[1] =
+ ri->i_addr[extra_size] = 0;
+ ri->i_addr[extra_size + 1] =
cpu_to_le32(new_encode_dev(inode->i_rdev));
- ri->i_addr[2] = 0;
+ ri->i_addr[extra_size + 2] = 0;
}
}
}
static void __recover_inline_status(struct inode *inode, struct page *ipage)
{
- void *inline_data = inline_data_addr(ipage);
+ void *inline_data = inline_data_addr(inode, ipage);
__le32 *start = inline_data;
- __le32 *end = start + MAX_INLINE_DATA / sizeof(__le32);
+ __le32 *end = start + MAX_INLINE_DATA(inode) / sizeof(__le32);
while (start < end) {
if (*start++) {
@@ -103,12 +114,84 @@
return;
}
+static bool f2fs_enable_inode_chksum(struct f2fs_sb_info *sbi, struct page *page)
+{
+ struct f2fs_inode *ri = &F2FS_NODE(page)->i;
+ int extra_isize = le32_to_cpu(ri->i_extra_isize);
+
+ if (!f2fs_sb_has_inode_chksum(sbi->sb))
+ return false;
+
+ if (!RAW_IS_INODE(F2FS_NODE(page)) || !(ri->i_inline & F2FS_EXTRA_ATTR))
+ return false;
+
+ if (!F2FS_FITS_IN_INODE(ri, extra_isize, i_inode_checksum))
+ return false;
+
+ return true;
+}
+
+static __u32 f2fs_inode_chksum(struct f2fs_sb_info *sbi, struct page *page)
+{
+ struct f2fs_node *node = F2FS_NODE(page);
+ struct f2fs_inode *ri = &node->i;
+ __le32 ino = node->footer.ino;
+ __le32 gen = ri->i_generation;
+ __u32 chksum, chksum_seed;
+ __u32 dummy_cs = 0;
+ unsigned int offset = offsetof(struct f2fs_inode, i_inode_checksum);
+ unsigned int cs_size = sizeof(dummy_cs);
+
+ chksum = f2fs_chksum(sbi, sbi->s_chksum_seed, (__u8 *)&ino,
+ sizeof(ino));
+ chksum_seed = f2fs_chksum(sbi, chksum, (__u8 *)&gen, sizeof(gen));
+
+ chksum = f2fs_chksum(sbi, chksum_seed, (__u8 *)ri, offset);
+ chksum = f2fs_chksum(sbi, chksum, (__u8 *)&dummy_cs, cs_size);
+ offset += cs_size;
+ chksum = f2fs_chksum(sbi, chksum, (__u8 *)ri + offset,
+ F2FS_BLKSIZE - offset);
+ return chksum;
+}
+
+bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page)
+{
+ struct f2fs_inode *ri;
+ __u32 provided, calculated;
+
+ if (!f2fs_enable_inode_chksum(sbi, page) ||
+ PageDirty(page) || PageWriteback(page))
+ return true;
+
+ ri = &F2FS_NODE(page)->i;
+ provided = le32_to_cpu(ri->i_inode_checksum);
+ calculated = f2fs_inode_chksum(sbi, page);
+
+ if (provided != calculated)
+ f2fs_msg(sbi->sb, KERN_WARNING,
+ "checksum invalid, ino = %x, %x vs. %x",
+ ino_of_node(page), provided, calculated);
+
+ return provided == calculated;
+}
+
+void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page)
+{
+ struct f2fs_inode *ri = &F2FS_NODE(page)->i;
+
+ if (!f2fs_enable_inode_chksum(sbi, page))
+ return;
+
+ ri->i_inode_checksum = cpu_to_le32(f2fs_inode_chksum(sbi, page));
+}
+
static int do_read_inode(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct f2fs_inode_info *fi = F2FS_I(inode);
struct page *node_page;
struct f2fs_inode *ri;
+ projid_t i_projid;
/* Check if ino is within scope */
if (check_nid_range(sbi, inode->i_ino)) {
@@ -129,7 +212,7 @@
i_gid_write(inode, le32_to_cpu(ri->i_gid));
set_nlink(inode, le32_to_cpu(ri->i_links));
inode->i_size = le64_to_cpu(ri->i_size);
- inode->i_blocks = le64_to_cpu(ri->i_blocks);
+ inode->i_blocks = SECTOR_FROM_BLOCK(le64_to_cpu(ri->i_blocks) - 1);
inode->i_atime.tv_sec = le64_to_cpu(ri->i_atime);
inode->i_ctime.tv_sec = le64_to_cpu(ri->i_ctime);
@@ -152,6 +235,26 @@
get_inline_info(inode, ri);
+ fi->i_extra_isize = f2fs_has_extra_attr(inode) ?
+ le16_to_cpu(ri->i_extra_isize) : 0;
+
+ if (f2fs_sb_has_flexible_inline_xattr(sbi->sb)) {
+ f2fs_bug_on(sbi, !f2fs_has_extra_attr(inode));
+ fi->i_inline_xattr_size = le16_to_cpu(ri->i_inline_xattr_size);
+ } else if (f2fs_has_inline_xattr(inode) ||
+ f2fs_has_inline_dentry(inode)) {
+ fi->i_inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
+ } else {
+
+ /*
+ * Previous inline data or directory always reserved 200 bytes
+ * in inode layout, even if inline_xattr is disabled. In order
+ * to keep inline_dentry's structure for backward compatibility,
+ * we get the space back only from inline_data.
+ */
+ fi->i_inline_xattr_size = 0;
+ }
+
/* check data exist */
if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode))
__recover_inline_status(inode, node_page);
@@ -165,6 +268,22 @@
if (!need_inode_block_update(sbi, inode->i_ino))
fi->last_disk_size = inode->i_size;
+ if (fi->i_flags & FS_PROJINHERIT_FL)
+ set_inode_flag(inode, FI_PROJ_INHERIT);
+
+ if (f2fs_has_extra_attr(inode) && f2fs_sb_has_project_quota(sbi->sb) &&
+ F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_projid))
+ i_projid = (projid_t)le32_to_cpu(ri->i_projid);
+ else
+ i_projid = F2FS_DEF_PROJID;
+ fi->i_projid = make_kprojid(&init_user_ns, i_projid);
+
+ if (f2fs_has_extra_attr(inode) && f2fs_sb_has_inode_crtime(sbi->sb) &&
+ F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_crtime)) {
+ fi->i_crtime.tv_sec = le64_to_cpu(ri->i_crtime);
+ fi->i_crtime.tv_nsec = le32_to_cpu(ri->i_crtime_nsec);
+ }
+
f2fs_put_page(node_page, 1);
stat_inc_inline_xattr(inode);
@@ -225,6 +344,7 @@
ret = -EIO;
goto bad_inode;
}
+ f2fs_set_inode_flags(inode);
unlock_new_inode(inode);
trace_f2fs_iget(inode);
return inode;
@@ -249,13 +369,15 @@
return inode;
}
-int update_inode(struct inode *inode, struct page *node_page)
+void update_inode(struct inode *inode, struct page *node_page)
{
struct f2fs_inode *ri;
-
- f2fs_inode_synced(inode);
+ struct extent_tree *et = F2FS_I(inode)->extent_tree;
f2fs_wait_on_page_writeback(node_page, NODE, true);
+ set_page_dirty(node_page);
+
+ f2fs_inode_synced(inode);
ri = F2FS_INODE(node_page);
@@ -265,13 +387,15 @@
ri->i_gid = cpu_to_le32(i_gid_read(inode));
ri->i_links = cpu_to_le32(inode->i_nlink);
ri->i_size = cpu_to_le64(i_size_read(inode));
- ri->i_blocks = cpu_to_le64(inode->i_blocks);
+ ri->i_blocks = cpu_to_le64(SECTOR_TO_BLOCK(inode->i_blocks) + 1);
- if (F2FS_I(inode)->extent_tree)
- set_raw_extent(&F2FS_I(inode)->extent_tree->largest,
- &ri->i_ext);
- else
+ if (et) {
+ read_lock(&et->lock);
+ set_raw_extent(&et->largest, &ri->i_ext);
+ read_unlock(&et->lock);
+ } else {
memset(&ri->i_ext, 0, sizeof(ri->i_ext));
+ }
set_raw_inline(inode, ri);
ri->i_atime = cpu_to_le64(inode->i_atime.tv_sec);
@@ -287,6 +411,33 @@
ri->i_generation = cpu_to_le32(inode->i_generation);
ri->i_dir_level = F2FS_I(inode)->i_dir_level;
+ if (f2fs_has_extra_attr(inode)) {
+ ri->i_extra_isize = cpu_to_le16(F2FS_I(inode)->i_extra_isize);
+
+ if (f2fs_sb_has_flexible_inline_xattr(F2FS_I_SB(inode)->sb))
+ ri->i_inline_xattr_size =
+ cpu_to_le16(F2FS_I(inode)->i_inline_xattr_size);
+
+ if (f2fs_sb_has_project_quota(F2FS_I_SB(inode)->sb) &&
+ F2FS_FITS_IN_INODE(ri, F2FS_I(inode)->i_extra_isize,
+ i_projid)) {
+ projid_t i_projid;
+
+ i_projid = from_kprojid(&init_user_ns,
+ F2FS_I(inode)->i_projid);
+ ri->i_projid = cpu_to_le32(i_projid);
+ }
+
+ if (f2fs_sb_has_inode_crtime(F2FS_I_SB(inode)->sb) &&
+ F2FS_FITS_IN_INODE(ri, F2FS_I(inode)->i_extra_isize,
+ i_crtime)) {
+ ri->i_crtime =
+ cpu_to_le64(F2FS_I(inode)->i_crtime.tv_sec);
+ ri->i_crtime_nsec =
+ cpu_to_le32(F2FS_I(inode)->i_crtime.tv_nsec);
+ }
+ }
+
__set_inode_rdev(inode, ri);
set_cold_node(inode, node_page);
@@ -294,14 +445,12 @@
if (inode->i_nlink == 0)
clear_inline_node(node_page);
- return set_page_dirty(node_page);
}
-int update_inode_page(struct inode *inode)
+void update_inode_page(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct page *node_page;
- int ret = 0;
retry:
node_page = get_node_page(sbi, inode->i_ino);
if (IS_ERR(node_page)) {
@@ -312,12 +461,10 @@
} else if (err != -ENOENT) {
f2fs_stop_checkpoint(sbi, false);
}
- f2fs_inode_synced(inode);
- return 0;
+ return;
}
- ret = update_inode(inode, node_page);
+ update_inode(inode, node_page);
f2fs_put_page(node_page, 1);
- return ret;
}
int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
@@ -335,7 +482,8 @@
* We need to balance fs here to prevent from producing dirty node pages
* during the urgent cleaning time when runing out of free sections.
*/
- if (update_inode_page(inode))
+ update_inode_page(inode);
+ if (wbc && wbc->nr_to_write)
f2fs_balance_fs(sbi, true);
return 0;
}
@@ -368,10 +516,11 @@
if (inode->i_nlink || is_bad_inode(inode))
goto no_delete;
-#ifdef CONFIG_F2FS_FAULT_INJECTION
- if (time_to_inject(sbi, FAULT_EVICT_INODE))
- goto no_delete;
-#endif
+ dquot_initialize(inode);
+
+ remove_ino_entry(sbi, inode->i_ino, APPEND_INO);
+ remove_ino_entry(sbi, inode->i_ino, UPDATE_INO);
+ remove_ino_entry(sbi, inode->i_ino, FLUSH_INO);
sb_start_intwrite(inode->i_sb);
set_inode_flag(inode, FI_NO_ALLOC);
@@ -380,10 +529,18 @@
if (F2FS_HAS_BLOCKS(inode))
err = f2fs_truncate(inode);
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+ if (time_to_inject(sbi, FAULT_EVICT_INODE)) {
+ f2fs_show_injection_info(FAULT_EVICT_INODE);
+ err = -EIO;
+ }
+#endif
if (!err) {
f2fs_lock_op(sbi);
err = remove_inode_page(inode);
f2fs_unlock_op(sbi);
+ if (err == -ENOENT)
+ err = 0;
}
/* give more chances, if ENOMEM case */
@@ -394,25 +551,39 @@
if (err)
update_inode_page(inode);
+ dquot_free_inode(inode);
sb_end_intwrite(inode->i_sb);
no_delete:
+ dquot_drop(inode);
+
stat_dec_inline_xattr(inode);
stat_dec_inline_dir(inode);
stat_dec_inline_inode(inode);
- invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino);
+ if (likely(!is_set_ckpt_flags(sbi, CP_ERROR_FLAG)))
+ f2fs_bug_on(sbi, is_inode_flag_set(inode, FI_DIRTY_INODE));
+ else
+ f2fs_inode_synced(inode);
+
+ /* ino == 0, if f2fs_new_inode() was failed t*/
+ if (inode->i_ino)
+ invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino,
+ inode->i_ino);
if (xnid)
invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid);
- if (is_inode_flag_set(inode, FI_APPEND_WRITE))
- add_ino_entry(sbi, inode->i_ino, APPEND_INO);
- if (is_inode_flag_set(inode, FI_UPDATE_WRITE))
- add_ino_entry(sbi, inode->i_ino, UPDATE_INO);
+ if (inode->i_nlink) {
+ if (is_inode_flag_set(inode, FI_APPEND_WRITE))
+ add_ino_entry(sbi, inode->i_ino, APPEND_INO);
+ if (is_inode_flag_set(inode, FI_UPDATE_WRITE))
+ add_ino_entry(sbi, inode->i_ino, UPDATE_INO);
+ }
if (is_inode_flag_set(inode, FI_FREE_NID)) {
alloc_nid_failed(sbi, inode->i_ino);
clear_inode_flag(inode, FI_FREE_NID);
+ } else {
+ f2fs_bug_on(sbi, err &&
+ !exist_written_data(sbi, inode->i_ino, ORPHAN_INO));
}
- f2fs_bug_on(sbi, err &&
- !exist_written_data(sbi, inode->i_ino, ORPHAN_INO));
out_clear:
fscrypt_put_encryption_info(inode, NULL);
clear_inode(inode);
@@ -424,6 +595,19 @@
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct node_info ni;
+ /*
+ * clear nlink of inode in order to release resource of inode
+ * immediately.
+ */
+ clear_nlink(inode);
+
+ /*
+ * we must call this to avoid inode being remained as dirty, resulting
+ * in a panic when flushing dirty inodes in gdirty_list.
+ */
+ update_inode_page(inode);
+ f2fs_inode_synced(inode);
+
/* don't make bad inode, since it becomes a regular file. */
unlock_new_inode(inode);
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 8556fe1..070b3a7 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -15,6 +15,7 @@
#include <linux/ctype.h>
#include <linux/dcache.h>
#include <linux/namei.h>
+#include <linux/quotaops.h>
#include "f2fs.h"
#include "node.h"
@@ -28,6 +29,7 @@
nid_t ino;
struct inode *inode;
bool nid_free = false;
+ int xattr_size = 0;
int err;
inode = new_inode(dir->i_sb);
@@ -42,39 +44,82 @@
}
f2fs_unlock_op(sbi);
+ nid_free = true;
+
inode_init_owner(inode, dir, mode);
inode->i_ino = ino;
inode->i_blocks = 0;
- inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
+ inode->i_mtime = inode->i_atime = inode->i_ctime =
+ F2FS_I(inode)->i_crtime = current_time(inode);
inode->i_generation = sbi->s_next_generation++;
err = insert_inode_locked(inode);
if (err) {
err = -EINVAL;
- nid_free = true;
goto fail;
}
+ if (f2fs_sb_has_project_quota(sbi->sb) &&
+ (F2FS_I(dir)->i_flags & FS_PROJINHERIT_FL))
+ F2FS_I(inode)->i_projid = F2FS_I(dir)->i_projid;
+ else
+ F2FS_I(inode)->i_projid = make_kprojid(&init_user_ns,
+ F2FS_DEF_PROJID);
+
+ err = dquot_initialize(inode);
+ if (err)
+ goto fail_drop;
+
+ err = dquot_alloc_inode(inode);
+ if (err)
+ goto fail_drop;
+
+ set_inode_flag(inode, FI_NEW_INODE);
+
/* If the directory encrypted, then we should encrypt the inode. */
if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode))
f2fs_set_encrypted_inode(inode);
- set_inode_flag(inode, FI_NEW_INODE);
+ if (f2fs_sb_has_extra_attr(sbi->sb)) {
+ set_inode_flag(inode, FI_EXTRA_ATTR);
+ F2FS_I(inode)->i_extra_isize = F2FS_TOTAL_EXTRA_ATTR_SIZE;
+ }
if (test_opt(sbi, INLINE_XATTR))
set_inode_flag(inode, FI_INLINE_XATTR);
+
if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode))
set_inode_flag(inode, FI_INLINE_DATA);
if (f2fs_may_inline_dentry(inode))
set_inode_flag(inode, FI_INLINE_DENTRY);
+ if (f2fs_sb_has_flexible_inline_xattr(sbi->sb)) {
+ f2fs_bug_on(sbi, !f2fs_has_extra_attr(inode));
+ if (f2fs_has_inline_xattr(inode))
+ xattr_size = sbi->inline_xattr_size;
+ /* Otherwise, will be 0 */
+ } else if (f2fs_has_inline_xattr(inode) ||
+ f2fs_has_inline_dentry(inode)) {
+ xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
+ }
+ F2FS_I(inode)->i_inline_xattr_size = xattr_size;
+
f2fs_init_extent_tree(inode, NULL);
stat_inc_inline_xattr(inode);
stat_inc_inline_inode(inode);
stat_inc_inline_dir(inode);
+ F2FS_I(inode)->i_flags =
+ f2fs_mask_flags(mode, F2FS_I(dir)->i_flags & F2FS_FL_INHERITED);
+
+ if (S_ISDIR(inode->i_mode))
+ F2FS_I(inode)->i_flags |= FS_INDEX_FL;
+
+ if (F2FS_I(inode)->i_flags & FS_PROJINHERIT_FL)
+ set_inode_flag(inode, FI_PROJ_INHERIT);
+
trace_f2fs_new_inode(inode, 0);
return inode;
@@ -85,6 +130,16 @@
set_inode_flag(inode, FI_FREE_NID);
iput(inode);
return ERR_PTR(err);
+fail_drop:
+ trace_f2fs_new_inode(inode, err);
+ dquot_drop(inode);
+ inode->i_flags |= S_NOQUOTA;
+ if (nid_free)
+ set_inode_flag(inode, FI_FREE_NID);
+ clear_nlink(inode);
+ unlock_new_inode(inode);
+ iput(inode);
+ return ERR_PTR(err);
}
static int is_multimedia_file(const unsigned char *s, const char *sub)
@@ -136,6 +191,13 @@
nid_t ino = 0;
int err;
+ if (unlikely(f2fs_cp_error(sbi)))
+ return -EIO;
+
+ err = dquot_initialize(dir);
+ if (err)
+ return err;
+
inode = f2fs_new_inode(dir, mode);
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -148,8 +210,6 @@
inode->i_mapping->a_ops = &f2fs_dblock_aops;
ino = inode->i_ino;
- f2fs_balance_fs(sbi, true);
-
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
if (err)
@@ -163,6 +223,8 @@
if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1);
+
+ f2fs_balance_fs(sbi, true);
return 0;
out:
handle_failed_inode(inode);
@@ -176,9 +238,21 @@
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
int err;
- if (f2fs_encrypted_inode(dir) &&
- !fscrypt_has_permitted_context(dir, inode))
- return -EPERM;
+ if (unlikely(f2fs_cp_error(sbi)))
+ return -EIO;
+
+ err = fscrypt_prepare_link(old_dentry, dir, dentry);
+ if (err)
+ return err;
+
+ if (is_inode_flag_set(dir, FI_PROJ_INHERIT) &&
+ (!projid_eq(F2FS_I(dir)->i_projid,
+ F2FS_I(old_dentry->d_inode)->i_projid)))
+ return -EXDEV;
+
+ err = dquot_initialize(dir);
+ if (err)
+ return err;
f2fs_balance_fs(sbi, true);
@@ -233,6 +307,10 @@
return 0;
}
+ err = dquot_initialize(dir);
+ if (err)
+ return err;
+
f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi);
@@ -273,33 +351,29 @@
struct inode *inode = NULL;
struct f2fs_dir_entry *de;
struct page *page;
- nid_t ino;
+ struct dentry *new;
+ nid_t ino = -1;
int err = 0;
unsigned int root_ino = F2FS_ROOT_INO(F2FS_I_SB(dir));
- if (f2fs_encrypted_inode(dir)) {
- int res = fscrypt_get_encryption_info(dir);
+ trace_f2fs_lookup_start(dir, dentry, flags);
- /*
- * DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is
- * created while the directory was encrypted and we
- * don't have access to the key.
- */
- if (fscrypt_has_encryption_key(dir))
- fscrypt_set_encrypted_dentry(dentry);
- fscrypt_set_d_op(dentry);
- if (res && res != -ENOKEY)
- return ERR_PTR(res);
+ err = fscrypt_prepare_lookup(dir, dentry, flags);
+ if (err)
+ goto out;
+
+ if (dentry->d_name.len > F2FS_NAME_LEN) {
+ err = -ENAMETOOLONG;
+ goto out;
}
- if (dentry->d_name.len > F2FS_NAME_LEN)
- return ERR_PTR(-ENAMETOOLONG);
-
de = f2fs_find_entry(dir, &dentry->d_name, &page);
if (!de) {
- if (IS_ERR(page))
- return (struct dentry *)page;
- return d_splice_alias(inode, dentry);
+ if (IS_ERR(page)) {
+ err = PTR_ERR(page);
+ goto out;
+ }
+ goto out_splice;
}
ino = le32_to_cpu(de->ino);
@@ -307,32 +381,41 @@
f2fs_put_page(page, 0);
inode = f2fs_iget(dir->i_sb, ino);
- if (IS_ERR(inode))
- return ERR_CAST(inode);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto out;
+ }
if ((dir->i_ino == root_ino) && f2fs_has_inline_dots(dir)) {
err = __recover_dot_dentries(dir, root_ino);
if (err)
- goto err_out;
+ goto out_iput;
}
if (f2fs_has_inline_dots(inode)) {
err = __recover_dot_dentries(inode, dir->i_ino);
if (err)
- goto err_out;
+ goto out_iput;
}
- if (!IS_ERR(inode) && f2fs_encrypted_inode(dir) &&
- (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
- !fscrypt_has_permitted_context(dir, inode)) {
- bool nokey = f2fs_encrypted_inode(inode) &&
- !fscrypt_has_encryption_key(inode);
- err = nokey ? -ENOKEY : -EPERM;
- goto err_out;
+ if (f2fs_encrypted_inode(dir) &&
+ (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
+ !fscrypt_has_permitted_context(dir, inode)) {
+ f2fs_msg(inode->i_sb, KERN_WARNING,
+ "Inconsistent encryption contexts: %lu/%lu",
+ dir->i_ino, inode->i_ino);
+ err = -EPERM;
+ goto out_iput;
}
- return d_splice_alias(inode, dentry);
-
-err_out:
+out_splice:
+ new = d_splice_alias(inode, dentry);
+ if (IS_ERR(new))
+ err = PTR_ERR(new);
+ trace_f2fs_lookup_end(dir, dentry, ino, err);
+ return new;
+out_iput:
iput(inode);
+out:
+ trace_f2fs_lookup_end(dir, dentry, ino, err);
return ERR_PTR(err);
}
@@ -346,6 +429,16 @@
trace_f2fs_unlink_enter(dir, dentry);
+ if (unlikely(f2fs_cp_error(sbi)))
+ return -EIO;
+
+ err = dquot_initialize(dir);
+ if (err)
+ return err;
+ err = dquot_initialize(inode);
+ if (err)
+ return err;
+
de = f2fs_find_entry(dir, &dentry->d_name, &page);
if (!de) {
if (IS_ERR(page))
@@ -397,6 +490,9 @@
struct fscrypt_symlink_data *sd = NULL;
int err;
+ if (unlikely(f2fs_cp_error(sbi)))
+ return -EIO;
+
if (f2fs_encrypted_inode(dir)) {
err = fscrypt_get_encryption_info(dir);
if (err)
@@ -412,6 +508,10 @@
if (disk_link.len > dir->i_sb->s_blocksize)
return -ENAMETOOLONG;
+ err = dquot_initialize(dir);
+ if (err)
+ return err;
+
inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO);
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -423,8 +523,6 @@
inode_nohighmem(inode);
inode->i_mapping->a_ops = &f2fs_dblock_aops;
- f2fs_balance_fs(sbi, true);
-
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
if (err)
@@ -436,7 +534,7 @@
struct qstr istr = QSTR_INIT(symname, len);
struct fscrypt_str ostr;
- sd = kzalloc(disk_link.len, GFP_NOFS);
+ sd = f2fs_kzalloc(sbi, disk_link.len, GFP_NOFS);
if (!sd) {
err = -ENOMEM;
goto err_out;
@@ -487,6 +585,8 @@
}
kfree(sd);
+
+ f2fs_balance_fs(sbi, true);
return err;
out:
handle_failed_inode(inode);
@@ -499,6 +599,13 @@
struct inode *inode;
int err;
+ if (unlikely(f2fs_cp_error(sbi)))
+ return -EIO;
+
+ err = dquot_initialize(dir);
+ if (err)
+ return err;
+
inode = f2fs_new_inode(dir, S_IFDIR | mode);
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -508,8 +615,6 @@
inode->i_mapping->a_ops = &f2fs_dblock_aops;
mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO);
- f2fs_balance_fs(sbi, true);
-
set_inode_flag(inode, FI_INC_LINK);
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
@@ -524,6 +629,8 @@
if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1);
+
+ f2fs_balance_fs(sbi, true);
return 0;
out_fail:
@@ -547,6 +654,13 @@
struct inode *inode;
int err = 0;
+ if (unlikely(f2fs_cp_error(sbi)))
+ return -EIO;
+
+ err = dquot_initialize(dir);
+ if (err)
+ return err;
+
inode = f2fs_new_inode(dir, mode);
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -554,8 +668,6 @@
init_special_inode(inode, inode->i_mode, rdev);
inode->i_op = &f2fs_special_inode_operations;
- f2fs_balance_fs(sbi, true);
-
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
if (err)
@@ -569,6 +681,8 @@
if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1);
+
+ f2fs_balance_fs(sbi, true);
return 0;
out:
handle_failed_inode(inode);
@@ -582,6 +696,10 @@
struct inode *inode;
int err;
+ err = dquot_initialize(dir);
+ if (err)
+ return err;
+
inode = f2fs_new_inode(dir, mode);
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -595,8 +713,6 @@
inode->i_mapping->a_ops = &f2fs_dblock_aops;
}
- f2fs_balance_fs(sbi, true);
-
f2fs_lock_op(sbi);
err = acquire_orphan_inode(sbi);
if (err)
@@ -622,6 +738,8 @@
/* link_count was changed by d_tmpfile as well. */
f2fs_unlock_op(sbi);
unlock_new_inode(inode);
+
+ f2fs_balance_fs(sbi, true);
return 0;
release_out:
@@ -633,6 +751,9 @@
static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
{
+ if (unlikely(f2fs_cp_error(F2FS_I_SB(dir))))
+ return -EIO;
+
if (f2fs_encrypted_inode(dir)) {
int err = fscrypt_get_encryption_info(dir);
if (err)
@@ -644,6 +765,9 @@
static int f2fs_create_whiteout(struct inode *dir, struct inode **whiteout)
{
+ if (unlikely(f2fs_cp_error(F2FS_I_SB(dir))))
+ return -EIO;
+
return __f2fs_tmpfile(dir, NULL, S_IFCHR | WHITEOUT_MODE, whiteout);
}
@@ -663,16 +787,26 @@
bool is_old_inline = f2fs_has_inline_dentry(old_dir);
int err = -ENOENT;
- if ((f2fs_encrypted_inode(old_dir) &&
- !fscrypt_has_encryption_key(old_dir)) ||
- (f2fs_encrypted_inode(new_dir) &&
- !fscrypt_has_encryption_key(new_dir)))
- return -ENOKEY;
+ if (unlikely(f2fs_cp_error(sbi)))
+ return -EIO;
- if ((old_dir != new_dir) && f2fs_encrypted_inode(new_dir) &&
- !fscrypt_has_permitted_context(new_dir, old_inode)) {
- err = -EPERM;
+ if (is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
+ (!projid_eq(F2FS_I(new_dir)->i_projid,
+ F2FS_I(old_dentry->d_inode)->i_projid)))
+ return -EXDEV;
+
+ err = dquot_initialize(old_dir);
+ if (err)
goto out;
+
+ err = dquot_initialize(new_dir);
+ if (err)
+ goto out;
+
+ if (new_inode) {
+ err = dquot_initialize(new_inode);
+ if (err)
+ goto out;
}
old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
@@ -720,13 +854,6 @@
if (err)
goto put_out_dir;
- err = update_dent_inode(old_inode, new_inode,
- &new_dentry->d_name);
- if (err) {
- release_orphan_inode(sbi);
- goto put_out_dir;
- }
-
f2fs_set_link(new_dir, new_entry, new_page, old_inode);
new_inode->i_ctime = current_time(new_inode);
@@ -778,13 +905,14 @@
}
down_write(&F2FS_I(old_inode)->i_sem);
- file_lost_pino(old_inode);
- if (new_inode && file_enc_name(new_inode))
- file_set_enc_name(old_inode);
+ if (!old_dir_entry || whiteout)
+ file_lost_pino(old_inode);
+ else
+ F2FS_I(old_inode)->i_pino = new_dir->i_ino;
up_write(&F2FS_I(old_inode)->i_sem);
old_inode->i_ctime = current_time(old_inode);
- f2fs_mark_inode_dirty_sync(old_inode);
+ f2fs_mark_inode_dirty_sync(old_inode, false);
f2fs_delete_entry(old_entry, old_page, old_dir, NULL);
@@ -808,6 +936,7 @@
}
f2fs_i_links_write(old_dir, false);
}
+ add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
f2fs_unlock_op(sbi);
@@ -849,17 +978,24 @@
int old_nlink = 0, new_nlink = 0;
int err = -ENOENT;
- if ((f2fs_encrypted_inode(old_dir) &&
- !fscrypt_has_encryption_key(old_dir)) ||
- (f2fs_encrypted_inode(new_dir) &&
- !fscrypt_has_encryption_key(new_dir)))
- return -ENOKEY;
+ if (unlikely(f2fs_cp_error(sbi)))
+ return -EIO;
- if ((f2fs_encrypted_inode(old_dir) || f2fs_encrypted_inode(new_dir)) &&
- (old_dir != new_dir) &&
- (!fscrypt_has_permitted_context(new_dir, old_inode) ||
- !fscrypt_has_permitted_context(old_dir, new_inode)))
- return -EPERM;
+ if ((is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
+ !projid_eq(F2FS_I(new_dir)->i_projid,
+ F2FS_I(old_dentry->d_inode)->i_projid)) ||
+ (is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
+ !projid_eq(F2FS_I(old_dir)->i_projid,
+ F2FS_I(new_dentry->d_inode)->i_projid)))
+ return -EXDEV;
+
+ err = dquot_initialize(old_dir);
+ if (err)
+ goto out;
+
+ err = dquot_initialize(new_dir);
+ if (err)
+ goto out;
old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
if (!old_entry) {
@@ -908,8 +1044,8 @@
old_nlink = old_dir_entry ? -1 : 1;
new_nlink = -old_nlink;
err = -EMLINK;
- if ((old_nlink > 0 && old_inode->i_nlink >= F2FS_LINK_MAX) ||
- (new_nlink > 0 && new_inode->i_nlink >= F2FS_LINK_MAX))
+ if ((old_nlink > 0 && old_dir->i_nlink >= F2FS_LINK_MAX) ||
+ (new_nlink > 0 && new_dir->i_nlink >= F2FS_LINK_MAX))
goto out_new_dir;
}
@@ -917,18 +1053,6 @@
f2fs_lock_op(sbi);
- err = update_dent_inode(old_inode, new_inode, &new_dentry->d_name);
- if (err)
- goto out_unlock;
- if (file_enc_name(new_inode))
- file_set_enc_name(old_inode);
-
- err = update_dent_inode(new_inode, old_inode, &old_dentry->d_name);
- if (err)
- goto out_undo;
- if (file_enc_name(old_inode))
- file_set_enc_name(new_inode);
-
/* update ".." directory entry info of old dentry */
if (old_dir_entry)
f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir);
@@ -950,7 +1074,7 @@
f2fs_i_links_write(old_dir, old_nlink > 0);
up_write(&F2FS_I(old_dir)->i_sem);
}
- f2fs_mark_inode_dirty_sync(old_dir);
+ f2fs_mark_inode_dirty_sync(old_dir, false);
/* update directory entry info of new dir inode */
f2fs_set_link(new_dir, new_entry, new_page, old_inode);
@@ -965,21 +1089,16 @@
f2fs_i_links_write(new_dir, new_nlink > 0);
up_write(&F2FS_I(new_dir)->i_sem);
}
- f2fs_mark_inode_dirty_sync(new_dir);
+ f2fs_mark_inode_dirty_sync(new_dir, false);
+
+ add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
+ add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
f2fs_unlock_op(sbi);
if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
f2fs_sync_fs(sbi->sb, 1);
return 0;
-out_undo:
- /*
- * Still we may fail to recover name info of f2fs_inode here
- * Drop it, once its name is set as encrypted
- */
- update_dent_inode(old_inode, old_inode, &old_dentry->d_name);
-out_unlock:
- f2fs_unlock_op(sbi);
out_new_dir:
if (new_dir_entry) {
f2fs_dentry_kunmap(new_inode, new_dir_page);
@@ -1004,9 +1123,16 @@
struct inode *new_dir, struct dentry *new_dentry,
unsigned int flags)
{
+ int err;
+
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
return -EINVAL;
+ err = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry,
+ flags);
+ if (err)
+ return err;
+
if (flags & RENAME_EXCHANGE) {
return f2fs_cross_rename(old_dir, old_dentry,
new_dir, new_dentry);
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 01177ec..7cded84 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -19,10 +19,11 @@
#include "f2fs.h"
#include "node.h"
#include "segment.h"
+#include "xattr.h"
#include "trace.h"
#include <trace/events/f2fs.h>
-#define on_build_free_nids(nmi) mutex_is_locked(&nm_i->build_lock)
+#define on_build_free_nids(nmi) mutex_is_locked(&(nm_i)->build_lock)
static struct kmem_cache *nat_entry_slab;
static struct kmem_cache *free_nid_slab;
@@ -45,8 +46,8 @@
* give 25%, 25%, 50%, 50%, 50% memory for each components respectively
*/
if (type == FREE_NIDS) {
- mem_size = (nm_i->fcnt * sizeof(struct free_nid)) >>
- PAGE_SHIFT;
+ mem_size = (nm_i->nid_cnt[FREE_NID] *
+ sizeof(struct free_nid)) >> PAGE_SHIFT;
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2);
} else if (type == NAT_ENTRIES) {
mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >>
@@ -62,9 +63,10 @@
} else if (type == INO_ENTRIES) {
int i;
- for (i = 0; i <= UPDATE_INO; i++)
- mem_size += (sbi->im[i].ino_num *
- sizeof(struct ino_entry)) >> PAGE_SHIFT;
+ for (i = 0; i < MAX_INO_ENTRY; i++)
+ mem_size += sbi->im[i].ino_num *
+ sizeof(struct ino_entry);
+ mem_size >>= PAGE_SHIFT;
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);
} else if (type == EXTENT_CACHE) {
mem_size = (atomic_read(&sbi->total_ext_tree) *
@@ -72,6 +74,10 @@
atomic_read(&sbi->total_ext_node) *
sizeof(struct extent_node)) >> PAGE_SHIFT;
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);
+ } else if (type == INMEM_PAGES) {
+ /* it allows 20% / total_ram for inmemory pages */
+ mem_size = get_pages(sbi, F2FS_INMEM_PAGES);
+ res = mem_size < (val.totalram / 5);
} else {
if (!sbi->sb->s_bdi->wb.dirty_exceeded)
return true;
@@ -132,6 +138,42 @@
return dst_page;
}
+static struct nat_entry *__alloc_nat_entry(nid_t nid, bool no_fail)
+{
+ struct nat_entry *new;
+
+ if (no_fail)
+ new = f2fs_kmem_cache_alloc(nat_entry_slab, GFP_F2FS_ZERO);
+ else
+ new = kmem_cache_alloc(nat_entry_slab, GFP_F2FS_ZERO);
+ if (new) {
+ nat_set_nid(new, nid);
+ nat_reset_flag(new);
+ }
+ return new;
+}
+
+static void __free_nat_entry(struct nat_entry *e)
+{
+ kmem_cache_free(nat_entry_slab, e);
+}
+
+/* must be locked by nat_tree_lock */
+static struct nat_entry *__init_nat_entry(struct f2fs_nm_info *nm_i,
+ struct nat_entry *ne, struct f2fs_nat_entry *raw_ne, bool no_fail)
+{
+ if (no_fail)
+ f2fs_radix_tree_insert(&nm_i->nat_root, nat_get_nid(ne), ne);
+ else if (radix_tree_insert(&nm_i->nat_root, nat_get_nid(ne), ne))
+ return NULL;
+
+ if (raw_ne)
+ node_info_from_raw_nat(&ne->ni, raw_ne);
+ list_add_tail(&ne->list, &nm_i->nat_entries);
+ nm_i->nat_cnt++;
+ return ne;
+}
+
static struct nat_entry *__lookup_nat_cache(struct f2fs_nm_info *nm_i, nid_t n)
{
return radix_tree_lookup(&nm_i->nat_root, n);
@@ -148,7 +190,7 @@
list_del(&e->list);
radix_tree_delete(&nm_i->nat_root, nat_get_nid(e));
nm_i->nat_cnt--;
- kmem_cache_free(nat_entry_slab, e);
+ __free_nat_entry(e);
}
static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
@@ -157,9 +199,6 @@
nid_t set = NAT_BLOCK_OFFSET(ne->ni.nid);
struct nat_entry_set *head;
- if (get_nat_flag(ne, IS_DIRTY))
- return;
-
head = radix_tree_lookup(&nm_i->nat_set_root, set);
if (!head) {
head = f2fs_kmem_cache_alloc(nat_entry_set_slab, GFP_NOFS);
@@ -170,25 +209,27 @@
head->entry_cnt = 0;
f2fs_radix_tree_insert(&nm_i->nat_set_root, set, head);
}
- list_move_tail(&ne->list, &head->entry_list);
+
+ if (get_nat_flag(ne, IS_DIRTY))
+ goto refresh_list;
+
nm_i->dirty_nat_cnt++;
head->entry_cnt++;
set_nat_flag(ne, IS_DIRTY, true);
+refresh_list:
+ if (nat_get_blkaddr(ne) == NEW_ADDR)
+ list_del_init(&ne->list);
+ else
+ list_move_tail(&ne->list, &head->entry_list);
}
static void __clear_nat_cache_dirty(struct f2fs_nm_info *nm_i,
- struct nat_entry *ne)
+ struct nat_entry_set *set, struct nat_entry *ne)
{
- nid_t set = NAT_BLOCK_OFFSET(ne->ni.nid);
- struct nat_entry_set *head;
-
- head = radix_tree_lookup(&nm_i->nat_set_root, set);
- if (head) {
- list_move_tail(&ne->list, &nm_i->nat_entries);
- set_nat_flag(ne, IS_DIRTY, false);
- head->entry_cnt--;
- nm_i->dirty_nat_cnt--;
- }
+ list_move_tail(&ne->list, &nm_i->nat_entries);
+ set_nat_flag(ne, IS_DIRTY, false);
+ set->entry_cnt--;
+ nm_i->dirty_nat_cnt--;
}
static unsigned int __gang_lookup_nat_set(struct f2fs_nm_info *nm_i,
@@ -245,35 +286,29 @@
return need_update;
}
-static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid)
-{
- struct nat_entry *new;
-
- new = f2fs_kmem_cache_alloc(nat_entry_slab, GFP_NOFS);
- f2fs_radix_tree_insert(&nm_i->nat_root, nid, new);
- memset(new, 0, sizeof(struct nat_entry));
- nat_set_nid(new, nid);
- nat_reset_flag(new);
- list_add_tail(&new->list, &nm_i->nat_entries);
- nm_i->nat_cnt++;
- return new;
-}
-
+/* must be locked by nat_tree_lock */
static void cache_nat_entry(struct f2fs_sb_info *sbi, nid_t nid,
struct f2fs_nat_entry *ne)
{
struct f2fs_nm_info *nm_i = NM_I(sbi);
- struct nat_entry *e;
+ struct nat_entry *new, *e;
+ new = __alloc_nat_entry(nid, false);
+ if (!new)
+ return;
+
+ down_write(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, nid);
- if (!e) {
- e = grab_nat_entry(nm_i, nid);
- node_info_from_raw_nat(&e->ni, ne);
- } else {
- f2fs_bug_on(sbi, nat_get_ino(e) != ne->ino ||
- nat_get_blkaddr(e) != ne->block_addr ||
+ if (!e)
+ e = __init_nat_entry(nm_i, new, ne, false);
+ else
+ f2fs_bug_on(sbi, nat_get_ino(e) != le32_to_cpu(ne->ino) ||
+ nat_get_blkaddr(e) !=
+ le32_to_cpu(ne->block_addr) ||
nat_get_version(e) != ne->version);
- }
+ up_write(&nm_i->nat_tree_lock);
+ if (e != new)
+ __free_nat_entry(new);
}
static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
@@ -281,11 +316,12 @@
{
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct nat_entry *e;
+ struct nat_entry *new = __alloc_nat_entry(ni->nid, true);
down_write(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, ni->nid);
if (!e) {
- e = grab_nat_entry(nm_i, ni->nid);
+ e = __init_nat_entry(nm_i, new, NULL, true);
copy_node_info(&e->ni, ni);
f2fs_bug_on(sbi, ni->blk_addr == NEW_ADDR);
} else if (new_blkaddr == NEW_ADDR) {
@@ -297,6 +333,9 @@
copy_node_info(&e->ni, ni);
f2fs_bug_on(sbi, ni->blk_addr != NULL_ADDR);
}
+ /* let's free early to reduce memory consumption */
+ if (e != new)
+ __free_nat_entry(new);
/* sanity check */
f2fs_bug_on(sbi, nat_get_blkaddr(e) != ni->blk_addr);
@@ -312,10 +351,6 @@
if (nat_get_blkaddr(e) != NEW_ADDR && new_blkaddr == NULL_ADDR) {
unsigned char version = nat_get_version(e);
nat_set_version(e, inc_node_version(version));
-
- /* in order to reuse the nid */
- if (nm_i->next_scan_nid > ni->nid)
- nm_i->next_scan_nid = ni->nid;
}
/* change address */
@@ -367,6 +402,7 @@
struct page *page = NULL;
struct f2fs_nat_entry ne;
struct nat_entry *e;
+ pgoff_t index;
int i;
ni->nid = nid;
@@ -392,21 +428,23 @@
node_info_from_raw_nat(ni, &ne);
}
up_read(&curseg->journal_rwsem);
- if (i >= 0)
+ if (i >= 0) {
+ up_read(&nm_i->nat_tree_lock);
goto cache;
+ }
/* Fill node_info from nat page */
- page = get_current_nat_page(sbi, start_nid);
+ index = current_nat_addr(sbi, nid);
+ up_read(&nm_i->nat_tree_lock);
+
+ page = get_meta_page(sbi, index);
nat_blk = (struct f2fs_nat_block *)page_address(page);
ne = nat_blk->entries[nid - start_nid];
node_info_from_raw_nat(ni, &ne);
f2fs_put_page(page, 1);
cache:
- up_read(&nm_i->nat_tree_lock);
/* cache nat entry */
- down_write(&nm_i->nat_tree_lock);
cache_nat_entry(sbi, nid, &ne);
- up_write(&nm_i->nat_tree_lock);
}
/*
@@ -535,7 +573,7 @@
level = 3;
goto got;
} else {
- BUG();
+ return -E2BIG;
}
got:
return level;
@@ -559,6 +597,8 @@
int err = 0;
level = get_node_path(dn->inode, index, offset, noffset);
+ if (level < 0)
+ return level;
nids[0] = dn->inode->i_ino;
npage[0] = dn->inode_page;
@@ -594,7 +634,7 @@
}
dn->nid = nids[i];
- npage[i] = new_node_page(dn, noffset[i], NULL);
+ npage[i] = new_node_page(dn, noffset[i]);
if (IS_ERR(npage[i])) {
alloc_nid_failed(sbi, nids[i]);
err = PTR_ERR(npage[i]);
@@ -635,7 +675,8 @@
dn->nid = nids[level];
dn->ofs_in_node = offset[level];
dn->node_page = npage[level];
- dn->data_blkaddr = datablock_addr(dn->node_page, dn->ofs_in_node);
+ dn->data_blkaddr = datablock_addr(dn->inode,
+ dn->node_page, dn->ofs_in_node);
return 0;
release_pages:
@@ -659,15 +700,10 @@
struct node_info ni;
get_node_info(sbi, dn->nid, &ni);
- if (dn->inode->i_blocks == 0) {
- f2fs_bug_on(sbi, ni.blk_addr != NULL_ADDR);
- goto invalidate;
- }
- f2fs_bug_on(sbi, ni.blk_addr == NULL_ADDR);
/* Deallocate node address */
invalidate_blocks(sbi, ni.blk_addr);
- dec_valid_node_count(sbi, dn->inode);
+ dec_valid_node_count(sbi, dn->inode, dn->nid == dn->inode->i_ino);
set_node_addr(sbi, &ni, NULL_ADDR, false);
if (dn->nid == dn->inode->i_ino) {
@@ -675,7 +711,7 @@
dec_valid_inode_count(sbi);
f2fs_inode_synced(dn->inode);
}
-invalidate:
+
clear_node_page_dirty(dn->node_page);
set_sbi_flag(sbi, SBI_IS_DIRTY);
@@ -861,6 +897,8 @@
trace_f2fs_truncate_inode_blocks_enter(inode, from);
level = get_node_path(inode, from, offset, noffset);
+ if (level < 0)
+ return level;
page = get_node_page(sbi, inode->i_ino);
if (IS_ERR(page)) {
@@ -941,7 +979,8 @@
return err > 0 ? 0 : err;
}
-int truncate_xattr_node(struct inode *inode, struct page *page)
+/* caller must lock inode page */
+int truncate_xattr_node(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
nid_t nid = F2FS_I(inode)->i_xattr_nid;
@@ -957,13 +996,7 @@
f2fs_i_xnid_write(inode, 0);
- /* need to do checkpoint during fsync */
- F2FS_I(inode)->xattr_ver = cur_cp_version(F2FS_CKPT(sbi));
-
- set_new_dnode(&dn, inode, page, npage, nid);
-
- if (page)
- dn.inode_page_locked = true;
+ set_new_dnode(&dn, inode, NULL, npage, nid);
truncate_node(&dn);
return 0;
}
@@ -982,7 +1015,7 @@
if (err)
return err;
- err = truncate_xattr_node(inode, dn.inode_page);
+ err = truncate_xattr_node(inode);
if (err) {
f2fs_put_dnode(&dn);
return err;
@@ -995,7 +1028,7 @@
/* 0 is possible, after f2fs_new_inode() has failed */
f2fs_bug_on(F2FS_I_SB(inode),
- inode->i_blocks != 0 && inode->i_blocks != 1);
+ inode->i_blocks != 0 && inode->i_blocks != 8);
/* will put inode & node pages */
truncate_node(&dn);
@@ -1010,14 +1043,13 @@
set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino);
/* caller should f2fs_put_page(page, 1); */
- return new_node_page(&dn, 0, NULL);
+ return new_node_page(&dn, 0);
}
-struct page *new_node_page(struct dnode_of_data *dn,
- unsigned int ofs, struct page *ipage)
+struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
- struct node_info old_ni, new_ni;
+ struct node_info new_ni;
struct page *page;
int err;
@@ -1028,17 +1060,18 @@
if (!page)
return ERR_PTR(-ENOMEM);
- if (unlikely(!inc_valid_node_count(sbi, dn->inode))) {
- err = -ENOSPC;
+ if (unlikely((err = inc_valid_node_count(sbi, dn->inode, !ofs))))
goto fail;
- }
- get_node_info(sbi, dn->nid, &old_ni);
-
- /* Reinitialize old_ni with new node page */
- f2fs_bug_on(sbi, old_ni.blk_addr != NULL_ADDR);
- new_ni = old_ni;
+#ifdef CONFIG_F2FS_CHECK_FS
+ get_node_info(sbi, dn->nid, &new_ni);
+ f2fs_bug_on(sbi, new_ni.blk_addr != NULL_ADDR);
+#endif
+ new_ni.nid = dn->nid;
new_ni.ino = dn->inode->i_ino;
+ new_ni.blk_addr = NULL_ADDR;
+ new_ni.flag = 0;
+ new_ni.version = 0;
set_node_addr(sbi, &new_ni, NEW_ADDR, false);
f2fs_wait_on_page_writeback(page, NODE, true);
@@ -1134,11 +1167,12 @@
if (!page)
return ERR_PTR(-ENOMEM);
- err = read_node_page(page, READ_SYNC);
+ err = read_node_page(page, 0);
if (err < 0) {
f2fs_put_page(page, 1);
return ERR_PTR(err);
} else if (err == LOCKED_PAGE) {
+ err = 0;
goto page_hit;
}
@@ -1152,15 +1186,27 @@
goto repeat;
}
- if (unlikely(!PageUptodate(page)))
+ if (unlikely(!PageUptodate(page))) {
+ err = -EIO;
goto out_err;
+ }
+
+ if (!f2fs_inode_chksum_verify(sbi, page)) {
+ err = -EBADMSG;
+ goto out_err;
+ }
page_hit:
if(unlikely(nid != nid_of_node(page))) {
- f2fs_bug_on(sbi, 1);
- ClearPageUptodate(page);
+ f2fs_msg(sbi->sb, KERN_WARNING, "inconsistent node block, "
+ "nid:%lu, node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]",
+ nid, nid_of_node(page), ino_of_node(page),
+ ofs_of_node(page), cpver_of_node(page),
+ next_blkaddr_of_node(page));
+ err = -EINVAL;
out_err:
+ ClearPageUptodate(page);
f2fs_put_page(page, 1);
- return ERR_PTR(-EIO);
+ return ERR_PTR(err);
}
return page;
}
@@ -1189,7 +1235,8 @@
if (!inode)
return;
- page = pagecache_get_page(inode->i_mapping, 0, FGP_LOCK|FGP_NOWAIT, 0);
+ page = f2fs_pagecache_get_page(inode->i_mapping, 0,
+ FGP_LOCK|FGP_NOWAIT, 0);
if (!page)
goto iput_out;
@@ -1204,6 +1251,7 @@
ret = f2fs_write_inline_data(inode, page);
inode_dec_dirty_pages(inode);
+ remove_dirty_inode(inode);
if (ret)
set_page_dirty(page);
page_out:
@@ -1212,37 +1260,6 @@
iput(inode);
}
-void move_node_page(struct page *node_page, int gc_type)
-{
- if (gc_type == FG_GC) {
- struct f2fs_sb_info *sbi = F2FS_P_SB(node_page);
- struct writeback_control wbc = {
- .sync_mode = WB_SYNC_ALL,
- .nr_to_write = 1,
- .for_reclaim = 0,
- };
-
- set_page_dirty(node_page);
- f2fs_wait_on_page_writeback(node_page, NODE, true);
-
- f2fs_bug_on(sbi, PageWriteback(node_page));
- if (!clear_page_dirty_for_io(node_page))
- goto out_page;
-
- if (NODE_MAPPING(sbi)->a_ops->writepage(node_page, &wbc))
- unlock_page(node_page);
- goto release_page;
- } else {
- /* set page dirty and write it */
- if (!PageWriteback(node_page))
- set_page_dirty(node_page);
- }
-out_page:
- unlock_page(node_page);
-release_page:
- f2fs_put_page(node_page, 0);
-}
-
static struct page *last_fsync_dnode(struct f2fs_sb_info *sbi, nid_t ino)
{
pgoff_t index, end;
@@ -1303,16 +1320,140 @@
return last_page;
}
+static int __write_node_page(struct page *page, bool atomic, bool *submitted,
+ struct writeback_control *wbc, bool do_balance,
+ enum iostat_type io_type)
+{
+ struct f2fs_sb_info *sbi = F2FS_P_SB(page);
+ nid_t nid;
+ struct node_info ni;
+ struct f2fs_io_info fio = {
+ .sbi = sbi,
+ .ino = ino_of_node(page),
+ .type = NODE,
+ .op = REQ_OP_WRITE,
+ .op_flags = wbc_to_write_flags(wbc),
+ .page = page,
+ .encrypted_page = NULL,
+ .submitted = false,
+ .io_type = io_type,
+ .io_wbc = wbc,
+ };
+
+ trace_f2fs_writepage(page, NODE);
+
+ if (unlikely(f2fs_cp_error(sbi))) {
+ dec_page_count(sbi, F2FS_DIRTY_NODES);
+ unlock_page(page);
+ return 0;
+ }
+
+ if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
+ goto redirty_out;
+
+ /* get old block addr of this node page */
+ nid = nid_of_node(page);
+ f2fs_bug_on(sbi, page->index != nid);
+
+ if (wbc->for_reclaim) {
+ if (!down_read_trylock(&sbi->node_write))
+ goto redirty_out;
+ } else {
+ down_read(&sbi->node_write);
+ }
+
+ get_node_info(sbi, nid, &ni);
+
+ /* This page is already truncated */
+ if (unlikely(ni.blk_addr == NULL_ADDR)) {
+ ClearPageUptodate(page);
+ dec_page_count(sbi, F2FS_DIRTY_NODES);
+ up_read(&sbi->node_write);
+ unlock_page(page);
+ return 0;
+ }
+
+ if (atomic && !test_opt(sbi, NOBARRIER))
+ fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
+
+ set_page_writeback(page);
+ fio.old_blkaddr = ni.blk_addr;
+ write_node_page(nid, &fio);
+ set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(page));
+ dec_page_count(sbi, F2FS_DIRTY_NODES);
+ up_read(&sbi->node_write);
+
+ if (wbc->for_reclaim) {
+ f2fs_submit_merged_write_cond(sbi, page->mapping->host, 0,
+ page->index, NODE);
+ submitted = NULL;
+ }
+
+ unlock_page(page);
+
+ if (unlikely(f2fs_cp_error(sbi))) {
+ f2fs_submit_merged_write(sbi, NODE);
+ submitted = NULL;
+ }
+ if (submitted)
+ *submitted = fio.submitted;
+
+ if (do_balance)
+ f2fs_balance_fs(sbi, false);
+ return 0;
+
+redirty_out:
+ redirty_page_for_writepage(wbc, page);
+ return AOP_WRITEPAGE_ACTIVATE;
+}
+
+void move_node_page(struct page *node_page, int gc_type)
+{
+ if (gc_type == FG_GC) {
+ struct writeback_control wbc = {
+ .sync_mode = WB_SYNC_ALL,
+ .nr_to_write = 1,
+ .for_reclaim = 0,
+ };
+
+ set_page_dirty(node_page);
+ f2fs_wait_on_page_writeback(node_page, NODE, true);
+
+ f2fs_bug_on(F2FS_P_SB(node_page), PageWriteback(node_page));
+ if (!clear_page_dirty_for_io(node_page))
+ goto out_page;
+
+ if (__write_node_page(node_page, false, NULL,
+ &wbc, false, FS_GC_NODE_IO))
+ unlock_page(node_page);
+ goto release_page;
+ } else {
+ /* set page dirty and write it */
+ if (!PageWriteback(node_page))
+ set_page_dirty(node_page);
+ }
+out_page:
+ unlock_page(node_page);
+release_page:
+ f2fs_put_page(node_page, 0);
+}
+
+static int f2fs_write_node_page(struct page *page,
+ struct writeback_control *wbc)
+{
+ return __write_node_page(page, false, NULL, wbc, false, FS_NODE_IO);
+}
+
int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
struct writeback_control *wbc, bool atomic)
{
pgoff_t index, end;
+ pgoff_t last_idx = ULONG_MAX;
struct pagevec pvec;
int ret = 0;
struct page *last_page = NULL;
bool marked = false;
nid_t ino = inode->i_ino;
- int nwritten = 0;
if (atomic) {
last_page = last_fsync_dnode(sbi, ino);
@@ -1334,11 +1475,13 @@
for (i = 0; i < nr_pages; i++) {
struct page *page = pvec.pages[i];
+ bool submitted = false;
if (unlikely(f2fs_cp_error(sbi))) {
f2fs_put_page(last_page, 0);
pagevec_release(&pvec);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
if (!IS_DNODE(page) || !is_cold_node(page))
@@ -1364,6 +1507,9 @@
f2fs_wait_on_page_writeback(page, NODE, true);
BUG_ON(PageWriteback(page));
+ set_fsync_mark(page, 0);
+ set_dentry_mark(page, 0);
+
if (!atomic || page == last_page) {
set_fsync_mark(page, 1);
if (IS_INODE(page)) {
@@ -1381,13 +1527,16 @@
if (!clear_page_dirty_for_io(page))
goto continue_unlock;
- ret = NODE_MAPPING(sbi)->a_ops->writepage(page, wbc);
+ ret = __write_node_page(page, atomic &&
+ page == last_page,
+ &submitted, wbc, true,
+ FS_NODE_IO);
if (ret) {
unlock_page(page);
f2fs_put_page(last_page, 0);
break;
- } else {
- nwritten++;
+ } else if (submitted) {
+ last_idx = page->index;
}
if (page == last_page) {
@@ -1407,17 +1556,19 @@
"Retry to write fsync mark: ino=%u, idx=%lx",
ino, last_page->index);
lock_page(last_page);
+ f2fs_wait_on_page_writeback(last_page, NODE, true);
set_page_dirty(last_page);
unlock_page(last_page);
goto retry;
}
-
- if (nwritten)
- f2fs_submit_merged_bio_cond(sbi, NULL, NULL, ino, NODE, WRITE);
+out:
+ if (last_idx != ULONG_MAX)
+ f2fs_submit_merged_write_cond(sbi, NULL, ino, last_idx, NODE);
return ret ? -EIO: 0;
}
-int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc)
+int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc,
+ bool do_balance, enum iostat_type io_type)
{
pgoff_t index, end;
struct pagevec pvec;
@@ -1441,12 +1592,7 @@
for (i = 0; i < nr_pages; i++) {
struct page *page = pvec.pages[i];
-
- if (unlikely(f2fs_cp_error(sbi))) {
- pagevec_release(&pvec);
- ret = -EIO;
- goto out;
- }
+ bool submitted = false;
/*
* flushing sequence with step:
@@ -1494,9 +1640,11 @@
set_fsync_mark(page, 0);
set_dentry_mark(page, 0);
- if (NODE_MAPPING(sbi)->a_ops->writepage(page, wbc))
+ ret = __write_node_page(page, false, &submitted,
+ wbc, do_balance, io_type);
+ if (ret)
unlock_page(page);
- else
+ else if (submitted)
nwritten++;
if (--wbc->nr_to_write == 0)
@@ -1515,9 +1663,12 @@
step++;
goto next_step;
}
-out:
+
if (nwritten)
- f2fs_submit_merged_bio(sbi, NODE, WRITE);
+ f2fs_submit_merged_write(sbi, NODE);
+
+ if (unlikely(f2fs_cp_error(sbi)))
+ return -EIO;
return ret;
}
@@ -1560,72 +1711,6 @@
return ret;
}
-static int f2fs_write_node_page(struct page *page,
- struct writeback_control *wbc)
-{
- struct f2fs_sb_info *sbi = F2FS_P_SB(page);
- nid_t nid;
- struct node_info ni;
- struct f2fs_io_info fio = {
- .sbi = sbi,
- .type = NODE,
- .op = REQ_OP_WRITE,
- .op_flags = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : 0,
- .page = page,
- .encrypted_page = NULL,
- };
-
- trace_f2fs_writepage(page, NODE);
-
- if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
- goto redirty_out;
- if (unlikely(f2fs_cp_error(sbi)))
- goto redirty_out;
-
- /* get old block addr of this node page */
- nid = nid_of_node(page);
- f2fs_bug_on(sbi, page->index != nid);
-
- if (wbc->for_reclaim) {
- if (!down_read_trylock(&sbi->node_write))
- goto redirty_out;
- } else {
- down_read(&sbi->node_write);
- }
-
- get_node_info(sbi, nid, &ni);
-
- /* This page is already truncated */
- if (unlikely(ni.blk_addr == NULL_ADDR)) {
- ClearPageUptodate(page);
- dec_page_count(sbi, F2FS_DIRTY_NODES);
- up_read(&sbi->node_write);
- unlock_page(page);
- return 0;
- }
-
- set_page_writeback(page);
- fio.old_blkaddr = ni.blk_addr;
- write_node_page(nid, &fio);
- set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(page));
- dec_page_count(sbi, F2FS_DIRTY_NODES);
- up_read(&sbi->node_write);
-
- if (wbc->for_reclaim)
- f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, NODE, WRITE);
-
- unlock_page(page);
-
- if (unlikely(f2fs_cp_error(sbi)))
- f2fs_submit_merged_bio(sbi, NODE, WRITE);
-
- return 0;
-
-redirty_out:
- redirty_page_for_writepage(wbc, page);
- return AOP_WRITEPAGE_ACTIVATE;
-}
-
static int f2fs_write_node_pages(struct address_space *mapping,
struct writeback_control *wbc)
{
@@ -1633,6 +1718,9 @@
struct blk_plug plug;
long diff;
+ if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
+ goto skip_write;
+
/* balancing f2fs's metadata in background */
f2fs_balance_fs_bg(sbi);
@@ -1645,7 +1733,7 @@
diff = nr_pages_to_write(sbi, NODE, wbc);
wbc->sync_mode = WB_SYNC_NONE;
blk_start_plug(&plug);
- sync_node_pages(sbi, wbc);
+ sync_node_pages(sbi, wbc, true, FS_NODE_IO);
blk_finish_plug(&plug);
wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff);
return 0;
@@ -1692,70 +1780,165 @@
return radix_tree_lookup(&nm_i->free_nid_root, n);
}
-static void __del_from_free_nid_list(struct f2fs_nm_info *nm_i,
- struct free_nid *i)
+static int __insert_free_nid(struct f2fs_sb_info *sbi,
+ struct free_nid *i, enum nid_state state)
{
- list_del(&i->list);
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+
+ int err = radix_tree_insert(&nm_i->free_nid_root, i->nid, i);
+ if (err)
+ return err;
+
+ f2fs_bug_on(sbi, state != i->state);
+ nm_i->nid_cnt[state]++;
+ if (state == FREE_NID)
+ list_add_tail(&i->list, &nm_i->free_nid_list);
+ return 0;
+}
+
+static void __remove_free_nid(struct f2fs_sb_info *sbi,
+ struct free_nid *i, enum nid_state state)
+{
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+
+ f2fs_bug_on(sbi, state != i->state);
+ nm_i->nid_cnt[state]--;
+ if (state == FREE_NID)
+ list_del(&i->list);
radix_tree_delete(&nm_i->free_nid_root, i->nid);
}
-static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
+static void __move_free_nid(struct f2fs_sb_info *sbi, struct free_nid *i,
+ enum nid_state org_state, enum nid_state dst_state)
{
struct f2fs_nm_info *nm_i = NM_I(sbi);
- struct free_nid *i;
- struct nat_entry *ne;
- if (!available_free_memory(sbi, FREE_NIDS))
- return -1;
+ f2fs_bug_on(sbi, org_state != i->state);
+ i->state = dst_state;
+ nm_i->nid_cnt[org_state]--;
+ nm_i->nid_cnt[dst_state]++;
+
+ switch (dst_state) {
+ case PREALLOC_NID:
+ list_del(&i->list);
+ break;
+ case FREE_NID:
+ list_add_tail(&i->list, &nm_i->free_nid_list);
+ break;
+ default:
+ BUG_ON(1);
+ }
+}
+
+static void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid,
+ bool set, bool build)
+{
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+ unsigned int nat_ofs = NAT_BLOCK_OFFSET(nid);
+ unsigned int nid_ofs = nid - START_NID(nid);
+
+ if (!test_bit_le(nat_ofs, nm_i->nat_block_bitmap))
+ return;
+
+ if (set) {
+ if (test_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]))
+ return;
+ __set_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]);
+ nm_i->free_nid_count[nat_ofs]++;
+ } else {
+ if (!test_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]))
+ return;
+ __clear_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]);
+ if (!build)
+ nm_i->free_nid_count[nat_ofs]--;
+ }
+}
+
+/* return if the nid is recognized as free */
+static bool add_free_nid(struct f2fs_sb_info *sbi,
+ nid_t nid, bool build, bool update)
+{
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+ struct free_nid *i, *e;
+ struct nat_entry *ne;
+ int err = -EINVAL;
+ bool ret = false;
/* 0 nid should not be used */
if (unlikely(nid == 0))
- return 0;
-
- if (build) {
- /* do not add allocated nids */
- ne = __lookup_nat_cache(nm_i, nid);
- if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) ||
- nat_get_blkaddr(ne) != NULL_ADDR))
- return 0;
- }
+ return false;
i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS);
i->nid = nid;
- i->state = NID_NEW;
+ i->state = FREE_NID;
- if (radix_tree_preload(GFP_NOFS)) {
- kmem_cache_free(free_nid_slab, i);
- return 0;
- }
+ radix_tree_preload(GFP_NOFS | __GFP_NOFAIL);
- spin_lock(&nm_i->free_nid_list_lock);
- if (radix_tree_insert(&nm_i->free_nid_root, i->nid, i)) {
- spin_unlock(&nm_i->free_nid_list_lock);
- radix_tree_preload_end();
- kmem_cache_free(free_nid_slab, i);
- return 0;
+ spin_lock(&nm_i->nid_list_lock);
+
+ if (build) {
+ /*
+ * Thread A Thread B
+ * - f2fs_create
+ * - f2fs_new_inode
+ * - alloc_nid
+ * - __insert_nid_to_list(PREALLOC_NID)
+ * - f2fs_balance_fs_bg
+ * - build_free_nids
+ * - __build_free_nids
+ * - scan_nat_page
+ * - add_free_nid
+ * - __lookup_nat_cache
+ * - f2fs_add_link
+ * - init_inode_metadata
+ * - new_inode_page
+ * - new_node_page
+ * - set_node_addr
+ * - alloc_nid_done
+ * - __remove_nid_from_list(PREALLOC_NID)
+ * - __insert_nid_to_list(FREE_NID)
+ */
+ ne = __lookup_nat_cache(nm_i, nid);
+ if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) ||
+ nat_get_blkaddr(ne) != NULL_ADDR))
+ goto err_out;
+
+ e = __lookup_free_nid_list(nm_i, nid);
+ if (e) {
+ if (e->state == FREE_NID)
+ ret = true;
+ goto err_out;
+ }
}
- list_add_tail(&i->list, &nm_i->free_nid_list);
- nm_i->fcnt++;
- spin_unlock(&nm_i->free_nid_list_lock);
+ ret = true;
+ err = __insert_free_nid(sbi, i, FREE_NID);
+err_out:
+ if (update) {
+ update_free_nid_bitmap(sbi, nid, ret, build);
+ if (!build)
+ nm_i->available_nids++;
+ }
+ spin_unlock(&nm_i->nid_list_lock);
radix_tree_preload_end();
- return 1;
+
+ if (err)
+ kmem_cache_free(free_nid_slab, i);
+ return ret;
}
-static void remove_free_nid(struct f2fs_nm_info *nm_i, nid_t nid)
+static void remove_free_nid(struct f2fs_sb_info *sbi, nid_t nid)
{
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
struct free_nid *i;
bool need_free = false;
- spin_lock(&nm_i->free_nid_list_lock);
+ spin_lock(&nm_i->nid_list_lock);
i = __lookup_free_nid_list(nm_i, nid);
- if (i && i->state == NID_NEW) {
- __del_from_free_nid_list(nm_i, i);
- nm_i->fcnt--;
+ if (i && i->state == FREE_NID) {
+ __remove_free_nid(sbi, i, FREE_NID);
need_free = true;
}
- spin_unlock(&nm_i->free_nid_list_lock);
+ spin_unlock(&nm_i->nid_list_lock);
if (need_free)
kmem_cache_free(free_nid_slab, i);
@@ -1767,36 +1950,106 @@
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct f2fs_nat_block *nat_blk = page_address(nat_page);
block_t blk_addr;
+ unsigned int nat_ofs = NAT_BLOCK_OFFSET(start_nid);
int i;
+ __set_bit_le(nat_ofs, nm_i->nat_block_bitmap);
+
i = start_nid % NAT_ENTRY_PER_BLOCK;
for (; i < NAT_ENTRY_PER_BLOCK; i++, start_nid++) {
-
if (unlikely(start_nid >= nm_i->max_nid))
break;
blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr);
f2fs_bug_on(sbi, blk_addr == NEW_ADDR);
if (blk_addr == NULL_ADDR) {
- if (add_free_nid(sbi, start_nid, true) < 0)
- break;
+ add_free_nid(sbi, start_nid, true, true);
+ } else {
+ spin_lock(&NM_I(sbi)->nid_list_lock);
+ update_free_nid_bitmap(sbi, start_nid, false, true);
+ spin_unlock(&NM_I(sbi)->nid_list_lock);
}
}
}
-void build_free_nids(struct f2fs_sb_info *sbi)
+static void scan_curseg_cache(struct f2fs_sb_info *sbi)
{
- struct f2fs_nm_info *nm_i = NM_I(sbi);
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
struct f2fs_journal *journal = curseg->journal;
+ int i;
+
+ down_read(&curseg->journal_rwsem);
+ for (i = 0; i < nats_in_cursum(journal); i++) {
+ block_t addr;
+ nid_t nid;
+
+ addr = le32_to_cpu(nat_in_journal(journal, i).block_addr);
+ nid = le32_to_cpu(nid_in_journal(journal, i));
+ if (addr == NULL_ADDR)
+ add_free_nid(sbi, nid, true, false);
+ else
+ remove_free_nid(sbi, nid);
+ }
+ up_read(&curseg->journal_rwsem);
+}
+
+static void scan_free_nid_bits(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+ unsigned int i, idx;
+ nid_t nid;
+
+ down_read(&nm_i->nat_tree_lock);
+
+ for (i = 0; i < nm_i->nat_blocks; i++) {
+ if (!test_bit_le(i, nm_i->nat_block_bitmap))
+ continue;
+ if (!nm_i->free_nid_count[i])
+ continue;
+ for (idx = 0; idx < NAT_ENTRY_PER_BLOCK; idx++) {
+ idx = find_next_bit_le(nm_i->free_nid_bitmap[i],
+ NAT_ENTRY_PER_BLOCK, idx);
+ if (idx >= NAT_ENTRY_PER_BLOCK)
+ break;
+
+ nid = i * NAT_ENTRY_PER_BLOCK + idx;
+ add_free_nid(sbi, nid, true, false);
+
+ if (nm_i->nid_cnt[FREE_NID] >= MAX_FREE_NIDS)
+ goto out;
+ }
+ }
+out:
+ scan_curseg_cache(sbi);
+
+ up_read(&nm_i->nat_tree_lock);
+}
+
+static void __build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
+{
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
int i = 0;
nid_t nid = nm_i->next_scan_nid;
+ if (unlikely(nid >= nm_i->max_nid))
+ nid = 0;
+
/* Enough entries */
- if (nm_i->fcnt >= NAT_ENTRY_PER_BLOCK)
+ if (nm_i->nid_cnt[FREE_NID] >= NAT_ENTRY_PER_BLOCK)
return;
+ if (!sync && !available_free_memory(sbi, FREE_NIDS))
+ return;
+
+ if (!mount) {
+ /* try to find free nids in free_nid_bitmap */
+ scan_free_nid_bits(sbi);
+
+ if (nm_i->nid_cnt[FREE_NID] >= NAT_ENTRY_PER_BLOCK)
+ return;
+ }
+
/* readahead nat pages to be scanned */
ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), FREE_NID_PAGES,
META_NAT, true);
@@ -1804,10 +2057,13 @@
down_read(&nm_i->nat_tree_lock);
while (1) {
- struct page *page = get_current_nat_page(sbi, nid);
+ if (!test_bit_le(NAT_BLOCK_OFFSET(nid),
+ nm_i->nat_block_bitmap)) {
+ struct page *page = get_current_nat_page(sbi, nid);
- scan_nat_page(sbi, page, nid);
- f2fs_put_page(page, 1);
+ scan_nat_page(sbi, page, nid);
+ f2fs_put_page(page, 1);
+ }
nid += (NAT_ENTRY_PER_BLOCK - (nid % NAT_ENTRY_PER_BLOCK));
if (unlikely(nid >= nm_i->max_nid))
@@ -1821,24 +2077,21 @@
nm_i->next_scan_nid = nid;
/* find free nids from current sum_pages */
- down_read(&curseg->journal_rwsem);
- for (i = 0; i < nats_in_cursum(journal); i++) {
- block_t addr;
+ scan_curseg_cache(sbi);
- addr = le32_to_cpu(nat_in_journal(journal, i).block_addr);
- nid = le32_to_cpu(nid_in_journal(journal, i));
- if (addr == NULL_ADDR)
- add_free_nid(sbi, nid, true);
- else
- remove_free_nid(nm_i, nid);
- }
- up_read(&curseg->journal_rwsem);
up_read(&nm_i->nat_tree_lock);
ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nm_i->next_scan_nid),
nm_i->ra_nid_pages, META_NAT, false);
}
+void build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
+{
+ mutex_lock(&NM_I(sbi)->build_lock);
+ __build_free_nids(sbi, sync, mount);
+ mutex_unlock(&NM_I(sbi)->build_lock);
+}
+
/*
* If this function returns success, caller can obtain a new nid
* from second parameter of this function.
@@ -1850,34 +2103,37 @@
struct free_nid *i = NULL;
retry:
#ifdef CONFIG_F2FS_FAULT_INJECTION
- if (time_to_inject(sbi, FAULT_ALLOC_NID))
+ if (time_to_inject(sbi, FAULT_ALLOC_NID)) {
+ f2fs_show_injection_info(FAULT_ALLOC_NID);
return false;
+ }
#endif
- if (unlikely(sbi->total_valid_node_count + 1 > nm_i->available_nids))
- return false;
+ spin_lock(&nm_i->nid_list_lock);
- spin_lock(&nm_i->free_nid_list_lock);
+ if (unlikely(nm_i->available_nids == 0)) {
+ spin_unlock(&nm_i->nid_list_lock);
+ return false;
+ }
/* We should not use stale free nids created by build_free_nids */
- if (nm_i->fcnt && !on_build_free_nids(nm_i)) {
+ if (nm_i->nid_cnt[FREE_NID] && !on_build_free_nids(nm_i)) {
f2fs_bug_on(sbi, list_empty(&nm_i->free_nid_list));
- list_for_each_entry(i, &nm_i->free_nid_list, list)
- if (i->state == NID_NEW)
- break;
-
- f2fs_bug_on(sbi, i->state != NID_NEW);
+ i = list_first_entry(&nm_i->free_nid_list,
+ struct free_nid, list);
*nid = i->nid;
- i->state = NID_ALLOC;
- nm_i->fcnt--;
- spin_unlock(&nm_i->free_nid_list_lock);
+
+ __move_free_nid(sbi, i, FREE_NID, PREALLOC_NID);
+ nm_i->available_nids--;
+
+ update_free_nid_bitmap(sbi, *nid, false, false);
+
+ spin_unlock(&nm_i->nid_list_lock);
return true;
}
- spin_unlock(&nm_i->free_nid_list_lock);
+ spin_unlock(&nm_i->nid_list_lock);
/* Let's scan nat pages and its caches to get free nids */
- mutex_lock(&nm_i->build_lock);
- build_free_nids(sbi);
- mutex_unlock(&nm_i->build_lock);
+ build_free_nids(sbi, true, false);
goto retry;
}
@@ -1889,11 +2145,11 @@
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct free_nid *i;
- spin_lock(&nm_i->free_nid_list_lock);
+ spin_lock(&nm_i->nid_list_lock);
i = __lookup_free_nid_list(nm_i, nid);
- f2fs_bug_on(sbi, !i || i->state != NID_ALLOC);
- __del_from_free_nid_list(nm_i, i);
- spin_unlock(&nm_i->free_nid_list_lock);
+ f2fs_bug_on(sbi, !i);
+ __remove_free_nid(sbi, i, PREALLOC_NID);
+ spin_unlock(&nm_i->nid_list_lock);
kmem_cache_free(free_nid_slab, i);
}
@@ -1910,17 +2166,22 @@
if (!nid)
return;
- spin_lock(&nm_i->free_nid_list_lock);
+ spin_lock(&nm_i->nid_list_lock);
i = __lookup_free_nid_list(nm_i, nid);
- f2fs_bug_on(sbi, !i || i->state != NID_ALLOC);
+ f2fs_bug_on(sbi, !i);
+
if (!available_free_memory(sbi, FREE_NIDS)) {
- __del_from_free_nid_list(nm_i, i);
+ __remove_free_nid(sbi, i, PREALLOC_NID);
need_free = true;
} else {
- i->state = NID_NEW;
- nm_i->fcnt++;
+ __move_free_nid(sbi, i, PREALLOC_NID, FREE_NID);
}
- spin_unlock(&nm_i->free_nid_list_lock);
+
+ nm_i->available_nids++;
+
+ update_free_nid_bitmap(sbi, nid, true, false);
+
+ spin_unlock(&nm_i->nid_list_lock);
if (need_free)
kmem_cache_free(free_nid_slab, i);
@@ -1932,24 +2193,23 @@
struct free_nid *i, *next;
int nr = nr_shrink;
- if (nm_i->fcnt <= MAX_FREE_NIDS)
+ if (nm_i->nid_cnt[FREE_NID] <= MAX_FREE_NIDS)
return 0;
if (!mutex_trylock(&nm_i->build_lock))
return 0;
- spin_lock(&nm_i->free_nid_list_lock);
+ spin_lock(&nm_i->nid_list_lock);
list_for_each_entry_safe(i, next, &nm_i->free_nid_list, list) {
- if (nr_shrink <= 0 || nm_i->fcnt <= MAX_FREE_NIDS)
+ if (nr_shrink <= 0 ||
+ nm_i->nid_cnt[FREE_NID] <= MAX_FREE_NIDS)
break;
- if (i->state == NID_ALLOC)
- continue;
- __del_from_free_nid_list(nm_i, i);
+
+ __remove_free_nid(sbi, i, FREE_NID);
kmem_cache_free(free_nid_slab, i);
- nm_i->fcnt--;
nr_shrink--;
}
- spin_unlock(&nm_i->free_nid_list_lock);
+ spin_unlock(&nm_i->nid_list_lock);
mutex_unlock(&nm_i->build_lock);
return nr - nr_shrink;
@@ -1966,13 +2226,15 @@
f2fs_bug_on(F2FS_I_SB(inode), IS_ERR(ipage));
ri = F2FS_INODE(page);
- if (!(ri->i_inline & F2FS_INLINE_XATTR)) {
+ if (ri->i_inline & F2FS_INLINE_XATTR) {
+ set_inode_flag(inode, FI_INLINE_XATTR);
+ } else {
clear_inode_flag(inode, FI_INLINE_XATTR);
goto update_inode;
}
- dst_addr = inline_xattr_addr(ipage);
- src_addr = inline_xattr_addr(page);
+ dst_addr = inline_xattr_addr(inode, ipage);
+ src_addr = inline_xattr_addr(inode, page);
inline_size = inline_xattr_size(inode);
f2fs_wait_on_page_writeback(ipage, NODE, true);
@@ -1982,38 +2244,46 @@
f2fs_put_page(ipage, 1);
}
-void recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr)
+int recover_xattr_data(struct inode *inode, struct page *page)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
nid_t prev_xnid = F2FS_I(inode)->i_xattr_nid;
- nid_t new_xnid = nid_of_node(page);
+ nid_t new_xnid;
+ struct dnode_of_data dn;
struct node_info ni;
+ struct page *xpage;
- /* 1: invalidate the previous xattr nid */
if (!prev_xnid)
goto recover_xnid;
- /* Deallocate node address */
+ /* 1: invalidate the previous xattr nid */
get_node_info(sbi, prev_xnid, &ni);
- f2fs_bug_on(sbi, ni.blk_addr == NULL_ADDR);
invalidate_blocks(sbi, ni.blk_addr);
- dec_valid_node_count(sbi, inode);
+ dec_valid_node_count(sbi, inode, false);
set_node_addr(sbi, &ni, NULL_ADDR, false);
recover_xnid:
- /* 2: allocate new xattr nid */
- if (unlikely(!inc_valid_node_count(sbi, inode)))
- f2fs_bug_on(sbi, 1);
+ /* 2: update xattr nid in inode */
+ if (!alloc_nid(sbi, &new_xnid))
+ return -ENOSPC;
- remove_free_nid(NM_I(sbi), new_xnid);
- get_node_info(sbi, new_xnid, &ni);
- ni.ino = inode->i_ino;
- set_node_addr(sbi, &ni, NEW_ADDR, false);
- f2fs_i_xnid_write(inode, new_xnid);
+ set_new_dnode(&dn, inode, NULL, NULL, new_xnid);
+ xpage = new_node_page(&dn, XATTR_NODE_OFFSET);
+ if (IS_ERR(xpage)) {
+ alloc_nid_failed(sbi, new_xnid);
+ return PTR_ERR(xpage);
+ }
- /* 3: update xattr blkaddr */
- refresh_sit_entry(sbi, NEW_ADDR, blkaddr);
- set_node_addr(sbi, &ni, blkaddr, false);
+ alloc_nid_done(sbi, new_xnid);
+ update_inode_page(inode);
+
+ /* 3: update and set xattr node page dirty */
+ memcpy(F2FS_NODE(xpage), F2FS_NODE(page), VALID_XATTR_BLOCK_SIZE);
+
+ set_page_dirty(xpage);
+ f2fs_put_page(xpage, 1);
+
+ return 0;
}
int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
@@ -2035,7 +2305,7 @@
}
/* Should not use this inode from free nid list */
- remove_free_nid(NM_I(sbi), ino);
+ remove_free_nid(sbi, ino);
if (!PageUptodate(ipage))
SetPageUptodate(ipage);
@@ -2049,12 +2319,25 @@
dst->i_blocks = cpu_to_le64(1);
dst->i_links = cpu_to_le32(1);
dst->i_xattr_nid = 0;
- dst->i_inline = src->i_inline & F2FS_INLINE_XATTR;
+ dst->i_inline = src->i_inline & (F2FS_INLINE_XATTR | F2FS_EXTRA_ATTR);
+ if (dst->i_inline & F2FS_EXTRA_ATTR) {
+ dst->i_extra_isize = src->i_extra_isize;
+
+ if (f2fs_sb_has_flexible_inline_xattr(sbi->sb) &&
+ F2FS_FITS_IN_INODE(src, le16_to_cpu(src->i_extra_isize),
+ i_inline_xattr_size))
+ dst->i_inline_xattr_size = src->i_inline_xattr_size;
+
+ if (f2fs_sb_has_project_quota(sbi->sb) &&
+ F2FS_FITS_IN_INODE(src, le16_to_cpu(src->i_extra_isize),
+ i_projid))
+ dst->i_projid = src->i_projid;
+ }
new_ni = old_ni;
new_ni.ino = ino;
- if (unlikely(!inc_valid_node_count(sbi, NULL)))
+ if (unlikely(inc_valid_node_count(sbi, NULL, true)))
WARN_ON(1);
set_node_addr(sbi, &new_ni, NEW_ADDR, false);
inc_valid_inode_count(sbi);
@@ -2063,13 +2346,12 @@
return 0;
}
-int restore_node_summary(struct f2fs_sb_info *sbi,
+void restore_node_summary(struct f2fs_sb_info *sbi,
unsigned int segno, struct f2fs_summary_block *sum)
{
struct f2fs_node *rn;
struct f2fs_summary *sum_entry;
block_t addr;
- int bio_blocks = MAX_BIO_BLOCKS(sbi);
int i, idx, last_offset, nrpages;
/* scan the node segment */
@@ -2078,7 +2360,7 @@
sum_entry = &sum->entries[0];
for (i = 0; i < last_offset; i += nrpages, addr += nrpages) {
- nrpages = min(last_offset - i, bio_blocks);
+ nrpages = min(last_offset - i, BIO_MAX_PAGES);
/* readahead node pages */
ra_meta_pages(sbi, addr, nrpages, META_POR, true);
@@ -2097,7 +2379,6 @@
invalidate_mapping_pages(META_MAPPING(sbi), addr,
addr + nrpages);
}
- return 0;
}
static void remove_nats_in_journal(struct f2fs_sb_info *sbi)
@@ -2117,9 +2398,22 @@
ne = __lookup_nat_cache(nm_i, nid);
if (!ne) {
- ne = grab_nat_entry(nm_i, nid);
- node_info_from_raw_nat(&ne->ni, &raw_ne);
+ ne = __alloc_nat_entry(nid, true);
+ __init_nat_entry(nm_i, ne, &raw_ne, true);
}
+
+ /*
+ * if a free nat in journal has not been used after last
+ * checkpoint, we should remove it from available nids,
+ * since later we will add it again.
+ */
+ if (!get_nat_flag(ne, IS_DIRTY) &&
+ le32_to_cpu(raw_ne.block_addr) == NULL_ADDR) {
+ spin_lock(&nm_i->nid_list_lock);
+ nm_i->available_nids--;
+ spin_unlock(&nm_i->nid_list_lock);
+ }
+
__set_nat_cache_dirty(nm_i, ne);
}
update_nats_in_cursum(journal, -i);
@@ -2144,8 +2438,41 @@
list_add_tail(&nes->set_list, head);
}
+static void __update_nat_bits(struct f2fs_sb_info *sbi, nid_t start_nid,
+ struct page *page)
+{
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+ unsigned int nat_index = start_nid / NAT_ENTRY_PER_BLOCK;
+ struct f2fs_nat_block *nat_blk = page_address(page);
+ int valid = 0;
+ int i = 0;
+
+ if (!enabled_nat_bits(sbi, NULL))
+ return;
+
+ if (nat_index == 0) {
+ valid = 1;
+ i = 1;
+ }
+ for (; i < NAT_ENTRY_PER_BLOCK; i++) {
+ if (nat_blk->entries[i].block_addr != NULL_ADDR)
+ valid++;
+ }
+ if (valid == 0) {
+ __set_bit_le(nat_index, nm_i->empty_nat_bits);
+ __clear_bit_le(nat_index, nm_i->full_nat_bits);
+ return;
+ }
+
+ __clear_bit_le(nat_index, nm_i->empty_nat_bits);
+ if (valid == NAT_ENTRY_PER_BLOCK)
+ __set_bit_le(nat_index, nm_i->full_nat_bits);
+ else
+ __clear_bit_le(nat_index, nm_i->full_nat_bits);
+}
+
static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
- struct nat_entry_set *set)
+ struct nat_entry_set *set, struct cp_control *cpc)
{
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
struct f2fs_journal *journal = curseg->journal;
@@ -2160,7 +2487,8 @@
* #1, flush nat entries to journal in current hot data summary block.
* #2, flush nat entries to nat page.
*/
- if (!__has_cursum_space(journal, set->entry_cnt, NAT_JOURNAL))
+ if (enabled_nat_bits(sbi, cpc) ||
+ !__has_cursum_space(journal, set->entry_cnt, NAT_JOURNAL))
to_journal = false;
if (to_journal) {
@@ -2177,8 +2505,7 @@
nid_t nid = nat_get_nid(ne);
int offset;
- if (nat_get_blkaddr(ne) == NEW_ADDR)
- continue;
+ f2fs_bug_on(sbi, nat_get_blkaddr(ne) == NEW_ADDR);
if (to_journal) {
offset = lookup_journal_in_cursum(journal,
@@ -2191,26 +2518,34 @@
}
raw_nat_from_node_info(raw_ne, &ne->ni);
nat_reset_flag(ne);
- __clear_nat_cache_dirty(NM_I(sbi), ne);
- if (nat_get_blkaddr(ne) == NULL_ADDR)
- add_free_nid(sbi, nid, false);
+ __clear_nat_cache_dirty(NM_I(sbi), set, ne);
+ if (nat_get_blkaddr(ne) == NULL_ADDR) {
+ add_free_nid(sbi, nid, false, true);
+ } else {
+ spin_lock(&NM_I(sbi)->nid_list_lock);
+ update_free_nid_bitmap(sbi, nid, false, false);
+ spin_unlock(&NM_I(sbi)->nid_list_lock);
+ }
}
- if (to_journal)
+ if (to_journal) {
up_write(&curseg->journal_rwsem);
- else
+ } else {
+ __update_nat_bits(sbi, start_nid, page);
f2fs_put_page(page, 1);
+ }
- f2fs_bug_on(sbi, set->entry_cnt);
-
- radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set);
- kmem_cache_free(nat_entry_set_slab, set);
+ /* Allow dirty nats by node block allocation in write_begin */
+ if (!set->entry_cnt) {
+ radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set);
+ kmem_cache_free(nat_entry_set_slab, set);
+ }
}
/*
* This function is called during the checkpointing process.
*/
-void flush_nat_entries(struct f2fs_sb_info *sbi)
+void flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
{
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
@@ -2231,7 +2566,8 @@
* entries, remove all entries from journal and merge them
* into nat entry set.
*/
- if (!__has_cursum_space(journal, nm_i->dirty_nat_cnt, NAT_JOURNAL))
+ if (enabled_nat_bits(sbi, cpc) ||
+ !__has_cursum_space(journal, nm_i->dirty_nat_cnt, NAT_JOURNAL))
remove_nats_in_journal(sbi);
while ((found = __gang_lookup_nat_set(nm_i,
@@ -2245,11 +2581,86 @@
/* flush dirty nats in nat entry set */
list_for_each_entry_safe(set, tmp, &sets, set_list)
- __flush_nat_entry_set(sbi, set);
+ __flush_nat_entry_set(sbi, set, cpc);
up_write(&nm_i->nat_tree_lock);
+ /* Allow dirty nats by node block allocation in write_begin */
+}
- f2fs_bug_on(sbi, nm_i->dirty_nat_cnt);
+static int __get_nat_bitmaps(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+ unsigned int nat_bits_bytes = nm_i->nat_blocks / BITS_PER_BYTE;
+ unsigned int i;
+ __u64 cp_ver = cur_cp_version(ckpt);
+ block_t nat_bits_addr;
+
+ if (!enabled_nat_bits(sbi, NULL))
+ return 0;
+
+ nm_i->nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + 8 +
+ F2FS_BLKSIZE - 1);
+ nm_i->nat_bits = f2fs_kzalloc(sbi,
+ nm_i->nat_bits_blocks << F2FS_BLKSIZE_BITS, GFP_KERNEL);
+ if (!nm_i->nat_bits)
+ return -ENOMEM;
+
+ nat_bits_addr = __start_cp_addr(sbi) + sbi->blocks_per_seg -
+ nm_i->nat_bits_blocks;
+ for (i = 0; i < nm_i->nat_bits_blocks; i++) {
+ struct page *page = get_meta_page(sbi, nat_bits_addr++);
+
+ memcpy(nm_i->nat_bits + (i << F2FS_BLKSIZE_BITS),
+ page_address(page), F2FS_BLKSIZE);
+ f2fs_put_page(page, 1);
+ }
+
+ cp_ver |= (cur_cp_crc(ckpt) << 32);
+ if (cpu_to_le64(cp_ver) != *(__le64 *)nm_i->nat_bits) {
+ disable_nat_bits(sbi, true);
+ return 0;
+ }
+
+ nm_i->full_nat_bits = nm_i->nat_bits + 8;
+ nm_i->empty_nat_bits = nm_i->full_nat_bits + nat_bits_bytes;
+
+ f2fs_msg(sbi->sb, KERN_NOTICE, "Found nat_bits in checkpoint");
+ return 0;
+}
+
+static inline void load_free_nid_bitmap(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+ unsigned int i = 0;
+ nid_t nid, last_nid;
+
+ if (!enabled_nat_bits(sbi, NULL))
+ return;
+
+ for (i = 0; i < nm_i->nat_blocks; i++) {
+ i = find_next_bit_le(nm_i->empty_nat_bits, nm_i->nat_blocks, i);
+ if (i >= nm_i->nat_blocks)
+ break;
+
+ __set_bit_le(i, nm_i->nat_block_bitmap);
+
+ nid = i * NAT_ENTRY_PER_BLOCK;
+ last_nid = nid + NAT_ENTRY_PER_BLOCK;
+
+ spin_lock(&NM_I(sbi)->nid_list_lock);
+ for (; nid < last_nid; nid++)
+ update_free_nid_bitmap(sbi, nid, true, true);
+ spin_unlock(&NM_I(sbi)->nid_list_lock);
+ }
+
+ for (i = 0; i < nm_i->nat_blocks; i++) {
+ i = find_next_bit_le(nm_i->full_nat_bits, nm_i->nat_blocks, i);
+ if (i >= nm_i->nat_blocks)
+ break;
+
+ __set_bit_le(i, nm_i->nat_block_bitmap);
+ }
}
static int init_node_manager(struct f2fs_sb_info *sbi)
@@ -2257,19 +2668,21 @@
struct f2fs_super_block *sb_raw = F2FS_RAW_SUPER(sbi);
struct f2fs_nm_info *nm_i = NM_I(sbi);
unsigned char *version_bitmap;
- unsigned int nat_segs, nat_blocks;
+ unsigned int nat_segs;
+ int err;
nm_i->nat_blkaddr = le32_to_cpu(sb_raw->nat_blkaddr);
/* segment_count_nat includes pair segment so divide to 2. */
nat_segs = le32_to_cpu(sb_raw->segment_count_nat) >> 1;
- nat_blocks = nat_segs << le32_to_cpu(sb_raw->log_blocks_per_seg);
-
- nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks;
+ nm_i->nat_blocks = nat_segs << le32_to_cpu(sb_raw->log_blocks_per_seg);
+ nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nm_i->nat_blocks;
/* not used nids: 0, node, meta, (and root counted as valid node) */
- nm_i->available_nids = nm_i->max_nid - F2FS_RESERVED_NODE_NUM;
- nm_i->fcnt = 0;
+ nm_i->available_nids = nm_i->max_nid - sbi->total_valid_node_count -
+ sbi->nquota_files - F2FS_RESERVED_NODE_NUM;
+ nm_i->nid_cnt[FREE_NID] = 0;
+ nm_i->nid_cnt[PREALLOC_NID] = 0;
nm_i->nat_cnt = 0;
nm_i->ram_thresh = DEF_RAM_THRESHOLD;
nm_i->ra_nid_pages = DEF_RA_NID_PAGES;
@@ -2282,7 +2695,7 @@
INIT_LIST_HEAD(&nm_i->nat_entries);
mutex_init(&nm_i->build_lock);
- spin_lock_init(&nm_i->free_nid_list_lock);
+ spin_lock_init(&nm_i->nid_list_lock);
init_rwsem(&nm_i->nat_tree_lock);
nm_i->next_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid);
@@ -2295,6 +2708,39 @@
GFP_KERNEL);
if (!nm_i->nat_bitmap)
return -ENOMEM;
+
+ err = __get_nat_bitmaps(sbi);
+ if (err)
+ return err;
+
+#ifdef CONFIG_F2FS_CHECK_FS
+ nm_i->nat_bitmap_mir = kmemdup(version_bitmap, nm_i->bitmap_size,
+ GFP_KERNEL);
+ if (!nm_i->nat_bitmap_mir)
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static int init_free_nid_cache(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+
+ nm_i->free_nid_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks *
+ NAT_ENTRY_BITMAP_SIZE, GFP_KERNEL);
+ if (!nm_i->free_nid_bitmap)
+ return -ENOMEM;
+
+ nm_i->nat_block_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks / 8,
+ GFP_KERNEL);
+ if (!nm_i->nat_block_bitmap)
+ return -ENOMEM;
+
+ nm_i->free_nid_count = f2fs_kvzalloc(sbi, nm_i->nat_blocks *
+ sizeof(unsigned short), GFP_KERNEL);
+ if (!nm_i->free_nid_count)
+ return -ENOMEM;
return 0;
}
@@ -2302,7 +2748,8 @@
{
int err;
- sbi->nm_info = kzalloc(sizeof(struct f2fs_nm_info), GFP_KERNEL);
+ sbi->nm_info = f2fs_kzalloc(sbi, sizeof(struct f2fs_nm_info),
+ GFP_KERNEL);
if (!sbi->nm_info)
return -ENOMEM;
@@ -2310,7 +2757,14 @@
if (err)
return err;
- build_free_nids(sbi);
+ err = init_free_nid_cache(sbi);
+ if (err)
+ return err;
+
+ /* load free nid status from nat_bits table */
+ load_free_nid_bitmap(sbi);
+
+ build_free_nids(sbi, true, true);
return 0;
}
@@ -2327,17 +2781,17 @@
return;
/* destroy free nid list */
- spin_lock(&nm_i->free_nid_list_lock);
+ spin_lock(&nm_i->nid_list_lock);
list_for_each_entry_safe(i, next_i, &nm_i->free_nid_list, list) {
- f2fs_bug_on(sbi, i->state == NID_ALLOC);
- __del_from_free_nid_list(nm_i, i);
- nm_i->fcnt--;
- spin_unlock(&nm_i->free_nid_list_lock);
+ __remove_free_nid(sbi, i, FREE_NID);
+ spin_unlock(&nm_i->nid_list_lock);
kmem_cache_free(free_nid_slab, i);
- spin_lock(&nm_i->free_nid_list_lock);
+ spin_lock(&nm_i->nid_list_lock);
}
- f2fs_bug_on(sbi, nm_i->fcnt);
- spin_unlock(&nm_i->free_nid_list_lock);
+ f2fs_bug_on(sbi, nm_i->nid_cnt[FREE_NID]);
+ f2fs_bug_on(sbi, nm_i->nid_cnt[PREALLOC_NID]);
+ f2fs_bug_on(sbi, !list_empty(&nm_i->free_nid_list));
+ spin_unlock(&nm_i->nid_list_lock);
/* destroy nat cache */
down_write(&nm_i->nat_tree_lock);
@@ -2367,7 +2821,15 @@
}
up_write(&nm_i->nat_tree_lock);
+ kvfree(nm_i->nat_block_bitmap);
+ kvfree(nm_i->free_nid_bitmap);
+ kvfree(nm_i->free_nid_count);
+
kfree(nm_i->nat_bitmap);
+ kfree(nm_i->nat_bits);
+#ifdef CONFIG_F2FS_CHECK_FS
+ kfree(nm_i->nat_bitmap_mir);
+#endif
sbi->nm_info = NULL;
kfree(nm_i);
}
diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h
index 868bec6..081ef0d 100644
--- a/fs/f2fs/node.h
+++ b/fs/f2fs/node.h
@@ -9,10 +9,10 @@
* published by the Free Software Foundation.
*/
/* start node id of a node block dedicated to the given node id */
-#define START_NID(nid) ((nid / NAT_ENTRY_PER_BLOCK) * NAT_ENTRY_PER_BLOCK)
+#define START_NID(nid) (((nid) / NAT_ENTRY_PER_BLOCK) * NAT_ENTRY_PER_BLOCK)
/* node block offset on the NAT area dedicated to the given start node id */
-#define NAT_BLOCK_OFFSET(start_nid) (start_nid / NAT_ENTRY_PER_BLOCK)
+#define NAT_BLOCK_OFFSET(start_nid) ((start_nid) / NAT_ENTRY_PER_BLOCK)
/* # of pages to perform synchronous readahead before building free nids */
#define FREE_NID_PAGES 8
@@ -62,16 +62,16 @@
struct node_info ni; /* in-memory node information */
};
-#define nat_get_nid(nat) (nat->ni.nid)
-#define nat_set_nid(nat, n) (nat->ni.nid = n)
-#define nat_get_blkaddr(nat) (nat->ni.blk_addr)
-#define nat_set_blkaddr(nat, b) (nat->ni.blk_addr = b)
-#define nat_get_ino(nat) (nat->ni.ino)
-#define nat_set_ino(nat, i) (nat->ni.ino = i)
-#define nat_get_version(nat) (nat->ni.version)
-#define nat_set_version(nat, v) (nat->ni.version = v)
+#define nat_get_nid(nat) ((nat)->ni.nid)
+#define nat_set_nid(nat, n) ((nat)->ni.nid = (n))
+#define nat_get_blkaddr(nat) ((nat)->ni.blk_addr)
+#define nat_set_blkaddr(nat, b) ((nat)->ni.blk_addr = (b))
+#define nat_get_ino(nat) ((nat)->ni.ino)
+#define nat_set_ino(nat, i) ((nat)->ni.ino = (i))
+#define nat_get_version(nat) ((nat)->ni.version)
+#define nat_set_version(nat, v) ((nat)->ni.version = (v))
-#define inc_node_version(version) (++version)
+#define inc_node_version(version) (++(version))
static inline void copy_node_info(struct node_info *dst,
struct node_info *src)
@@ -140,6 +140,7 @@
DIRTY_DENTS, /* indicates dirty dentry pages */
INO_ENTRIES, /* indicates inode entries */
EXTENT_CACHE, /* indicates extent cache */
+ INMEM_PAGES, /* indicates inmemory pages */
BASE_CHECK, /* check kernel status */
};
@@ -150,18 +151,10 @@
unsigned int entry_cnt; /* the # of nat entries in set */
};
-/*
- * For free nid mangement
- */
-enum nid_state {
- NID_NEW, /* newly added to free nid list */
- NID_ALLOC /* it is allocated */
-};
-
struct free_nid {
struct list_head list; /* for free node id list */
nid_t nid; /* node id */
- int state; /* in use or not: NID_NEW or NID_ALLOC */
+ int state; /* in use or not: FREE_NID or PREALLOC_NID */
};
static inline void next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid)
@@ -169,14 +162,14 @@
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct free_nid *fnid;
- spin_lock(&nm_i->free_nid_list_lock);
- if (nm_i->fcnt <= 0) {
- spin_unlock(&nm_i->free_nid_list_lock);
+ spin_lock(&nm_i->nid_list_lock);
+ if (nm_i->nid_cnt[FREE_NID] <= 0) {
+ spin_unlock(&nm_i->nid_list_lock);
return;
}
- fnid = list_entry(nm_i->free_nid_list.next, struct free_nid, list);
+ fnid = list_first_entry(&nm_i->free_nid_list, struct free_nid, list);
*nid = fnid->nid;
- spin_unlock(&nm_i->free_nid_list_lock);
+ spin_unlock(&nm_i->nid_list_lock);
}
/*
@@ -185,6 +178,12 @@
static inline void get_nat_bitmap(struct f2fs_sb_info *sbi, void *addr)
{
struct f2fs_nm_info *nm_i = NM_I(sbi);
+
+#ifdef CONFIG_F2FS_CHECK_FS
+ if (memcmp(nm_i->nat_bitmap, nm_i->nat_bitmap_mir,
+ nm_i->bitmap_size))
+ f2fs_bug_on(sbi, 1);
+#endif
memcpy(addr, nm_i->nat_bitmap, nm_i->bitmap_size);
}
@@ -193,13 +192,16 @@
struct f2fs_nm_info *nm_i = NM_I(sbi);
pgoff_t block_off;
pgoff_t block_addr;
- int seg_off;
+ /*
+ * block_off = segment_off * 512 + off_in_segment
+ * OLD = (segment_off * 512) * 2 + off_in_segment
+ * NEW = 2 * (segment_off * 512 + off_in_segment) - off_in_segment
+ */
block_off = NAT_BLOCK_OFFSET(start);
- seg_off = block_off >> sbi->log_blocks_per_seg;
block_addr = (pgoff_t)(nm_i->nat_blkaddr +
- (seg_off << sbi->log_blocks_per_seg << 1) +
+ (block_off << 1) -
(block_off & (sbi->blocks_per_seg - 1)));
if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
@@ -214,11 +216,7 @@
struct f2fs_nm_info *nm_i = NM_I(sbi);
block_addr -= nm_i->nat_blkaddr;
- if ((block_addr >> sbi->log_blocks_per_seg) % 2)
- block_addr -= sbi->blocks_per_seg;
- else
- block_addr += sbi->blocks_per_seg;
-
+ block_addr ^= 1 << sbi->log_blocks_per_seg;
return block_addr + nm_i->nat_blkaddr;
}
@@ -227,6 +225,9 @@
unsigned int block_off = NAT_BLOCK_OFFSET(start_nid);
f2fs_change_bit(block_off, nm_i->nat_bitmap);
+#ifdef CONFIG_F2FS_CHECK_FS
+ f2fs_change_bit(block_off, nm_i->nat_bitmap_mir);
+#endif
}
static inline nid_t ino_of_node(struct page *node_page)
@@ -290,14 +291,11 @@
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_P_SB(page));
struct f2fs_node *rn = F2FS_NODE(page);
- size_t crc_offset = le32_to_cpu(ckpt->checksum_offset);
- __u64 cp_ver = le64_to_cpu(ckpt->checkpoint_ver);
+ __u64 cp_ver = cur_cp_version(ckpt);
- if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
- __u64 crc = le32_to_cpu(*((__le32 *)
- ((unsigned char *)ckpt + crc_offset)));
- cp_ver |= (crc << 32);
- }
+ if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG))
+ cp_ver |= (cur_cp_crc(ckpt) << 32);
+
rn->footer.cp_ver = cpu_to_le64(cp_ver);
rn->footer.next_blkaddr = cpu_to_le32(blkaddr);
}
@@ -305,15 +303,16 @@
static inline bool is_recoverable_dnode(struct page *page)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_P_SB(page));
- size_t crc_offset = le32_to_cpu(ckpt->checksum_offset);
__u64 cp_ver = cur_cp_version(ckpt);
- if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
- __u64 crc = le32_to_cpu(*((__le32 *)
- ((unsigned char *)ckpt + crc_offset)));
- cp_ver |= (crc << 32);
- }
- return cpu_to_le64(cp_ver) == cpver_of_node(page);
+ /* Don't care crc part, if fsck.f2fs sets it. */
+ if (__is_set_ckpt_flags(ckpt, CP_NOCRC_RECOVERY_FLAG))
+ return (cp_ver << 32) == (cpver_of_node(page) << 32);
+
+ if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG))
+ cp_ver |= (cur_cp_crc(ckpt) << 32);
+
+ return cp_ver == cpver_of_node(page);
}
/*
@@ -342,7 +341,7 @@
unsigned int ofs = ofs_of_node(node_page);
if (f2fs_has_xattr_block(ofs))
- return false;
+ return true;
if (ofs == 3 || ofs == 4 + NIDS_PER_BLOCK ||
ofs == 5 + 2 * NIDS_PER_BLOCK)
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index 98c1a63..b6d1ec6 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -69,20 +69,34 @@
}
static struct fsync_inode_entry *add_fsync_inode(struct f2fs_sb_info *sbi,
- struct list_head *head, nid_t ino)
+ struct list_head *head, nid_t ino, bool quota_inode)
{
struct inode *inode;
struct fsync_inode_entry *entry;
+ int err;
inode = f2fs_iget_retry(sbi->sb, ino);
if (IS_ERR(inode))
return ERR_CAST(inode);
+ err = dquot_initialize(inode);
+ if (err)
+ goto err_out;
+
+ if (quota_inode) {
+ err = dquot_alloc_inode(inode);
+ if (err)
+ goto err_out;
+ }
+
entry = f2fs_kmem_cache_alloc(fsync_entry_slab, GFP_F2FS_ZERO);
entry->inode = inode;
list_add_tail(&entry->list, head);
return entry;
+err_out:
+ iput(inode);
+ return ERR_PTR(err);
}
static void del_fsync_inode(struct fsync_inode_entry *entry)
@@ -107,7 +121,8 @@
entry = get_fsync_inode(dir_list, pino);
if (!entry) {
- entry = add_fsync_inode(F2FS_I_SB(inode), dir_list, pino);
+ entry = add_fsync_inode(F2FS_I_SB(inode), dir_list,
+ pino, false);
if (IS_ERR(entry)) {
dir = ERR_CAST(entry);
err = PTR_ERR(entry);
@@ -140,6 +155,13 @@
err = -EEXIST;
goto out_unmap_put;
}
+
+ err = dquot_initialize(einode);
+ if (err) {
+ iput(einode);
+ goto out_unmap_put;
+ }
+
err = acquire_orphan_inode(F2FS_I_SB(inode));
if (err) {
iput(einode);
@@ -173,6 +195,20 @@
return err;
}
+static void recover_inline_flags(struct inode *inode, struct f2fs_inode *ri)
+{
+ if (ri->i_inline & F2FS_PIN_FILE)
+ set_inode_flag(inode, FI_PIN_FILE);
+ else
+ clear_inode_flag(inode, FI_PIN_FILE);
+ if (ri->i_inline & F2FS_DATA_EXIST)
+ set_inode_flag(inode, FI_DATA_EXIST);
+ else
+ clear_inode_flag(inode, FI_DATA_EXIST);
+ if (!(ri->i_inline & F2FS_INLINE_DOTS))
+ clear_inode_flag(inode, FI_INLINE_DOTS);
+}
+
static void recover_inode(struct inode *inode, struct page *page)
{
struct f2fs_inode *raw = F2FS_INODE(page);
@@ -180,49 +216,29 @@
inode->i_mode = le16_to_cpu(raw->i_mode);
f2fs_i_size_write(inode, le64_to_cpu(raw->i_size));
- inode->i_atime.tv_sec = le64_to_cpu(raw->i_mtime);
+ inode->i_atime.tv_sec = le64_to_cpu(raw->i_atime);
inode->i_ctime.tv_sec = le64_to_cpu(raw->i_ctime);
inode->i_mtime.tv_sec = le64_to_cpu(raw->i_mtime);
- inode->i_atime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec);
+ inode->i_atime.tv_nsec = le32_to_cpu(raw->i_atime_nsec);
inode->i_ctime.tv_nsec = le32_to_cpu(raw->i_ctime_nsec);
inode->i_mtime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec);
+ F2FS_I(inode)->i_advise = raw->i_advise;
+
+ recover_inline_flags(inode, raw);
+
if (file_enc_name(inode))
name = "<encrypted>";
else
name = F2FS_INODE(page)->i_name;
- f2fs_msg(inode->i_sb, KERN_NOTICE, "recover_inode: ino = %x, name = %s",
- ino_of_node(page), name);
+ f2fs_msg(inode->i_sb, KERN_NOTICE,
+ "recover_inode: ino = %x, name = %s, inline = %x",
+ ino_of_node(page), name, raw->i_inline);
}
-static bool is_same_inode(struct inode *inode, struct page *ipage)
-{
- struct f2fs_inode *ri = F2FS_INODE(ipage);
- struct timespec disk;
-
- if (!IS_INODE(ipage))
- return true;
-
- disk.tv_sec = le64_to_cpu(ri->i_ctime);
- disk.tv_nsec = le32_to_cpu(ri->i_ctime_nsec);
- if (timespec_compare(&inode->i_ctime, &disk) > 0)
- return false;
-
- disk.tv_sec = le64_to_cpu(ri->i_atime);
- disk.tv_nsec = le32_to_cpu(ri->i_atime_nsec);
- if (timespec_compare(&inode->i_atime, &disk) > 0)
- return false;
-
- disk.tv_sec = le64_to_cpu(ri->i_mtime);
- disk.tv_nsec = le32_to_cpu(ri->i_mtime_nsec);
- if (timespec_compare(&inode->i_mtime, &disk) > 0)
- return false;
-
- return true;
-}
-
-static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
+static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
+ bool check_only)
{
struct curseg_info *curseg;
struct page *page = NULL;
@@ -248,21 +264,23 @@
goto next;
entry = get_fsync_inode(head, ino_of_node(page));
- if (entry) {
- if (!is_same_inode(entry->inode, page))
- goto next;
- } else {
- if (IS_INODE(page) && is_dent_dnode(page)) {
+ if (!entry) {
+ bool quota_inode = false;
+
+ if (!check_only &&
+ IS_INODE(page) && is_dent_dnode(page)) {
err = recover_inode_page(sbi, page);
if (err)
break;
+ quota_inode = true;
}
/*
* CP | dnode(F) | inode(DF)
* For this case, we should not give up now.
*/
- entry = add_fsync_inode(sbi, head, ino_of_node(page));
+ entry = add_fsync_inode(sbi, head, ino_of_node(page),
+ quota_inode);
if (IS_ERR(entry)) {
err = PTR_ERR(entry);
if (err == -ENOENT) {
@@ -353,10 +371,18 @@
f2fs_put_page(node_page, 1);
if (ino != dn->inode->i_ino) {
+ int ret;
+
/* Deallocate previous index in the node page */
inode = f2fs_iget_retry(sbi->sb, ino);
if (IS_ERR(inode))
return PTR_ERR(inode);
+
+ ret = dquot_initialize(inode);
+ if (ret) {
+ iput(inode);
+ return ret;
+ }
} else {
inode = dn->inode;
}
@@ -386,7 +412,8 @@
return 0;
truncate_out:
- if (datablock_addr(tdn.node_page, tdn.ofs_in_node) == blkaddr)
+ if (datablock_addr(tdn.inode, tdn.node_page,
+ tdn.ofs_in_node) == blkaddr)
truncate_data_blocks_range(&tdn, 1);
if (dn->inode->i_ino == nid && !dn->inode_page_locked)
unlock_page(dn->inode_page);
@@ -394,7 +421,7 @@
}
static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
- struct page *page, block_t blkaddr)
+ struct page *page)
{
struct dnode_of_data dn;
struct node_info ni;
@@ -405,11 +432,9 @@
if (IS_INODE(page)) {
recover_inline_xattr(inode, page);
} else if (f2fs_has_xattr_block(ofs_of_node(page))) {
- /*
- * Deprecated; xattr blocks should be found from cold log.
- * But, we should remain this for backward compatibility.
- */
- recover_xattr_data(inode, page, blkaddr);
+ err = recover_xattr_data(inode, page);
+ if (!err)
+ recovered++;
goto out;
}
@@ -441,8 +466,8 @@
for (; start < end; start++, dn.ofs_in_node++) {
block_t src, dest;
- src = datablock_addr(dn.node_page, dn.ofs_in_node);
- dest = datablock_addr(page, dn.ofs_in_node);
+ src = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
+ dest = datablock_addr(dn.inode, page, dn.ofs_in_node);
/* skip recovering if dest is the same as src */
if (src == dest)
@@ -454,8 +479,10 @@
continue;
}
- if ((start + 1) << PAGE_SHIFT > i_size_read(inode))
- f2fs_i_size_write(inode, (start + 1) << PAGE_SHIFT);
+ if (!file_keep_isize(inode) &&
+ (i_size_read(inode) <= ((loff_t)start << PAGE_SHIFT)))
+ f2fs_i_size_write(inode,
+ (loff_t)(start + 1) << PAGE_SHIFT);
/*
* dest is reserved block, invalidate src block
@@ -507,8 +534,10 @@
f2fs_put_dnode(&dn);
out:
f2fs_msg(sbi->sb, KERN_NOTICE,
- "recover_data: ino = %lx, recovered = %d blocks, err = %d",
- inode->i_ino, recovered, err);
+ "recover_data: ino = %lx (i_size: %s) recovered = %d, err = %d",
+ inode->i_ino,
+ file_keep_isize(inode) ? "keep" : "recover",
+ recovered, err);
return err;
}
@@ -556,7 +585,7 @@
break;
}
}
- err = do_recover_data(sbi, entry->inode, page, blkaddr);
+ err = do_recover_data(sbi, entry->inode, page);
if (err) {
f2fs_put_page(page, 1);
break;
@@ -576,18 +605,34 @@
int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
{
- struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
struct list_head inode_list;
struct list_head dir_list;
- block_t blkaddr;
int err;
int ret = 0;
+ unsigned long s_flags = sbi->sb->s_flags;
bool need_writecp = false;
+#ifdef CONFIG_QUOTA
+ int quota_enabled;
+#endif
+
+ if (s_flags & MS_RDONLY) {
+ f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs");
+ sbi->sb->s_flags &= ~MS_RDONLY;
+ }
+
+#ifdef CONFIG_QUOTA
+ /* Needed for iput() to work correctly and not trash data */
+ sbi->sb->s_flags |= MS_ACTIVE;
+ /* Turn on quotas so that they are updated correctly */
+ quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
+#endif
fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
sizeof(struct fsync_inode_entry));
- if (!fsync_entry_slab)
- return -ENOMEM;
+ if (!fsync_entry_slab) {
+ err = -ENOMEM;
+ goto out;
+ }
INIT_LIST_HEAD(&inode_list);
INIT_LIST_HEAD(&dir_list);
@@ -595,16 +640,14 @@
/* prevent checkpoint */
mutex_lock(&sbi->cp_mutex);
- blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
-
/* step #1: find fsynced inode numbers */
- err = find_fsync_dnodes(sbi, &inode_list);
+ err = find_fsync_dnodes(sbi, &inode_list, check_only);
if (err || list_empty(&inode_list))
- goto out;
+ goto skip;
if (check_only) {
ret = 1;
- goto out;
+ goto skip;
}
need_writecp = true;
@@ -613,7 +656,7 @@
err = recover_data(sbi, &inode_list, &dir_list);
if (!err)
f2fs_bug_on(sbi, !list_empty(&inode_list));
-out:
+skip:
destroy_fsync_dnodes(&inode_list);
/* truncate meta pages to be used by the recovery */
@@ -639,5 +682,13 @@
}
kmem_cache_destroy(fsync_entry_slab);
+out:
+#ifdef CONFIG_QUOTA
+ /* Turn quotas off */
+ if (quota_enabled)
+ f2fs_quota_off_umount(sbi->sb);
+#endif
+ sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
+
return ret ? ret: err;
}
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index e10f616..cc34d88 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -16,17 +16,20 @@
#include <linux/kthread.h>
#include <linux/swap.h>
#include <linux/timer.h>
+#include <linux/freezer.h>
+#include <linux/sched.h>
#include "f2fs.h"
#include "segment.h"
#include "node.h"
+#include "gc.h"
#include "trace.h"
#include <trace/events/f2fs.h>
#define __reverse_ffz(x) __reverse_ffs(~(x))
static struct kmem_cache *discard_entry_slab;
-static struct kmem_cache *bio_entry_slab;
+static struct kmem_cache *discard_cmd_slab;
static struct kmem_cache *sit_entry_set_slab;
static struct kmem_cache *inmem_entry_slab;
@@ -166,8 +169,24 @@
return result - size + __reverse_ffz(tmp);
}
+bool need_SSR(struct f2fs_sb_info *sbi)
+{
+ int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
+ int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
+ int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA);
+
+ if (test_opt(sbi, LFS))
+ return false;
+ if (sbi->gc_thread && sbi->gc_thread->gc_urgent)
+ return true;
+
+ return free_sections(sbi) <= (node_secs + 2 * dent_secs + imeta_secs +
+ SM_I(sbi)->min_ssr_sections + reserved_sections(sbi));
+}
+
void register_inmem_page(struct inode *inode, struct page *page)
{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct f2fs_inode_info *fi = F2FS_I(inode);
struct inmem_pages *new;
@@ -186,6 +205,10 @@
mutex_lock(&fi->inmem_lock);
get_page(page);
list_add_tail(&new->list, &fi->inmem_pages);
+ spin_lock(&sbi->inode_lock[ATOMIC_FILE]);
+ if (list_empty(&fi->inmem_ilist))
+ list_add_tail(&fi->inmem_ilist, &sbi->inode_list[ATOMIC_FILE]);
+ spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
inc_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES);
mutex_unlock(&fi->inmem_lock);
@@ -212,14 +235,24 @@
struct node_info ni;
trace_f2fs_commit_inmem_page(page, INMEM_REVOKE);
-
+retry:
set_new_dnode(&dn, inode, NULL, NULL, 0);
- if (get_dnode_of_data(&dn, page->index, LOOKUP_NODE)) {
+ err = get_dnode_of_data(&dn, page->index, LOOKUP_NODE);
+ if (err) {
+ if (err == -ENOMEM) {
+ congestion_wait(BLK_RW_ASYNC, HZ/50);
+ cond_resched();
+ goto retry;
+ }
err = -EAGAIN;
goto next;
}
get_node_info(sbi, dn.nid, &ni);
- f2fs_replace_block(sbi, &dn, dn.data_blkaddr,
+ if (cur->old_addr == NEW_ADDR) {
+ invalidate_blocks(sbi, dn.data_blkaddr);
+ f2fs_update_data_blkaddr(&dn, NEW_ADDR);
+ } else
+ f2fs_replace_block(sbi, &dn, dn.data_blkaddr,
cur->old_addr, ni.version, true, true);
f2fs_put_dnode(&dn);
}
@@ -238,15 +271,76 @@
return err;
}
+void drop_inmem_pages_all(struct f2fs_sb_info *sbi)
+{
+ struct list_head *head = &sbi->inode_list[ATOMIC_FILE];
+ struct inode *inode;
+ struct f2fs_inode_info *fi;
+next:
+ spin_lock(&sbi->inode_lock[ATOMIC_FILE]);
+ if (list_empty(head)) {
+ spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
+ return;
+ }
+ fi = list_first_entry(head, struct f2fs_inode_info, inmem_ilist);
+ inode = igrab(&fi->vfs_inode);
+ spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
+
+ if (inode) {
+ drop_inmem_pages(inode);
+ iput(inode);
+ }
+ congestion_wait(BLK_RW_ASYNC, HZ/50);
+ cond_resched();
+ goto next;
+}
+
void drop_inmem_pages(struct inode *inode)
{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct f2fs_inode_info *fi = F2FS_I(inode);
- clear_inode_flag(inode, FI_ATOMIC_FILE);
-
mutex_lock(&fi->inmem_lock);
__revoke_inmem_pages(inode, &fi->inmem_pages, true, false);
+ spin_lock(&sbi->inode_lock[ATOMIC_FILE]);
+ if (!list_empty(&fi->inmem_ilist))
+ list_del_init(&fi->inmem_ilist);
+ spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
mutex_unlock(&fi->inmem_lock);
+
+ clear_inode_flag(inode, FI_ATOMIC_FILE);
+ clear_inode_flag(inode, FI_HOT_DATA);
+ stat_dec_atomic_write(inode);
+}
+
+void drop_inmem_page(struct inode *inode, struct page *page)
+{
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct list_head *head = &fi->inmem_pages;
+ struct inmem_pages *cur = NULL;
+
+ f2fs_bug_on(sbi, !IS_ATOMIC_WRITTEN_PAGE(page));
+
+ mutex_lock(&fi->inmem_lock);
+ list_for_each_entry(cur, head, list) {
+ if (cur->page == page)
+ break;
+ }
+
+ f2fs_bug_on(sbi, !cur || cur->page != page);
+ list_del(&cur->list);
+ mutex_unlock(&fi->inmem_lock);
+
+ dec_page_count(sbi, F2FS_INMEM_PAGES);
+ kmem_cache_free(inmem_entry_slab, cur);
+
+ ClearPageUptodate(page);
+ set_page_private(page, 0);
+ ClearPagePrivate(page);
+ f2fs_put_page(page, 0);
+
+ trace_f2fs_commit_inmem_page(page, INMEM_INVALIDATE);
}
static int __commit_inmem_pages(struct inode *inode,
@@ -257,12 +351,13 @@
struct inmem_pages *cur, *tmp;
struct f2fs_io_info fio = {
.sbi = sbi,
+ .ino = inode->i_ino,
.type = DATA,
.op = REQ_OP_WRITE,
- .op_flags = WRITE_SYNC | REQ_PRIO,
- .encrypted_page = NULL,
+ .op_flags = REQ_SYNC | REQ_PRIO,
+ .io_type = FS_DATA_IO,
};
- bool submit_bio = false;
+ pgoff_t last_idx = ULONG_MAX;
int err = 0;
list_for_each_entry_safe(cur, tmp, &fi->inmem_pages, list) {
@@ -274,28 +369,35 @@
set_page_dirty(page);
f2fs_wait_on_page_writeback(page, DATA, true);
- if (clear_page_dirty_for_io(page))
+ if (clear_page_dirty_for_io(page)) {
inode_dec_dirty_pages(inode);
-
+ remove_dirty_inode(inode);
+ }
+retry:
fio.page = page;
+ fio.old_blkaddr = NULL_ADDR;
+ fio.encrypted_page = NULL;
+ fio.need_lock = LOCK_DONE;
err = do_write_data_page(&fio);
if (err) {
+ if (err == -ENOMEM) {
+ congestion_wait(BLK_RW_ASYNC, HZ/50);
+ cond_resched();
+ goto retry;
+ }
unlock_page(page);
break;
}
-
/* record old blkaddr for revoking */
cur->old_addr = fio.old_blkaddr;
-
- clear_cold_data(page);
- submit_bio = true;
+ last_idx = page->index;
}
unlock_page(page);
list_move_tail(&cur->list, revoke_list);
}
- if (submit_bio)
- f2fs_submit_merged_bio_cond(sbi, inode, NULL, 0, DATA, WRITE);
+ if (last_idx != ULONG_MAX)
+ f2fs_submit_merged_write_cond(sbi, inode, 0, last_idx, DATA);
if (!err)
__revoke_inmem_pages(inode, revoke_list, false, false);
@@ -314,6 +416,8 @@
f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi);
+ set_inode_flag(inode, FI_ATOMIC_COMMIT);
+
mutex_lock(&fi->inmem_lock);
err = __commit_inmem_pages(inode, &revoke_list);
if (err) {
@@ -333,8 +437,14 @@
/* drop all uncommitted pages */
__revoke_inmem_pages(inode, &fi->inmem_pages, true, false);
}
+ spin_lock(&sbi->inode_lock[ATOMIC_FILE]);
+ if (!list_empty(&fi->inmem_ilist))
+ list_del_init(&fi->inmem_ilist);
+ spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
mutex_unlock(&fi->inmem_lock);
+ clear_inode_flag(inode, FI_ATOMIC_COMMIT);
+
f2fs_unlock_op(sbi);
return err;
}
@@ -346,15 +456,14 @@
void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
{
#ifdef CONFIG_F2FS_FAULT_INJECTION
- if (time_to_inject(sbi, FAULT_CHECKPOINT))
+ if (time_to_inject(sbi, FAULT_CHECKPOINT)) {
+ f2fs_show_injection_info(FAULT_CHECKPOINT);
f2fs_stop_checkpoint(sbi, false);
+ }
#endif
- if (!need)
- return;
-
/* balance_fs_bg is able to be pending */
- if (excess_cached_nats(sbi))
+ if (need && excess_cached_nats(sbi))
f2fs_balance_fs_bg(sbi);
/*
@@ -363,7 +472,7 @@
*/
if (has_not_enough_free_secs(sbi, 0, 0)) {
mutex_lock(&sbi->gc_mutex);
- f2fs_gc(sbi, false);
+ f2fs_gc(sbi, false, false, NULL_SEGNO);
}
}
@@ -380,14 +489,17 @@
if (!available_free_memory(sbi, FREE_NIDS))
try_to_free_nids(sbi, MAX_FREE_NIDS);
else
- build_free_nids(sbi);
+ build_free_nids(sbi, false, false);
+
+ if (!is_idle(sbi) && !excess_dirty_nats(sbi))
+ return;
/* checkpoint is the only way to shrink partial cached entries */
if (!available_free_memory(sbi, NAT_ENTRIES) ||
!available_free_memory(sbi, INO_ENTRIES) ||
excess_prefree_segs(sbi) ||
excess_dirty_nats(sbi) ||
- (is_idle(sbi) && f2fs_time_over(sbi, CP_TIME))) {
+ f2fs_time_over(sbi, CP_TIME)) {
if (test_opt(sbi, DATA_FLUSH)) {
struct blk_plug plug;
@@ -400,77 +512,138 @@
}
}
+static int __submit_flush_wait(struct f2fs_sb_info *sbi,
+ struct block_device *bdev)
+{
+ struct bio *bio = f2fs_bio_alloc(sbi, 0, true);
+ int ret;
+
+ bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH;
+ bio->bi_bdev = bdev;
+ ret = submit_bio_wait(bio);
+ bio_put(bio);
+
+ trace_f2fs_issue_flush(bdev, test_opt(sbi, NOBARRIER),
+ test_opt(sbi, FLUSH_MERGE), ret);
+ return ret;
+}
+
+static int submit_flush_wait(struct f2fs_sb_info *sbi, nid_t ino)
+{
+ int ret = 0;
+ int i;
+
+ if (!sbi->s_ndevs)
+ return __submit_flush_wait(sbi, sbi->sb->s_bdev);
+
+ for (i = 0; i < sbi->s_ndevs; i++) {
+ if (!is_dirty_device(sbi, ino, i, FLUSH_INO))
+ continue;
+ ret = __submit_flush_wait(sbi, FDEV(i).bdev);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
static int issue_flush_thread(void *data)
{
struct f2fs_sb_info *sbi = data;
- struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info;
+ struct flush_cmd_control *fcc = SM_I(sbi)->fcc_info;
wait_queue_head_t *q = &fcc->flush_wait_queue;
repeat:
if (kthread_should_stop())
return 0;
+ sb_start_intwrite(sbi->sb);
+
if (!llist_empty(&fcc->issue_list)) {
- struct bio *bio;
struct flush_cmd *cmd, *next;
int ret;
- bio = f2fs_bio_alloc(0);
-
fcc->dispatch_list = llist_del_all(&fcc->issue_list);
fcc->dispatch_list = llist_reverse_order(fcc->dispatch_list);
- bio->bi_bdev = sbi->sb->s_bdev;
- bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_FLUSH);
- ret = submit_bio_wait(bio);
+ cmd = llist_entry(fcc->dispatch_list, struct flush_cmd, llnode);
+
+ ret = submit_flush_wait(sbi, cmd->ino);
+ atomic_inc(&fcc->issued_flush);
llist_for_each_entry_safe(cmd, next,
fcc->dispatch_list, llnode) {
cmd->ret = ret;
complete(&cmd->wait);
}
- bio_put(bio);
fcc->dispatch_list = NULL;
}
+ sb_end_intwrite(sbi->sb);
+
wait_event_interruptible(*q,
kthread_should_stop() || !llist_empty(&fcc->issue_list));
goto repeat;
}
-int f2fs_issue_flush(struct f2fs_sb_info *sbi)
+int f2fs_issue_flush(struct f2fs_sb_info *sbi, nid_t ino)
{
- struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info;
+ struct flush_cmd_control *fcc = SM_I(sbi)->fcc_info;
struct flush_cmd cmd;
-
- trace_f2fs_issue_flush(sbi->sb, test_opt(sbi, NOBARRIER),
- test_opt(sbi, FLUSH_MERGE));
+ int ret;
if (test_opt(sbi, NOBARRIER))
return 0;
- if (!test_opt(sbi, FLUSH_MERGE) || !atomic_read(&fcc->submit_flush)) {
- struct bio *bio = f2fs_bio_alloc(0);
- int ret;
-
- atomic_inc(&fcc->submit_flush);
- bio->bi_bdev = sbi->sb->s_bdev;
- bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_FLUSH);
- ret = submit_bio_wait(bio);
- atomic_dec(&fcc->submit_flush);
- bio_put(bio);
+ if (!test_opt(sbi, FLUSH_MERGE)) {
+ ret = submit_flush_wait(sbi, ino);
+ atomic_inc(&fcc->issued_flush);
return ret;
}
+ if (atomic_inc_return(&fcc->issing_flush) == 1 || sbi->s_ndevs > 1) {
+ ret = submit_flush_wait(sbi, ino);
+ atomic_dec(&fcc->issing_flush);
+
+ atomic_inc(&fcc->issued_flush);
+ return ret;
+ }
+
+ cmd.ino = ino;
init_completion(&cmd.wait);
- atomic_inc(&fcc->submit_flush);
llist_add(&cmd.llnode, &fcc->issue_list);
- if (!fcc->dispatch_list)
+ /* update issue_list before we wake up issue_flush thread */
+ smp_mb();
+
+ if (waitqueue_active(&fcc->flush_wait_queue))
wake_up(&fcc->flush_wait_queue);
- wait_for_completion(&cmd.wait);
- atomic_dec(&fcc->submit_flush);
+ if (fcc->f2fs_issue_flush) {
+ wait_for_completion(&cmd.wait);
+ atomic_dec(&fcc->issing_flush);
+ } else {
+ struct llist_node *list;
+
+ list = llist_del_all(&fcc->issue_list);
+ if (!list) {
+ wait_for_completion(&cmd.wait);
+ atomic_dec(&fcc->issing_flush);
+ } else {
+ struct flush_cmd *tmp, *next;
+
+ ret = submit_flush_wait(sbi, ino);
+
+ llist_for_each_entry_safe(tmp, next, list, llnode) {
+ if (tmp == &cmd) {
+ cmd.ret = ret;
+ atomic_dec(&fcc->issing_flush);
+ continue;
+ }
+ tmp->ret = ret;
+ complete(&tmp->wait);
+ }
+ }
+ }
return cmd.ret;
}
@@ -481,33 +654,73 @@
struct flush_cmd_control *fcc;
int err = 0;
- fcc = kzalloc(sizeof(struct flush_cmd_control), GFP_KERNEL);
+ if (SM_I(sbi)->fcc_info) {
+ fcc = SM_I(sbi)->fcc_info;
+ if (fcc->f2fs_issue_flush)
+ return err;
+ goto init_thread;
+ }
+
+ fcc = f2fs_kzalloc(sbi, sizeof(struct flush_cmd_control), GFP_KERNEL);
if (!fcc)
return -ENOMEM;
- atomic_set(&fcc->submit_flush, 0);
+ atomic_set(&fcc->issued_flush, 0);
+ atomic_set(&fcc->issing_flush, 0);
init_waitqueue_head(&fcc->flush_wait_queue);
init_llist_head(&fcc->issue_list);
- SM_I(sbi)->cmd_control_info = fcc;
+ SM_I(sbi)->fcc_info = fcc;
+ if (!test_opt(sbi, FLUSH_MERGE))
+ return err;
+
+init_thread:
fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
"f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
if (IS_ERR(fcc->f2fs_issue_flush)) {
err = PTR_ERR(fcc->f2fs_issue_flush);
kfree(fcc);
- SM_I(sbi)->cmd_control_info = NULL;
+ SM_I(sbi)->fcc_info = NULL;
return err;
}
return err;
}
-void destroy_flush_cmd_control(struct f2fs_sb_info *sbi)
+void destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free)
{
- struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info;
+ struct flush_cmd_control *fcc = SM_I(sbi)->fcc_info;
- if (fcc && fcc->f2fs_issue_flush)
- kthread_stop(fcc->f2fs_issue_flush);
- kfree(fcc);
- SM_I(sbi)->cmd_control_info = NULL;
+ if (fcc && fcc->f2fs_issue_flush) {
+ struct task_struct *flush_thread = fcc->f2fs_issue_flush;
+
+ fcc->f2fs_issue_flush = NULL;
+ kthread_stop(flush_thread);
+ }
+ if (free) {
+ kfree(fcc);
+ SM_I(sbi)->fcc_info = NULL;
+ }
+}
+
+int f2fs_flush_device_cache(struct f2fs_sb_info *sbi)
+{
+ int ret = 0, i;
+
+ if (!sbi->s_ndevs)
+ return 0;
+
+ for (i = 1; i < sbi->s_ndevs; i++) {
+ if (!f2fs_test_bit(i, (char *)&sbi->dirty_device))
+ continue;
+ ret = __submit_flush_wait(sbi, FDEV(i).bdev);
+ if (ret)
+ break;
+
+ spin_lock(&sbi->dev_lock);
+ f2fs_clear_bit(i, (char *)&sbi->dirty_device);
+ spin_unlock(&sbi->dev_lock);
+ }
+
+ return ret;
}
static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
@@ -550,8 +763,8 @@
if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
dirty_i->nr_dirty[t]--;
- if (get_valid_blocks(sbi, segno, sbi->segs_per_sec) == 0)
- clear_bit(GET_SECNO(sbi, segno),
+ if (get_valid_blocks(sbi, segno, true) == 0)
+ clear_bit(GET_SEC_FROM_SEG(sbi, segno),
dirty_i->victim_secmap);
}
}
@@ -571,7 +784,7 @@
mutex_lock(&dirty_i->seglist_lock);
- valid_blocks = get_valid_blocks(sbi, segno, 0);
+ valid_blocks = get_valid_blocks(sbi, segno, false);
if (valid_blocks == 0) {
__locate_dirty_segment(sbi, segno, PRE);
@@ -586,120 +799,741 @@
mutex_unlock(&dirty_i->seglist_lock);
}
-static struct bio_entry *__add_bio_entry(struct f2fs_sb_info *sbi,
- struct bio *bio)
+static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi,
+ struct block_device *bdev, block_t lstart,
+ block_t start, block_t len)
{
- struct list_head *wait_list = &(SM_I(sbi)->wait_list);
- struct bio_entry *be = f2fs_kmem_cache_alloc(bio_entry_slab, GFP_NOFS);
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct list_head *pend_list;
+ struct discard_cmd *dc;
- INIT_LIST_HEAD(&be->list);
- be->bio = bio;
- init_completion(&be->event);
- list_add_tail(&be->list, wait_list);
+ f2fs_bug_on(sbi, !len);
- return be;
+ pend_list = &dcc->pend_list[plist_idx(len)];
+
+ dc = f2fs_kmem_cache_alloc(discard_cmd_slab, GFP_NOFS);
+ INIT_LIST_HEAD(&dc->list);
+ dc->bdev = bdev;
+ dc->lstart = lstart;
+ dc->start = start;
+ dc->len = len;
+ dc->ref = 0;
+ dc->state = D_PREP;
+ dc->error = 0;
+ init_completion(&dc->wait);
+ list_add_tail(&dc->list, pend_list);
+ atomic_inc(&dcc->discard_cmd_cnt);
+ dcc->undiscard_blks += len;
+
+ return dc;
}
-void f2fs_wait_all_discard_bio(struct f2fs_sb_info *sbi)
+static struct discard_cmd *__attach_discard_cmd(struct f2fs_sb_info *sbi,
+ struct block_device *bdev, block_t lstart,
+ block_t start, block_t len,
+ struct rb_node *parent, struct rb_node **p)
{
- struct list_head *wait_list = &(SM_I(sbi)->wait_list);
- struct bio_entry *be, *tmp;
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct discard_cmd *dc;
- list_for_each_entry_safe(be, tmp, wait_list, list) {
- struct bio *bio = be->bio;
- int err;
+ dc = __create_discard_cmd(sbi, bdev, lstart, start, len);
- wait_for_completion_io(&be->event);
- err = be->error;
- if (err == -EOPNOTSUPP)
- err = 0;
+ rb_link_node(&dc->rb_node, parent, p);
+ rb_insert_color(&dc->rb_node, &dcc->root);
- if (err)
- f2fs_msg(sbi->sb, KERN_INFO,
- "Issue discard failed, ret: %d", err);
+ return dc;
+}
- bio_put(bio);
- list_del(&be->list);
- kmem_cache_free(bio_entry_slab, be);
+static void __detach_discard_cmd(struct discard_cmd_control *dcc,
+ struct discard_cmd *dc)
+{
+ if (dc->state == D_DONE)
+ atomic_dec(&dcc->issing_discard);
+
+ list_del(&dc->list);
+ rb_erase(&dc->rb_node, &dcc->root);
+ dcc->undiscard_blks -= dc->len;
+
+ kmem_cache_free(discard_cmd_slab, dc);
+
+ atomic_dec(&dcc->discard_cmd_cnt);
+}
+
+static void __remove_discard_cmd(struct f2fs_sb_info *sbi,
+ struct discard_cmd *dc)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+
+ trace_f2fs_remove_discard(dc->bdev, dc->start, dc->len);
+
+ f2fs_bug_on(sbi, dc->ref);
+
+ if (dc->error == -EOPNOTSUPP)
+ dc->error = 0;
+
+ if (dc->error)
+ f2fs_msg(sbi->sb, KERN_INFO,
+ "Issue discard(%u, %u, %u) failed, ret: %d",
+ dc->lstart, dc->start, dc->len, dc->error);
+ __detach_discard_cmd(dcc, dc);
+}
+
+static void f2fs_submit_discard_endio(struct bio *bio)
+{
+ struct discard_cmd *dc = (struct discard_cmd *)bio->bi_private;
+
+ dc->error = bio->bi_error;
+ dc->state = D_DONE;
+ complete_all(&dc->wait);
+ bio_put(bio);
+}
+
+static void __check_sit_bitmap(struct f2fs_sb_info *sbi,
+ block_t start, block_t end)
+{
+#ifdef CONFIG_F2FS_CHECK_FS
+ struct seg_entry *sentry;
+ unsigned int segno;
+ block_t blk = start;
+ unsigned long offset, size, max_blocks = sbi->blocks_per_seg;
+ unsigned long *map;
+
+ while (blk < end) {
+ segno = GET_SEGNO(sbi, blk);
+ sentry = get_seg_entry(sbi, segno);
+ offset = GET_BLKOFF_FROM_SEG0(sbi, blk);
+
+ if (end < START_BLOCK(sbi, segno + 1))
+ size = GET_BLKOFF_FROM_SEG0(sbi, end);
+ else
+ size = max_blocks;
+ map = (unsigned long *)(sentry->cur_valid_map);
+ offset = __find_rev_next_bit(map, size, offset);
+ f2fs_bug_on(sbi, offset != size);
+ blk = START_BLOCK(sbi, segno + 1);
}
-}
-
-static void f2fs_submit_bio_wait_endio(struct bio *bio)
-{
- struct bio_entry *be = (struct bio_entry *)bio->bi_private;
-
- be->error = bio->bi_error;
- complete(&be->event);
+#endif
}
/* this function is copied from blkdev_issue_discard from block/blk-lib.c */
-int __f2fs_issue_discard_async(struct f2fs_sb_info *sbi, sector_t sector,
- sector_t nr_sects, gfp_t gfp_mask, unsigned long flags)
+static void __submit_discard_cmd(struct f2fs_sb_info *sbi,
+ struct discard_policy *dpolicy,
+ struct discard_cmd *dc)
{
- struct block_device *bdev = sbi->sb->s_bdev;
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct list_head *wait_list = (dpolicy->type == DPOLICY_FSTRIM) ?
+ &(dcc->fstrim_list) : &(dcc->wait_list);
struct bio *bio = NULL;
- int err;
+ int flag = dpolicy->sync ? REQ_SYNC : 0;
- err = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, flags,
- &bio);
- if (!err && bio) {
- struct bio_entry *be = __add_bio_entry(sbi, bio);
+ if (dc->state != D_PREP)
+ return;
- bio->bi_private = be;
- bio->bi_end_io = f2fs_submit_bio_wait_endio;
- bio->bi_opf |= REQ_SYNC;
- submit_bio(bio);
+ trace_f2fs_issue_discard(dc->bdev, dc->start, dc->len);
+
+ dc->error = __blkdev_issue_discard(dc->bdev,
+ SECTOR_FROM_BLOCK(dc->start),
+ SECTOR_FROM_BLOCK(dc->len),
+ GFP_NOFS, 0, &bio);
+ if (!dc->error) {
+ /* should keep before submission to avoid D_DONE right away */
+ dc->state = D_SUBMIT;
+ atomic_inc(&dcc->issued_discard);
+ atomic_inc(&dcc->issing_discard);
+ if (bio) {
+ bio->bi_private = dc;
+ bio->bi_end_io = f2fs_submit_discard_endio;
+ bio->bi_opf |= flag;
+ submit_bio(bio);
+ list_move_tail(&dc->list, wait_list);
+ __check_sit_bitmap(sbi, dc->start, dc->start + dc->len);
+
+ f2fs_update_iostat(sbi, FS_DISCARD, 1);
+ }
+ } else {
+ __remove_discard_cmd(sbi, dc);
+ }
+}
+
+static struct discard_cmd *__insert_discard_tree(struct f2fs_sb_info *sbi,
+ struct block_device *bdev, block_t lstart,
+ block_t start, block_t len,
+ struct rb_node **insert_p,
+ struct rb_node *insert_parent)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct rb_node **p;
+ struct rb_node *parent = NULL;
+ struct discard_cmd *dc = NULL;
+
+ if (insert_p && insert_parent) {
+ parent = insert_parent;
+ p = insert_p;
+ goto do_insert;
}
- return err;
+ p = __lookup_rb_tree_for_insert(sbi, &dcc->root, &parent, lstart);
+do_insert:
+ dc = __attach_discard_cmd(sbi, bdev, lstart, start, len, parent, p);
+ if (!dc)
+ return NULL;
+
+ return dc;
+}
+
+static void __relocate_discard_cmd(struct discard_cmd_control *dcc,
+ struct discard_cmd *dc)
+{
+ list_move_tail(&dc->list, &dcc->pend_list[plist_idx(dc->len)]);
+}
+
+static void __punch_discard_cmd(struct f2fs_sb_info *sbi,
+ struct discard_cmd *dc, block_t blkaddr)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct discard_info di = dc->di;
+ bool modified = false;
+
+ if (dc->state == D_DONE || dc->len == 1) {
+ __remove_discard_cmd(sbi, dc);
+ return;
+ }
+
+ dcc->undiscard_blks -= di.len;
+
+ if (blkaddr > di.lstart) {
+ dc->len = blkaddr - dc->lstart;
+ dcc->undiscard_blks += dc->len;
+ __relocate_discard_cmd(dcc, dc);
+ modified = true;
+ }
+
+ if (blkaddr < di.lstart + di.len - 1) {
+ if (modified) {
+ __insert_discard_tree(sbi, dc->bdev, blkaddr + 1,
+ di.start + blkaddr + 1 - di.lstart,
+ di.lstart + di.len - 1 - blkaddr,
+ NULL, NULL);
+ } else {
+ dc->lstart++;
+ dc->len--;
+ dc->start++;
+ dcc->undiscard_blks += dc->len;
+ __relocate_discard_cmd(dcc, dc);
+ }
+ }
+}
+
+static void __update_discard_tree_range(struct f2fs_sb_info *sbi,
+ struct block_device *bdev, block_t lstart,
+ block_t start, block_t len)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct discard_cmd *prev_dc = NULL, *next_dc = NULL;
+ struct discard_cmd *dc;
+ struct discard_info di = {0};
+ struct rb_node **insert_p = NULL, *insert_parent = NULL;
+ block_t end = lstart + len;
+
+ mutex_lock(&dcc->cmd_lock);
+
+ dc = (struct discard_cmd *)__lookup_rb_tree_ret(&dcc->root,
+ NULL, lstart,
+ (struct rb_entry **)&prev_dc,
+ (struct rb_entry **)&next_dc,
+ &insert_p, &insert_parent, true);
+ if (dc)
+ prev_dc = dc;
+
+ if (!prev_dc) {
+ di.lstart = lstart;
+ di.len = next_dc ? next_dc->lstart - lstart : len;
+ di.len = min(di.len, len);
+ di.start = start;
+ }
+
+ while (1) {
+ struct rb_node *node;
+ bool merged = false;
+ struct discard_cmd *tdc = NULL;
+
+ if (prev_dc) {
+ di.lstart = prev_dc->lstart + prev_dc->len;
+ if (di.lstart < lstart)
+ di.lstart = lstart;
+ if (di.lstart >= end)
+ break;
+
+ if (!next_dc || next_dc->lstart > end)
+ di.len = end - di.lstart;
+ else
+ di.len = next_dc->lstart - di.lstart;
+ di.start = start + di.lstart - lstart;
+ }
+
+ if (!di.len)
+ goto next;
+
+ if (prev_dc && prev_dc->state == D_PREP &&
+ prev_dc->bdev == bdev &&
+ __is_discard_back_mergeable(&di, &prev_dc->di)) {
+ prev_dc->di.len += di.len;
+ dcc->undiscard_blks += di.len;
+ __relocate_discard_cmd(dcc, prev_dc);
+ di = prev_dc->di;
+ tdc = prev_dc;
+ merged = true;
+ }
+
+ if (next_dc && next_dc->state == D_PREP &&
+ next_dc->bdev == bdev &&
+ __is_discard_front_mergeable(&di, &next_dc->di)) {
+ next_dc->di.lstart = di.lstart;
+ next_dc->di.len += di.len;
+ next_dc->di.start = di.start;
+ dcc->undiscard_blks += di.len;
+ __relocate_discard_cmd(dcc, next_dc);
+ if (tdc)
+ __remove_discard_cmd(sbi, tdc);
+ merged = true;
+ }
+
+ if (!merged) {
+ __insert_discard_tree(sbi, bdev, di.lstart, di.start,
+ di.len, NULL, NULL);
+ }
+ next:
+ prev_dc = next_dc;
+ if (!prev_dc)
+ break;
+
+ node = rb_next(&prev_dc->rb_node);
+ next_dc = rb_entry_safe(node, struct discard_cmd, rb_node);
+ }
+
+ mutex_unlock(&dcc->cmd_lock);
+}
+
+static int __queue_discard_cmd(struct f2fs_sb_info *sbi,
+ struct block_device *bdev, block_t blkstart, block_t blklen)
+{
+ block_t lblkstart = blkstart;
+
+ trace_f2fs_queue_discard(bdev, blkstart, blklen);
+
+ if (sbi->s_ndevs) {
+ int devi = f2fs_target_device_index(sbi, blkstart);
+
+ blkstart -= FDEV(devi).start_blk;
+ }
+ __update_discard_tree_range(sbi, bdev, lblkstart, blkstart, blklen);
+ return 0;
+}
+
+static void __issue_discard_cmd_range(struct f2fs_sb_info *sbi,
+ struct discard_policy *dpolicy,
+ unsigned int start, unsigned int end)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct discard_cmd *prev_dc = NULL, *next_dc = NULL;
+ struct rb_node **insert_p = NULL, *insert_parent = NULL;
+ struct discard_cmd *dc;
+ struct blk_plug plug;
+ int issued;
+
+next:
+ issued = 0;
+
+ mutex_lock(&dcc->cmd_lock);
+ f2fs_bug_on(sbi, !__check_rb_tree_consistence(sbi, &dcc->root));
+
+ dc = (struct discard_cmd *)__lookup_rb_tree_ret(&dcc->root,
+ NULL, start,
+ (struct rb_entry **)&prev_dc,
+ (struct rb_entry **)&next_dc,
+ &insert_p, &insert_parent, true);
+ if (!dc)
+ dc = next_dc;
+
+ blk_start_plug(&plug);
+
+ while (dc && dc->lstart <= end) {
+ struct rb_node *node;
+
+ if (dc->len < dpolicy->granularity)
+ goto skip;
+
+ if (dc->state != D_PREP) {
+ list_move_tail(&dc->list, &dcc->fstrim_list);
+ goto skip;
+ }
+
+ __submit_discard_cmd(sbi, dpolicy, dc);
+
+ if (++issued >= dpolicy->max_requests) {
+ start = dc->lstart + dc->len;
+
+ blk_finish_plug(&plug);
+ mutex_unlock(&dcc->cmd_lock);
+
+ schedule();
+
+ goto next;
+ }
+skip:
+ node = rb_next(&dc->rb_node);
+ dc = rb_entry_safe(node, struct discard_cmd, rb_node);
+
+ if (fatal_signal_pending(current))
+ break;
+ }
+
+ blk_finish_plug(&plug);
+ mutex_unlock(&dcc->cmd_lock);
+}
+
+static int __issue_discard_cmd(struct f2fs_sb_info *sbi,
+ struct discard_policy *dpolicy)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct list_head *pend_list;
+ struct discard_cmd *dc, *tmp;
+ struct blk_plug plug;
+ int i, iter = 0, issued = 0;
+ bool io_interrupted = false;
+
+ for (i = MAX_PLIST_NUM - 1; i >= 0; i--) {
+ if (i + 1 < dpolicy->granularity)
+ break;
+ pend_list = &dcc->pend_list[i];
+
+ mutex_lock(&dcc->cmd_lock);
+ if (list_empty(pend_list))
+ goto next;
+ f2fs_bug_on(sbi, !__check_rb_tree_consistence(sbi, &dcc->root));
+ blk_start_plug(&plug);
+ list_for_each_entry_safe(dc, tmp, pend_list, list) {
+ f2fs_bug_on(sbi, dc->state != D_PREP);
+
+ if (dpolicy->io_aware && i < dpolicy->io_aware_gran &&
+ !is_idle(sbi)) {
+ io_interrupted = true;
+ goto skip;
+ }
+
+ __submit_discard_cmd(sbi, dpolicy, dc);
+ issued++;
+skip:
+ if (++iter >= dpolicy->max_requests)
+ break;
+ }
+ blk_finish_plug(&plug);
+next:
+ mutex_unlock(&dcc->cmd_lock);
+
+ if (iter >= dpolicy->max_requests)
+ break;
+ }
+
+ if (!issued && io_interrupted)
+ issued = -1;
+
+ return issued;
+}
+
+static bool __drop_discard_cmd(struct f2fs_sb_info *sbi)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct list_head *pend_list;
+ struct discard_cmd *dc, *tmp;
+ int i;
+ bool dropped = false;
+
+ mutex_lock(&dcc->cmd_lock);
+ for (i = MAX_PLIST_NUM - 1; i >= 0; i--) {
+ pend_list = &dcc->pend_list[i];
+ list_for_each_entry_safe(dc, tmp, pend_list, list) {
+ f2fs_bug_on(sbi, dc->state != D_PREP);
+ __remove_discard_cmd(sbi, dc);
+ dropped = true;
+ }
+ }
+ mutex_unlock(&dcc->cmd_lock);
+
+ return dropped;
+}
+
+void drop_discard_cmd(struct f2fs_sb_info *sbi)
+{
+ __drop_discard_cmd(sbi);
+}
+
+static unsigned int __wait_one_discard_bio(struct f2fs_sb_info *sbi,
+ struct discard_cmd *dc)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ unsigned int len = 0;
+
+ wait_for_completion_io(&dc->wait);
+ mutex_lock(&dcc->cmd_lock);
+ f2fs_bug_on(sbi, dc->state != D_DONE);
+ dc->ref--;
+ if (!dc->ref) {
+ if (!dc->error)
+ len = dc->len;
+ __remove_discard_cmd(sbi, dc);
+ }
+ mutex_unlock(&dcc->cmd_lock);
+
+ return len;
+}
+
+static unsigned int __wait_discard_cmd_range(struct f2fs_sb_info *sbi,
+ struct discard_policy *dpolicy,
+ block_t start, block_t end)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct list_head *wait_list = (dpolicy->type == DPOLICY_FSTRIM) ?
+ &(dcc->fstrim_list) : &(dcc->wait_list);
+ struct discard_cmd *dc, *tmp;
+ bool need_wait;
+ unsigned int trimmed = 0;
+
+next:
+ need_wait = false;
+
+ mutex_lock(&dcc->cmd_lock);
+ list_for_each_entry_safe(dc, tmp, wait_list, list) {
+ if (dc->lstart + dc->len <= start || end <= dc->lstart)
+ continue;
+ if (dc->len < dpolicy->granularity)
+ continue;
+ if (dc->state == D_DONE && !dc->ref) {
+ wait_for_completion_io(&dc->wait);
+ if (!dc->error)
+ trimmed += dc->len;
+ __remove_discard_cmd(sbi, dc);
+ } else {
+ dc->ref++;
+ need_wait = true;
+ break;
+ }
+ }
+ mutex_unlock(&dcc->cmd_lock);
+
+ if (need_wait) {
+ trimmed += __wait_one_discard_bio(sbi, dc);
+ goto next;
+ }
+
+ return trimmed;
+}
+
+static void __wait_all_discard_cmd(struct f2fs_sb_info *sbi,
+ struct discard_policy *dpolicy)
+{
+ __wait_discard_cmd_range(sbi, dpolicy, 0, UINT_MAX);
+}
+
+/* This should be covered by global mutex, &sit_i->sentry_lock */
+static void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct discard_cmd *dc;
+ bool need_wait = false;
+
+ mutex_lock(&dcc->cmd_lock);
+ dc = (struct discard_cmd *)__lookup_rb_tree(&dcc->root, NULL, blkaddr);
+ if (dc) {
+ if (dc->state == D_PREP) {
+ __punch_discard_cmd(sbi, dc, blkaddr);
+ } else {
+ dc->ref++;
+ need_wait = true;
+ }
+ }
+ mutex_unlock(&dcc->cmd_lock);
+
+ if (need_wait)
+ __wait_one_discard_bio(sbi, dc);
+}
+
+void stop_discard_thread(struct f2fs_sb_info *sbi)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+
+ if (dcc && dcc->f2fs_issue_discard) {
+ struct task_struct *discard_thread = dcc->f2fs_issue_discard;
+
+ dcc->f2fs_issue_discard = NULL;
+ kthread_stop(discard_thread);
+ }
+}
+
+/* This comes from f2fs_put_super */
+bool f2fs_wait_discard_bios(struct f2fs_sb_info *sbi)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct discard_policy dpolicy;
+ bool dropped;
+
+ init_discard_policy(&dpolicy, DPOLICY_UMOUNT, dcc->discard_granularity);
+ __issue_discard_cmd(sbi, &dpolicy);
+ dropped = __drop_discard_cmd(sbi);
+ __wait_all_discard_cmd(sbi, &dpolicy);
+
+ return dropped;
+}
+
+static int issue_discard_thread(void *data)
+{
+ struct f2fs_sb_info *sbi = data;
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ wait_queue_head_t *q = &dcc->discard_wait_queue;
+ struct discard_policy dpolicy;
+ unsigned int wait_ms = DEF_MIN_DISCARD_ISSUE_TIME;
+ int issued;
+
+ set_freezable();
+
+ do {
+ init_discard_policy(&dpolicy, DPOLICY_BG,
+ dcc->discard_granularity);
+
+ wait_event_interruptible_timeout(*q,
+ kthread_should_stop() || freezing(current) ||
+ dcc->discard_wake,
+ msecs_to_jiffies(wait_ms));
+ if (try_to_freeze())
+ continue;
+ if (f2fs_readonly(sbi->sb))
+ continue;
+ if (kthread_should_stop())
+ return 0;
+
+ if (dcc->discard_wake) {
+ dcc->discard_wake = 0;
+ if (sbi->gc_thread && sbi->gc_thread->gc_urgent)
+ init_discard_policy(&dpolicy,
+ DPOLICY_FORCE, 1);
+ }
+
+ sb_start_intwrite(sbi->sb);
+
+ issued = __issue_discard_cmd(sbi, &dpolicy);
+ if (issued) {
+ __wait_all_discard_cmd(sbi, &dpolicy);
+ wait_ms = dpolicy.min_interval;
+ } else {
+ wait_ms = dpolicy.max_interval;
+ }
+
+ sb_end_intwrite(sbi->sb);
+
+ } while (!kthread_should_stop());
+ return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_ZONED
+static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi,
+ struct block_device *bdev, block_t blkstart, block_t blklen)
+{
+ sector_t sector, nr_sects;
+ block_t lblkstart = blkstart;
+ int devi = 0;
+
+ if (sbi->s_ndevs) {
+ devi = f2fs_target_device_index(sbi, blkstart);
+ blkstart -= FDEV(devi).start_blk;
+ }
+
+ /*
+ * We need to know the type of the zone: for conventional zones,
+ * use regular discard if the drive supports it. For sequential
+ * zones, reset the zone write pointer.
+ */
+ switch (get_blkz_type(sbi, bdev, blkstart)) {
+
+ case BLK_ZONE_TYPE_CONVENTIONAL:
+ if (!blk_queue_discard(bdev_get_queue(bdev)))
+ return 0;
+ return __queue_discard_cmd(sbi, bdev, lblkstart, blklen);
+ case BLK_ZONE_TYPE_SEQWRITE_REQ:
+ case BLK_ZONE_TYPE_SEQWRITE_PREF:
+ sector = SECTOR_FROM_BLOCK(blkstart);
+ nr_sects = SECTOR_FROM_BLOCK(blklen);
+
+ if (sector & (bdev_zone_sectors(bdev) - 1) ||
+ nr_sects != bdev_zone_sectors(bdev)) {
+ f2fs_msg(sbi->sb, KERN_INFO,
+ "(%d) %s: Unaligned discard attempted (block %x + %x)",
+ devi, sbi->s_ndevs ? FDEV(devi).path: "",
+ blkstart, blklen);
+ return -EIO;
+ }
+ trace_f2fs_issue_reset_zone(bdev, blkstart);
+ return blkdev_reset_zones(bdev, sector,
+ nr_sects, GFP_NOFS);
+ default:
+ /* Unknown zone type: broken device ? */
+ return -EIO;
+ }
+}
+#endif
+
+static int __issue_discard_async(struct f2fs_sb_info *sbi,
+ struct block_device *bdev, block_t blkstart, block_t blklen)
+{
+#ifdef CONFIG_BLK_DEV_ZONED
+ if (f2fs_sb_mounted_blkzoned(sbi->sb) &&
+ bdev_zoned_model(bdev) != BLK_ZONED_NONE)
+ return __f2fs_issue_discard_zone(sbi, bdev, blkstart, blklen);
+#endif
+ return __queue_discard_cmd(sbi, bdev, blkstart, blklen);
}
static int f2fs_issue_discard(struct f2fs_sb_info *sbi,
block_t blkstart, block_t blklen)
{
- sector_t start = SECTOR_FROM_BLOCK(blkstart);
- sector_t len = SECTOR_FROM_BLOCK(blklen);
+ sector_t start = blkstart, len = 0;
+ struct block_device *bdev;
struct seg_entry *se;
unsigned int offset;
block_t i;
+ int err = 0;
- for (i = blkstart; i < blkstart + blklen; i++) {
+ bdev = f2fs_target_device(sbi, blkstart, NULL);
+
+ for (i = blkstart; i < blkstart + blklen; i++, len++) {
+ if (i != start) {
+ struct block_device *bdev2 =
+ f2fs_target_device(sbi, i, NULL);
+
+ if (bdev2 != bdev) {
+ err = __issue_discard_async(sbi, bdev,
+ start, len);
+ if (err)
+ return err;
+ bdev = bdev2;
+ start = i;
+ len = 0;
+ }
+ }
+
se = get_seg_entry(sbi, GET_SEGNO(sbi, i));
offset = GET_BLKOFF_FROM_SEG0(sbi, i);
if (!f2fs_test_and_set_bit(offset, se->discard_map))
sbi->discard_blks--;
}
- trace_f2fs_issue_discard(sbi->sb, blkstart, blklen);
- return __f2fs_issue_discard_async(sbi, start, len, GFP_NOFS, 0);
+
+ if (len)
+ err = __issue_discard_async(sbi, bdev, start, len);
+ return err;
}
-static void __add_discard_entry(struct f2fs_sb_info *sbi,
- struct cp_control *cpc, struct seg_entry *se,
- unsigned int start, unsigned int end)
-{
- struct list_head *head = &SM_I(sbi)->discard_list;
- struct discard_entry *new, *last;
-
- if (!list_empty(head)) {
- last = list_last_entry(head, struct discard_entry, list);
- if (START_BLOCK(sbi, cpc->trim_start) + start ==
- last->blkaddr + last->len) {
- last->len += end - start;
- goto done;
- }
- }
-
- new = f2fs_kmem_cache_alloc(discard_entry_slab, GFP_NOFS);
- INIT_LIST_HEAD(&new->list);
- new->blkaddr = START_BLOCK(sbi, cpc->trim_start) + start;
- new->len = end - start;
- list_add_tail(&new->list, head);
-done:
- SM_I(sbi)->nr_discards += end - start;
-}
-
-static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc)
+static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
+ bool check_only)
{
int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long);
int max_blocks = sbi->blocks_per_seg;
@@ -709,16 +1543,19 @@
unsigned long *discard_map = (unsigned long *)se->discard_map;
unsigned long *dmap = SIT_I(sbi)->tmp_map;
unsigned int start = 0, end = -1;
- bool force = (cpc->reason == CP_DISCARD);
+ bool force = (cpc->reason & CP_DISCARD);
+ struct discard_entry *de = NULL;
+ struct list_head *head = &SM_I(sbi)->dcc_info->entry_list;
int i;
if (se->valid_blocks == max_blocks || !f2fs_discard_en(sbi))
- return;
+ return false;
if (!force) {
if (!test_opt(sbi, DISCARD) || !se->valid_blocks ||
- SM_I(sbi)->nr_discards >= SM_I(sbi)->max_discards)
- return;
+ SM_I(sbi)->dcc_info->nr_discards >=
+ SM_I(sbi)->dcc_info->max_discards)
+ return false;
}
/* SIT_VBLOCK_MAP_SIZE should be multiple of sizeof(unsigned long) */
@@ -726,7 +1563,8 @@
dmap[i] = force ? ~ckpt_map[i] & ~discard_map[i] :
(cur_map[i] ^ ckpt_map[i]) & ckpt_map[i];
- while (force || SM_I(sbi)->nr_discards <= SM_I(sbi)->max_discards) {
+ while (force || SM_I(sbi)->dcc_info->nr_discards <=
+ SM_I(sbi)->dcc_info->max_discards) {
start = __find_rev_next_bit(dmap, max_blocks, end + 1);
if (start >= max_blocks)
break;
@@ -736,13 +1574,27 @@
&& (end - start) < cpc->trim_minlen)
continue;
- __add_discard_entry(sbi, cpc, se, start, end);
+ if (check_only)
+ return true;
+
+ if (!de) {
+ de = f2fs_kmem_cache_alloc(discard_entry_slab,
+ GFP_F2FS_ZERO);
+ de->start_blkaddr = START_BLOCK(sbi, cpc->trim_start);
+ list_add_tail(&de->list, head);
+ }
+
+ for (i = start; i < end; i++)
+ __set_bit_le(i, (void *)de->discard_map);
+
+ SM_I(sbi)->dcc_info->nr_discards += end - start;
}
+ return false;
}
void release_discard_addrs(struct f2fs_sb_info *sbi)
{
- struct list_head *head = &(SM_I(sbi)->discard_list);
+ struct list_head *head = &(SM_I(sbi)->dcc_info->entry_list);
struct discard_entry *entry, *this;
/* drop caches */
@@ -768,16 +1620,14 @@
void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc)
{
- struct list_head *head = &(SM_I(sbi)->discard_list);
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct list_head *head = &dcc->entry_list;
struct discard_entry *entry, *this;
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
- struct blk_plug plug;
unsigned long *prefree_map = dirty_i->dirty_segmap[PRE];
unsigned int start = 0, end = -1;
unsigned int secno, start_segno;
- bool force = (cpc->reason == CP_DISCARD);
-
- blk_start_plug(&plug);
+ bool force = (cpc->reason & CP_DISCARD);
mutex_lock(&dirty_i->seglist_lock);
@@ -794,19 +1644,23 @@
dirty_i->nr_dirty[PRE] -= end - start;
- if (force || !test_opt(sbi, DISCARD))
+ if (!test_opt(sbi, DISCARD))
continue;
+ if (force && start >= cpc->trim_start &&
+ (end - 1) <= cpc->trim_end)
+ continue;
+
if (!test_opt(sbi, LFS) || sbi->segs_per_sec == 1) {
f2fs_issue_discard(sbi, START_BLOCK(sbi, start),
(end - start) << sbi->log_blocks_per_seg);
continue;
}
next:
- secno = GET_SECNO(sbi, start);
- start_segno = secno * sbi->segs_per_sec;
+ secno = GET_SEC_FROM_SEG(sbi, start);
+ start_segno = GET_SEG_FROM_SEC(sbi, secno);
if (!IS_CURSEC(sbi, secno) &&
- !get_valid_blocks(sbi, start, sbi->segs_per_sec))
+ !get_valid_blocks(sbi, start, true))
f2fs_issue_discard(sbi, START_BLOCK(sbi, start_segno),
sbi->segs_per_sec << sbi->log_blocks_per_seg);
@@ -820,17 +1674,123 @@
/* send small discards */
list_for_each_entry_safe(entry, this, head, list) {
- if (force && entry->len < cpc->trim_minlen)
- goto skip;
- f2fs_issue_discard(sbi, entry->blkaddr, entry->len);
- cpc->trimmed += entry->len;
+ unsigned int cur_pos = 0, next_pos, len, total_len = 0;
+ bool is_valid = test_bit_le(0, entry->discard_map);
+
+find_next:
+ if (is_valid) {
+ next_pos = find_next_zero_bit_le(entry->discard_map,
+ sbi->blocks_per_seg, cur_pos);
+ len = next_pos - cur_pos;
+
+ if (f2fs_sb_mounted_blkzoned(sbi->sb) ||
+ (force && len < cpc->trim_minlen))
+ goto skip;
+
+ f2fs_issue_discard(sbi, entry->start_blkaddr + cur_pos,
+ len);
+ total_len += len;
+ } else {
+ next_pos = find_next_bit_le(entry->discard_map,
+ sbi->blocks_per_seg, cur_pos);
+ }
skip:
+ cur_pos = next_pos;
+ is_valid = !is_valid;
+
+ if (cur_pos < sbi->blocks_per_seg)
+ goto find_next;
+
list_del(&entry->list);
- SM_I(sbi)->nr_discards -= entry->len;
+ dcc->nr_discards -= total_len;
kmem_cache_free(discard_entry_slab, entry);
}
- blk_finish_plug(&plug);
+ wake_up_discard_thread(sbi, false);
+}
+
+void init_discard_policy(struct discard_policy *dpolicy,
+ int discard_type, unsigned int granularity)
+{
+ /* common policy */
+ dpolicy->type = discard_type;
+ dpolicy->sync = true;
+ dpolicy->granularity = granularity;
+
+ dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST;
+ dpolicy->io_aware_gran = MAX_PLIST_NUM;
+
+ if (discard_type == DPOLICY_BG) {
+ dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME;
+ dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME;
+ dpolicy->io_aware = true;
+ } else if (discard_type == DPOLICY_FORCE) {
+ dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME;
+ dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME;
+ dpolicy->io_aware = true;
+ } else if (discard_type == DPOLICY_FSTRIM) {
+ dpolicy->io_aware = false;
+ } else if (discard_type == DPOLICY_UMOUNT) {
+ dpolicy->io_aware = false;
+ }
+}
+
+static int create_discard_cmd_control(struct f2fs_sb_info *sbi)
+{
+ dev_t dev = sbi->sb->s_bdev->bd_dev;
+ struct discard_cmd_control *dcc;
+ int err = 0, i;
+
+ if (SM_I(sbi)->dcc_info) {
+ dcc = SM_I(sbi)->dcc_info;
+ goto init_thread;
+ }
+
+ dcc = f2fs_kzalloc(sbi, sizeof(struct discard_cmd_control), GFP_KERNEL);
+ if (!dcc)
+ return -ENOMEM;
+
+ dcc->discard_granularity = DEFAULT_DISCARD_GRANULARITY;
+ INIT_LIST_HEAD(&dcc->entry_list);
+ for (i = 0; i < MAX_PLIST_NUM; i++)
+ INIT_LIST_HEAD(&dcc->pend_list[i]);
+ INIT_LIST_HEAD(&dcc->wait_list);
+ INIT_LIST_HEAD(&dcc->fstrim_list);
+ mutex_init(&dcc->cmd_lock);
+ atomic_set(&dcc->issued_discard, 0);
+ atomic_set(&dcc->issing_discard, 0);
+ atomic_set(&dcc->discard_cmd_cnt, 0);
+ dcc->nr_discards = 0;
+ dcc->max_discards = MAIN_SEGS(sbi) << sbi->log_blocks_per_seg;
+ dcc->undiscard_blks = 0;
+ dcc->root = RB_ROOT;
+
+ init_waitqueue_head(&dcc->discard_wait_queue);
+ SM_I(sbi)->dcc_info = dcc;
+init_thread:
+ dcc->f2fs_issue_discard = kthread_run(issue_discard_thread, sbi,
+ "f2fs_discard-%u:%u", MAJOR(dev), MINOR(dev));
+ if (IS_ERR(dcc->f2fs_issue_discard)) {
+ err = PTR_ERR(dcc->f2fs_issue_discard);
+ kfree(dcc);
+ SM_I(sbi)->dcc_info = NULL;
+ return err;
+ }
+
+ return err;
+}
+
+static void destroy_discard_cmd_control(struct f2fs_sb_info *sbi)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+
+ if (!dcc)
+ return;
+
+ stop_discard_thread(sbi);
+
+ kfree(dcc);
+ SM_I(sbi)->dcc_info = NULL;
}
static bool __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno)
@@ -859,6 +1819,10 @@
struct seg_entry *se;
unsigned int segno, offset;
long int new_vblocks;
+ bool exist;
+#ifdef CONFIG_F2FS_CHECK_FS
+ bool mir_exist;
+#endif
segno = GET_SEGNO(sbi, blkaddr);
@@ -875,14 +1839,54 @@
/* Update valid block bitmap */
if (del > 0) {
- if (f2fs_test_and_set_bit(offset, se->cur_valid_map))
+ exist = f2fs_test_and_set_bit(offset, se->cur_valid_map);
+#ifdef CONFIG_F2FS_CHECK_FS
+ mir_exist = f2fs_test_and_set_bit(offset,
+ se->cur_valid_map_mir);
+ if (unlikely(exist != mir_exist)) {
+ f2fs_msg(sbi->sb, KERN_ERR, "Inconsistent error "
+ "when setting bitmap, blk:%u, old bit:%d",
+ blkaddr, exist);
f2fs_bug_on(sbi, 1);
+ }
+#endif
+ if (unlikely(exist)) {
+ f2fs_msg(sbi->sb, KERN_ERR,
+ "Bitmap was wrongly set, blk:%u", blkaddr);
+ f2fs_bug_on(sbi, 1);
+ se->valid_blocks--;
+ del = 0;
+ }
+
if (f2fs_discard_en(sbi) &&
!f2fs_test_and_set_bit(offset, se->discard_map))
sbi->discard_blks--;
+
+ /* don't overwrite by SSR to keep node chain */
+ if (se->type == CURSEG_WARM_NODE) {
+ if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map))
+ se->ckpt_valid_blocks++;
+ }
} else {
- if (!f2fs_test_and_clear_bit(offset, se->cur_valid_map))
+ exist = f2fs_test_and_clear_bit(offset, se->cur_valid_map);
+#ifdef CONFIG_F2FS_CHECK_FS
+ mir_exist = f2fs_test_and_clear_bit(offset,
+ se->cur_valid_map_mir);
+ if (unlikely(exist != mir_exist)) {
+ f2fs_msg(sbi->sb, KERN_ERR, "Inconsistent error "
+ "when clearing bitmap, blk:%u, old bit:%d",
+ blkaddr, exist);
f2fs_bug_on(sbi, 1);
+ }
+#endif
+ if (unlikely(!exist)) {
+ f2fs_msg(sbi->sb, KERN_ERR,
+ "Bitmap was wrongly cleared, blk:%u", blkaddr);
+ f2fs_bug_on(sbi, 1);
+ se->valid_blocks++;
+ del = 0;
+ }
+
if (f2fs_discard_en(sbi) &&
f2fs_test_and_clear_bit(offset, se->discard_map))
sbi->discard_blks++;
@@ -899,16 +1903,6 @@
get_sec_entry(sbi, segno)->valid_blocks += del;
}
-void refresh_sit_entry(struct f2fs_sb_info *sbi, block_t old, block_t new)
-{
- update_sit_entry(sbi, new, 1);
- if (GET_SEGNO(sbi, old) != NULL_SEGNO)
- update_sit_entry(sbi, old, -1);
-
- locate_dirty_segment(sbi, GET_SEGNO(sbi, old));
- locate_dirty_segment(sbi, GET_SEGNO(sbi, new));
-}
-
void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
{
unsigned int segno = GET_SEGNO(sbi, addr);
@@ -919,14 +1913,14 @@
return;
/* add it into sit main buffer */
- mutex_lock(&sit_i->sentry_lock);
+ down_write(&sit_i->sentry_lock);
update_sit_entry(sbi, addr, -1);
/* add it into dirty seglist */
locate_dirty_segment(sbi, segno);
- mutex_unlock(&sit_i->sentry_lock);
+ up_write(&sit_i->sentry_lock);
}
bool is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)
@@ -939,7 +1933,7 @@
if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
return true;
- mutex_lock(&sit_i->sentry_lock);
+ down_read(&sit_i->sentry_lock);
segno = GET_SEGNO(sbi, blkaddr);
se = get_seg_entry(sbi, segno);
@@ -948,7 +1942,7 @@
if (f2fs_test_bit(offset, se->ckpt_valid_map))
is_cp = true;
- mutex_unlock(&sit_i->sentry_lock);
+ up_read(&sit_i->sentry_lock);
return is_cp;
}
@@ -1006,12 +2000,8 @@
void update_meta_page(struct f2fs_sb_info *sbi, void *src, block_t blk_addr)
{
struct page *page = grab_meta_page(sbi, blk_addr);
- void *dst = page_address(page);
- if (src)
- memcpy(dst, src, PAGE_SIZE);
- else
- memset(dst, 0, PAGE_SIZE);
+ memcpy(page_address(page), src, PAGE_SIZE);
set_page_dirty(page);
f2fs_put_page(page, 1);
}
@@ -1068,8 +2058,8 @@
struct free_segmap_info *free_i = FREE_I(sbi);
unsigned int segno, secno, zoneno;
unsigned int total_zones = MAIN_SECS(sbi) / sbi->secs_per_zone;
- unsigned int hint = *newseg / sbi->segs_per_sec;
- unsigned int old_zoneno = GET_ZONENO_FROM_SEGNO(sbi, *newseg);
+ unsigned int hint = GET_SEC_FROM_SEG(sbi, *newseg);
+ unsigned int old_zoneno = GET_ZONE_FROM_SEG(sbi, *newseg);
unsigned int left_start = hint;
bool init = true;
int go_left = 0;
@@ -1079,8 +2069,8 @@
if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) {
segno = find_next_zero_bit(free_i->free_segmap,
- (hint + 1) * sbi->segs_per_sec, *newseg + 1);
- if (segno < (hint + 1) * sbi->segs_per_sec)
+ GET_SEG_FROM_SEC(sbi, hint + 1), *newseg + 1);
+ if (segno < GET_SEG_FROM_SEC(sbi, hint + 1))
goto got_it;
}
find_other_zone:
@@ -1110,9 +2100,8 @@
}
secno = left_start;
skip_left:
- hint = secno;
- segno = secno * sbi->segs_per_sec;
- zoneno = secno / sbi->secs_per_zone;
+ segno = GET_SEG_FROM_SEC(sbi, secno);
+ zoneno = GET_ZONE_FROM_SEC(sbi, secno);
/* give up on finding another zone */
if (!init)
@@ -1156,7 +2145,7 @@
struct summary_footer *sum_footer;
curseg->segno = curseg->next_segno;
- curseg->zone = GET_ZONENO_FROM_SEGNO(sbi, curseg->segno);
+ curseg->zone = GET_ZONE_FROM_SEG(sbi, curseg->segno);
curseg->next_blkoff = 0;
curseg->next_segno = NULL_SEGNO;
@@ -1169,6 +2158,20 @@
__set_sit_entry_type(sbi, type, curseg->segno, modified);
}
+static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
+{
+ /* if segs_per_sec is large than 1, we need to keep original policy. */
+ if (sbi->segs_per_sec != 1)
+ return CURSEG_I(sbi, type)->segno;
+
+ if (type == CURSEG_HOT_DATA || IS_NODESEG(type))
+ return 0;
+
+ if (SIT_I(sbi)->last_victim[ALLOC_NEXT])
+ return SIT_I(sbi)->last_victim[ALLOC_NEXT];
+ return CURSEG_I(sbi, type)->segno;
+}
+
/*
* Allocate a current working segment.
* This function always allocates a free segment in LFS manner.
@@ -1187,6 +2190,7 @@
if (test_opt(sbi, NOHEAP))
dir = ALLOC_RIGHT;
+ segno = __get_next_segno(sbi, type);
get_new_segment(sbi, &segno, new_sec, dir);
curseg->next_segno = segno;
reset_curseg(sbi, type, 1);
@@ -1229,7 +2233,7 @@
* This function always allocates a used segment(from dirty seglist) by SSR
* manner, so it should recover the existing segment information of valid blocks
*/
-static void change_curseg(struct f2fs_sb_info *sbi, int type, bool reuse)
+static void change_curseg(struct f2fs_sb_info *sbi, int type)
{
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
struct curseg_info *curseg = CURSEG_I(sbi, type);
@@ -1250,28 +2254,53 @@
curseg->alloc_type = SSR;
__next_free_blkoff(sbi, curseg, 0);
- if (reuse) {
- sum_page = get_sum_page(sbi, new_segno);
- sum_node = (struct f2fs_summary_block *)page_address(sum_page);
- memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE);
- f2fs_put_page(sum_page, 1);
- }
+ sum_page = get_sum_page(sbi, new_segno);
+ sum_node = (struct f2fs_summary_block *)page_address(sum_page);
+ memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE);
+ f2fs_put_page(sum_page, 1);
}
static int get_ssr_segment(struct f2fs_sb_info *sbi, int type)
{
struct curseg_info *curseg = CURSEG_I(sbi, type);
const struct victim_selection *v_ops = DIRTY_I(sbi)->v_ops;
+ unsigned segno = NULL_SEGNO;
+ int i, cnt;
+ bool reversed = false;
- if (IS_NODESEG(type))
- return v_ops->get_victim(sbi,
- &(curseg)->next_segno, BG_GC, type, SSR);
+ /* need_SSR() already forces to do this */
+ if (v_ops->get_victim(sbi, &segno, BG_GC, type, SSR)) {
+ curseg->next_segno = segno;
+ return 1;
+ }
- /* For data segments, let's do SSR more intensively */
- for (; type >= CURSEG_HOT_DATA; type--)
- if (v_ops->get_victim(sbi, &(curseg)->next_segno,
- BG_GC, type, SSR))
+ /* For node segments, let's do SSR more intensively */
+ if (IS_NODESEG(type)) {
+ if (type >= CURSEG_WARM_NODE) {
+ reversed = true;
+ i = CURSEG_COLD_NODE;
+ } else {
+ i = CURSEG_HOT_NODE;
+ }
+ cnt = NR_CURSEG_NODE_TYPE;
+ } else {
+ if (type >= CURSEG_WARM_DATA) {
+ reversed = true;
+ i = CURSEG_COLD_DATA;
+ } else {
+ i = CURSEG_HOT_DATA;
+ }
+ cnt = NR_CURSEG_DATA_TYPE;
+ }
+
+ for (; cnt-- > 0; reversed ? i-- : i++) {
+ if (i == type)
+ continue;
+ if (v_ops->get_victim(sbi, &segno, BG_GC, i, SSR)) {
+ curseg->next_segno = segno;
return 1;
+ }
+ }
return 0;
}
@@ -1286,55 +2315,73 @@
if (force)
new_curseg(sbi, type, true);
- else if (type == CURSEG_WARM_NODE)
+ else if (!is_set_ckpt_flags(sbi, CP_CRC_RECOVERY_FLAG) &&
+ type == CURSEG_WARM_NODE)
new_curseg(sbi, type, false);
else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type))
new_curseg(sbi, type, false);
else if (need_SSR(sbi) && get_ssr_segment(sbi, type))
- change_curseg(sbi, type, true);
+ change_curseg(sbi, type);
else
new_curseg(sbi, type, false);
stat_inc_seg_type(sbi, curseg);
}
-static void __allocate_new_segments(struct f2fs_sb_info *sbi, int type)
-{
- struct curseg_info *curseg = CURSEG_I(sbi, type);
- unsigned int old_segno;
-
- old_segno = curseg->segno;
- SIT_I(sbi)->s_ops->allocate_segment(sbi, type, true);
- locate_dirty_segment(sbi, old_segno);
-}
-
void allocate_new_segments(struct f2fs_sb_info *sbi)
{
+ struct curseg_info *curseg;
+ unsigned int old_segno;
int i;
- if (test_opt(sbi, LFS))
- return;
+ down_write(&SIT_I(sbi)->sentry_lock);
- for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++)
- __allocate_new_segments(sbi, i);
+ for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
+ curseg = CURSEG_I(sbi, i);
+ old_segno = curseg->segno;
+ SIT_I(sbi)->s_ops->allocate_segment(sbi, i, true);
+ locate_dirty_segment(sbi, old_segno);
+ }
+
+ up_write(&SIT_I(sbi)->sentry_lock);
}
static const struct segment_allocation default_salloc_ops = {
.allocate_segment = allocate_segment_by_default,
};
+bool exist_trim_candidates(struct f2fs_sb_info *sbi, struct cp_control *cpc)
+{
+ __u64 trim_start = cpc->trim_start;
+ bool has_candidate = false;
+
+ down_write(&SIT_I(sbi)->sentry_lock);
+ for (; cpc->trim_start <= cpc->trim_end; cpc->trim_start++) {
+ if (add_discard_addrs(sbi, cpc, true)) {
+ has_candidate = true;
+ break;
+ }
+ }
+ up_write(&SIT_I(sbi)->sentry_lock);
+
+ cpc->trim_start = trim_start;
+ return has_candidate;
+}
+
int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
{
__u64 start = F2FS_BYTES_TO_BLK(range->start);
__u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1;
- unsigned int start_segno, end_segno;
+ unsigned int start_segno, end_segno, cur_segno;
+ block_t start_block, end_block;
struct cp_control cpc;
+ struct discard_policy dpolicy;
+ unsigned long long trimmed = 0;
int err = 0;
if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize)
return -EINVAL;
- cpc.trimmed = 0;
if (end <= MAIN_BLKADDR(sbi))
goto out;
@@ -1348,12 +2395,14 @@
start_segno = (start <= MAIN_BLKADDR(sbi)) ? 0 : GET_SEGNO(sbi, start);
end_segno = (end >= MAX_BLKADDR(sbi)) ? MAIN_SEGS(sbi) - 1 :
GET_SEGNO(sbi, end);
+
cpc.reason = CP_DISCARD;
cpc.trim_minlen = max_t(__u64, 1, F2FS_BYTES_TO_BLK(range->minlen));
/* do checkpoint to issue discard commands safely */
- for (; start_segno <= end_segno; start_segno = cpc.trim_end + 1) {
- cpc.trim_start = start_segno;
+ for (cur_segno = start_segno; cur_segno <= end_segno;
+ cur_segno = cpc.trim_end + 1) {
+ cpc.trim_start = cur_segno;
if (sbi->discard_blks == 0)
break;
@@ -1361,7 +2410,7 @@
cpc.trim_end = end_segno;
else
cpc.trim_end = min_t(unsigned int,
- rounddown(start_segno +
+ rounddown(cur_segno +
BATCHED_TRIM_SEGMENTS(sbi),
sbi->segs_per_sec) - 1, end_segno);
@@ -1373,8 +2422,16 @@
schedule();
}
+
+ start_block = START_BLOCK(sbi, start_segno);
+ end_block = START_BLOCK(sbi, min(cur_segno, end_segno) + 1);
+
+ init_discard_policy(&dpolicy, DPOLICY_FSTRIM, cpc.trim_minlen);
+ __issue_discard_cmd_range(sbi, &dpolicy, start_block, end_block);
+ trimmed = __wait_discard_cmd_range(sbi, &dpolicy,
+ start_block, end_block);
out:
- range->len = F2FS_BLK_TO_BYTES(cpc.trimmed);
+ range->len = F2FS_BLK_TO_BYTES(trimmed);
return err;
}
@@ -1386,87 +2443,106 @@
return false;
}
-static int __get_segment_type_2(struct page *page, enum page_type p_type)
+int rw_hint_to_seg_type(enum rw_hint hint)
{
- if (p_type == DATA)
+ switch (hint) {
+ case WRITE_LIFE_SHORT:
+ return CURSEG_HOT_DATA;
+ case WRITE_LIFE_EXTREME:
+ return CURSEG_COLD_DATA;
+ default:
+ return CURSEG_WARM_DATA;
+ }
+}
+
+static int __get_segment_type_2(struct f2fs_io_info *fio)
+{
+ if (fio->type == DATA)
return CURSEG_HOT_DATA;
else
return CURSEG_HOT_NODE;
}
-static int __get_segment_type_4(struct page *page, enum page_type p_type)
+static int __get_segment_type_4(struct f2fs_io_info *fio)
{
- if (p_type == DATA) {
- struct inode *inode = page->mapping->host;
+ if (fio->type == DATA) {
+ struct inode *inode = fio->page->mapping->host;
if (S_ISDIR(inode->i_mode))
return CURSEG_HOT_DATA;
else
return CURSEG_COLD_DATA;
} else {
- if (IS_DNODE(page) && is_cold_node(page))
+ if (IS_DNODE(fio->page) && is_cold_node(fio->page))
return CURSEG_WARM_NODE;
else
return CURSEG_COLD_NODE;
}
}
-static int __get_segment_type_6(struct page *page, enum page_type p_type)
+static int __get_segment_type_6(struct f2fs_io_info *fio)
{
- if (p_type == DATA) {
- struct inode *inode = page->mapping->host;
+ if (fio->type == DATA) {
+ struct inode *inode = fio->page->mapping->host;
- if (S_ISDIR(inode->i_mode))
- return CURSEG_HOT_DATA;
- else if (is_cold_data(page) || file_is_cold(inode))
+ if (is_cold_data(fio->page) || file_is_cold(inode))
return CURSEG_COLD_DATA;
- else
- return CURSEG_WARM_DATA;
+ if (is_inode_flag_set(inode, FI_HOT_DATA))
+ return CURSEG_HOT_DATA;
+ /* rw_hint_to_seg_type(inode->i_write_hint); */
+ return CURSEG_WARM_DATA;
} else {
- if (IS_DNODE(page))
- return is_cold_node(page) ? CURSEG_WARM_NODE :
+ if (IS_DNODE(fio->page))
+ return is_cold_node(fio->page) ? CURSEG_WARM_NODE :
CURSEG_HOT_NODE;
- else
- return CURSEG_COLD_NODE;
+ return CURSEG_COLD_NODE;
}
}
-static int __get_segment_type(struct page *page, enum page_type p_type)
+static int __get_segment_type(struct f2fs_io_info *fio)
{
- switch (F2FS_P_SB(page)->active_logs) {
+ int type = 0;
+
+ switch (fio->sbi->active_logs) {
case 2:
- return __get_segment_type_2(page, p_type);
+ type = __get_segment_type_2(fio);
+ break;
case 4:
- return __get_segment_type_4(page, p_type);
+ type = __get_segment_type_4(fio);
+ break;
+ case 6:
+ type = __get_segment_type_6(fio);
+ break;
+ default:
+ f2fs_bug_on(fio->sbi, true);
}
- /* NR_CURSEG_TYPE(6) logs by default */
- f2fs_bug_on(F2FS_P_SB(page),
- F2FS_P_SB(page)->active_logs != NR_CURSEG_TYPE);
- return __get_segment_type_6(page, p_type);
+
+ if (IS_HOT(type))
+ fio->temp = HOT;
+ else if (IS_WARM(type))
+ fio->temp = WARM;
+ else
+ fio->temp = COLD;
+ return type;
}
void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
block_t old_blkaddr, block_t *new_blkaddr,
- struct f2fs_summary *sum, int type)
+ struct f2fs_summary *sum, int type,
+ struct f2fs_io_info *fio, bool add_list)
{
struct sit_info *sit_i = SIT_I(sbi);
- struct curseg_info *curseg;
- bool direct_io = (type == CURSEG_DIRECT_IO);
+ struct curseg_info *curseg = CURSEG_I(sbi, type);
- type = direct_io ? CURSEG_WARM_DATA : type;
-
- curseg = CURSEG_I(sbi, type);
+ down_read(&SM_I(sbi)->curseg_lock);
mutex_lock(&curseg->curseg_mutex);
- mutex_lock(&sit_i->sentry_lock);
-
- /* direct_io'ed data is aligned to the segment for better performance */
- if (direct_io && curseg->next_blkoff &&
- !has_not_enough_free_secs(sbi, 0, 0))
- __allocate_new_segments(sbi, type);
+ down_write(&sit_i->sentry_lock);
*new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
+ f2fs_wait_discard_bio(sbi, *new_blkaddr);
+
/*
* __add_sum_entry should be resided under the curseg_mutex
* because, this function updates a summary entry in the
@@ -1478,57 +2554,111 @@
stat_inc_block_count(sbi, curseg);
- if (!__has_curseg_space(sbi, type))
- sit_i->s_ops->allocate_segment(sbi, type, false);
/*
* SIT information should be updated before segment allocation,
* since SSR needs latest valid block information.
*/
- refresh_sit_entry(sbi, old_blkaddr, *new_blkaddr);
+ update_sit_entry(sbi, *new_blkaddr, 1);
+ if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
+ update_sit_entry(sbi, old_blkaddr, -1);
- mutex_unlock(&sit_i->sentry_lock);
+ if (!__has_curseg_space(sbi, type))
+ sit_i->s_ops->allocate_segment(sbi, type, false);
- if (page && IS_NODESEG(type))
+ /*
+ * segment dirty status should be updated after segment allocation,
+ * so we just need to update status only one time after previous
+ * segment being closed.
+ */
+ locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
+ locate_dirty_segment(sbi, GET_SEGNO(sbi, *new_blkaddr));
+
+ up_write(&sit_i->sentry_lock);
+
+ if (page && IS_NODESEG(type)) {
fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg));
+ f2fs_inode_chksum_set(sbi, page);
+ }
+
+ if (add_list) {
+ struct f2fs_bio_info *io;
+
+ INIT_LIST_HEAD(&fio->list);
+ fio->in_list = true;
+ io = sbi->write_io[fio->type] + fio->temp;
+ spin_lock(&io->io_lock);
+ list_add_tail(&fio->list, &io->io_list);
+ spin_unlock(&io->io_lock);
+ }
+
mutex_unlock(&curseg->curseg_mutex);
+
+ up_read(&SM_I(sbi)->curseg_lock);
+}
+
+static void update_device_state(struct f2fs_io_info *fio)
+{
+ struct f2fs_sb_info *sbi = fio->sbi;
+ unsigned int devidx;
+
+ if (!sbi->s_ndevs)
+ return;
+
+ devidx = f2fs_target_device_index(sbi, fio->new_blkaddr);
+
+ /* update device state for fsync */
+ set_dirty_device(sbi, fio->ino, devidx, FLUSH_INO);
+
+ /* update device state for checkpoint */
+ if (!f2fs_test_bit(devidx, (char *)&sbi->dirty_device)) {
+ spin_lock(&sbi->dev_lock);
+ f2fs_set_bit(devidx, (char *)&sbi->dirty_device);
+ spin_unlock(&sbi->dev_lock);
+ }
}
static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
{
- int type = __get_segment_type(fio->page, fio->type);
+ int type = __get_segment_type(fio);
+ int err;
- if (fio->type == NODE || fio->type == DATA)
- mutex_lock(&fio->sbi->wio_mutex[fio->type]);
-
+reallocate:
allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
- &fio->new_blkaddr, sum, type);
+ &fio->new_blkaddr, sum, type, fio, true);
/* writeout dirty page into bdev */
- f2fs_submit_page_mbio(fio);
-
- if (fio->type == NODE || fio->type == DATA)
- mutex_unlock(&fio->sbi->wio_mutex[fio->type]);
+ err = f2fs_submit_page_write(fio);
+ if (err == -EAGAIN) {
+ fio->old_blkaddr = fio->new_blkaddr;
+ goto reallocate;
+ } else if (!err) {
+ update_device_state(fio);
+ }
}
-void write_meta_page(struct f2fs_sb_info *sbi, struct page *page)
+void write_meta_page(struct f2fs_sb_info *sbi, struct page *page,
+ enum iostat_type io_type)
{
struct f2fs_io_info fio = {
.sbi = sbi,
.type = META,
.op = REQ_OP_WRITE,
- .op_flags = WRITE_SYNC | REQ_META | REQ_PRIO,
+ .op_flags = REQ_SYNC | REQ_META | REQ_PRIO,
.old_blkaddr = page->index,
.new_blkaddr = page->index,
.page = page,
.encrypted_page = NULL,
+ .in_list = false,
};
if (unlikely(page->index >= MAIN_BLKADDR(sbi)))
fio.op_flags &= ~REQ_META;
set_page_writeback(page);
- f2fs_submit_page_mbio(&fio);
+ f2fs_submit_page_write(&fio);
+
+ f2fs_update_iostat(sbi, io_type, F2FS_BLKSIZE);
}
void write_node_page(unsigned int nid, struct f2fs_io_info *fio)
@@ -1537,6 +2667,8 @@
set_summary(&sum, nid, 0, 0);
do_write_page(&sum, fio);
+
+ f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE);
}
void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio)
@@ -1550,13 +2682,36 @@
set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
do_write_page(&sum, fio);
f2fs_update_data_blkaddr(dn, fio->new_blkaddr);
+
+ f2fs_update_iostat(sbi, fio->io_type, F2FS_BLKSIZE);
}
-void rewrite_data_page(struct f2fs_io_info *fio)
+int rewrite_data_page(struct f2fs_io_info *fio)
{
+ int err;
+
fio->new_blkaddr = fio->old_blkaddr;
stat_inc_inplace_blocks(fio->sbi);
- f2fs_submit_page_mbio(fio);
+
+ err = f2fs_submit_page_bio(fio);
+ if (!err)
+ update_device_state(fio);
+
+ f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE);
+
+ return err;
+}
+
+static inline int __f2fs_get_curseg(struct f2fs_sb_info *sbi,
+ unsigned int segno)
+{
+ int i;
+
+ for (i = CURSEG_HOT_DATA; i < NO_CHECK_TYPE; i++) {
+ if (CURSEG_I(sbi, i)->segno == segno)
+ break;
+ }
+ return i;
}
void __f2fs_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
@@ -1574,6 +2729,8 @@
se = get_seg_entry(sbi, segno);
type = se->type;
+ down_write(&SM_I(sbi)->curseg_lock);
+
if (!recover_curseg) {
/* for recovery flow */
if (se->valid_blocks == 0 && !IS_CURSEG(sbi, segno)) {
@@ -1583,14 +2740,20 @@
type = CURSEG_WARM_DATA;
}
} else {
- if (!IS_CURSEG(sbi, segno))
+ if (IS_CURSEG(sbi, segno)) {
+ /* se->type is volatile as SSR allocation */
+ type = __f2fs_get_curseg(sbi, segno);
+ f2fs_bug_on(sbi, type == NO_CHECK_TYPE);
+ } else {
type = CURSEG_WARM_DATA;
+ }
}
+ f2fs_bug_on(sbi, !IS_DATASEG(type));
curseg = CURSEG_I(sbi, type);
mutex_lock(&curseg->curseg_mutex);
- mutex_lock(&sit_i->sentry_lock);
+ down_write(&sit_i->sentry_lock);
old_cursegno = curseg->segno;
old_blkoff = curseg->next_blkoff;
@@ -1598,7 +2761,7 @@
/* change the current segment */
if (segno != curseg->segno) {
curseg->next_segno = segno;
- change_curseg(sbi, type, true);
+ change_curseg(sbi, type);
}
curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr);
@@ -1617,13 +2780,14 @@
if (recover_curseg) {
if (old_cursegno != curseg->segno) {
curseg->next_segno = old_cursegno;
- change_curseg(sbi, type, true);
+ change_curseg(sbi, type);
}
curseg->next_blkoff = old_blkoff;
}
- mutex_unlock(&sit_i->sentry_lock);
+ up_write(&sit_i->sentry_lock);
mutex_unlock(&curseg->curseg_mutex);
+ up_write(&SM_I(sbi)->curseg_lock);
}
void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
@@ -1647,7 +2811,8 @@
if (PageWriteback(page)) {
struct f2fs_sb_info *sbi = F2FS_P_SB(page);
- f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, type, WRITE);
+ f2fs_submit_merged_write_cond(sbi, page->mapping->host,
+ 0, page->index, type);
if (ordered)
wait_on_page_writeback(page);
else
@@ -1655,8 +2820,7 @@
}
}
-void f2fs_wait_on_encrypted_page_writeback(struct f2fs_sb_info *sbi,
- block_t blkaddr)
+void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr)
{
struct page *cpage;
@@ -1670,7 +2834,7 @@
}
}
-static int read_compacted_summaries(struct f2fs_sb_info *sbi)
+static void read_compacted_summaries(struct f2fs_sb_info *sbi)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct curseg_info *seg_i;
@@ -1727,7 +2891,6 @@
}
}
f2fs_put_page(page, 1);
- return 0;
}
static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
@@ -1773,13 +2936,7 @@
ns->ofs_in_node = 0;
}
} else {
- int err;
-
- err = restore_node_summary(sbi, segno, sum);
- if (err) {
- f2fs_put_page(new, 1);
- return err;
- }
+ restore_node_summary(sbi, segno, sum);
}
}
@@ -1818,8 +2975,7 @@
META_CP, true);
/* restore for compacted data summary */
- if (read_compacted_summaries(sbi))
- return -EINVAL;
+ read_compacted_summaries(sbi);
type = CURSEG_HOT_NODE;
}
@@ -1955,28 +3111,19 @@
unsigned int start)
{
struct sit_info *sit_i = SIT_I(sbi);
- struct page *src_page, *dst_page;
+ struct page *page;
pgoff_t src_off, dst_off;
- void *src_addr, *dst_addr;
src_off = current_sit_addr(sbi, start);
dst_off = next_sit_addr(sbi, src_off);
- /* get current sit block page without lock */
- src_page = get_meta_page(sbi, src_off);
- dst_page = grab_meta_page(sbi, dst_off);
- f2fs_bug_on(sbi, PageDirty(src_page));
+ page = grab_meta_page(sbi, dst_off);
+ seg_info_to_sit_page(sbi, page, start);
- src_addr = page_address(src_page);
- dst_addr = page_address(dst_page);
- memcpy(dst_addr, src_addr, PAGE_SIZE);
-
- set_page_dirty(dst_page);
- f2fs_put_page(src_page, 1);
-
+ set_page_dirty(page);
set_to_next_sit(sit_i, start);
- return dst_page;
+ return page;
}
static struct sit_entry_set *grab_sit_entry_set(void)
@@ -2077,7 +3224,7 @@
bool to_journal = true;
struct seg_entry *se;
- mutex_lock(&sit_i->sentry_lock);
+ down_write(&sit_i->sentry_lock);
if (!sit_i->dirty_sentries)
goto out;
@@ -2127,9 +3274,9 @@
se = get_seg_entry(sbi, segno);
/* add discard candidates */
- if (cpc->reason != CP_DISCARD) {
+ if (!(cpc->reason & CP_DISCARD)) {
cpc->trim_start = segno;
- add_discard_addrs(sbi, cpc);
+ add_discard_addrs(sbi, cpc, false);
}
if (to_journal) {
@@ -2163,11 +3310,15 @@
f2fs_bug_on(sbi, !list_empty(head));
f2fs_bug_on(sbi, sit_i->dirty_sentries);
out:
- if (cpc->reason == CP_DISCARD) {
+ if (cpc->reason & CP_DISCARD) {
+ __u64 trim_start = cpc->trim_start;
+
for (; cpc->trim_start <= cpc->trim_end; cpc->trim_start++)
- add_discard_addrs(sbi, cpc);
+ add_discard_addrs(sbi, cpc, false);
+
+ cpc->trim_start = trim_start;
}
- mutex_unlock(&sit_i->sentry_lock);
+ up_write(&sit_i->sentry_lock);
set_prefree_as_free_segments(sbi);
}
@@ -2175,52 +3326,60 @@
static int build_sit_info(struct f2fs_sb_info *sbi)
{
struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
- struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct sit_info *sit_i;
unsigned int sit_segs, start;
- char *src_bitmap, *dst_bitmap;
+ char *src_bitmap;
unsigned int bitmap_size;
/* allocate memory for SIT information */
- sit_i = kzalloc(sizeof(struct sit_info), GFP_KERNEL);
+ sit_i = f2fs_kzalloc(sbi, sizeof(struct sit_info), GFP_KERNEL);
if (!sit_i)
return -ENOMEM;
SM_I(sbi)->sit_info = sit_i;
- sit_i->sentries = f2fs_kvzalloc(MAIN_SEGS(sbi) *
+ sit_i->sentries = f2fs_kvzalloc(sbi, MAIN_SEGS(sbi) *
sizeof(struct seg_entry), GFP_KERNEL);
if (!sit_i->sentries)
return -ENOMEM;
bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
- sit_i->dirty_sentries_bitmap = f2fs_kvzalloc(bitmap_size, GFP_KERNEL);
+ sit_i->dirty_sentries_bitmap = f2fs_kvzalloc(sbi, bitmap_size,
+ GFP_KERNEL);
if (!sit_i->dirty_sentries_bitmap)
return -ENOMEM;
for (start = 0; start < MAIN_SEGS(sbi); start++) {
sit_i->sentries[start].cur_valid_map
- = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
+ = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
sit_i->sentries[start].ckpt_valid_map
- = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
+ = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
if (!sit_i->sentries[start].cur_valid_map ||
!sit_i->sentries[start].ckpt_valid_map)
return -ENOMEM;
+#ifdef CONFIG_F2FS_CHECK_FS
+ sit_i->sentries[start].cur_valid_map_mir
+ = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
+ if (!sit_i->sentries[start].cur_valid_map_mir)
+ return -ENOMEM;
+#endif
+
if (f2fs_discard_en(sbi)) {
sit_i->sentries[start].discard_map
- = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
+ = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE,
+ GFP_KERNEL);
if (!sit_i->sentries[start].discard_map)
return -ENOMEM;
}
}
- sit_i->tmp_map = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
+ sit_i->tmp_map = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
if (!sit_i->tmp_map)
return -ENOMEM;
if (sbi->segs_per_sec > 1) {
- sit_i->sec_entries = f2fs_kvzalloc(MAIN_SECS(sbi) *
+ sit_i->sec_entries = f2fs_kvzalloc(sbi, MAIN_SECS(sbi) *
sizeof(struct sec_entry), GFP_KERNEL);
if (!sit_i->sec_entries)
return -ENOMEM;
@@ -2233,23 +3392,28 @@
bitmap_size = __bitmap_size(sbi, SIT_BITMAP);
src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP);
- dst_bitmap = kmemdup(src_bitmap, bitmap_size, GFP_KERNEL);
- if (!dst_bitmap)
+ sit_i->sit_bitmap = kmemdup(src_bitmap, bitmap_size, GFP_KERNEL);
+ if (!sit_i->sit_bitmap)
return -ENOMEM;
+#ifdef CONFIG_F2FS_CHECK_FS
+ sit_i->sit_bitmap_mir = kmemdup(src_bitmap, bitmap_size, GFP_KERNEL);
+ if (!sit_i->sit_bitmap_mir)
+ return -ENOMEM;
+#endif
+
/* init SIT information */
sit_i->s_ops = &default_salloc_ops;
sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr);
sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg;
- sit_i->written_valid_blocks = le64_to_cpu(ckpt->valid_block_count);
- sit_i->sit_bitmap = dst_bitmap;
+ sit_i->written_valid_blocks = 0;
sit_i->bitmap_size = bitmap_size;
sit_i->dirty_sentries = 0;
sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK;
sit_i->elapsed_time = le64_to_cpu(sbi->ckpt->elapsed_time);
- sit_i->mounted_time = CURRENT_TIME_SEC.tv_sec;
- mutex_init(&sit_i->sentry_lock);
+ sit_i->mounted_time = ktime_get_real_seconds();
+ init_rwsem(&sit_i->sentry_lock);
return 0;
}
@@ -2259,19 +3423,19 @@
unsigned int bitmap_size, sec_bitmap_size;
/* allocate memory for free segmap information */
- free_i = kzalloc(sizeof(struct free_segmap_info), GFP_KERNEL);
+ free_i = f2fs_kzalloc(sbi, sizeof(struct free_segmap_info), GFP_KERNEL);
if (!free_i)
return -ENOMEM;
SM_I(sbi)->free_info = free_i;
bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
- free_i->free_segmap = f2fs_kvmalloc(bitmap_size, GFP_KERNEL);
+ free_i->free_segmap = f2fs_kvmalloc(sbi, bitmap_size, GFP_KERNEL);
if (!free_i->free_segmap)
return -ENOMEM;
sec_bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi));
- free_i->free_secmap = f2fs_kvmalloc(sec_bitmap_size, GFP_KERNEL);
+ free_i->free_secmap = f2fs_kvmalloc(sbi, sec_bitmap_size, GFP_KERNEL);
if (!free_i->free_secmap)
return -ENOMEM;
@@ -2292,7 +3456,7 @@
struct curseg_info *array;
int i;
- array = kcalloc(NR_CURSEG_TYPE, sizeof(*array), GFP_KERNEL);
+ array = f2fs_kzalloc(sbi, sizeof(*array) * NR_CURSEG_TYPE, GFP_KERNEL);
if (!array)
return -ENOMEM;
@@ -2300,12 +3464,12 @@
for (i = 0; i < NR_CURSEG_TYPE; i++) {
mutex_init(&array[i].curseg_mutex);
- array[i].sum_blk = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ array[i].sum_blk = f2fs_kzalloc(sbi, PAGE_SIZE, GFP_KERNEL);
if (!array[i].sum_blk)
return -ENOMEM;
init_rwsem(&array[i].journal_rwsem);
- array[i].journal = kzalloc(sizeof(struct f2fs_journal),
- GFP_KERNEL);
+ array[i].journal = f2fs_kzalloc(sbi,
+ sizeof(struct f2fs_journal), GFP_KERNEL);
if (!array[i].journal)
return -ENOMEM;
array[i].segno = NULL_SEGNO;
@@ -2314,7 +3478,7 @@
return restore_curseg_summaries(sbi);
}
-static void build_sit_entries(struct f2fs_sb_info *sbi)
+static int build_sit_entries(struct f2fs_sb_info *sbi)
{
struct sit_info *sit_i = SIT_I(sbi);
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
@@ -2324,10 +3488,11 @@
int sit_blk_cnt = SIT_BLK_CNT(sbi);
unsigned int i, start, end;
unsigned int readed, start_blk = 0;
- int nrpages = MAX_BIO_BLOCKS(sbi) * 8;
+ int err = 0;
do {
- readed = ra_meta_pages(sbi, start_blk, nrpages, META_SIT, true);
+ readed = ra_meta_pages(sbi, start_blk, BIO_MAX_PAGES,
+ META_SIT, true);
start = start_blk * sit_i->sents_per_block;
end = (start_blk + readed) * sit_i->sents_per_block;
@@ -2342,15 +3507,24 @@
sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)];
f2fs_put_page(page, 1);
- check_block_count(sbi, start, &sit);
+ err = check_block_count(sbi, start, &sit);
+ if (err)
+ return err;
seg_info_from_raw_sit(se, &sit);
/* build discard map only one time */
if (f2fs_discard_en(sbi)) {
- memcpy(se->discard_map, se->cur_valid_map,
- SIT_VBLOCK_MAP_SIZE);
- sbi->discard_blks += sbi->blocks_per_seg -
- se->valid_blocks;
+ if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
+ memset(se->discard_map, 0xff,
+ SIT_VBLOCK_MAP_SIZE);
+ } else {
+ memcpy(se->discard_map,
+ se->cur_valid_map,
+ SIT_VBLOCK_MAP_SIZE);
+ sbi->discard_blks +=
+ sbi->blocks_per_seg -
+ se->valid_blocks;
+ }
}
if (sbi->segs_per_sec > 1)
@@ -2370,14 +3544,21 @@
old_valid_blocks = se->valid_blocks;
- check_block_count(sbi, start, &sit);
+ err = check_block_count(sbi, start, &sit);
+ if (err)
+ break;
seg_info_from_raw_sit(se, &sit);
if (f2fs_discard_en(sbi)) {
- memcpy(se->discard_map, se->cur_valid_map,
- SIT_VBLOCK_MAP_SIZE);
- sbi->discard_blks += old_valid_blocks -
- se->valid_blocks;
+ if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
+ memset(se->discard_map, 0xff,
+ SIT_VBLOCK_MAP_SIZE);
+ } else {
+ memcpy(se->discard_map, se->cur_valid_map,
+ SIT_VBLOCK_MAP_SIZE);
+ sbi->discard_blks += old_valid_blocks -
+ se->valid_blocks;
+ }
}
if (sbi->segs_per_sec > 1)
@@ -2385,6 +3566,7 @@
se->valid_blocks - old_valid_blocks;
}
up_read(&curseg->journal_rwsem);
+ return err;
}
static void init_free_segmap(struct f2fs_sb_info *sbi)
@@ -2396,6 +3578,9 @@
struct seg_entry *sentry = get_seg_entry(sbi, start);
if (!sentry->valid_blocks)
__set_free(sbi, start);
+ else
+ SIT_I(sbi)->written_valid_blocks +=
+ sentry->valid_blocks;
}
/* set use the current segments */
@@ -2418,7 +3603,7 @@
if (segno >= MAIN_SEGS(sbi))
break;
offset = segno + 1;
- valid_blocks = get_valid_blocks(sbi, segno, 0);
+ valid_blocks = get_valid_blocks(sbi, segno, false);
if (valid_blocks == sbi->blocks_per_seg || !valid_blocks)
continue;
if (valid_blocks > sbi->blocks_per_seg) {
@@ -2436,7 +3621,7 @@
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
unsigned int bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi));
- dirty_i->victim_secmap = f2fs_kvzalloc(bitmap_size, GFP_KERNEL);
+ dirty_i->victim_secmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
if (!dirty_i->victim_secmap)
return -ENOMEM;
return 0;
@@ -2448,7 +3633,8 @@
unsigned int bitmap_size, i;
/* allocate memory for dirty segments list information */
- dirty_i = kzalloc(sizeof(struct dirty_seglist_info), GFP_KERNEL);
+ dirty_i = f2fs_kzalloc(sbi, sizeof(struct dirty_seglist_info),
+ GFP_KERNEL);
if (!dirty_i)
return -ENOMEM;
@@ -2458,7 +3644,8 @@
bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
for (i = 0; i < NR_DIRTY_TYPE; i++) {
- dirty_i->dirty_segmap[i] = f2fs_kvzalloc(bitmap_size, GFP_KERNEL);
+ dirty_i->dirty_segmap[i] = f2fs_kvzalloc(sbi, bitmap_size,
+ GFP_KERNEL);
if (!dirty_i->dirty_segmap[i])
return -ENOMEM;
}
@@ -2475,7 +3662,7 @@
struct sit_info *sit_i = SIT_I(sbi);
unsigned int segno;
- mutex_lock(&sit_i->sentry_lock);
+ down_write(&sit_i->sentry_lock);
sit_i->min_mtime = LLONG_MAX;
@@ -2492,7 +3679,7 @@
sit_i->min_mtime = mtime;
}
sit_i->max_mtime = get_mtime(sbi);
- mutex_unlock(&sit_i->sentry_lock);
+ up_write(&sit_i->sentry_lock);
}
int build_segment_manager(struct f2fs_sb_info *sbi)
@@ -2502,7 +3689,7 @@
struct f2fs_sm_info *sm_info;
int err;
- sm_info = kzalloc(sizeof(struct f2fs_sm_info), GFP_KERNEL);
+ sm_info = f2fs_kzalloc(sbi, sizeof(struct f2fs_sm_info), GFP_KERNEL);
if (!sm_info)
return -ENOMEM;
@@ -2524,22 +3711,25 @@
sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC;
sm_info->min_ipu_util = DEF_MIN_IPU_UTIL;
sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS;
-
- INIT_LIST_HEAD(&sm_info->discard_list);
- INIT_LIST_HEAD(&sm_info->wait_list);
- sm_info->nr_discards = 0;
- sm_info->max_discards = 0;
+ sm_info->min_hot_blocks = DEF_MIN_HOT_BLOCKS;
+ sm_info->min_ssr_sections = reserved_sections(sbi);
sm_info->trim_sections = DEF_BATCHED_TRIM_SECTIONS;
INIT_LIST_HEAD(&sm_info->sit_entry_set);
- if (test_opt(sbi, FLUSH_MERGE) && !f2fs_readonly(sbi->sb)) {
+ init_rwsem(&sm_info->curseg_lock);
+
+ if (!f2fs_readonly(sbi->sb)) {
err = create_flush_cmd_control(sbi);
if (err)
return err;
}
+ err = create_discard_cmd_control(sbi);
+ if (err)
+ return err;
+
err = build_sit_info(sbi);
if (err)
return err;
@@ -2551,7 +3741,9 @@
return err;
/* reinit free segmap based on SIT */
- build_sit_entries(sbi);
+ err = build_sit_entries(sbi);
+ if (err)
+ return err;
init_free_segmap(sbi);
err = build_dirty_segmap(sbi);
@@ -2633,6 +3825,9 @@
if (sit_i->sentries) {
for (start = 0; start < MAIN_SEGS(sbi); start++) {
kfree(sit_i->sentries[start].cur_valid_map);
+#ifdef CONFIG_F2FS_CHECK_FS
+ kfree(sit_i->sentries[start].cur_valid_map_mir);
+#endif
kfree(sit_i->sentries[start].ckpt_valid_map);
kfree(sit_i->sentries[start].discard_map);
}
@@ -2645,6 +3840,9 @@
SM_I(sbi)->sit_info = NULL;
kfree(sit_i->sit_bitmap);
+#ifdef CONFIG_F2FS_CHECK_FS
+ kfree(sit_i->sit_bitmap_mir);
+#endif
kfree(sit_i);
}
@@ -2654,7 +3852,8 @@
if (!sm_info)
return;
- destroy_flush_cmd_control(sbi);
+ destroy_flush_cmd_control(sbi, true);
+ destroy_discard_cmd_control(sbi);
destroy_dirty_segmap(sbi);
destroy_curseg(sbi);
destroy_free_segmap(sbi);
@@ -2670,15 +3869,15 @@
if (!discard_entry_slab)
goto fail;
- bio_entry_slab = f2fs_kmem_cache_create("bio_entry",
- sizeof(struct bio_entry));
- if (!bio_entry_slab)
+ discard_cmd_slab = f2fs_kmem_cache_create("discard_cmd",
+ sizeof(struct discard_cmd));
+ if (!discard_cmd_slab)
goto destroy_discard_entry;
sit_entry_set_slab = f2fs_kmem_cache_create("sit_entry_set",
sizeof(struct sit_entry_set));
if (!sit_entry_set_slab)
- goto destroy_bio_entry;
+ goto destroy_discard_cmd;
inmem_entry_slab = f2fs_kmem_cache_create("inmem_page_entry",
sizeof(struct inmem_pages));
@@ -2688,8 +3887,8 @@
destroy_sit_entry_set:
kmem_cache_destroy(sit_entry_set_slab);
-destroy_bio_entry:
- kmem_cache_destroy(bio_entry_slab);
+destroy_discard_cmd:
+ kmem_cache_destroy(discard_cmd_slab);
destroy_discard_entry:
kmem_cache_destroy(discard_entry_slab);
fail:
@@ -2699,7 +3898,7 @@
void destroy_segment_manager_caches(void)
{
kmem_cache_destroy(sit_entry_set_slab);
- kmem_cache_destroy(bio_entry_slab);
+ kmem_cache_destroy(discard_cmd_slab);
kmem_cache_destroy(discard_entry_slab);
kmem_cache_destroy(inmem_entry_slab);
}
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index b164f83..f11c4bc 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -18,79 +18,91 @@
#define DEF_RECLAIM_PREFREE_SEGMENTS 5 /* 5% over total segments */
#define DEF_MAX_RECLAIM_PREFREE_SEGMENTS 4096 /* 8GB in maximum */
-/* L: Logical segment # in volume, R: Relative segment # in main area */
-#define GET_L2R_SEGNO(free_i, segno) (segno - free_i->start_segno)
-#define GET_R2L_SEGNO(free_i, segno) (segno + free_i->start_segno)
+#define F2FS_MIN_SEGMENTS 9 /* SB + 2 (CP + SIT + NAT) + SSA + MAIN */
-#define IS_DATASEG(t) (t <= CURSEG_COLD_DATA)
-#define IS_NODESEG(t) (t >= CURSEG_HOT_NODE)
+/* L: Logical segment # in volume, R: Relative segment # in main area */
+#define GET_L2R_SEGNO(free_i, segno) ((segno) - (free_i)->start_segno)
+#define GET_R2L_SEGNO(free_i, segno) ((segno) + (free_i)->start_segno)
+
+#define IS_DATASEG(t) ((t) <= CURSEG_COLD_DATA)
+#define IS_NODESEG(t) ((t) >= CURSEG_HOT_NODE)
+
+#define IS_HOT(t) ((t) == CURSEG_HOT_NODE || (t) == CURSEG_HOT_DATA)
+#define IS_WARM(t) ((t) == CURSEG_WARM_NODE || (t) == CURSEG_WARM_DATA)
+#define IS_COLD(t) ((t) == CURSEG_COLD_NODE || (t) == CURSEG_COLD_DATA)
#define IS_CURSEG(sbi, seg) \
- ((seg == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) || \
- (seg == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) || \
- (seg == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno) || \
- (seg == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno) || \
- (seg == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno) || \
- (seg == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno))
+ (((seg) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) || \
+ ((seg) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) || \
+ ((seg) == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno) || \
+ ((seg) == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno) || \
+ ((seg) == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno) || \
+ ((seg) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno))
#define IS_CURSEC(sbi, secno) \
- ((secno == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno / \
- sbi->segs_per_sec) || \
- (secno == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno / \
- sbi->segs_per_sec) || \
- (secno == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno / \
- sbi->segs_per_sec) || \
- (secno == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno / \
- sbi->segs_per_sec) || \
- (secno == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno / \
- sbi->segs_per_sec) || \
- (secno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \
- sbi->segs_per_sec)) \
+ (((secno) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno / \
+ (sbi)->segs_per_sec) || \
+ ((secno) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno / \
+ (sbi)->segs_per_sec) || \
+ ((secno) == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno / \
+ (sbi)->segs_per_sec) || \
+ ((secno) == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno / \
+ (sbi)->segs_per_sec) || \
+ ((secno) == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno / \
+ (sbi)->segs_per_sec) || \
+ ((secno) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \
+ (sbi)->segs_per_sec)) \
#define MAIN_BLKADDR(sbi) (SM_I(sbi)->main_blkaddr)
#define SEG0_BLKADDR(sbi) (SM_I(sbi)->seg0_blkaddr)
#define MAIN_SEGS(sbi) (SM_I(sbi)->main_segments)
-#define MAIN_SECS(sbi) (sbi->total_sections)
+#define MAIN_SECS(sbi) ((sbi)->total_sections)
#define TOTAL_SEGS(sbi) (SM_I(sbi)->segment_count)
-#define TOTAL_BLKS(sbi) (TOTAL_SEGS(sbi) << sbi->log_blocks_per_seg)
+#define TOTAL_BLKS(sbi) (TOTAL_SEGS(sbi) << (sbi)->log_blocks_per_seg)
#define MAX_BLKADDR(sbi) (SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi))
-#define SEGMENT_SIZE(sbi) (1ULL << (sbi->log_blocksize + \
- sbi->log_blocks_per_seg))
+#define SEGMENT_SIZE(sbi) (1ULL << ((sbi)->log_blocksize + \
+ (sbi)->log_blocks_per_seg))
#define START_BLOCK(sbi, segno) (SEG0_BLKADDR(sbi) + \
- (GET_R2L_SEGNO(FREE_I(sbi), segno) << sbi->log_blocks_per_seg))
+ (GET_R2L_SEGNO(FREE_I(sbi), segno) << (sbi)->log_blocks_per_seg))
#define NEXT_FREE_BLKADDR(sbi, curseg) \
- (START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff)
+ (START_BLOCK(sbi, (curseg)->segno) + (curseg)->next_blkoff)
#define GET_SEGOFF_FROM_SEG0(sbi, blk_addr) ((blk_addr) - SEG0_BLKADDR(sbi))
#define GET_SEGNO_FROM_SEG0(sbi, blk_addr) \
- (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg)
+ (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> (sbi)->log_blocks_per_seg)
#define GET_BLKOFF_FROM_SEG0(sbi, blk_addr) \
- (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & (sbi->blocks_per_seg - 1))
+ (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & ((sbi)->blocks_per_seg - 1))
#define GET_SEGNO(sbi, blk_addr) \
- (((blk_addr == NULL_ADDR) || (blk_addr == NEW_ADDR)) ? \
+ ((((blk_addr) == NULL_ADDR) || ((blk_addr) == NEW_ADDR)) ? \
NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi), \
GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
-#define GET_SECNO(sbi, segno) \
- ((segno) / sbi->segs_per_sec)
-#define GET_ZONENO_FROM_SEGNO(sbi, segno) \
- ((segno / sbi->segs_per_sec) / sbi->secs_per_zone)
+#define BLKS_PER_SEC(sbi) \
+ ((sbi)->segs_per_sec * (sbi)->blocks_per_seg)
+#define GET_SEC_FROM_SEG(sbi, segno) \
+ ((segno) / (sbi)->segs_per_sec)
+#define GET_SEG_FROM_SEC(sbi, secno) \
+ ((secno) * (sbi)->segs_per_sec)
+#define GET_ZONE_FROM_SEC(sbi, secno) \
+ ((secno) / (sbi)->secs_per_zone)
+#define GET_ZONE_FROM_SEG(sbi, segno) \
+ GET_ZONE_FROM_SEC(sbi, GET_SEC_FROM_SEG(sbi, segno))
#define GET_SUM_BLOCK(sbi, segno) \
- ((sbi->sm_info->ssa_blkaddr) + segno)
+ ((sbi)->sm_info->ssa_blkaddr + (segno))
#define GET_SUM_TYPE(footer) ((footer)->entry_type)
-#define SET_SUM_TYPE(footer, type) ((footer)->entry_type = type)
+#define SET_SUM_TYPE(footer, type) ((footer)->entry_type = (type))
#define SIT_ENTRY_OFFSET(sit_i, segno) \
- (segno % sit_i->sents_per_block)
+ ((segno) % (sit_i)->sents_per_block)
#define SIT_BLOCK_OFFSET(segno) \
- (segno / SIT_ENTRY_PER_BLOCK)
+ ((segno) / SIT_ENTRY_PER_BLOCK)
#define START_SEGNO(segno) \
(SIT_BLOCK_OFFSET(segno) * SIT_ENTRY_PER_BLOCK)
#define SIT_BLK_CNT(sbi) \
@@ -101,9 +113,7 @@
#define SECTOR_FROM_BLOCK(blk_addr) \
(((sector_t)blk_addr) << F2FS_LOG_SECTORS_PER_BLOCK)
#define SECTOR_TO_BLOCK(sectors) \
- (sectors >> F2FS_LOG_SECTORS_PER_BLOCK)
-#define MAX_BIO_BLOCKS(sbi) \
- ((int)min((int)max_hw_blocks(sbi), BIO_MAX_PAGES))
+ ((sectors) >> F2FS_LOG_SECTORS_PER_BLOCK)
/*
* indicate a block allocation direction: RIGHT and LEFT.
@@ -132,7 +142,10 @@
*/
enum {
GC_CB = 0,
- GC_GREEDY
+ GC_GREEDY,
+ ALLOC_NEXT,
+ FLUSH_DEVICE,
+ MAX_GC_POLICY,
};
/*
@@ -164,6 +177,9 @@
unsigned int ckpt_valid_blocks:10; /* # of valid blocks last cp */
unsigned int padding:6; /* padding */
unsigned char *cur_valid_map; /* validity bitmap of blocks */
+#ifdef CONFIG_F2FS_CHECK_FS
+ unsigned char *cur_valid_map_mir; /* mirror of current valid bitmap */
+#endif
/*
* # of valid blocks and the validity bitmap stored in the the last
* checkpoint pack. This information is used by the SSR mode.
@@ -186,9 +202,12 @@
* the page is atomically written, and it is in inmem_pages list.
*/
#define ATOMIC_WRITTEN_PAGE ((unsigned long)-1)
+#define DUMMY_WRITTEN_PAGE ((unsigned long)-2)
#define IS_ATOMIC_WRITTEN_PAGE(page) \
(page_private(page) == (unsigned long)ATOMIC_WRITTEN_PAGE)
+#define IS_DUMMY_WRITTEN_PAGE(page) \
+ (page_private(page) == (unsigned long)DUMMY_WRITTEN_PAGE)
struct inmem_pages {
struct list_head list;
@@ -203,13 +222,16 @@
block_t sit_blocks; /* # of blocks used by SIT area */
block_t written_valid_blocks; /* # of valid blocks in main area */
char *sit_bitmap; /* SIT bitmap pointer */
+#ifdef CONFIG_F2FS_CHECK_FS
+ char *sit_bitmap_mir; /* SIT bitmap mirror */
+#endif
unsigned int bitmap_size; /* SIT bitmap size */
unsigned long *tmp_map; /* bitmap for temporal use */
unsigned long *dirty_sentries_bitmap; /* bitmap for dirty sentries */
unsigned int dirty_sentries; /* # of dirty sentries */
unsigned int sents_per_block; /* # of SIT entries per block */
- struct mutex sentry_lock; /* to protect SIT cache */
+ struct rw_semaphore sentry_lock; /* to protect SIT cache */
struct seg_entry *sentries; /* SIT segment-level cache */
struct sec_entry *sec_entries; /* SIT section-level cache */
@@ -218,6 +240,8 @@
unsigned long long mounted_time; /* mount time */
unsigned long long min_mtime; /* min. modification time */
unsigned long long max_mtime; /* max. modification time */
+
+ unsigned int last_victim[MAX_GC_POLICY]; /* last victim segment # */
};
struct free_segmap_info {
@@ -294,17 +318,17 @@
unsigned int segno)
{
struct sit_info *sit_i = SIT_I(sbi);
- return &sit_i->sec_entries[GET_SECNO(sbi, segno)];
+ return &sit_i->sec_entries[GET_SEC_FROM_SEG(sbi, segno)];
}
static inline unsigned int get_valid_blocks(struct f2fs_sb_info *sbi,
- unsigned int segno, int section)
+ unsigned int segno, bool use_section)
{
/*
* In order to get # of valid blocks in a section instantly from many
* segments, f2fs manages two counting structures separately.
*/
- if (section > 1)
+ if (use_section && sbi->segs_per_sec > 1)
return get_sec_entry(sbi, segno)->valid_blocks;
else
return get_seg_entry(sbi, segno)->valid_blocks;
@@ -317,20 +341,48 @@
se->ckpt_valid_blocks = GET_SIT_VBLOCKS(rs);
memcpy(se->cur_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
+#ifdef CONFIG_F2FS_CHECK_FS
+ memcpy(se->cur_valid_map_mir, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
+#endif
se->type = GET_SIT_TYPE(rs);
se->mtime = le64_to_cpu(rs->mtime);
}
-static inline void seg_info_to_raw_sit(struct seg_entry *se,
+static inline void __seg_info_to_raw_sit(struct seg_entry *se,
struct f2fs_sit_entry *rs)
{
unsigned short raw_vblocks = (se->type << SIT_VBLOCKS_SHIFT) |
se->valid_blocks;
rs->vblocks = cpu_to_le16(raw_vblocks);
memcpy(rs->valid_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
+ rs->mtime = cpu_to_le64(se->mtime);
+}
+
+static inline void seg_info_to_sit_page(struct f2fs_sb_info *sbi,
+ struct page *page, unsigned int start)
+{
+ struct f2fs_sit_block *raw_sit;
+ struct seg_entry *se;
+ struct f2fs_sit_entry *rs;
+ unsigned int end = min(start + SIT_ENTRY_PER_BLOCK,
+ (unsigned long)MAIN_SEGS(sbi));
+ int i;
+
+ raw_sit = (struct f2fs_sit_block *)page_address(page);
+ for (i = 0; i < end - start; i++) {
+ rs = &raw_sit->entries[i];
+ se = get_seg_entry(sbi, start + i);
+ __seg_info_to_raw_sit(se, rs);
+ }
+}
+
+static inline void seg_info_to_raw_sit(struct seg_entry *se,
+ struct f2fs_sit_entry *rs)
+{
+ __seg_info_to_raw_sit(se, rs);
+
memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
se->ckpt_valid_blocks = se->valid_blocks;
- rs->mtime = cpu_to_le64(se->mtime);
}
static inline unsigned int find_next_inuse(struct free_segmap_info *free_i,
@@ -346,8 +398,8 @@
static inline void __set_free(struct f2fs_sb_info *sbi, unsigned int segno)
{
struct free_segmap_info *free_i = FREE_I(sbi);
- unsigned int secno = segno / sbi->segs_per_sec;
- unsigned int start_segno = secno * sbi->segs_per_sec;
+ unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
+ unsigned int start_segno = GET_SEG_FROM_SEC(sbi, secno);
unsigned int next;
spin_lock(&free_i->segmap_lock);
@@ -367,7 +419,8 @@
unsigned int segno)
{
struct free_segmap_info *free_i = FREE_I(sbi);
- unsigned int secno = segno / sbi->segs_per_sec;
+ unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
+
set_bit(segno, free_i->free_segmap);
free_i->free_segments--;
if (!test_and_set_bit(secno, free_i->free_secmap))
@@ -378,8 +431,8 @@
unsigned int segno)
{
struct free_segmap_info *free_i = FREE_I(sbi);
- unsigned int secno = segno / sbi->segs_per_sec;
- unsigned int start_segno = secno * sbi->segs_per_sec;
+ unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
+ unsigned int start_segno = GET_SEG_FROM_SEC(sbi, secno);
unsigned int next;
spin_lock(&free_i->segmap_lock);
@@ -400,7 +453,8 @@
unsigned int segno)
{
struct free_segmap_info *free_i = FREE_I(sbi);
- unsigned int secno = segno / sbi->segs_per_sec;
+ unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
+
spin_lock(&free_i->segmap_lock);
if (!test_and_set_bit(segno, free_i->free_segmap)) {
free_i->free_segments--;
@@ -414,6 +468,12 @@
void *dst_addr)
{
struct sit_info *sit_i = SIT_I(sbi);
+
+#ifdef CONFIG_F2FS_CHECK_FS
+ if (memcmp(sit_i->sit_bitmap, sit_i->sit_bitmap_mir,
+ sit_i->bitmap_size))
+ f2fs_bug_on(sbi, 1);
+#endif
memcpy(dst_addr, sit_i->sit_bitmap, sit_i->bitmap_size);
}
@@ -457,26 +517,36 @@
return SM_I(sbi)->ovp_segments;
}
-static inline int overprovision_sections(struct f2fs_sb_info *sbi)
-{
- return ((unsigned int) overprovision_segments(sbi)) / sbi->segs_per_sec;
-}
-
static inline int reserved_sections(struct f2fs_sb_info *sbi)
{
- return ((unsigned int) reserved_segments(sbi)) / sbi->segs_per_sec;
+ return GET_SEC_FROM_SEG(sbi, (unsigned int)reserved_segments(sbi));
}
-static inline bool need_SSR(struct f2fs_sb_info *sbi)
+static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi)
{
- int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
- int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
+ unsigned int node_blocks = get_pages(sbi, F2FS_DIRTY_NODES) +
+ get_pages(sbi, F2FS_DIRTY_DENTS);
+ unsigned int dent_blocks = get_pages(sbi, F2FS_DIRTY_DENTS);
+ unsigned int segno, left_blocks;
+ int i;
- if (test_opt(sbi, LFS))
+ /* check current node segment */
+ for (i = CURSEG_HOT_NODE; i <= CURSEG_COLD_NODE; i++) {
+ segno = CURSEG_I(sbi, i)->segno;
+ left_blocks = sbi->blocks_per_seg -
+ get_seg_entry(sbi, segno)->ckpt_valid_blocks;
+
+ if (node_blocks > left_blocks)
+ return false;
+ }
+
+ /* check current data segment */
+ segno = CURSEG_I(sbi, CURSEG_HOT_DATA)->segno;
+ left_blocks = sbi->blocks_per_seg -
+ get_seg_entry(sbi, segno)->ckpt_valid_blocks;
+ if (dent_blocks > left_blocks)
return false;
-
- return free_sections(sbi) <= (node_secs + 2 * dent_secs +
- reserved_sections(sbi) + 1);
+ return true;
}
static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi,
@@ -484,14 +554,17 @@
{
int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
-
- node_secs += get_blocktype_secs(sbi, F2FS_DIRTY_IMETA);
+ int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA);
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
return false;
+ if (free_sections(sbi) + freed == reserved_sections(sbi) + needed &&
+ has_curseg_enough_space(sbi))
+ return false;
return (free_sections(sbi) + freed) <=
- (node_secs + 2 * dent_secs + reserved_sections(sbi) + needed);
+ (node_secs + 2 * dent_secs + imeta_secs +
+ reserved_sections(sbi) + needed);
}
static inline bool excess_prefree_segs(struct f2fs_sb_info *sbi)
@@ -521,6 +594,7 @@
*/
#define DEF_MIN_IPU_UTIL 70
#define DEF_MIN_FSYNC_BLOCKS 8
+#define DEF_MIN_HOT_BLOCKS 16
enum {
F2FS_IPU_FORCE,
@@ -528,39 +602,9 @@
F2FS_IPU_UTIL,
F2FS_IPU_SSR_UTIL,
F2FS_IPU_FSYNC,
+ F2FS_IPU_ASYNC,
};
-static inline bool need_inplace_update(struct inode *inode)
-{
- struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- unsigned int policy = SM_I(sbi)->ipu_policy;
-
- /* IPU can be done only for the user data */
- if (S_ISDIR(inode->i_mode) || f2fs_is_atomic_file(inode))
- return false;
-
- if (test_opt(sbi, LFS))
- return false;
-
- if (policy & (0x1 << F2FS_IPU_FORCE))
- return true;
- if (policy & (0x1 << F2FS_IPU_SSR) && need_SSR(sbi))
- return true;
- if (policy & (0x1 << F2FS_IPU_UTIL) &&
- utilization(sbi) > SM_I(sbi)->min_ipu_util)
- return true;
- if (policy & (0x1 << F2FS_IPU_SSR_UTIL) && need_SSR(sbi) &&
- utilization(sbi) > SM_I(sbi)->min_ipu_util)
- return true;
-
- /* this is only set during fdatasync */
- if (policy & (0x1 << F2FS_IPU_FSYNC) &&
- is_inode_flag_set(inode, FI_NEED_IPU))
- return true;
-
- return false;
-}
-
static inline unsigned int curseg_segno(struct f2fs_sb_info *sbi,
int type)
{
@@ -595,7 +639,7 @@
/*
* Summary block is always treated as an invalid block
*/
-static inline void check_block_count(struct f2fs_sb_info *sbi,
+static inline int check_block_count(struct f2fs_sb_info *sbi,
int segno, struct f2fs_sit_entry *raw_sit)
{
#ifdef CONFIG_F2FS_CHECK_FS
@@ -617,11 +661,25 @@
cur_pos = next_pos;
is_valid = !is_valid;
} while (cur_pos < sbi->blocks_per_seg);
- BUG_ON(GET_SIT_VBLOCKS(raw_sit) != valid_blocks);
+
+ if (unlikely(GET_SIT_VBLOCKS(raw_sit) != valid_blocks)) {
+ f2fs_msg(sbi->sb, KERN_ERR,
+ "Mismatch valid blocks %d vs. %d",
+ GET_SIT_VBLOCKS(raw_sit), valid_blocks);
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
+ return -EINVAL;
+ }
#endif
/* check segment usage, and check boundary of a given segment number */
- f2fs_bug_on(sbi, GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg
- || segno > TOTAL_SEGS(sbi) - 1);
+ if (unlikely(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg
+ || segno > TOTAL_SEGS(sbi) - 1)) {
+ f2fs_msg(sbi->sb, KERN_ERR,
+ "Wrong valid blocks %d or segno %u",
+ GET_SIT_VBLOCKS(raw_sit), segno);
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
+ return -EINVAL;
+ }
+ return 0;
}
static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi,
@@ -633,6 +691,12 @@
check_seg_range(sbi, start);
+#ifdef CONFIG_F2FS_CHECK_FS
+ if (f2fs_test_bit(offset, sit_i->sit_bitmap) !=
+ f2fs_test_bit(offset, sit_i->sit_bitmap_mir))
+ f2fs_bug_on(sbi, 1);
+#endif
+
/* calculate sit block address */
if (f2fs_test_bit(offset, sit_i->sit_bitmap))
blk_addr += sit_i->sit_blocks;
@@ -658,13 +722,17 @@
unsigned int block_off = SIT_BLOCK_OFFSET(start);
f2fs_change_bit(block_off, sit_i->sit_bitmap);
+#ifdef CONFIG_F2FS_CHECK_FS
+ f2fs_change_bit(block_off, sit_i->sit_bitmap_mir);
+#endif
}
static inline unsigned long long get_mtime(struct f2fs_sb_info *sbi)
{
struct sit_info *sit_i = SIT_I(sbi);
- return sit_i->elapsed_time + CURRENT_TIME_SEC.tv_sec -
- sit_i->mounted_time;
+ time64_t now = ktime_get_real_seconds();
+
+ return sit_i->elapsed_time + now - sit_i->mounted_time;
}
static inline void set_summary(struct f2fs_summary *sum, nid_t nid,
@@ -691,7 +759,7 @@
static inline bool no_fggc_candidate(struct f2fs_sb_info *sbi,
unsigned int secno)
{
- if (get_valid_blocks(sbi, secno, sbi->segs_per_sec) >=
+ if (get_valid_blocks(sbi, GET_SEG_FROM_SEC(sbi, secno), true) >
sbi->fggc_threshold)
return true;
return false;
@@ -704,19 +772,12 @@
return false;
}
-static inline unsigned int max_hw_blocks(struct f2fs_sb_info *sbi)
-{
- struct block_device *bdev = sbi->sb->s_bdev;
- struct request_queue *q = bdev_get_queue(bdev);
- return SECTOR_TO_BLOCK(queue_max_sectors(q));
-}
-
/*
* It is very important to gather dirty pages and write at once, so that we can
* submit a big bio without interfering other data writes.
* By default, 512 pages for directory data,
- * 512 pages (2MB) * 3 for three types of nodes, and
- * max_bio_blocks for meta are set.
+ * 512 pages (2MB) * 8 for nodes, and
+ * 256 pages * 8 for meta are set.
*/
static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type)
{
@@ -728,7 +789,7 @@
else if (type == NODE)
return 8 * sbi->blocks_per_seg;
else if (type == META)
- return 8 * MAX_BIO_BLOCKS(sbi);
+ return 8 * BIO_MAX_PAGES;
else
return 0;
}
@@ -745,12 +806,36 @@
return 0;
nr_to_write = wbc->nr_to_write;
-
+ desired = BIO_MAX_PAGES;
if (type == NODE)
- desired = 2 * max_hw_blocks(sbi);
- else
- desired = MAX_BIO_BLOCKS(sbi);
+ desired <<= 1;
wbc->nr_to_write = desired;
return desired - nr_to_write;
}
+
+static inline void wake_up_discard_thread(struct f2fs_sb_info *sbi, bool force)
+{
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ bool wakeup = false;
+ int i;
+
+ if (force)
+ goto wake_up;
+
+ mutex_lock(&dcc->cmd_lock);
+ for (i = MAX_PLIST_NUM - 1; i >= 0; i--) {
+ if (i + 1 < dcc->discard_granularity)
+ break;
+ if (!list_empty(&dcc->pend_list[i])) {
+ wakeup = true;
+ break;
+ }
+ }
+ mutex_unlock(&dcc->cmd_lock);
+ if (!wakeup)
+ return;
+wake_up:
+ dcc->discard_wake = 1;
+ wake_up_interruptible_all(&dcc->discard_wait_queue);
+}
diff --git a/fs/f2fs/shrinker.c b/fs/f2fs/shrinker.c
index 46c9154..0b5664a 100644
--- a/fs/f2fs/shrinker.c
+++ b/fs/f2fs/shrinker.c
@@ -21,14 +21,16 @@
static unsigned long __count_nat_entries(struct f2fs_sb_info *sbi)
{
- return NM_I(sbi)->nat_cnt - NM_I(sbi)->dirty_nat_cnt;
+ long count = NM_I(sbi)->nat_cnt - NM_I(sbi)->dirty_nat_cnt;
+
+ return count > 0 ? count : 0;
}
static unsigned long __count_free_nids(struct f2fs_sb_info *sbi)
{
- if (NM_I(sbi)->fcnt > MAX_FREE_NIDS)
- return NM_I(sbi)->fcnt - MAX_FREE_NIDS;
- return 0;
+ long count = NM_I(sbi)->nid_cnt[FREE_NID] - MAX_FREE_NIDS;
+
+ return count > 0 ? count : 0;
}
static unsigned long __count_extent_cache(struct f2fs_sb_info *sbi)
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index b81998e..1692c26 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -22,8 +22,10 @@
#include <linux/random.h>
#include <linux/exportfs.h>
#include <linux/blkdev.h>
+#include <linux/quotaops.h>
#include <linux/f2fs_fs.h>
#include <linux/sysfs.h>
+#include <linux/quota.h>
#include "f2fs.h"
#include "node.h"
@@ -35,20 +37,22 @@
#define CREATE_TRACE_POINTS
#include <trace/events/f2fs.h>
-static struct proc_dir_entry *f2fs_proc_root;
static struct kmem_cache *f2fs_inode_cachep;
-static struct kset *f2fs_kset;
#ifdef CONFIG_F2FS_FAULT_INJECTION
char *fault_name[FAULT_MAX] = {
[FAULT_KMALLOC] = "kmalloc",
+ [FAULT_KVMALLOC] = "kvmalloc",
[FAULT_PAGE_ALLOC] = "page alloc",
+ [FAULT_PAGE_GET] = "page get",
+ [FAULT_ALLOC_BIO] = "alloc bio",
[FAULT_ALLOC_NID] = "alloc nid",
[FAULT_ORPHAN] = "orphan",
[FAULT_BLOCK] = "no more block",
[FAULT_DIR_DEPTH] = "too big dir depth",
[FAULT_EVICT_INODE] = "evict_inode fail",
+ [FAULT_TRUNCATE] = "truncate fail",
[FAULT_IO] = "IO error",
[FAULT_CHECKPOINT] = "checkpoint error",
};
@@ -82,6 +86,7 @@
Opt_discard,
Opt_nodiscard,
Opt_noheap,
+ Opt_heap,
Opt_user_xattr,
Opt_nouser_xattr,
Opt_acl,
@@ -89,6 +94,8 @@
Opt_active_logs,
Opt_disable_ext_identify,
Opt_inline_xattr,
+ Opt_noinline_xattr,
+ Opt_inline_xattr_size,
Opt_inline_data,
Opt_inline_dentry,
Opt_noinline_dentry,
@@ -100,10 +107,28 @@
Opt_noextent_cache,
Opt_noinline_data,
Opt_data_flush,
+ Opt_reserve_root,
+ Opt_resgid,
+ Opt_resuid,
Opt_mode,
+ Opt_io_size_bits,
Opt_fault_injection,
Opt_lazytime,
Opt_nolazytime,
+ Opt_quota,
+ Opt_noquota,
+ Opt_usrquota,
+ Opt_grpquota,
+ Opt_prjquota,
+ Opt_usrjquota,
+ Opt_grpjquota,
+ Opt_prjjquota,
+ Opt_offusrjquota,
+ Opt_offgrpjquota,
+ Opt_offprjjquota,
+ Opt_jqfmt_vfsold,
+ Opt_jqfmt_vfsv0,
+ Opt_jqfmt_vfsv1,
Opt_err,
};
@@ -114,6 +139,7 @@
{Opt_discard, "discard"},
{Opt_nodiscard, "nodiscard"},
{Opt_noheap, "no_heap"},
+ {Opt_heap, "heap"},
{Opt_user_xattr, "user_xattr"},
{Opt_nouser_xattr, "nouser_xattr"},
{Opt_acl, "acl"},
@@ -121,6 +147,8 @@
{Opt_active_logs, "active_logs=%u"},
{Opt_disable_ext_identify, "disable_ext_identify"},
{Opt_inline_xattr, "inline_xattr"},
+ {Opt_noinline_xattr, "noinline_xattr"},
+ {Opt_inline_xattr_size, "inline_xattr_size=%u"},
{Opt_inline_data, "inline_data"},
{Opt_inline_dentry, "inline_dentry"},
{Opt_noinline_dentry, "noinline_dentry"},
@@ -132,211 +160,31 @@
{Opt_noextent_cache, "noextent_cache"},
{Opt_noinline_data, "noinline_data"},
{Opt_data_flush, "data_flush"},
+ {Opt_reserve_root, "reserve_root=%u"},
+ {Opt_resgid, "resgid=%u"},
+ {Opt_resuid, "resuid=%u"},
{Opt_mode, "mode=%s"},
+ {Opt_io_size_bits, "io_bits=%u"},
{Opt_fault_injection, "fault_injection=%u"},
{Opt_lazytime, "lazytime"},
{Opt_nolazytime, "nolazytime"},
+ {Opt_quota, "quota"},
+ {Opt_noquota, "noquota"},
+ {Opt_usrquota, "usrquota"},
+ {Opt_grpquota, "grpquota"},
+ {Opt_prjquota, "prjquota"},
+ {Opt_usrjquota, "usrjquota=%s"},
+ {Opt_grpjquota, "grpjquota=%s"},
+ {Opt_prjjquota, "prjjquota=%s"},
+ {Opt_offusrjquota, "usrjquota="},
+ {Opt_offgrpjquota, "grpjquota="},
+ {Opt_offprjjquota, "prjjquota="},
+ {Opt_jqfmt_vfsold, "jqfmt=vfsold"},
+ {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
+ {Opt_jqfmt_vfsv1, "jqfmt=vfsv1"},
{Opt_err, NULL},
};
-/* Sysfs support for f2fs */
-enum {
- GC_THREAD, /* struct f2fs_gc_thread */
- SM_INFO, /* struct f2fs_sm_info */
- NM_INFO, /* struct f2fs_nm_info */
- F2FS_SBI, /* struct f2fs_sb_info */
-#ifdef CONFIG_F2FS_FAULT_INJECTION
- FAULT_INFO_RATE, /* struct f2fs_fault_info */
- FAULT_INFO_TYPE, /* struct f2fs_fault_info */
-#endif
-};
-
-struct f2fs_attr {
- struct attribute attr;
- ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *);
- ssize_t (*store)(struct f2fs_attr *, struct f2fs_sb_info *,
- const char *, size_t);
- int struct_type;
- int offset;
-};
-
-static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type)
-{
- if (struct_type == GC_THREAD)
- return (unsigned char *)sbi->gc_thread;
- else if (struct_type == SM_INFO)
- return (unsigned char *)SM_I(sbi);
- else if (struct_type == NM_INFO)
- return (unsigned char *)NM_I(sbi);
- else if (struct_type == F2FS_SBI)
- return (unsigned char *)sbi;
-#ifdef CONFIG_F2FS_FAULT_INJECTION
- else if (struct_type == FAULT_INFO_RATE ||
- struct_type == FAULT_INFO_TYPE)
- return (unsigned char *)&sbi->fault_info;
-#endif
- return NULL;
-}
-
-static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a,
- struct f2fs_sb_info *sbi, char *buf)
-{
- struct super_block *sb = sbi->sb;
-
- if (!sb->s_bdev->bd_part)
- return snprintf(buf, PAGE_SIZE, "0\n");
-
- return snprintf(buf, PAGE_SIZE, "%llu\n",
- (unsigned long long)(sbi->kbytes_written +
- BD_PART_WRITTEN(sbi)));
-}
-
-static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
- struct f2fs_sb_info *sbi, char *buf)
-{
- unsigned char *ptr = NULL;
- unsigned int *ui;
-
- ptr = __struct_ptr(sbi, a->struct_type);
- if (!ptr)
- return -EINVAL;
-
- ui = (unsigned int *)(ptr + a->offset);
-
- return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
-}
-
-static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
- struct f2fs_sb_info *sbi,
- const char *buf, size_t count)
-{
- unsigned char *ptr;
- unsigned long t;
- unsigned int *ui;
- ssize_t ret;
-
- ptr = __struct_ptr(sbi, a->struct_type);
- if (!ptr)
- return -EINVAL;
-
- ui = (unsigned int *)(ptr + a->offset);
-
- ret = kstrtoul(skip_spaces(buf), 0, &t);
- if (ret < 0)
- return ret;
-#ifdef CONFIG_F2FS_FAULT_INJECTION
- if (a->struct_type == FAULT_INFO_TYPE && t >= (1 << FAULT_MAX))
- return -EINVAL;
-#endif
- *ui = t;
- return count;
-}
-
-static ssize_t f2fs_attr_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info,
- s_kobj);
- struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr);
-
- return a->show ? a->show(a, sbi, buf) : 0;
-}
-
-static ssize_t f2fs_attr_store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t len)
-{
- struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info,
- s_kobj);
- struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr);
-
- return a->store ? a->store(a, sbi, buf, len) : 0;
-}
-
-static void f2fs_sb_release(struct kobject *kobj)
-{
- struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info,
- s_kobj);
- complete(&sbi->s_kobj_unregister);
-}
-
-#define F2FS_ATTR_OFFSET(_struct_type, _name, _mode, _show, _store, _offset) \
-static struct f2fs_attr f2fs_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .show = _show, \
- .store = _store, \
- .struct_type = _struct_type, \
- .offset = _offset \
-}
-
-#define F2FS_RW_ATTR(struct_type, struct_name, name, elname) \
- F2FS_ATTR_OFFSET(struct_type, name, 0644, \
- f2fs_sbi_show, f2fs_sbi_store, \
- offsetof(struct struct_name, elname))
-
-#define F2FS_GENERAL_RO_ATTR(name) \
-static struct f2fs_attr f2fs_attr_##name = __ATTR(name, 0444, name##_show, NULL)
-
-F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time);
-F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time);
-F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time);
-F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle);
-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments);
-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, max_small_discards, max_discards);
-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections);
-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy);
-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util);
-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks);
-F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh);
-F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages);
-F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio);
-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search);
-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level);
-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);
-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]);
-#ifdef CONFIG_F2FS_FAULT_INJECTION
-F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate);
-F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type);
-#endif
-F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes);
-
-#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
-static struct attribute *f2fs_attrs[] = {
- ATTR_LIST(gc_min_sleep_time),
- ATTR_LIST(gc_max_sleep_time),
- ATTR_LIST(gc_no_gc_sleep_time),
- ATTR_LIST(gc_idle),
- ATTR_LIST(reclaim_segments),
- ATTR_LIST(max_small_discards),
- ATTR_LIST(batched_trim_sections),
- ATTR_LIST(ipu_policy),
- ATTR_LIST(min_ipu_util),
- ATTR_LIST(min_fsync_blocks),
- ATTR_LIST(max_victim_search),
- ATTR_LIST(dir_level),
- ATTR_LIST(ram_thresh),
- ATTR_LIST(ra_nid_pages),
- ATTR_LIST(dirty_nats_ratio),
- ATTR_LIST(cp_interval),
- ATTR_LIST(idle_interval),
-#ifdef CONFIG_F2FS_FAULT_INJECTION
- ATTR_LIST(inject_rate),
- ATTR_LIST(inject_type),
-#endif
- ATTR_LIST(lifetime_write_kbytes),
- NULL,
-};
-
-static const struct sysfs_ops f2fs_attr_ops = {
- .show = f2fs_attr_show,
- .store = f2fs_attr_store,
-};
-
-static struct kobj_type f2fs_ktype = {
- .default_attrs = f2fs_attrs,
- .sysfs_ops = &f2fs_attr_ops,
- .release = f2fs_sb_release,
-};
-
void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...)
{
struct va_format vaf;
@@ -345,10 +193,32 @@
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
- printk("%sF2FS-fs (%s): %pV\n", level, sb->s_id, &vaf);
+ printk_ratelimited("%sF2FS-fs (%s): %pV\n", level, sb->s_id, &vaf);
va_end(args);
}
+static inline void limit_reserve_root(struct f2fs_sb_info *sbi)
+{
+ block_t limit = (sbi->user_block_count << 1) / 1000;
+
+ /* limit is 0.2% */
+ if (test_opt(sbi, RESERVE_ROOT) && sbi->root_reserved_blocks > limit) {
+ sbi->root_reserved_blocks = limit;
+ f2fs_msg(sbi->sb, KERN_INFO,
+ "Reduce reserved blocks for root = %u",
+ sbi->root_reserved_blocks);
+ }
+ if (!test_opt(sbi, RESERVE_ROOT) &&
+ (!uid_eq(sbi->s_resuid,
+ make_kuid(&init_user_ns, F2FS_DEF_RESUID)) ||
+ !gid_eq(sbi->s_resgid,
+ make_kgid(&init_user_ns, F2FS_DEF_RESGID))))
+ f2fs_msg(sbi->sb, KERN_INFO,
+ "Ignore s_resuid=%u, s_resgid=%u w/o reserve_root",
+ from_kuid_munged(&init_user_ns, sbi->s_resuid),
+ from_kgid_munged(&init_user_ns, sbi->s_resgid));
+}
+
static void init_once(void *foo)
{
struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo;
@@ -356,6 +226,122 @@
inode_init_once(&fi->vfs_inode);
}
+#ifdef CONFIG_QUOTA
+static const char * const quotatypes[] = INITQFNAMES;
+#define QTYPE2NAME(t) (quotatypes[t])
+static int f2fs_set_qf_name(struct super_block *sb, int qtype,
+ substring_t *args)
+{
+ struct f2fs_sb_info *sbi = F2FS_SB(sb);
+ char *qname;
+ int ret = -EINVAL;
+
+ if (sb_any_quota_loaded(sb) && !sbi->s_qf_names[qtype]) {
+ f2fs_msg(sb, KERN_ERR,
+ "Cannot change journaled "
+ "quota options when quota turned on");
+ return -EINVAL;
+ }
+ if (f2fs_sb_has_quota_ino(sb)) {
+ f2fs_msg(sb, KERN_INFO,
+ "QUOTA feature is enabled, so ignore qf_name");
+ return 0;
+ }
+
+ qname = match_strdup(args);
+ if (!qname) {
+ f2fs_msg(sb, KERN_ERR,
+ "Not enough memory for storing quotafile name");
+ return -EINVAL;
+ }
+ if (sbi->s_qf_names[qtype]) {
+ if (strcmp(sbi->s_qf_names[qtype], qname) == 0)
+ ret = 0;
+ else
+ f2fs_msg(sb, KERN_ERR,
+ "%s quota file already specified",
+ QTYPE2NAME(qtype));
+ goto errout;
+ }
+ if (strchr(qname, '/')) {
+ f2fs_msg(sb, KERN_ERR,
+ "quotafile must be on filesystem root");
+ goto errout;
+ }
+ sbi->s_qf_names[qtype] = qname;
+ set_opt(sbi, QUOTA);
+ return 0;
+errout:
+ kfree(qname);
+ return ret;
+}
+
+static int f2fs_clear_qf_name(struct super_block *sb, int qtype)
+{
+ struct f2fs_sb_info *sbi = F2FS_SB(sb);
+
+ if (sb_any_quota_loaded(sb) && sbi->s_qf_names[qtype]) {
+ f2fs_msg(sb, KERN_ERR, "Cannot change journaled quota options"
+ " when quota turned on");
+ return -EINVAL;
+ }
+ kfree(sbi->s_qf_names[qtype]);
+ sbi->s_qf_names[qtype] = NULL;
+ return 0;
+}
+
+static int f2fs_check_quota_options(struct f2fs_sb_info *sbi)
+{
+ /*
+ * We do the test below only for project quotas. 'usrquota' and
+ * 'grpquota' mount options are allowed even without quota feature
+ * to support legacy quotas in quota files.
+ */
+ if (test_opt(sbi, PRJQUOTA) && !f2fs_sb_has_project_quota(sbi->sb)) {
+ f2fs_msg(sbi->sb, KERN_ERR, "Project quota feature not enabled. "
+ "Cannot enable project quota enforcement.");
+ return -1;
+ }
+ if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA] ||
+ sbi->s_qf_names[PRJQUOTA]) {
+ if (test_opt(sbi, USRQUOTA) && sbi->s_qf_names[USRQUOTA])
+ clear_opt(sbi, USRQUOTA);
+
+ if (test_opt(sbi, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA])
+ clear_opt(sbi, GRPQUOTA);
+
+ if (test_opt(sbi, PRJQUOTA) && sbi->s_qf_names[PRJQUOTA])
+ clear_opt(sbi, PRJQUOTA);
+
+ if (test_opt(sbi, GRPQUOTA) || test_opt(sbi, USRQUOTA) ||
+ test_opt(sbi, PRJQUOTA)) {
+ f2fs_msg(sbi->sb, KERN_ERR, "old and new quota "
+ "format mixing");
+ return -1;
+ }
+
+ if (!sbi->s_jquota_fmt) {
+ f2fs_msg(sbi->sb, KERN_ERR, "journaled quota format "
+ "not specified");
+ return -1;
+ }
+ }
+
+ if (f2fs_sb_has_quota_ino(sbi->sb) && sbi->s_jquota_fmt) {
+ f2fs_msg(sbi->sb, KERN_INFO,
+ "QUOTA feature is enabled, so ignore jquota_fmt");
+ sbi->s_jquota_fmt = 0;
+ }
+ if (f2fs_sb_has_quota_ino(sbi->sb) && sb_rdonly(sbi->sb)) {
+ f2fs_msg(sbi->sb, KERN_INFO,
+ "Filesystem with quota feature cannot be mounted RDWR "
+ "without CONFIG_QUOTA");
+ return -1;
+ }
+ return 0;
+}
+#endif
+
static int parse_options(struct super_block *sb, char *options)
{
struct f2fs_sb_info *sbi = F2FS_SB(sb);
@@ -363,6 +349,11 @@
substring_t args[MAX_OPT_ARGS];
char *p, *name;
int arg = 0;
+ kuid_t uid;
+ kgid_t gid;
+#ifdef CONFIG_QUOTA
+ int ret;
+#endif
if (!options)
return 0;
@@ -412,17 +403,26 @@
q = bdev_get_queue(sb->s_bdev);
if (blk_queue_discard(q)) {
set_opt(sbi, DISCARD);
- } else {
+ } else if (!f2fs_sb_mounted_blkzoned(sb)) {
f2fs_msg(sb, KERN_WARNING,
"mounting with \"discard\" option, but "
"the device does not support discard");
}
break;
case Opt_nodiscard:
+ if (f2fs_sb_mounted_blkzoned(sb)) {
+ f2fs_msg(sb, KERN_WARNING,
+ "discard is required for zoned block devices");
+ return -EINVAL;
+ }
clear_opt(sbi, DISCARD);
+ break;
case Opt_noheap:
set_opt(sbi, NOHEAP);
break;
+ case Opt_heap:
+ clear_opt(sbi, NOHEAP);
+ break;
#ifdef CONFIG_F2FS_FS_XATTR
case Opt_user_xattr:
set_opt(sbi, XATTR_USER);
@@ -433,6 +433,15 @@
case Opt_inline_xattr:
set_opt(sbi, INLINE_XATTR);
break;
+ case Opt_noinline_xattr:
+ clear_opt(sbi, INLINE_XATTR);
+ break;
+ case Opt_inline_xattr_size:
+ if (args->from && match_int(args, &arg))
+ return -EINVAL;
+ set_opt(sbi, INLINE_XATTR_SIZE);
+ sbi->inline_xattr_size = arg;
+ break;
#else
case Opt_user_xattr:
f2fs_msg(sb, KERN_INFO,
@@ -446,6 +455,10 @@
f2fs_msg(sb, KERN_INFO,
"inline_xattr options not supported");
break;
+ case Opt_noinline_xattr:
+ f2fs_msg(sb, KERN_INFO,
+ "noinline_xattr options not supported");
+ break;
#endif
#ifdef CONFIG_F2FS_FS_POSIX_ACL
case Opt_acl:
@@ -505,6 +518,40 @@
case Opt_data_flush:
set_opt(sbi, DATA_FLUSH);
break;
+ case Opt_reserve_root:
+ if (args->from && match_int(args, &arg))
+ return -EINVAL;
+ if (test_opt(sbi, RESERVE_ROOT)) {
+ f2fs_msg(sb, KERN_INFO,
+ "Preserve previous reserve_root=%u",
+ sbi->root_reserved_blocks);
+ } else {
+ sbi->root_reserved_blocks = arg;
+ set_opt(sbi, RESERVE_ROOT);
+ }
+ break;
+ case Opt_resuid:
+ if (args->from && match_int(args, &arg))
+ return -EINVAL;
+ uid = make_kuid(current_user_ns(), arg);
+ if (!uid_valid(uid)) {
+ f2fs_msg(sb, KERN_ERR,
+ "Invalid uid value %d", arg);
+ return -EINVAL;
+ }
+ sbi->s_resuid = uid;
+ break;
+ case Opt_resgid:
+ if (args->from && match_int(args, &arg))
+ return -EINVAL;
+ gid = make_kgid(current_user_ns(), arg);
+ if (!gid_valid(gid)) {
+ f2fs_msg(sb, KERN_ERR,
+ "Invalid gid value %d", arg);
+ return -EINVAL;
+ }
+ sbi->s_resgid = gid;
+ break;
case Opt_mode:
name = match_strdup(&args[0]);
@@ -512,6 +559,13 @@
return -ENOMEM;
if (strlen(name) == 8 &&
!strncmp(name, "adaptive", 8)) {
+ if (f2fs_sb_mounted_blkzoned(sb)) {
+ f2fs_msg(sb, KERN_WARNING,
+ "adaptive mode is not allowed with "
+ "zoned block device feature");
+ kfree(name);
+ return -EINVAL;
+ }
set_opt_mode(sbi, F2FS_MOUNT_ADAPTIVE);
} else if (strlen(name) == 3 &&
!strncmp(name, "lfs", 3)) {
@@ -522,11 +576,23 @@
}
kfree(name);
break;
+ case Opt_io_size_bits:
+ if (args->from && match_int(args, &arg))
+ return -EINVAL;
+ if (arg > __ilog2_u32(BIO_MAX_PAGES)) {
+ f2fs_msg(sb, KERN_WARNING,
+ "Not support %d, larger than %d",
+ 1 << arg, BIO_MAX_PAGES);
+ return -EINVAL;
+ }
+ sbi->write_io_size_bits = arg;
+ break;
case Opt_fault_injection:
if (args->from && match_int(args, &arg))
return -EINVAL;
#ifdef CONFIG_F2FS_FAULT_INJECTION
f2fs_build_fault_attr(sbi, arg);
+ set_opt(sbi, FAULT_INJECTION);
#else
f2fs_msg(sb, KERN_INFO,
"FAULT_INJECTION was not selected");
@@ -538,6 +604,81 @@
case Opt_nolazytime:
sb->s_flags &= ~MS_LAZYTIME;
break;
+#ifdef CONFIG_QUOTA
+ case Opt_quota:
+ case Opt_usrquota:
+ set_opt(sbi, USRQUOTA);
+ break;
+ case Opt_grpquota:
+ set_opt(sbi, GRPQUOTA);
+ break;
+ case Opt_prjquota:
+ set_opt(sbi, PRJQUOTA);
+ break;
+ case Opt_usrjquota:
+ ret = f2fs_set_qf_name(sb, USRQUOTA, &args[0]);
+ if (ret)
+ return ret;
+ break;
+ case Opt_grpjquota:
+ ret = f2fs_set_qf_name(sb, GRPQUOTA, &args[0]);
+ if (ret)
+ return ret;
+ break;
+ case Opt_prjjquota:
+ ret = f2fs_set_qf_name(sb, PRJQUOTA, &args[0]);
+ if (ret)
+ return ret;
+ break;
+ case Opt_offusrjquota:
+ ret = f2fs_clear_qf_name(sb, USRQUOTA);
+ if (ret)
+ return ret;
+ break;
+ case Opt_offgrpjquota:
+ ret = f2fs_clear_qf_name(sb, GRPQUOTA);
+ if (ret)
+ return ret;
+ break;
+ case Opt_offprjjquota:
+ ret = f2fs_clear_qf_name(sb, PRJQUOTA);
+ if (ret)
+ return ret;
+ break;
+ case Opt_jqfmt_vfsold:
+ sbi->s_jquota_fmt = QFMT_VFS_OLD;
+ break;
+ case Opt_jqfmt_vfsv0:
+ sbi->s_jquota_fmt = QFMT_VFS_V0;
+ break;
+ case Opt_jqfmt_vfsv1:
+ sbi->s_jquota_fmt = QFMT_VFS_V1;
+ break;
+ case Opt_noquota:
+ clear_opt(sbi, QUOTA);
+ clear_opt(sbi, USRQUOTA);
+ clear_opt(sbi, GRPQUOTA);
+ clear_opt(sbi, PRJQUOTA);
+ break;
+#else
+ case Opt_quota:
+ case Opt_usrquota:
+ case Opt_grpquota:
+ case Opt_prjquota:
+ case Opt_usrjquota:
+ case Opt_grpjquota:
+ case Opt_prjjquota:
+ case Opt_offusrjquota:
+ case Opt_offgrpjquota:
+ case Opt_offprjjquota:
+ case Opt_jqfmt_vfsold:
+ case Opt_jqfmt_vfsv0:
+ case Opt_jqfmt_vfsv1:
+ case Opt_noquota:
+ f2fs_msg(sb, KERN_INFO,
+ "quota operations not supported");
+ break;
+#endif
default:
f2fs_msg(sb, KERN_ERR,
"Unrecognized mount option \"%s\" or missing value",
@@ -545,6 +686,35 @@
return -EINVAL;
}
}
+#ifdef CONFIG_QUOTA
+ if (f2fs_check_quota_options(sbi))
+ return -EINVAL;
+#endif
+
+ if (F2FS_IO_SIZE_BITS(sbi) && !test_opt(sbi, LFS)) {
+ f2fs_msg(sb, KERN_ERR,
+ "Should set mode=lfs with %uKB-sized IO",
+ F2FS_IO_SIZE_KB(sbi));
+ return -EINVAL;
+ }
+
+ if (test_opt(sbi, INLINE_XATTR_SIZE)) {
+ if (!test_opt(sbi, INLINE_XATTR)) {
+ f2fs_msg(sb, KERN_ERR,
+ "inline_xattr_size option should be "
+ "set with inline_xattr option");
+ return -EINVAL;
+ }
+ if (!sbi->inline_xattr_size ||
+ sbi->inline_xattr_size >= DEF_ADDRS_PER_INODE -
+ F2FS_TOTAL_EXTRA_ATTR_SIZE -
+ DEF_INLINE_RESERVED_SIZE -
+ DEF_MIN_INLINE_SIZE) {
+ f2fs_msg(sb, KERN_ERR,
+ "inline xattr size is out of range");
+ return -EINVAL;
+ }
+ }
return 0;
}
@@ -559,25 +729,33 @@
init_once((void *) fi);
/* Initialize f2fs-specific inode info */
- fi->vfs_inode.i_version = 1;
atomic_set(&fi->dirty_pages, 0);
fi->i_current_depth = 1;
fi->i_advise = 0;
init_rwsem(&fi->i_sem);
INIT_LIST_HEAD(&fi->dirty_list);
INIT_LIST_HEAD(&fi->gdirty_list);
+ INIT_LIST_HEAD(&fi->inmem_ilist);
INIT_LIST_HEAD(&fi->inmem_pages);
mutex_init(&fi->inmem_lock);
init_rwsem(&fi->dio_rwsem[READ]);
init_rwsem(&fi->dio_rwsem[WRITE]);
+ init_rwsem(&fi->i_mmap_sem);
+ init_rwsem(&fi->i_xattr_sem);
+#ifdef CONFIG_QUOTA
+ memset(&fi->i_dquot, 0, sizeof(fi->i_dquot));
+ fi->i_reserved_quota = 0;
+#endif
/* Will be used by directory only */
fi->i_dir_level = F2FS_SB(sb)->dir_level;
+
return &fi->vfs_inode;
}
static int f2fs_drop_inode(struct inode *inode)
{
+ int ret;
/*
* This is to avoid a deadlock condition like below.
* writeback_single_inode(inode)
@@ -606,34 +784,36 @@
sb_end_intwrite(inode->i_sb);
- fscrypt_put_encryption_info(inode, NULL);
spin_lock(&inode->i_lock);
atomic_dec(&inode->i_count);
}
+ trace_f2fs_drop_inode(inode, 0);
return 0;
}
-
- return generic_drop_inode(inode);
+ ret = generic_drop_inode(inode);
+ trace_f2fs_drop_inode(inode, ret);
+ return ret;
}
-int f2fs_inode_dirtied(struct inode *inode)
+int f2fs_inode_dirtied(struct inode *inode, bool sync)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ int ret = 0;
spin_lock(&sbi->inode_lock[DIRTY_META]);
if (is_inode_flag_set(inode, FI_DIRTY_INODE)) {
- spin_unlock(&sbi->inode_lock[DIRTY_META]);
- return 1;
+ ret = 1;
+ } else {
+ set_inode_flag(inode, FI_DIRTY_INODE);
+ stat_inc_dirty_inode(sbi, DIRTY_META);
}
-
- set_inode_flag(inode, FI_DIRTY_INODE);
- list_add_tail(&F2FS_I(inode)->gdirty_list,
+ if (sync && list_empty(&F2FS_I(inode)->gdirty_list)) {
+ list_add_tail(&F2FS_I(inode)->gdirty_list,
&sbi->inode_list[DIRTY_META]);
- inc_page_count(sbi, F2FS_DIRTY_IMETA);
- stat_inc_dirty_inode(sbi, DIRTY_META);
+ inc_page_count(sbi, F2FS_DIRTY_IMETA);
+ }
spin_unlock(&sbi->inode_lock[DIRTY_META]);
-
- return 0;
+ return ret;
}
void f2fs_inode_synced(struct inode *inode)
@@ -645,10 +825,12 @@
spin_unlock(&sbi->inode_lock[DIRTY_META]);
return;
}
- list_del_init(&F2FS_I(inode)->gdirty_list);
+ if (!list_empty(&F2FS_I(inode)->gdirty_list)) {
+ list_del_init(&F2FS_I(inode)->gdirty_list);
+ dec_page_count(sbi, F2FS_DIRTY_IMETA);
+ }
clear_inode_flag(inode, FI_DIRTY_INODE);
clear_inode_flag(inode, FI_AUTO_RECOVER);
- dec_page_count(sbi, F2FS_DIRTY_IMETA);
stat_dec_dirty_inode(F2FS_I_SB(inode), DIRTY_META);
spin_unlock(&sbi->inode_lock[DIRTY_META]);
}
@@ -672,7 +854,7 @@
if (is_inode_flag_set(inode, FI_AUTO_RECOVER))
clear_inode_flag(inode, FI_AUTO_RECOVER);
- f2fs_inode_dirtied(inode);
+ f2fs_inode_dirtied(inode, false);
}
static void f2fs_i_callback(struct rcu_head *head)
@@ -692,18 +874,26 @@
percpu_counter_destroy(&sbi->total_valid_inode_count);
}
+static void destroy_device_list(struct f2fs_sb_info *sbi)
+{
+ int i;
+
+ for (i = 0; i < sbi->s_ndevs; i++) {
+ blkdev_put(FDEV(i).bdev, FMODE_EXCL);
+#ifdef CONFIG_BLK_DEV_ZONED
+ kfree(FDEV(i).blkz_type);
+#endif
+ }
+ kfree(sbi->devs);
+}
+
static void f2fs_put_super(struct super_block *sb)
{
struct f2fs_sb_info *sbi = F2FS_SB(sb);
+ int i;
+ bool dropped;
- if (sbi->s_proc) {
- remove_proc_entry("segment_info", sbi->s_proc);
- remove_proc_entry("segment_bits", sbi->s_proc);
- remove_proc_entry(sb->s_id, f2fs_proc_root);
- }
- kobject_del(&sbi->s_kobj);
-
- stop_gc_thread(sbi);
+ f2fs_quota_off_umount(sb);
/* prevent remaining shrinker jobs */
mutex_lock(&sbi->umount_mutex);
@@ -721,6 +911,16 @@
write_checkpoint(sbi, &cpc);
}
+ /* be sure to wait for any on-going discard commands */
+ dropped = f2fs_wait_discard_bios(sbi);
+
+ if (f2fs_discard_en(sbi) && !sbi->discard_blks && !dropped) {
+ struct cp_control cpc = {
+ .reason = CP_UMOUNT | CP_TRIMMED,
+ };
+ write_checkpoint(sbi, &cpc);
+ }
+
/* write_checkpoint can update stat informaion */
f2fs_destroy_stats(sbi);
@@ -729,13 +929,12 @@
* In addition, EIO will skip do checkpoint, we need this as well.
*/
release_ino_entry(sbi, true);
- release_discard_addrs(sbi);
f2fs_leave_shrinker(sbi);
mutex_unlock(&sbi->umount_mutex);
/* our cp_error case, we can wait for any writeback page */
- f2fs_flush_merged_bios(sbi);
+ f2fs_flush_merged_writes(sbi);
iput(sbi->node_inode);
iput(sbi->meta_inode);
@@ -745,15 +944,23 @@
destroy_segment_manager(sbi);
kfree(sbi->ckpt);
- kobject_put(&sbi->s_kobj);
- wait_for_completion(&sbi->s_kobj_unregister);
+
+ f2fs_unregister_sysfs(sbi);
sb->s_fs_info = NULL;
if (sbi->s_chksum_driver)
crypto_free_shash(sbi->s_chksum_driver);
kfree(sbi->raw_super);
+ destroy_device_list(sbi);
+ mempool_destroy(sbi->write_io_dummy);
+#ifdef CONFIG_QUOTA
+ for (i = 0; i < MAXQUOTAS; i++)
+ kfree(sbi->s_qf_names[i]);
+#endif
destroy_percpu_info(sbi);
+ for (i = 0; i < NR_PAGE_TYPE; i++)
+ kfree(sbi->write_io[i]);
kfree(sbi);
}
@@ -762,8 +969,14 @@
struct f2fs_sb_info *sbi = F2FS_SB(sb);
int err = 0;
+ if (unlikely(f2fs_cp_error(sbi)))
+ return 0;
+
trace_f2fs_sync_fs(sb, sync);
+ if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
+ return -EAGAIN;
+
if (sync) {
struct cp_control cpc;
@@ -780,13 +993,17 @@
static int f2fs_freeze(struct super_block *sb)
{
- int err;
-
if (f2fs_readonly(sb))
return 0;
- err = f2fs_sync_fs(sb, 1);
- return err;
+ /* IO error happened before */
+ if (unlikely(f2fs_cp_error(F2FS_SB(sb))))
+ return -EIO;
+
+ /* must be clean, since sync_filesystem() was already called */
+ if (is_sbi_flag_set(F2FS_SB(sb), SBI_IS_DIRTY))
+ return -EINVAL;
+ return 0;
}
static int f2fs_unfreeze(struct super_block *sb)
@@ -794,34 +1011,129 @@
return 0;
}
+#ifdef CONFIG_QUOTA
+static int f2fs_statfs_project(struct super_block *sb,
+ kprojid_t projid, struct kstatfs *buf)
+{
+ struct kqid qid;
+ struct dquot *dquot;
+ u64 limit;
+ u64 curblock;
+
+ qid = make_kqid_projid(projid);
+ dquot = dqget(sb, qid);
+ if (IS_ERR(dquot))
+ return PTR_ERR(dquot);
+ spin_lock(&dq_data_lock);
+
+ limit = (dquot->dq_dqb.dqb_bsoftlimit ?
+ dquot->dq_dqb.dqb_bsoftlimit :
+ dquot->dq_dqb.dqb_bhardlimit) >> sb->s_blocksize_bits;
+ if (limit && buf->f_blocks > limit) {
+ curblock = dquot->dq_dqb.dqb_curspace >> sb->s_blocksize_bits;
+ buf->f_blocks = limit;
+ buf->f_bfree = buf->f_bavail =
+ (buf->f_blocks > curblock) ?
+ (buf->f_blocks - curblock) : 0;
+ }
+
+ limit = dquot->dq_dqb.dqb_isoftlimit ?
+ dquot->dq_dqb.dqb_isoftlimit :
+ dquot->dq_dqb.dqb_ihardlimit;
+ if (limit && buf->f_files > limit) {
+ buf->f_files = limit;
+ buf->f_ffree =
+ (buf->f_files > dquot->dq_dqb.dqb_curinodes) ?
+ (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0;
+ }
+
+ spin_unlock(&dq_data_lock);
+ dqput(dquot);
+ return 0;
+}
+#endif
+
static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
struct f2fs_sb_info *sbi = F2FS_SB(sb);
u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
- block_t total_count, user_block_count, start_count, ovp_count;
+ block_t total_count, user_block_count, start_count;
+ u64 avail_node_count;
total_count = le64_to_cpu(sbi->raw_super->block_count);
user_block_count = sbi->user_block_count;
start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr);
- ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
buf->f_type = F2FS_SUPER_MAGIC;
buf->f_bsize = sbi->blocksize;
buf->f_blocks = total_count - start_count;
- buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
- buf->f_bavail = user_block_count - valid_user_blocks(sbi);
+ buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
+ sbi->current_reserved_blocks;
+ if (buf->f_bfree > sbi->root_reserved_blocks)
+ buf->f_bavail = buf->f_bfree - sbi->root_reserved_blocks;
+ else
+ buf->f_bavail = 0;
- buf->f_files = sbi->total_node_count - F2FS_RESERVED_NODE_NUM;
- buf->f_ffree = buf->f_files - valid_inode_count(sbi);
+ avail_node_count = sbi->total_node_count - sbi->nquota_files -
+ F2FS_RESERVED_NODE_NUM;
+
+ if (avail_node_count > user_block_count) {
+ buf->f_files = user_block_count;
+ buf->f_ffree = buf->f_bavail;
+ } else {
+ buf->f_files = avail_node_count;
+ buf->f_ffree = min(avail_node_count - valid_node_count(sbi),
+ buf->f_bavail);
+ }
buf->f_namelen = F2FS_NAME_LEN;
buf->f_fsid.val[0] = (u32)id;
buf->f_fsid.val[1] = (u32)(id >> 32);
+#ifdef CONFIG_QUOTA
+ if (is_inode_flag_set(dentry->d_inode, FI_PROJ_INHERIT) &&
+ sb_has_quota_limits_enabled(sb, PRJQUOTA)) {
+ f2fs_statfs_project(sb, F2FS_I(dentry->d_inode)->i_projid, buf);
+ }
+#endif
return 0;
}
+static inline void f2fs_show_quota_options(struct seq_file *seq,
+ struct super_block *sb)
+{
+#ifdef CONFIG_QUOTA
+ struct f2fs_sb_info *sbi = F2FS_SB(sb);
+
+ if (sbi->s_jquota_fmt) {
+ char *fmtname = "";
+
+ switch (sbi->s_jquota_fmt) {
+ case QFMT_VFS_OLD:
+ fmtname = "vfsold";
+ break;
+ case QFMT_VFS_V0:
+ fmtname = "vfsv0";
+ break;
+ case QFMT_VFS_V1:
+ fmtname = "vfsv1";
+ break;
+ }
+ seq_printf(seq, ",jqfmt=%s", fmtname);
+ }
+
+ if (sbi->s_qf_names[USRQUOTA])
+ seq_show_option(seq, "usrjquota", sbi->s_qf_names[USRQUOTA]);
+
+ if (sbi->s_qf_names[GRPQUOTA])
+ seq_show_option(seq, "grpjquota", sbi->s_qf_names[GRPQUOTA]);
+
+ if (sbi->s_qf_names[PRJQUOTA])
+ seq_show_option(seq, "prjjquota", sbi->s_qf_names[PRJQUOTA]);
+#endif
+}
+
static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
{
struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb);
@@ -839,7 +1151,9 @@
if (test_opt(sbi, DISCARD))
seq_puts(seq, ",discard");
if (test_opt(sbi, NOHEAP))
- seq_puts(seq, ",no_heap_alloc");
+ seq_puts(seq, ",no_heap");
+ else
+ seq_puts(seq, ",heap");
#ifdef CONFIG_F2FS_FS_XATTR
if (test_opt(sbi, XATTR_USER))
seq_puts(seq, ",user_xattr");
@@ -847,6 +1161,11 @@
seq_puts(seq, ",nouser_xattr");
if (test_opt(sbi, INLINE_XATTR))
seq_puts(seq, ",inline_xattr");
+ else
+ seq_puts(seq, ",noinline_xattr");
+ if (test_opt(sbi, INLINE_XATTR_SIZE))
+ seq_printf(seq, ",inline_xattr_size=%u",
+ sbi->inline_xattr_size);
#endif
#ifdef CONFIG_F2FS_FS_POSIX_ACL
if (test_opt(sbi, POSIX_ACL))
@@ -883,89 +1202,48 @@
else if (test_opt(sbi, LFS))
seq_puts(seq, "lfs");
seq_printf(seq, ",active_logs=%u", sbi->active_logs);
+ if (test_opt(sbi, RESERVE_ROOT))
+ seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u",
+ sbi->root_reserved_blocks,
+ from_kuid_munged(&init_user_ns, sbi->s_resuid),
+ from_kgid_munged(&init_user_ns, sbi->s_resgid));
+ if (F2FS_IO_SIZE_BITS(sbi))
+ seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+ if (test_opt(sbi, FAULT_INJECTION))
+ seq_printf(seq, ",fault_injection=%u",
+ sbi->fault_info.inject_rate);
+#endif
+#ifdef CONFIG_QUOTA
+ if (test_opt(sbi, QUOTA))
+ seq_puts(seq, ",quota");
+ if (test_opt(sbi, USRQUOTA))
+ seq_puts(seq, ",usrquota");
+ if (test_opt(sbi, GRPQUOTA))
+ seq_puts(seq, ",grpquota");
+ if (test_opt(sbi, PRJQUOTA))
+ seq_puts(seq, ",prjquota");
+#endif
+ f2fs_show_quota_options(seq, sbi->sb);
return 0;
}
-static int segment_info_seq_show(struct seq_file *seq, void *offset)
-{
- struct super_block *sb = seq->private;
- struct f2fs_sb_info *sbi = F2FS_SB(sb);
- unsigned int total_segs =
- le32_to_cpu(sbi->raw_super->segment_count_main);
- int i;
-
- seq_puts(seq, "format: segment_type|valid_blocks\n"
- "segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)\n");
-
- for (i = 0; i < total_segs; i++) {
- struct seg_entry *se = get_seg_entry(sbi, i);
-
- if ((i % 10) == 0)
- seq_printf(seq, "%-10d", i);
- seq_printf(seq, "%d|%-3u", se->type,
- get_valid_blocks(sbi, i, 1));
- if ((i % 10) == 9 || i == (total_segs - 1))
- seq_putc(seq, '\n');
- else
- seq_putc(seq, ' ');
- }
-
- return 0;
-}
-
-static int segment_bits_seq_show(struct seq_file *seq, void *offset)
-{
- struct super_block *sb = seq->private;
- struct f2fs_sb_info *sbi = F2FS_SB(sb);
- unsigned int total_segs =
- le32_to_cpu(sbi->raw_super->segment_count_main);
- int i, j;
-
- seq_puts(seq, "format: segment_type|valid_blocks|bitmaps\n"
- "segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)\n");
-
- for (i = 0; i < total_segs; i++) {
- struct seg_entry *se = get_seg_entry(sbi, i);
-
- seq_printf(seq, "%-10d", i);
- seq_printf(seq, "%d|%-3u|", se->type,
- get_valid_blocks(sbi, i, 1));
- for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++)
- seq_printf(seq, " %.2x", se->cur_valid_map[j]);
- seq_putc(seq, '\n');
- }
- return 0;
-}
-
-#define F2FS_PROC_FILE_DEF(_name) \
-static int _name##_open_fs(struct inode *inode, struct file *file) \
-{ \
- return single_open(file, _name##_seq_show, PDE_DATA(inode)); \
-} \
- \
-static const struct file_operations f2fs_seq_##_name##_fops = { \
- .open = _name##_open_fs, \
- .read = seq_read, \
- .llseek = seq_lseek, \
- .release = single_release, \
-};
-
-F2FS_PROC_FILE_DEF(segment_info);
-F2FS_PROC_FILE_DEF(segment_bits);
-
static void default_options(struct f2fs_sb_info *sbi)
{
/* init some FS parameters */
sbi->active_logs = NR_CURSEG_TYPE;
+ sbi->inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
set_opt(sbi, BG_GC);
+ set_opt(sbi, INLINE_XATTR);
set_opt(sbi, INLINE_DATA);
set_opt(sbi, INLINE_DENTRY);
set_opt(sbi, EXTENT_CACHE);
+ set_opt(sbi, NOHEAP);
sbi->sb->s_flags |= MS_LAZYTIME;
set_opt(sbi, FLUSH_MERGE);
- if (f2fs_sb_mounted_hmsmr(sbi->sb)) {
+ if (f2fs_sb_mounted_blkzoned(sbi->sb)) {
set_opt_mode(sbi, F2FS_MOUNT_LFS);
set_opt(sbi, DISCARD);
} else {
@@ -984,10 +1262,14 @@
#endif
}
+#ifdef CONFIG_QUOTA
+static int f2fs_enable_quotas(struct super_block *sb);
+#endif
static int f2fs_remount(struct super_block *sb, int *flags, char *data)
{
struct f2fs_sb_info *sbi = F2FS_SB(sb);
struct f2fs_mount_info org_mount_opt;
+ unsigned long old_sb_flags;
int err, active_logs;
bool need_restart_gc = false;
bool need_stop_gc = false;
@@ -995,14 +1277,37 @@
#ifdef CONFIG_F2FS_FAULT_INJECTION
struct f2fs_fault_info ffi = sbi->fault_info;
#endif
+#ifdef CONFIG_QUOTA
+ int s_jquota_fmt;
+ char *s_qf_names[MAXQUOTAS];
+ int i, j;
+#endif
/*
* Save the old mount options in case we
* need to restore them.
*/
org_mount_opt = sbi->mount_opt;
+ old_sb_flags = sb->s_flags;
active_logs = sbi->active_logs;
+#ifdef CONFIG_QUOTA
+ s_jquota_fmt = sbi->s_jquota_fmt;
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (sbi->s_qf_names[i]) {
+ s_qf_names[i] = kstrdup(sbi->s_qf_names[i],
+ GFP_KERNEL);
+ if (!s_qf_names[i]) {
+ for (j = 0; j < i; j++)
+ kfree(s_qf_names[j]);
+ return -ENOMEM;
+ }
+ } else {
+ s_qf_names[i] = NULL;
+ }
+ }
+#endif
+
/* recover superblocks we couldn't write due to previous RO mount */
if (!(*flags & MS_RDONLY) && is_sbi_flag_set(sbi, SBI_NEED_SB_WRITE)) {
err = f2fs_commit_super(sbi, false);
@@ -1012,7 +1317,6 @@
clear_sbi_flag(sbi, SBI_NEED_SB_WRITE);
}
- sbi->mount_opt.opt = 0;
default_options(sbi);
/* parse mount options */
@@ -1027,6 +1331,23 @@
if (f2fs_readonly(sb) && (*flags & MS_RDONLY))
goto skip;
+#ifdef CONFIG_QUOTA
+ if (!f2fs_readonly(sb) && (*flags & MS_RDONLY)) {
+ err = dquot_suspend(sb, -1);
+ if (err < 0)
+ goto restore_opts;
+ } else if (f2fs_readonly(sb) && !(*flags & MS_RDONLY)) {
+ /* dquot_resume needs RW */
+ sb->s_flags &= ~MS_RDONLY;
+ if (sb_any_quota_suspended(sb)) {
+ dquot_resume(sb, -1);
+ } else if (f2fs_sb_has_quota_ino(sb)) {
+ err = f2fs_enable_quotas(sb);
+ if (err)
+ goto restore_opts;
+ }
+ }
+#endif
/* disallow enable/disable extent_cache dynamically */
if (no_extent_cache == !!test_opt(sbi, EXTENT_CACHE)) {
err = -EINVAL;
@@ -1067,17 +1388,24 @@
* or if flush_merge is not passed in mount option.
*/
if ((*flags & MS_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) {
- destroy_flush_cmd_control(sbi);
- } else if (!SM_I(sbi)->cmd_control_info) {
+ clear_opt(sbi, FLUSH_MERGE);
+ destroy_flush_cmd_control(sbi, false);
+ } else {
err = create_flush_cmd_control(sbi);
if (err)
goto restore_gc;
}
skip:
+#ifdef CONFIG_QUOTA
+ /* Release old quota file names */
+ for (i = 0; i < MAXQUOTAS; i++)
+ kfree(s_qf_names[i]);
+#endif
/* Update the POSIXACL Flag */
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
(test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0);
+ limit_reserve_root(sbi);
return 0;
restore_gc:
if (need_restart_gc) {
@@ -1088,21 +1416,367 @@
stop_gc_thread(sbi);
}
restore_opts:
+#ifdef CONFIG_QUOTA
+ sbi->s_jquota_fmt = s_jquota_fmt;
+ for (i = 0; i < MAXQUOTAS; i++) {
+ kfree(sbi->s_qf_names[i]);
+ sbi->s_qf_names[i] = s_qf_names[i];
+ }
+#endif
sbi->mount_opt = org_mount_opt;
sbi->active_logs = active_logs;
+ sb->s_flags = old_sb_flags;
#ifdef CONFIG_F2FS_FAULT_INJECTION
sbi->fault_info = ffi;
#endif
return err;
}
-static struct super_operations f2fs_sops = {
+#ifdef CONFIG_QUOTA
+/* Read data from quotafile */
+static ssize_t f2fs_quota_read(struct super_block *sb, int type, char *data,
+ size_t len, loff_t off)
+{
+ struct inode *inode = sb_dqopt(sb)->files[type];
+ struct address_space *mapping = inode->i_mapping;
+ block_t blkidx = F2FS_BYTES_TO_BLK(off);
+ int offset = off & (sb->s_blocksize - 1);
+ int tocopy;
+ size_t toread;
+ loff_t i_size = i_size_read(inode);
+ struct page *page;
+ char *kaddr;
+
+ if (off > i_size)
+ return 0;
+
+ if (off + len > i_size)
+ len = i_size - off;
+ toread = len;
+ while (toread > 0) {
+ tocopy = min_t(unsigned long, sb->s_blocksize - offset, toread);
+repeat:
+ page = read_mapping_page(mapping, blkidx, NULL);
+ if (IS_ERR(page)) {
+ if (PTR_ERR(page) == -ENOMEM) {
+ congestion_wait(BLK_RW_ASYNC, HZ/50);
+ goto repeat;
+ }
+ return PTR_ERR(page);
+ }
+
+ lock_page(page);
+
+ if (unlikely(page->mapping != mapping)) {
+ f2fs_put_page(page, 1);
+ goto repeat;
+ }
+ if (unlikely(!PageUptodate(page))) {
+ f2fs_put_page(page, 1);
+ return -EIO;
+ }
+
+ kaddr = kmap_atomic(page);
+ memcpy(data, kaddr + offset, tocopy);
+ kunmap_atomic(kaddr);
+ f2fs_put_page(page, 1);
+
+ offset = 0;
+ toread -= tocopy;
+ data += tocopy;
+ blkidx++;
+ }
+ return len;
+}
+
+/* Write to quotafile */
+static ssize_t f2fs_quota_write(struct super_block *sb, int type,
+ const char *data, size_t len, loff_t off)
+{
+ struct inode *inode = sb_dqopt(sb)->files[type];
+ struct address_space *mapping = inode->i_mapping;
+ const struct address_space_operations *a_ops = mapping->a_ops;
+ int offset = off & (sb->s_blocksize - 1);
+ size_t towrite = len;
+ struct page *page;
+ char *kaddr;
+ int err = 0;
+ int tocopy;
+
+ while (towrite > 0) {
+ tocopy = min_t(unsigned long, sb->s_blocksize - offset,
+ towrite);
+retry:
+ err = a_ops->write_begin(NULL, mapping, off, tocopy, 0,
+ &page, NULL);
+ if (unlikely(err)) {
+ if (err == -ENOMEM) {
+ congestion_wait(BLK_RW_ASYNC, HZ/50);
+ goto retry;
+ }
+ break;
+ }
+
+ kaddr = kmap_atomic(page);
+ memcpy(kaddr + offset, data, tocopy);
+ kunmap_atomic(kaddr);
+ flush_dcache_page(page);
+
+ a_ops->write_end(NULL, mapping, off, tocopy, tocopy,
+ page, NULL);
+ offset = 0;
+ towrite -= tocopy;
+ off += tocopy;
+ data += tocopy;
+ cond_resched();
+ }
+
+ if (len == towrite)
+ return err;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
+ f2fs_mark_inode_dirty_sync(inode, false);
+ return len - towrite;
+}
+
+static struct dquot **f2fs_get_dquots(struct inode *inode)
+{
+ return F2FS_I(inode)->i_dquot;
+}
+
+static qsize_t *f2fs_get_reserved_space(struct inode *inode)
+{
+ return &F2FS_I(inode)->i_reserved_quota;
+}
+
+static int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type)
+{
+ return dquot_quota_on_mount(sbi->sb, sbi->s_qf_names[type],
+ sbi->s_jquota_fmt, type);
+}
+
+int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly)
+{
+ int enabled = 0;
+ int i, err;
+
+ if (f2fs_sb_has_quota_ino(sbi->sb) && rdonly) {
+ err = f2fs_enable_quotas(sbi->sb);
+ if (err) {
+ f2fs_msg(sbi->sb, KERN_ERR,
+ "Cannot turn on quota_ino: %d", err);
+ return 0;
+ }
+ return 1;
+ }
+
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (sbi->s_qf_names[i]) {
+ err = f2fs_quota_on_mount(sbi, i);
+ if (!err) {
+ enabled = 1;
+ continue;
+ }
+ f2fs_msg(sbi->sb, KERN_ERR,
+ "Cannot turn on quotas: %d on %d", err, i);
+ }
+ }
+ return enabled;
+}
+
+static int f2fs_quota_enable(struct super_block *sb, int type, int format_id,
+ unsigned int flags)
+{
+ struct inode *qf_inode;
+ unsigned long qf_inum;
+ int err;
+
+ BUG_ON(!f2fs_sb_has_quota_ino(sb));
+
+ qf_inum = f2fs_qf_ino(sb, type);
+ if (!qf_inum)
+ return -EPERM;
+
+ qf_inode = f2fs_iget(sb, qf_inum);
+ if (IS_ERR(qf_inode)) {
+ f2fs_msg(sb, KERN_ERR,
+ "Bad quota inode %u:%lu", type, qf_inum);
+ return PTR_ERR(qf_inode);
+ }
+
+ /* Don't account quota for quota files to avoid recursion */
+ qf_inode->i_flags |= S_NOQUOTA;
+ err = dquot_enable(qf_inode, type, format_id, flags);
+ iput(qf_inode);
+ return err;
+}
+
+static int f2fs_enable_quotas(struct super_block *sb)
+{
+ int type, err = 0;
+ unsigned long qf_inum;
+ bool quota_mopt[MAXQUOTAS] = {
+ test_opt(F2FS_SB(sb), USRQUOTA),
+ test_opt(F2FS_SB(sb), GRPQUOTA),
+ test_opt(F2FS_SB(sb), PRJQUOTA),
+ };
+
+ sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
+ for (type = 0; type < MAXQUOTAS; type++) {
+ qf_inum = f2fs_qf_ino(sb, type);
+ if (qf_inum) {
+ err = f2fs_quota_enable(sb, type, QFMT_VFS_V1,
+ DQUOT_USAGE_ENABLED |
+ (quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0));
+ if (err) {
+ f2fs_msg(sb, KERN_ERR,
+ "Failed to enable quota tracking "
+ "(type=%d, err=%d). Please run "
+ "fsck to fix.", type, err);
+ for (type--; type >= 0; type--)
+ dquot_quota_off(sb, type);
+ return err;
+ }
+ }
+ }
+ return 0;
+}
+
+static int f2fs_quota_sync(struct super_block *sb, int type)
+{
+ struct quota_info *dqopt = sb_dqopt(sb);
+ int cnt;
+ int ret;
+
+ ret = dquot_writeback_dquots(sb, type);
+ if (ret)
+ return ret;
+
+ /*
+ * Now when everything is written we can discard the pagecache so
+ * that userspace sees the changes.
+ */
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+ if (type != -1 && cnt != type)
+ continue;
+ if (!sb_has_quota_active(sb, cnt))
+ continue;
+
+ ret = filemap_write_and_wait(dqopt->files[cnt]->i_mapping);
+ if (ret)
+ return ret;
+
+ inode_lock(dqopt->files[cnt]);
+ truncate_inode_pages(&dqopt->files[cnt]->i_data, 0);
+ inode_unlock(dqopt->files[cnt]);
+ }
+ return 0;
+}
+
+static int f2fs_quota_on(struct super_block *sb, int type, int format_id,
+ struct path *path)
+{
+ struct inode *inode;
+ int err;
+
+ err = f2fs_quota_sync(sb, type);
+ if (err)
+ return err;
+
+ err = dquot_quota_on(sb, type, format_id, path);
+ if (err)
+ return err;
+
+ inode = d_inode(path->dentry);
+
+ inode_lock(inode);
+ F2FS_I(inode)->i_flags |= FS_NOATIME_FL | FS_IMMUTABLE_FL;
+ inode_set_flags(inode, S_NOATIME | S_IMMUTABLE,
+ S_NOATIME | S_IMMUTABLE);
+ inode_unlock(inode);
+ f2fs_mark_inode_dirty_sync(inode, false);
+
+ return 0;
+}
+
+static int f2fs_quota_off(struct super_block *sb, int type)
+{
+ struct inode *inode = sb_dqopt(sb)->files[type];
+ int err;
+
+ if (!inode || !igrab(inode))
+ return dquot_quota_off(sb, type);
+
+ f2fs_quota_sync(sb, type);
+
+ err = dquot_quota_off(sb, type);
+ if (err || f2fs_sb_has_quota_ino(sb))
+ goto out_put;
+
+ inode_lock(inode);
+ F2FS_I(inode)->i_flags &= ~(FS_NOATIME_FL | FS_IMMUTABLE_FL);
+ inode_set_flags(inode, 0, S_NOATIME | S_IMMUTABLE);
+ inode_unlock(inode);
+ f2fs_mark_inode_dirty_sync(inode, false);
+out_put:
+ iput(inode);
+ return err;
+}
+
+void f2fs_quota_off_umount(struct super_block *sb)
+{
+ int type;
+
+ for (type = 0; type < MAXQUOTAS; type++)
+ f2fs_quota_off(sb, type);
+}
+
+static int f2fs_get_projid(struct inode *inode, kprojid_t *projid)
+{
+ *projid = F2FS_I(inode)->i_projid;
+ return 0;
+}
+
+static const struct dquot_operations f2fs_quota_operations = {
+ .get_reserved_space = f2fs_get_reserved_space,
+ .write_dquot = dquot_commit,
+ .acquire_dquot = dquot_acquire,
+ .release_dquot = dquot_release,
+ .mark_dirty = dquot_mark_dquot_dirty,
+ .write_info = dquot_commit_info,
+ .alloc_dquot = dquot_alloc,
+ .destroy_dquot = dquot_destroy,
+ .get_projid = f2fs_get_projid,
+ .get_next_id = dquot_get_next_id,
+};
+
+static const struct quotactl_ops f2fs_quotactl_ops = {
+ .quota_on = f2fs_quota_on,
+ .quota_off = f2fs_quota_off,
+ .quota_sync = f2fs_quota_sync,
+ .get_state = dquot_get_state,
+ .set_info = dquot_set_dqinfo,
+ .get_dqblk = dquot_get_dqblk,
+ .set_dqblk = dquot_set_dqblk,
+ .get_nextdqblk = dquot_get_next_dqblk,
+};
+#else
+void f2fs_quota_off_umount(struct super_block *sb)
+{
+}
+#endif
+
+static const struct super_operations f2fs_sops = {
.alloc_inode = f2fs_alloc_inode,
.drop_inode = f2fs_drop_inode,
.destroy_inode = f2fs_destroy_inode,
.write_inode = f2fs_write_inode,
.dirty_inode = f2fs_dirty_inode,
.show_options = f2fs_show_options,
+#ifdef CONFIG_QUOTA
+ .quota_read = f2fs_quota_read,
+ .quota_write = f2fs_quota_write,
+ .get_dquots = f2fs_get_dquots,
+#endif
.evict_inode = f2fs_evict_inode,
.put_super = f2fs_put_super,
.sync_fs = f2fs_sync_fs,
@@ -1120,12 +1794,6 @@
ctx, len, NULL);
}
-static int f2fs_key_prefix(struct inode *inode, u8 **key)
-{
- *key = F2FS_I_SB(inode)->key_prefix;
- return F2FS_I_SB(inode)->key_prefix_size;
-}
-
static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len,
void *fs_data)
{
@@ -1140,18 +1808,13 @@
inode->i_sb->s_blocksize : F2FS_NAME_LEN;
}
-static struct fscrypt_operations f2fs_cryptops = {
+static const struct fscrypt_operations f2fs_cryptops = {
+ .key_prefix = "f2fs:",
.get_context = f2fs_get_context,
- .key_prefix = f2fs_key_prefix,
.set_context = f2fs_set_context,
- .is_encrypted = f2fs_encrypted_inode,
.empty_dir = f2fs_empty_dir,
.max_namelen = f2fs_max_namelen,
};
-#else
-static struct fscrypt_operations f2fs_cryptops = {
- .is_encrypted = f2fs_encrypted_inode,
-};
#endif
static struct inode *f2fs_nfs_get_inode(struct super_block *sb,
@@ -1201,9 +1864,16 @@
static loff_t max_file_blocks(void)
{
- loff_t result = (DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS);
+ loff_t result = 0;
loff_t leaf_count = ADDRS_PER_BLOCK;
+ /*
+ * note: previously, result is equal to (DEF_ADDRS_PER_INODE -
+ * DEFAULT_INLINE_XATTR_ADDRS), but now f2fs try to reserve more
+ * space in inode.i_addr, it will be more safe to reassign
+ * result as zero.
+ */
+
/* two direct node blocks */
result += (leaf_count * 2);
@@ -1229,7 +1899,7 @@
unlock_buffer(bh);
/* it's rare case, we can do fua all the time */
- return __sync_dirty_buffer(bh, WRITE_FLUSH_FUA);
+ return __sync_dirty_buffer(bh, REQ_SYNC | REQ_PREFLUSH | REQ_FUA);
}
static inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi,
@@ -1424,6 +2094,7 @@
unsigned int total, fsmeta;
struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+ unsigned int ovp_segments, reserved_segments;
unsigned int main_segs, blocks_per_seg;
int i;
@@ -1437,20 +2108,28 @@
if (unlikely(fsmeta >= total))
return 1;
- main_segs = le32_to_cpu(sbi->raw_super->segment_count_main);
+ ovp_segments = le32_to_cpu(ckpt->overprov_segment_count);
+ reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count);
+
+ if (unlikely(fsmeta < F2FS_MIN_SEGMENTS ||
+ ovp_segments == 0 || reserved_segments == 0)) {
+ f2fs_msg(sbi->sb, KERN_ERR,
+ "Wrong layout: check mkfs.f2fs version");
+ return 1;
+ }
+
+ main_segs = le32_to_cpu(raw_super->segment_count_main);
blocks_per_seg = sbi->blocks_per_seg;
for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs ||
- le16_to_cpu(ckpt->cur_node_blkoff[i]) >= blocks_per_seg) {
+ le16_to_cpu(ckpt->cur_node_blkoff[i]) >= blocks_per_seg)
return 1;
- }
}
for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) {
if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs ||
- le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg) {
+ le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg)
return 1;
- }
}
if (unlikely(f2fs_cp_error(sbi))) {
@@ -1463,7 +2142,7 @@
static void init_sb_info(struct f2fs_sb_info *sbi)
{
struct f2fs_super_block *raw_super = sbi->raw_super;
- int i;
+ int i, j;
sbi->log_sectors_per_block =
le32_to_cpu(raw_super->log_sectors_per_block);
@@ -1491,17 +2170,17 @@
for (i = 0; i < NR_COUNT_TYPE; i++)
atomic_set(&sbi->nr_pages[i], 0);
+ atomic_set(&sbi->wb_sync_req, 0);
+
INIT_LIST_HEAD(&sbi->s_list);
mutex_init(&sbi->umount_mutex);
- mutex_init(&sbi->wio_mutex[NODE]);
- mutex_init(&sbi->wio_mutex[DATA]);
+ for (i = 0; i < NR_PAGE_TYPE - 1; i++)
+ for (j = HOT; j < NR_TEMP_TYPE; j++)
+ mutex_init(&sbi->wio_mutex[i][j]);
spin_lock_init(&sbi->cp_lock);
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
- memcpy(sbi->key_prefix, F2FS_KEY_DESC_PREFIX,
- F2FS_KEY_DESC_PREFIX_SIZE);
- sbi->key_prefix_size = F2FS_KEY_DESC_PREFIX_SIZE;
-#endif
+ sbi->dirty_device = 0;
+ spin_lock_init(&sbi->dev_lock);
}
static int init_percpu_info(struct f2fs_sb_info *sbi)
@@ -1516,6 +2195,72 @@
GFP_KERNEL);
}
+#ifdef CONFIG_BLK_DEV_ZONED
+static int init_blkz_info(struct f2fs_sb_info *sbi, int devi)
+{
+ struct block_device *bdev = FDEV(devi).bdev;
+ sector_t nr_sectors = bdev->bd_part->nr_sects;
+ sector_t sector = 0;
+ struct blk_zone *zones;
+ unsigned int i, nr_zones;
+ unsigned int n = 0;
+ int err = -EIO;
+
+ if (!f2fs_sb_mounted_blkzoned(sbi->sb))
+ return 0;
+
+ if (sbi->blocks_per_blkz && sbi->blocks_per_blkz !=
+ SECTOR_TO_BLOCK(bdev_zone_sectors(bdev)))
+ return -EINVAL;
+ sbi->blocks_per_blkz = SECTOR_TO_BLOCK(bdev_zone_sectors(bdev));
+ if (sbi->log_blocks_per_blkz && sbi->log_blocks_per_blkz !=
+ __ilog2_u32(sbi->blocks_per_blkz))
+ return -EINVAL;
+ sbi->log_blocks_per_blkz = __ilog2_u32(sbi->blocks_per_blkz);
+ FDEV(devi).nr_blkz = SECTOR_TO_BLOCK(nr_sectors) >>
+ sbi->log_blocks_per_blkz;
+ if (nr_sectors & (bdev_zone_sectors(bdev) - 1))
+ FDEV(devi).nr_blkz++;
+
+ FDEV(devi).blkz_type = f2fs_kmalloc(sbi, FDEV(devi).nr_blkz,
+ GFP_KERNEL);
+ if (!FDEV(devi).blkz_type)
+ return -ENOMEM;
+
+#define F2FS_REPORT_NR_ZONES 4096
+
+ zones = f2fs_kzalloc(sbi, sizeof(struct blk_zone) *
+ F2FS_REPORT_NR_ZONES, GFP_KERNEL);
+ if (!zones)
+ return -ENOMEM;
+
+ /* Get block zones type */
+ while (zones && sector < nr_sectors) {
+
+ nr_zones = F2FS_REPORT_NR_ZONES;
+ err = blkdev_report_zones(bdev, sector,
+ zones, &nr_zones,
+ GFP_KERNEL);
+ if (err)
+ break;
+ if (!nr_zones) {
+ err = -EIO;
+ break;
+ }
+
+ for (i = 0; i < nr_zones; i++) {
+ FDEV(devi).blkz_type[n] = zones[i].type;
+ sector += zones[i].len;
+ n++;
+ }
+ }
+
+ kfree(zones);
+
+ return err;
+}
+#endif
+
/*
* Read f2fs raw super block.
* Because we have two copies of super block, so read both of them
@@ -1608,6 +2353,104 @@
return err;
}
+static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
+ unsigned int max_devices = MAX_DEVICES;
+ int i;
+
+ /* Initialize single device information */
+ if (!RDEV(0).path[0]) {
+#ifdef CONFIG_BLK_DEV_ZONED
+ if (!bdev_is_zoned(sbi->sb->s_bdev))
+ return 0;
+ max_devices = 1;
+#else
+ return 0;
+#endif
+ }
+
+ /*
+ * Initialize multiple devices information, or single
+ * zoned block device information.
+ */
+ sbi->devs = f2fs_kzalloc(sbi, sizeof(struct f2fs_dev_info) *
+ max_devices, GFP_KERNEL);
+ if (!sbi->devs)
+ return -ENOMEM;
+
+ for (i = 0; i < max_devices; i++) {
+
+ if (i > 0 && !RDEV(i).path[0])
+ break;
+
+ if (max_devices == 1) {
+ /* Single zoned block device mount */
+ FDEV(0).bdev =
+ blkdev_get_by_dev(sbi->sb->s_bdev->bd_dev,
+ sbi->sb->s_mode, sbi->sb->s_type);
+ } else {
+ /* Multi-device mount */
+ memcpy(FDEV(i).path, RDEV(i).path, MAX_PATH_LEN);
+ FDEV(i).total_segments =
+ le32_to_cpu(RDEV(i).total_segments);
+ if (i == 0) {
+ FDEV(i).start_blk = 0;
+ FDEV(i).end_blk = FDEV(i).start_blk +
+ (FDEV(i).total_segments <<
+ sbi->log_blocks_per_seg) - 1 +
+ le32_to_cpu(raw_super->segment0_blkaddr);
+ } else {
+ FDEV(i).start_blk = FDEV(i - 1).end_blk + 1;
+ FDEV(i).end_blk = FDEV(i).start_blk +
+ (FDEV(i).total_segments <<
+ sbi->log_blocks_per_seg) - 1;
+ }
+ FDEV(i).bdev = blkdev_get_by_path(FDEV(i).path,
+ sbi->sb->s_mode, sbi->sb->s_type);
+ }
+ if (IS_ERR(FDEV(i).bdev))
+ return PTR_ERR(FDEV(i).bdev);
+
+ /* to release errored devices */
+ sbi->s_ndevs = i + 1;
+
+#ifdef CONFIG_BLK_DEV_ZONED
+ if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM &&
+ !f2fs_sb_mounted_blkzoned(sbi->sb)) {
+ f2fs_msg(sbi->sb, KERN_ERR,
+ "Zoned block device feature not enabled\n");
+ return -EINVAL;
+ }
+ if (bdev_zoned_model(FDEV(i).bdev) != BLK_ZONED_NONE) {
+ if (init_blkz_info(sbi, i)) {
+ f2fs_msg(sbi->sb, KERN_ERR,
+ "Failed to initialize F2FS blkzone information");
+ return -EINVAL;
+ }
+ if (max_devices == 1)
+ break;
+ f2fs_msg(sbi->sb, KERN_INFO,
+ "Mount Device [%2d]: %20s, %8u, %8x - %8x (zone: %s)",
+ i, FDEV(i).path,
+ FDEV(i).total_segments,
+ FDEV(i).start_blk, FDEV(i).end_blk,
+ bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HA ?
+ "Host-aware" : "Host-managed");
+ continue;
+ }
+#endif
+ f2fs_msg(sbi->sb, KERN_INFO,
+ "Mount Device [%2d]: %20s, %8u, %8x - %8x",
+ i, FDEV(i).path,
+ FDEV(i).total_segments,
+ FDEV(i).start_blk, FDEV(i).end_blk);
+ }
+ f2fs_msg(sbi->sb, KERN_INFO,
+ "IO Block Size: %8d KB", F2FS_IO_SIZE_KB(sbi));
+ return 0;
+}
+
static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
{
struct f2fs_sb_info *sbi;
@@ -1655,6 +2498,27 @@
sb->s_fs_info = sbi;
sbi->raw_super = raw_super;
+ sbi->s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID);
+ sbi->s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID);
+
+ /* precompute checksum seed for metadata */
+ if (f2fs_sb_has_inode_chksum(sb))
+ sbi->s_chksum_seed = f2fs_chksum(sbi, ~0, raw_super->uuid,
+ sizeof(raw_super->uuid));
+
+ /*
+ * The BLKZONED feature indicates that the drive was formatted with
+ * zone alignment optimization. This is optional for host-aware
+ * devices, but mandatory for host-managed zoned block devices.
+ */
+#ifndef CONFIG_BLK_DEV_ZONED
+ if (f2fs_sb_mounted_blkzoned(sb)) {
+ f2fs_msg(sb, KERN_ERR,
+ "Zoned block device support is not enabled\n");
+ err = -EOPNOTSUPP;
+ goto free_sb_buf;
+ }
+#endif
default_options(sbi);
/* parse mount options */
options = kstrdup((const char *)data, GFP_KERNEL);
@@ -1673,33 +2537,69 @@
sb->s_max_links = F2FS_LINK_MAX;
get_random_bytes(&sbi->s_next_generation, sizeof(u32));
+#ifdef CONFIG_QUOTA
+ sb->dq_op = &f2fs_quota_operations;
+ if (f2fs_sb_has_quota_ino(sb))
+ sb->s_qcop = &dquot_quotactl_sysfile_ops;
+ else
+ sb->s_qcop = &f2fs_quotactl_ops;
+ sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
+
+ if (f2fs_sb_has_quota_ino(sbi->sb)) {
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (f2fs_qf_ino(sbi->sb, i))
+ sbi->nquota_files++;
+ }
+ }
+#endif
+
sb->s_op = &f2fs_sops;
+#ifdef CONFIG_F2FS_FS_ENCRYPTION
sb->s_cop = &f2fs_cryptops;
+#endif
sb->s_xattr = f2fs_xattr_handlers;
sb->s_export_op = &f2fs_export_ops;
sb->s_magic = F2FS_SUPER_MAGIC;
sb->s_time_gran = 1;
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
(test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0);
- memcpy(sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid));
+ memcpy(&sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid));
+ sb->s_iflags |= SB_I_CGROUPWB;
/* init f2fs-specific super block info */
sbi->valid_super_block = valid_super_block;
mutex_init(&sbi->gc_mutex);
mutex_init(&sbi->cp_mutex);
init_rwsem(&sbi->node_write);
+ init_rwsem(&sbi->node_change);
/* disallow all the data/node/meta page writes */
set_sbi_flag(sbi, SBI_POR_DOING);
spin_lock_init(&sbi->stat_lock);
- init_rwsem(&sbi->read_io.io_rwsem);
- sbi->read_io.sbi = sbi;
- sbi->read_io.bio = NULL;
+ /* init iostat info */
+ spin_lock_init(&sbi->iostat_lock);
+ sbi->iostat_enable = false;
+
for (i = 0; i < NR_PAGE_TYPE; i++) {
- init_rwsem(&sbi->write_io[i].io_rwsem);
- sbi->write_io[i].sbi = sbi;
- sbi->write_io[i].bio = NULL;
+ int n = (i == META) ? 1: NR_TEMP_TYPE;
+ int j;
+
+ sbi->write_io[i] = f2fs_kmalloc(sbi,
+ n * sizeof(struct f2fs_bio_info),
+ GFP_KERNEL);
+ if (!sbi->write_io[i]) {
+ err = -ENOMEM;
+ goto free_options;
+ }
+
+ for (j = HOT; j < n; j++) {
+ init_rwsem(&sbi->write_io[i][j].io_rwsem);
+ sbi->write_io[i][j].sbi = sbi;
+ sbi->write_io[i][j].bio = NULL;
+ spin_lock_init(&sbi->write_io[i][j].io_lock);
+ INIT_LIST_HEAD(&sbi->write_io[i][j].io_list);
+ }
}
init_rwsem(&sbi->cp_rwsem);
@@ -1708,14 +2608,23 @@
err = init_percpu_info(sbi);
if (err)
- goto free_options;
+ goto free_bio_info;
+
+ if (F2FS_IO_SIZE(sbi) > 1) {
+ sbi->write_io_dummy =
+ mempool_create_page_pool(2 * (F2FS_IO_SIZE(sbi) - 1), 0);
+ if (!sbi->write_io_dummy) {
+ err = -ENOMEM;
+ goto free_percpu;
+ }
+ }
/* get an inode for meta space */
sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
if (IS_ERR(sbi->meta_inode)) {
f2fs_msg(sb, KERN_ERR, "Failed to read F2FS meta data inode");
err = PTR_ERR(sbi->meta_inode);
- goto free_options;
+ goto free_io_dummy;
}
err = get_valid_checkpoint(sbi);
@@ -1724,6 +2633,13 @@
goto free_meta_inode;
}
+ /* Initialize device list */
+ err = f2fs_scan_devices(sbi);
+ if (err) {
+ f2fs_msg(sb, KERN_ERR, "Failed to find devices");
+ goto free_devices;
+ }
+
sbi->total_valid_node_count =
le32_to_cpu(sbi->ckpt->valid_node_count);
percpu_counter_set(&sbi->total_valid_inode_count,
@@ -1732,6 +2648,9 @@
sbi->total_valid_block_count =
le64_to_cpu(sbi->ckpt->valid_block_count);
sbi->last_valid_block_count = sbi->total_valid_block_count;
+ sbi->reserved_blocks = 0;
+ sbi->current_reserved_blocks = 0;
+ limit_reserve_root(sbi);
for (i = 0; i < NR_INODE_TYPE; i++) {
INIT_LIST_HEAD(&sbi->inode_list[i]);
@@ -1777,10 +2696,7 @@
goto free_nm;
}
- f2fs_join_shrinker(sbi);
-
- /* if there are nt orphan nodes free them */
- err = recover_orphan_inodes(sbi);
+ err = f2fs_build_stats(sbi);
if (err)
goto free_node_inode;
@@ -1789,7 +2705,7 @@
if (IS_ERR(root)) {
f2fs_msg(sb, KERN_ERR, "Failed to read root inode");
err = PTR_ERR(root);
- goto free_node_inode;
+ goto free_stats;
}
if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
iput(root);
@@ -1803,26 +2719,28 @@
goto free_root_inode;
}
- err = f2fs_build_stats(sbi);
+ err = f2fs_register_sysfs(sbi);
if (err)
goto free_root_inode;
- if (f2fs_proc_root)
- sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root);
-
- if (sbi->s_proc) {
- proc_create_data("segment_info", S_IRUGO, sbi->s_proc,
- &f2fs_seq_segment_info_fops, sb);
- proc_create_data("segment_bits", S_IRUGO, sbi->s_proc,
- &f2fs_seq_segment_bits_fops, sb);
+#ifdef CONFIG_QUOTA
+ /*
+ * Turn on quotas which were not enabled for read-only mounts if
+ * filesystem has quota feature, so that they are updated correctly.
+ */
+ if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb)) {
+ err = f2fs_enable_quotas(sb);
+ if (err) {
+ f2fs_msg(sb, KERN_ERR,
+ "Cannot turn on quotas: error %d", err);
+ goto free_sysfs;
+ }
}
-
- sbi->s_kobj.kset = f2fs_kset;
- init_completion(&sbi->s_kobj_unregister);
- err = kobject_init_and_add(&sbi->s_kobj, &f2fs_ktype, NULL,
- "%s", sb->s_id);
+#endif
+ /* if there are nt orphan nodes free them */
+ err = recover_orphan_inodes(sbi);
if (err)
- goto free_proc;
+ goto free_meta;
/* recover fsynced data */
if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
@@ -1833,7 +2751,7 @@
if (bdev_read_only(sb->s_bdev) &&
!is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
err = -EROFS;
- goto free_kobj;
+ goto free_meta;
}
if (need_fsck)
@@ -1847,7 +2765,7 @@
need_fsck = true;
f2fs_msg(sb, KERN_ERR,
"Cannot recover all fsync data errno=%d", err);
- goto free_kobj;
+ goto free_meta;
}
} else {
err = recover_fsync_data(sbi, true);
@@ -1856,7 +2774,7 @@
err = -EINVAL;
f2fs_msg(sb, KERN_ERR,
"Need to recover fsync data");
- goto free_kobj;
+ goto free_meta;
}
}
skip_recovery:
@@ -1871,7 +2789,7 @@
/* After POR, we can run background GC thread.*/
err = start_gc_thread(sbi);
if (err)
- goto free_kobj;
+ goto free_meta;
}
kfree(options);
@@ -1883,42 +2801,62 @@
sbi->valid_super_block ? 1 : 2, err);
}
+ f2fs_join_shrinker(sbi);
+
+ f2fs_msg(sbi->sb, KERN_NOTICE, "Mounted with checkpoint version = %llx",
+ cur_cp_version(F2FS_CKPT(sbi)));
f2fs_update_time(sbi, CP_TIME);
f2fs_update_time(sbi, REQ_TIME);
return 0;
-free_kobj:
+free_meta:
+#ifdef CONFIG_QUOTA
+ if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb))
+ f2fs_quota_off_umount(sbi->sb);
+#endif
f2fs_sync_inode_meta(sbi);
- kobject_del(&sbi->s_kobj);
- kobject_put(&sbi->s_kobj);
- wait_for_completion(&sbi->s_kobj_unregister);
-free_proc:
- if (sbi->s_proc) {
- remove_proc_entry("segment_info", sbi->s_proc);
- remove_proc_entry("segment_bits", sbi->s_proc);
- remove_proc_entry(sb->s_id, f2fs_proc_root);
- }
- f2fs_destroy_stats(sbi);
+ /*
+ * Some dirty meta pages can be produced by recover_orphan_inodes()
+ * failed by EIO. Then, iput(node_inode) can trigger balance_fs_bg()
+ * followed by write_checkpoint() through f2fs_write_node_pages(), which
+ * falls into an infinite loop in sync_meta_pages().
+ */
+ truncate_inode_pages_final(META_MAPPING(sbi));
+#ifdef CONFIG_QUOTA
+free_sysfs:
+#endif
+ f2fs_unregister_sysfs(sbi);
free_root_inode:
dput(sb->s_root);
sb->s_root = NULL;
+free_stats:
+ f2fs_destroy_stats(sbi);
free_node_inode:
- truncate_inode_pages_final(NODE_MAPPING(sbi));
- mutex_lock(&sbi->umount_mutex);
release_ino_entry(sbi, true);
- f2fs_leave_shrinker(sbi);
+ truncate_inode_pages_final(NODE_MAPPING(sbi));
iput(sbi->node_inode);
- mutex_unlock(&sbi->umount_mutex);
free_nm:
destroy_node_manager(sbi);
free_sm:
destroy_segment_manager(sbi);
+free_devices:
+ destroy_device_list(sbi);
kfree(sbi->ckpt);
free_meta_inode:
make_bad_inode(sbi->meta_inode);
iput(sbi->meta_inode);
-free_options:
+free_io_dummy:
+ mempool_destroy(sbi->write_io_dummy);
+free_percpu:
destroy_percpu_info(sbi);
+free_bio_info:
+ for (i = 0; i < NR_PAGE_TYPE; i++)
+ kfree(sbi->write_io[i]);
+free_options:
+#ifdef CONFIG_QUOTA
+ for (i = 0; i < MAXQUOTAS; i++)
+ kfree(sbi->s_qf_names[i]);
+#endif
kfree(options);
free_sb_buf:
kfree(raw_super);
@@ -1944,8 +2882,11 @@
static void kill_f2fs_super(struct super_block *sb)
{
- if (sb->s_root)
+ if (sb->s_root) {
set_sbi_flag(F2FS_SB(sb), SBI_IS_CLOSE);
+ stop_gc_thread(F2FS_SB(sb));
+ stop_discard_thread(F2FS_SB(sb));
+ }
kill_block_super(sb);
}
@@ -1999,30 +2940,26 @@
err = create_extent_cache();
if (err)
goto free_checkpoint_caches;
- f2fs_kset = kset_create_and_add("f2fs", NULL, fs_kobj);
- if (!f2fs_kset) {
- err = -ENOMEM;
+ err = f2fs_init_sysfs();
+ if (err)
goto free_extent_cache;
- }
err = register_shrinker(&f2fs_shrinker_info);
if (err)
- goto free_kset;
-
+ goto free_sysfs;
err = register_filesystem(&f2fs_fs_type);
if (err)
goto free_shrinker;
err = f2fs_create_root_stats();
if (err)
goto free_filesystem;
- f2fs_proc_root = proc_mkdir("fs/f2fs", NULL);
return 0;
free_filesystem:
unregister_filesystem(&f2fs_fs_type);
free_shrinker:
unregister_shrinker(&f2fs_shrinker_info);
-free_kset:
- kset_unregister(f2fs_kset);
+free_sysfs:
+ f2fs_exit_sysfs();
free_extent_cache:
destroy_extent_cache();
free_checkpoint_caches:
@@ -2039,11 +2976,10 @@
static void __exit exit_f2fs_fs(void)
{
- remove_proc_entry("fs/f2fs", NULL);
f2fs_destroy_root_stats();
unregister_filesystem(&f2fs_fs_type);
unregister_shrinker(&f2fs_shrinker_info);
- kset_unregister(f2fs_kset);
+ f2fs_exit_sysfs();
destroy_extent_cache();
destroy_checkpoint_caches();
destroy_segment_manager_caches();
@@ -2058,3 +2994,4 @@
MODULE_AUTHOR("Samsung Electronics's Praesto Team");
MODULE_DESCRIPTION("Flash Friendly File System");
MODULE_LICENSE("GPL");
+
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
new file mode 100644
index 0000000..d978c7b
--- /dev/null
+++ b/fs/f2fs/sysfs.c
@@ -0,0 +1,589 @@
+/*
+ * f2fs sysfs interface
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ * Copyright (c) 2017 Chao Yu <chao@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/proc_fs.h>
+#include <linux/f2fs_fs.h>
+#include <linux/seq_file.h>
+
+#include "f2fs.h"
+#include "segment.h"
+#include "gc.h"
+
+static struct proc_dir_entry *f2fs_proc_root;
+
+/* Sysfs support for f2fs */
+enum {
+ GC_THREAD, /* struct f2fs_gc_thread */
+ SM_INFO, /* struct f2fs_sm_info */
+ DCC_INFO, /* struct discard_cmd_control */
+ NM_INFO, /* struct f2fs_nm_info */
+ F2FS_SBI, /* struct f2fs_sb_info */
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+ FAULT_INFO_RATE, /* struct f2fs_fault_info */
+ FAULT_INFO_TYPE, /* struct f2fs_fault_info */
+#endif
+ RESERVED_BLOCKS, /* struct f2fs_sb_info */
+};
+
+struct f2fs_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *);
+ ssize_t (*store)(struct f2fs_attr *, struct f2fs_sb_info *,
+ const char *, size_t);
+ int struct_type;
+ int offset;
+ int id;
+};
+
+static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type)
+{
+ if (struct_type == GC_THREAD)
+ return (unsigned char *)sbi->gc_thread;
+ else if (struct_type == SM_INFO)
+ return (unsigned char *)SM_I(sbi);
+ else if (struct_type == DCC_INFO)
+ return (unsigned char *)SM_I(sbi)->dcc_info;
+ else if (struct_type == NM_INFO)
+ return (unsigned char *)NM_I(sbi);
+ else if (struct_type == F2FS_SBI || struct_type == RESERVED_BLOCKS)
+ return (unsigned char *)sbi;
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+ else if (struct_type == FAULT_INFO_RATE ||
+ struct_type == FAULT_INFO_TYPE)
+ return (unsigned char *)&sbi->fault_info;
+#endif
+ return NULL;
+}
+
+static ssize_t dirty_segments_show(struct f2fs_attr *a,
+ struct f2fs_sb_info *sbi, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%llu\n",
+ (unsigned long long)(dirty_segments(sbi)));
+}
+
+static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a,
+ struct f2fs_sb_info *sbi, char *buf)
+{
+ struct super_block *sb = sbi->sb;
+
+ if (!sb->s_bdev->bd_part)
+ return snprintf(buf, PAGE_SIZE, "0\n");
+
+ return snprintf(buf, PAGE_SIZE, "%llu\n",
+ (unsigned long long)(sbi->kbytes_written +
+ BD_PART_WRITTEN(sbi)));
+}
+
+static ssize_t features_show(struct f2fs_attr *a,
+ struct f2fs_sb_info *sbi, char *buf)
+{
+ struct super_block *sb = sbi->sb;
+ int len = 0;
+
+ if (!sb->s_bdev->bd_part)
+ return snprintf(buf, PAGE_SIZE, "0\n");
+
+ if (f2fs_sb_has_crypto(sb))
+ len += snprintf(buf, PAGE_SIZE - len, "%s",
+ "encryption");
+ if (f2fs_sb_mounted_blkzoned(sb))
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
+ len ? ", " : "", "blkzoned");
+ if (f2fs_sb_has_extra_attr(sb))
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
+ len ? ", " : "", "extra_attr");
+ if (f2fs_sb_has_project_quota(sb))
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
+ len ? ", " : "", "projquota");
+ if (f2fs_sb_has_inode_chksum(sb))
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
+ len ? ", " : "", "inode_checksum");
+ if (f2fs_sb_has_flexible_inline_xattr(sb))
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
+ len ? ", " : "", "flexible_inline_xattr");
+ if (f2fs_sb_has_quota_ino(sb))
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
+ len ? ", " : "", "quota_ino");
+ if (f2fs_sb_has_inode_crtime(sb))
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
+ len ? ", " : "", "inode_crtime");
+ len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+ return len;
+}
+
+static ssize_t current_reserved_blocks_show(struct f2fs_attr *a,
+ struct f2fs_sb_info *sbi, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", sbi->current_reserved_blocks);
+}
+
+static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
+ struct f2fs_sb_info *sbi, char *buf)
+{
+ unsigned char *ptr = NULL;
+ unsigned int *ui;
+
+ ptr = __struct_ptr(sbi, a->struct_type);
+ if (!ptr)
+ return -EINVAL;
+
+ ui = (unsigned int *)(ptr + a->offset);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
+}
+
+static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
+ struct f2fs_sb_info *sbi,
+ const char *buf, size_t count)
+{
+ unsigned char *ptr;
+ unsigned long t;
+ unsigned int *ui;
+ ssize_t ret;
+
+ ptr = __struct_ptr(sbi, a->struct_type);
+ if (!ptr)
+ return -EINVAL;
+
+ ui = (unsigned int *)(ptr + a->offset);
+
+ ret = kstrtoul(skip_spaces(buf), 0, &t);
+ if (ret < 0)
+ return ret;
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+ if (a->struct_type == FAULT_INFO_TYPE && t >= (1 << FAULT_MAX))
+ return -EINVAL;
+#endif
+ if (a->struct_type == RESERVED_BLOCKS) {
+ spin_lock(&sbi->stat_lock);
+ if (t > (unsigned long)(sbi->user_block_count -
+ sbi->root_reserved_blocks)) {
+ spin_unlock(&sbi->stat_lock);
+ return -EINVAL;
+ }
+ *ui = t;
+ sbi->current_reserved_blocks = min(sbi->reserved_blocks,
+ sbi->user_block_count - valid_user_blocks(sbi));
+ spin_unlock(&sbi->stat_lock);
+ return count;
+ }
+
+ if (!strcmp(a->attr.name, "discard_granularity")) {
+ if (t == 0 || t > MAX_PLIST_NUM)
+ return -EINVAL;
+ if (t == *ui)
+ return count;
+ *ui = t;
+ return count;
+ }
+
+ *ui = t;
+
+ if (!strcmp(a->attr.name, "iostat_enable") && *ui == 0)
+ f2fs_reset_iostat(sbi);
+ if (!strcmp(a->attr.name, "gc_urgent") && t == 1 && sbi->gc_thread) {
+ sbi->gc_thread->gc_wake = 1;
+ wake_up_interruptible_all(&sbi->gc_thread->gc_wait_queue_head);
+ wake_up_discard_thread(sbi, true);
+ }
+
+ return count;
+}
+
+static ssize_t f2fs_attr_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info,
+ s_kobj);
+ struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr);
+
+ return a->show ? a->show(a, sbi, buf) : 0;
+}
+
+static ssize_t f2fs_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t len)
+{
+ struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info,
+ s_kobj);
+ struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr);
+
+ return a->store ? a->store(a, sbi, buf, len) : 0;
+}
+
+static void f2fs_sb_release(struct kobject *kobj)
+{
+ struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info,
+ s_kobj);
+ complete(&sbi->s_kobj_unregister);
+}
+
+enum feat_id {
+ FEAT_CRYPTO = 0,
+ FEAT_BLKZONED,
+ FEAT_ATOMIC_WRITE,
+ FEAT_EXTRA_ATTR,
+ FEAT_PROJECT_QUOTA,
+ FEAT_INODE_CHECKSUM,
+ FEAT_FLEXIBLE_INLINE_XATTR,
+ FEAT_QUOTA_INO,
+ FEAT_INODE_CRTIME,
+};
+
+static ssize_t f2fs_feature_show(struct f2fs_attr *a,
+ struct f2fs_sb_info *sbi, char *buf)
+{
+ switch (a->id) {
+ case FEAT_CRYPTO:
+ case FEAT_BLKZONED:
+ case FEAT_ATOMIC_WRITE:
+ case FEAT_EXTRA_ATTR:
+ case FEAT_PROJECT_QUOTA:
+ case FEAT_INODE_CHECKSUM:
+ case FEAT_FLEXIBLE_INLINE_XATTR:
+ case FEAT_QUOTA_INO:
+ case FEAT_INODE_CRTIME:
+ return snprintf(buf, PAGE_SIZE, "supported\n");
+ }
+ return 0;
+}
+
+#define F2FS_ATTR_OFFSET(_struct_type, _name, _mode, _show, _store, _offset) \
+static struct f2fs_attr f2fs_attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+ .struct_type = _struct_type, \
+ .offset = _offset \
+}
+
+#define F2FS_RW_ATTR(struct_type, struct_name, name, elname) \
+ F2FS_ATTR_OFFSET(struct_type, name, 0644, \
+ f2fs_sbi_show, f2fs_sbi_store, \
+ offsetof(struct struct_name, elname))
+
+#define F2FS_GENERAL_RO_ATTR(name) \
+static struct f2fs_attr f2fs_attr_##name = __ATTR(name, 0444, name##_show, NULL)
+
+#define F2FS_FEATURE_RO_ATTR(_name, _id) \
+static struct f2fs_attr f2fs_attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = 0444 }, \
+ .show = f2fs_feature_show, \
+ .id = _id, \
+}
+
+F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_urgent_sleep_time,
+ urgent_sleep_time);
+F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time);
+F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time);
+F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time);
+F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle);
+F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_urgent, gc_urgent);
+F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments);
+F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_small_discards, max_discards);
+F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, discard_granularity, discard_granularity);
+F2FS_RW_ATTR(RESERVED_BLOCKS, f2fs_sb_info, reserved_blocks, reserved_blocks);
+F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections);
+F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy);
+F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util);
+F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks);
+F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_hot_blocks, min_hot_blocks);
+F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ssr_sections, min_ssr_sections);
+F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh);
+F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages);
+F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate);
+F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type);
+#endif
+F2FS_GENERAL_RO_ATTR(dirty_segments);
+F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes);
+F2FS_GENERAL_RO_ATTR(features);
+F2FS_GENERAL_RO_ATTR(current_reserved_blocks);
+
+#ifdef CONFIG_F2FS_FS_ENCRYPTION
+F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO);
+#endif
+#ifdef CONFIG_BLK_DEV_ZONED
+F2FS_FEATURE_RO_ATTR(block_zoned, FEAT_BLKZONED);
+#endif
+F2FS_FEATURE_RO_ATTR(atomic_write, FEAT_ATOMIC_WRITE);
+F2FS_FEATURE_RO_ATTR(extra_attr, FEAT_EXTRA_ATTR);
+F2FS_FEATURE_RO_ATTR(project_quota, FEAT_PROJECT_QUOTA);
+F2FS_FEATURE_RO_ATTR(inode_checksum, FEAT_INODE_CHECKSUM);
+F2FS_FEATURE_RO_ATTR(flexible_inline_xattr, FEAT_FLEXIBLE_INLINE_XATTR);
+F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO);
+F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME);
+
+#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
+static struct attribute *f2fs_attrs[] = {
+ ATTR_LIST(gc_urgent_sleep_time),
+ ATTR_LIST(gc_min_sleep_time),
+ ATTR_LIST(gc_max_sleep_time),
+ ATTR_LIST(gc_no_gc_sleep_time),
+ ATTR_LIST(gc_idle),
+ ATTR_LIST(gc_urgent),
+ ATTR_LIST(reclaim_segments),
+ ATTR_LIST(max_small_discards),
+ ATTR_LIST(discard_granularity),
+ ATTR_LIST(batched_trim_sections),
+ ATTR_LIST(ipu_policy),
+ ATTR_LIST(min_ipu_util),
+ ATTR_LIST(min_fsync_blocks),
+ ATTR_LIST(min_hot_blocks),
+ ATTR_LIST(min_ssr_sections),
+ ATTR_LIST(max_victim_search),
+ ATTR_LIST(dir_level),
+ ATTR_LIST(ram_thresh),
+ ATTR_LIST(ra_nid_pages),
+ ATTR_LIST(dirty_nats_ratio),
+ ATTR_LIST(cp_interval),
+ ATTR_LIST(idle_interval),
+ ATTR_LIST(iostat_enable),
+ ATTR_LIST(readdir_ra),
+ ATTR_LIST(gc_pin_file_thresh),
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+ ATTR_LIST(inject_rate),
+ ATTR_LIST(inject_type),
+#endif
+ ATTR_LIST(dirty_segments),
+ ATTR_LIST(lifetime_write_kbytes),
+ ATTR_LIST(features),
+ ATTR_LIST(reserved_blocks),
+ ATTR_LIST(current_reserved_blocks),
+ NULL,
+};
+
+static struct attribute *f2fs_feat_attrs[] = {
+#ifdef CONFIG_F2FS_FS_ENCRYPTION
+ ATTR_LIST(encryption),
+#endif
+#ifdef CONFIG_BLK_DEV_ZONED
+ ATTR_LIST(block_zoned),
+#endif
+ ATTR_LIST(atomic_write),
+ ATTR_LIST(extra_attr),
+ ATTR_LIST(project_quota),
+ ATTR_LIST(inode_checksum),
+ ATTR_LIST(flexible_inline_xattr),
+ ATTR_LIST(quota_ino),
+ ATTR_LIST(inode_crtime),
+ NULL,
+};
+
+static const struct sysfs_ops f2fs_attr_ops = {
+ .show = f2fs_attr_show,
+ .store = f2fs_attr_store,
+};
+
+static struct kobj_type f2fs_sb_ktype = {
+ .default_attrs = f2fs_attrs,
+ .sysfs_ops = &f2fs_attr_ops,
+ .release = f2fs_sb_release,
+};
+
+static struct kobj_type f2fs_ktype = {
+ .sysfs_ops = &f2fs_attr_ops,
+};
+
+static struct kset f2fs_kset = {
+ .kobj = {.ktype = &f2fs_ktype},
+};
+
+static struct kobj_type f2fs_feat_ktype = {
+ .default_attrs = f2fs_feat_attrs,
+ .sysfs_ops = &f2fs_attr_ops,
+};
+
+static struct kobject f2fs_feat = {
+ .kset = &f2fs_kset,
+};
+
+static int segment_info_seq_show(struct seq_file *seq, void *offset)
+{
+ struct super_block *sb = seq->private;
+ struct f2fs_sb_info *sbi = F2FS_SB(sb);
+ unsigned int total_segs =
+ le32_to_cpu(sbi->raw_super->segment_count_main);
+ int i;
+
+ seq_puts(seq, "format: segment_type|valid_blocks\n"
+ "segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)\n");
+
+ for (i = 0; i < total_segs; i++) {
+ struct seg_entry *se = get_seg_entry(sbi, i);
+
+ if ((i % 10) == 0)
+ seq_printf(seq, "%-10d", i);
+ seq_printf(seq, "%d|%-3u", se->type,
+ get_valid_blocks(sbi, i, false));
+ if ((i % 10) == 9 || i == (total_segs - 1))
+ seq_putc(seq, '\n');
+ else
+ seq_putc(seq, ' ');
+ }
+
+ return 0;
+}
+
+static int segment_bits_seq_show(struct seq_file *seq, void *offset)
+{
+ struct super_block *sb = seq->private;
+ struct f2fs_sb_info *sbi = F2FS_SB(sb);
+ unsigned int total_segs =
+ le32_to_cpu(sbi->raw_super->segment_count_main);
+ int i, j;
+
+ seq_puts(seq, "format: segment_type|valid_blocks|bitmaps\n"
+ "segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)\n");
+
+ for (i = 0; i < total_segs; i++) {
+ struct seg_entry *se = get_seg_entry(sbi, i);
+
+ seq_printf(seq, "%-10d", i);
+ seq_printf(seq, "%d|%-3u|", se->type,
+ get_valid_blocks(sbi, i, false));
+ for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++)
+ seq_printf(seq, " %.2x", se->cur_valid_map[j]);
+ seq_putc(seq, '\n');
+ }
+ return 0;
+}
+
+static int iostat_info_seq_show(struct seq_file *seq, void *offset)
+{
+ struct super_block *sb = seq->private;
+ struct f2fs_sb_info *sbi = F2FS_SB(sb);
+ time64_t now = ktime_get_real_seconds();
+
+ if (!sbi->iostat_enable)
+ return 0;
+
+ seq_printf(seq, "time: %-16llu\n", now);
+
+ /* print app IOs */
+ seq_printf(seq, "app buffered: %-16llu\n",
+ sbi->write_iostat[APP_BUFFERED_IO]);
+ seq_printf(seq, "app direct: %-16llu\n",
+ sbi->write_iostat[APP_DIRECT_IO]);
+ seq_printf(seq, "app mapped: %-16llu\n",
+ sbi->write_iostat[APP_MAPPED_IO]);
+
+ /* print fs IOs */
+ seq_printf(seq, "fs data: %-16llu\n",
+ sbi->write_iostat[FS_DATA_IO]);
+ seq_printf(seq, "fs node: %-16llu\n",
+ sbi->write_iostat[FS_NODE_IO]);
+ seq_printf(seq, "fs meta: %-16llu\n",
+ sbi->write_iostat[FS_META_IO]);
+ seq_printf(seq, "fs gc data: %-16llu\n",
+ sbi->write_iostat[FS_GC_DATA_IO]);
+ seq_printf(seq, "fs gc node: %-16llu\n",
+ sbi->write_iostat[FS_GC_NODE_IO]);
+ seq_printf(seq, "fs cp data: %-16llu\n",
+ sbi->write_iostat[FS_CP_DATA_IO]);
+ seq_printf(seq, "fs cp node: %-16llu\n",
+ sbi->write_iostat[FS_CP_NODE_IO]);
+ seq_printf(seq, "fs cp meta: %-16llu\n",
+ sbi->write_iostat[FS_CP_META_IO]);
+ seq_printf(seq, "fs discard: %-16llu\n",
+ sbi->write_iostat[FS_DISCARD]);
+
+ return 0;
+}
+
+#define F2FS_PROC_FILE_DEF(_name) \
+static int _name##_open_fs(struct inode *inode, struct file *file) \
+{ \
+ return single_open(file, _name##_seq_show, PDE_DATA(inode)); \
+} \
+ \
+static const struct file_operations f2fs_seq_##_name##_fops = { \
+ .open = _name##_open_fs, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+};
+
+F2FS_PROC_FILE_DEF(segment_info);
+F2FS_PROC_FILE_DEF(segment_bits);
+F2FS_PROC_FILE_DEF(iostat_info);
+
+int __init f2fs_init_sysfs(void)
+{
+ int ret;
+
+ kobject_set_name(&f2fs_kset.kobj, "f2fs");
+ f2fs_kset.kobj.parent = fs_kobj;
+ ret = kset_register(&f2fs_kset);
+ if (ret)
+ return ret;
+
+ ret = kobject_init_and_add(&f2fs_feat, &f2fs_feat_ktype,
+ NULL, "features");
+ if (ret)
+ kset_unregister(&f2fs_kset);
+ else
+ f2fs_proc_root = proc_mkdir("fs/f2fs", NULL);
+ return ret;
+}
+
+void f2fs_exit_sysfs(void)
+{
+ kobject_put(&f2fs_feat);
+ kset_unregister(&f2fs_kset);
+ remove_proc_entry("fs/f2fs", NULL);
+ f2fs_proc_root = NULL;
+}
+
+int f2fs_register_sysfs(struct f2fs_sb_info *sbi)
+{
+ struct super_block *sb = sbi->sb;
+ int err;
+
+ sbi->s_kobj.kset = &f2fs_kset;
+ init_completion(&sbi->s_kobj_unregister);
+ err = kobject_init_and_add(&sbi->s_kobj, &f2fs_sb_ktype, NULL,
+ "%s", sb->s_id);
+ if (err)
+ return err;
+
+ if (f2fs_proc_root)
+ sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root);
+
+ if (sbi->s_proc) {
+ proc_create_data("segment_info", S_IRUGO, sbi->s_proc,
+ &f2fs_seq_segment_info_fops, sb);
+ proc_create_data("segment_bits", S_IRUGO, sbi->s_proc,
+ &f2fs_seq_segment_bits_fops, sb);
+ proc_create_data("iostat_info", S_IRUGO, sbi->s_proc,
+ &f2fs_seq_iostat_info_fops, sb);
+ }
+ return 0;
+}
+
+void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi)
+{
+ if (sbi->s_proc) {
+ remove_proc_entry("iostat_info", sbi->s_proc);
+ remove_proc_entry("segment_info", sbi->s_proc);
+ remove_proc_entry("segment_bits", sbi->s_proc);
+ remove_proc_entry(sbi->sb->s_id, f2fs_proc_root);
+ }
+ kobject_del(&sbi->s_kobj);
+}
diff --git a/fs/f2fs/trace.c b/fs/f2fs/trace.c
index 73b4e1d..a1fcd00 100644
--- a/fs/f2fs/trace.c
+++ b/fs/f2fs/trace.c
@@ -17,7 +17,7 @@
#include "trace.h"
static RADIX_TREE(pids, GFP_ATOMIC);
-static spinlock_t pids_lock;
+static struct mutex pids_lock;
static struct last_io_info last_io;
static inline void __print_last_io(void)
@@ -59,12 +59,12 @@
pid_t pid = task_pid_nr(current);
void *p;
- page->private = pid;
+ set_page_private(page, (unsigned long)pid);
if (radix_tree_preload(GFP_NOFS))
return;
- spin_lock(&pids_lock);
+ mutex_lock(&pids_lock);
p = radix_tree_lookup(&pids, pid);
if (p == current)
goto out;
@@ -77,7 +77,7 @@
MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev),
pid, current->comm);
out:
- spin_unlock(&pids_lock);
+ mutex_unlock(&pids_lock);
radix_tree_preload_end();
}
@@ -122,7 +122,7 @@
void f2fs_build_trace_ios(void)
{
- spin_lock_init(&pids_lock);
+ mutex_init(&pids_lock);
}
#define PIDVEC_SIZE 128
@@ -138,7 +138,7 @@
radix_tree_for_each_slot(slot, &pids, &iter, first_index) {
results[ret] = iter.index;
- if (++ret == PIDVEC_SIZE)
+ if (++ret == max_items)
break;
}
return ret;
@@ -150,7 +150,7 @@
pid_t next_pid = 0;
unsigned int found;
- spin_lock(&pids_lock);
+ mutex_lock(&pids_lock);
while ((found = gang_lookup_pids(pid, next_pid, PIDVEC_SIZE))) {
unsigned idx;
@@ -158,5 +158,5 @@
for (idx = 0; idx < found; idx++)
radix_tree_delete(&pids, pid[idx]);
}
- spin_unlock(&pids_lock);
+ mutex_unlock(&pids_lock);
}
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 3e1c028..ae2dfa7 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -106,7 +106,7 @@
return -EINVAL;
F2FS_I(inode)->i_advise |= *(char *)value;
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, true);
return 0;
}
@@ -217,55 +217,157 @@
return entry;
}
-static int read_all_xattrs(struct inode *inode, struct page *ipage,
- void **base_addr)
+static struct f2fs_xattr_entry *__find_inline_xattr(struct inode *inode,
+ void *base_addr, void **last_addr, int index,
+ size_t len, const char *name)
+{
+ struct f2fs_xattr_entry *entry;
+ unsigned int inline_size = inline_xattr_size(inode);
+
+ list_for_each_xattr(entry, base_addr) {
+ if ((void *)entry + sizeof(__u32) > base_addr + inline_size ||
+ (void *)XATTR_NEXT_ENTRY(entry) + sizeof(__u32) >
+ base_addr + inline_size) {
+ *last_addr = entry;
+ return NULL;
+ }
+ if (entry->e_name_index != index)
+ continue;
+ if (entry->e_name_len != len)
+ continue;
+ if (!memcmp(entry->e_name, name, len))
+ break;
+ }
+ return entry;
+}
+
+static int read_inline_xattr(struct inode *inode, struct page *ipage,
+ void *txattr_addr)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- struct f2fs_xattr_header *header;
- size_t size = PAGE_SIZE, inline_size = 0;
- void *txattr_addr;
- int err;
+ unsigned int inline_size = inline_xattr_size(inode);
+ struct page *page = NULL;
+ void *inline_addr;
- inline_size = inline_xattr_size(inode);
+ if (ipage) {
+ inline_addr = inline_xattr_addr(inode, ipage);
+ } else {
+ page = get_node_page(sbi, inode->i_ino);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
- txattr_addr = kzalloc(inline_size + size, GFP_F2FS_ZERO);
+ inline_addr = inline_xattr_addr(inode, page);
+ }
+ memcpy(txattr_addr, inline_addr, inline_size);
+ f2fs_put_page(page, 1);
+
+ return 0;
+}
+
+static int read_xattr_block(struct inode *inode, void *txattr_addr)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+ unsigned int inline_size = inline_xattr_size(inode);
+ struct page *xpage;
+ void *xattr_addr;
+
+ /* The inode already has an extended attribute block. */
+ xpage = get_node_page(sbi, xnid);
+ if (IS_ERR(xpage))
+ return PTR_ERR(xpage);
+
+ xattr_addr = page_address(xpage);
+ memcpy(txattr_addr + inline_size, xattr_addr, VALID_XATTR_BLOCK_SIZE);
+ f2fs_put_page(xpage, 1);
+
+ return 0;
+}
+
+static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
+ unsigned int index, unsigned int len,
+ const char *name, struct f2fs_xattr_entry **xe,
+ void **base_addr)
+{
+ void *cur_addr, *txattr_addr, *last_addr = NULL;
+ nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+ unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
+ unsigned int inline_size = inline_xattr_size(inode);
+ int err = 0;
+
+ if (!size && !inline_size)
+ return -ENODATA;
+
+ txattr_addr = f2fs_kzalloc(F2FS_I_SB(inode),
+ inline_size + size + XATTR_PADDING_SIZE, GFP_NOFS);
if (!txattr_addr)
return -ENOMEM;
/* read from inline xattr */
if (inline_size) {
- struct page *page = NULL;
- void *inline_addr;
+ err = read_inline_xattr(inode, ipage, txattr_addr);
+ if (err)
+ goto out;
- if (ipage) {
- inline_addr = inline_xattr_addr(ipage);
- } else {
- page = get_node_page(sbi, inode->i_ino);
- if (IS_ERR(page)) {
- err = PTR_ERR(page);
- goto fail;
- }
- inline_addr = inline_xattr_addr(page);
- }
- memcpy(txattr_addr, inline_addr, inline_size);
- f2fs_put_page(page, 1);
+ *xe = __find_inline_xattr(inode, txattr_addr, &last_addr,
+ index, len, name);
+ if (*xe)
+ goto check;
}
/* read from xattr node block */
- if (F2FS_I(inode)->i_xattr_nid) {
- struct page *xpage;
- void *xattr_addr;
+ if (xnid) {
+ err = read_xattr_block(inode, txattr_addr);
+ if (err)
+ goto out;
+ }
- /* The inode already has an extended attribute block. */
- xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid);
- if (IS_ERR(xpage)) {
- err = PTR_ERR(xpage);
+ if (last_addr)
+ cur_addr = XATTR_HDR(last_addr) - 1;
+ else
+ cur_addr = txattr_addr;
+
+ *xe = __find_xattr(cur_addr, index, len, name);
+check:
+ if (IS_XATTR_LAST_ENTRY(*xe)) {
+ err = -ENODATA;
+ goto out;
+ }
+
+ *base_addr = txattr_addr;
+ return 0;
+out:
+ kzfree(txattr_addr);
+ return err;
+}
+
+static int read_all_xattrs(struct inode *inode, struct page *ipage,
+ void **base_addr)
+{
+ struct f2fs_xattr_header *header;
+ nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+ unsigned int size = VALID_XATTR_BLOCK_SIZE;
+ unsigned int inline_size = inline_xattr_size(inode);
+ void *txattr_addr;
+ int err;
+
+ txattr_addr = f2fs_kzalloc(F2FS_I_SB(inode),
+ inline_size + size + XATTR_PADDING_SIZE, GFP_NOFS);
+ if (!txattr_addr)
+ return -ENOMEM;
+
+ /* read from inline xattr */
+ if (inline_size) {
+ err = read_inline_xattr(inode, ipage, txattr_addr);
+ if (err)
goto fail;
- }
+ }
- xattr_addr = page_address(xpage);
- memcpy(txattr_addr + inline_size, xattr_addr, PAGE_SIZE);
- f2fs_put_page(xpage, 1);
+ /* read from xattr node block */
+ if (xnid) {
+ err = read_xattr_block(inode, txattr_addr);
+ if (err)
+ goto fail;
}
header = XATTR_HDR(txattr_addr);
@@ -286,13 +388,13 @@
void *txattr_addr, struct page *ipage)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- size_t inline_size = 0;
+ size_t inline_size = inline_xattr_size(inode);
+ struct page *in_page = NULL;
void *xattr_addr;
+ void *inline_addr = NULL;
struct page *xpage;
nid_t new_nid = 0;
- int err;
-
- inline_size = inline_xattr_size(inode);
+ int err = 0;
if (hsize > inline_size && !F2FS_I(inode)->i_xattr_nid)
if (!alloc_nid(sbi, &new_nid))
@@ -300,30 +402,30 @@
/* write to inline xattr */
if (inline_size) {
- struct page *page = NULL;
- void *inline_addr;
-
if (ipage) {
- inline_addr = inline_xattr_addr(ipage);
- f2fs_wait_on_page_writeback(ipage, NODE, true);
- set_page_dirty(ipage);
+ inline_addr = inline_xattr_addr(inode, ipage);
} else {
- page = get_node_page(sbi, inode->i_ino);
- if (IS_ERR(page)) {
+ in_page = get_node_page(sbi, inode->i_ino);
+ if (IS_ERR(in_page)) {
alloc_nid_failed(sbi, new_nid);
- return PTR_ERR(page);
+ return PTR_ERR(in_page);
}
- inline_addr = inline_xattr_addr(page);
- f2fs_wait_on_page_writeback(page, NODE, true);
+ inline_addr = inline_xattr_addr(inode, in_page);
}
- memcpy(inline_addr, txattr_addr, inline_size);
- f2fs_put_page(page, 1);
+ f2fs_wait_on_page_writeback(ipage ? ipage : in_page,
+ NODE, true);
/* no need to use xattr node block */
if (hsize <= inline_size) {
- err = truncate_xattr_node(inode, ipage);
+ err = truncate_xattr_node(inode);
alloc_nid_failed(sbi, new_nid);
- return err;
+ if (err) {
+ f2fs_put_page(in_page, 1);
+ return err;
+ }
+ memcpy(inline_addr, txattr_addr, inline_size);
+ set_page_dirty(ipage ? ipage : in_page);
+ goto in_page_out;
}
}
@@ -331,40 +433,46 @@
if (F2FS_I(inode)->i_xattr_nid) {
xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid);
if (IS_ERR(xpage)) {
+ err = PTR_ERR(xpage);
alloc_nid_failed(sbi, new_nid);
- return PTR_ERR(xpage);
+ goto in_page_out;
}
f2fs_bug_on(sbi, new_nid);
f2fs_wait_on_page_writeback(xpage, NODE, true);
} else {
struct dnode_of_data dn;
set_new_dnode(&dn, inode, NULL, NULL, new_nid);
- xpage = new_node_page(&dn, XATTR_NODE_OFFSET, ipage);
+ xpage = new_node_page(&dn, XATTR_NODE_OFFSET);
if (IS_ERR(xpage)) {
+ err = PTR_ERR(xpage);
alloc_nid_failed(sbi, new_nid);
- return PTR_ERR(xpage);
+ goto in_page_out;
}
alloc_nid_done(sbi, new_nid);
}
-
xattr_addr = page_address(xpage);
- memcpy(xattr_addr, txattr_addr + inline_size, PAGE_SIZE -
- sizeof(struct node_footer));
- set_page_dirty(xpage);
- f2fs_put_page(xpage, 1);
- /* need to checkpoint during fsync */
- F2FS_I(inode)->xattr_ver = cur_cp_version(F2FS_CKPT(sbi));
- return 0;
+ if (inline_size)
+ memcpy(inline_addr, txattr_addr, inline_size);
+ memcpy(xattr_addr, txattr_addr + inline_size, VALID_XATTR_BLOCK_SIZE);
+
+ if (inline_size)
+ set_page_dirty(ipage ? ipage : in_page);
+ set_page_dirty(xpage);
+
+ f2fs_put_page(xpage, 1);
+in_page_out:
+ f2fs_put_page(in_page, 1);
+ return err;
}
int f2fs_getxattr(struct inode *inode, int index, const char *name,
void *buffer, size_t buffer_size, struct page *ipage)
{
- struct f2fs_xattr_entry *entry;
- void *base_addr;
+ struct f2fs_xattr_entry *entry = NULL;
int error = 0;
- size_t size, len;
+ unsigned int size, len;
+ void *base_addr = NULL;
if (name == NULL)
return -EINVAL;
@@ -373,21 +481,18 @@
if (len > F2FS_NAME_LEN)
return -ERANGE;
- error = read_all_xattrs(inode, ipage, &base_addr);
+ down_read(&F2FS_I(inode)->i_xattr_sem);
+ error = lookup_all_xattrs(inode, ipage, index, len, name,
+ &entry, &base_addr);
+ up_read(&F2FS_I(inode)->i_xattr_sem);
if (error)
return error;
- entry = __find_xattr(base_addr, index, len, name);
- if (IS_XATTR_LAST_ENTRY(entry)) {
- error = -ENODATA;
- goto cleanup;
- }
-
size = le16_to_cpu(entry->e_value_size);
if (buffer && size > buffer_size) {
error = -ERANGE;
- goto cleanup;
+ goto out;
}
if (buffer) {
@@ -395,8 +500,7 @@
memcpy(buffer, pval, size);
}
error = size;
-
-cleanup:
+out:
kzfree(base_addr);
return error;
}
@@ -409,7 +513,9 @@
int error = 0;
size_t rest = buffer_size;
+ down_read(&F2FS_I(inode)->i_xattr_sem);
error = read_all_xattrs(inode, NULL, &base_addr);
+ up_read(&F2FS_I(inode)->i_xattr_sem);
if (error)
return error;
@@ -445,6 +551,15 @@
return error;
}
+static bool f2fs_xattr_value_same(struct f2fs_xattr_entry *entry,
+ const void *value, size_t size)
+{
+ void *pval = entry->e_name + entry->e_name_len;
+
+ return (le16_to_cpu(entry->e_value_size) == size) &&
+ !memcmp(pval, value, size);
+}
+
static int __f2fs_setxattr(struct inode *inode, int index,
const char *name, const void *value, size_t size,
struct page *ipage, int flags)
@@ -479,12 +594,17 @@
found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
- if ((flags & XATTR_REPLACE) && !found) {
+ if (found) {
+ if ((flags & XATTR_CREATE)) {
+ error = -EEXIST;
+ goto exit;
+ }
+
+ if (value && f2fs_xattr_value_same(here, value, size))
+ goto exit;
+ } else if ((flags & XATTR_REPLACE)) {
error = -ENODATA;
goto exit;
- } else if ((flags & XATTR_CREATE) && found) {
- error = -EEXIST;
- goto exit;
}
last = here;
@@ -554,7 +674,7 @@
if (index == F2FS_XATTR_INDEX_ENCRYPTION &&
!strcmp(name, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT))
f2fs_set_encrypted_inode(inode);
- f2fs_mark_inode_dirty_sync(inode);
+ f2fs_mark_inode_dirty_sync(inode, true);
if (!error && S_ISDIR(inode->i_mode))
set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_CP);
exit:
@@ -569,6 +689,10 @@
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
int err;
+ err = dquot_initialize(inode);
+ if (err)
+ return err;
+
/* this case is only from init_inode_metadata */
if (ipage)
return __f2fs_setxattr(inode, index, name, value,
@@ -578,7 +702,9 @@
f2fs_lock_op(sbi);
/* protect xattr_ver */
down_write(&F2FS_I(inode)->i_sem);
+ down_write(&F2FS_I(inode)->i_xattr_sem);
err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags);
+ up_write(&F2FS_I(inode)->i_xattr_sem);
up_write(&F2FS_I(inode)->i_sem);
f2fs_unlock_op(sbi);
diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h
index f990de2..dbcd1d1 100644
--- a/fs/f2fs/xattr.h
+++ b/fs/f2fs/xattr.h
@@ -58,10 +58,10 @@
#define XATTR_FIRST_ENTRY(ptr) (XATTR_ENTRY(XATTR_HDR(ptr) + 1))
#define XATTR_ROUND (3)
-#define XATTR_ALIGN(size) ((size + XATTR_ROUND) & ~XATTR_ROUND)
+#define XATTR_ALIGN(size) (((size) + XATTR_ROUND) & ~XATTR_ROUND)
#define ENTRY_SIZE(entry) (XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + \
- entry->e_name_len + le16_to_cpu(entry->e_value_size)))
+ (entry)->e_name_len + le16_to_cpu((entry)->e_value_size)))
#define XATTR_NEXT_ENTRY(entry) ((struct f2fs_xattr_entry *)((char *)(entry) +\
ENTRY_SIZE(entry)))
@@ -72,9 +72,10 @@
for (entry = XATTR_FIRST_ENTRY(addr);\
!IS_XATTR_LAST_ENTRY(entry);\
entry = XATTR_NEXT_ENTRY(entry))
-
-#define MIN_OFFSET(i) XATTR_ALIGN(inline_xattr_size(i) + PAGE_SIZE - \
- sizeof(struct node_footer) - sizeof(__u32))
+#define VALID_XATTR_BLOCK_SIZE (PAGE_SIZE - sizeof(struct node_footer))
+#define XATTR_PADDING_SIZE (sizeof(__u32))
+#define MIN_OFFSET(i) XATTR_ALIGN(inline_xattr_size(i) + \
+ VALID_XATTR_BLOCK_SIZE)
#define MAX_VALUE_LEN(i) (MIN_OFFSET(i) - \
sizeof(struct f2fs_xattr_header) - \
diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c
index 37e0c31d..5eb2e24 100644
--- a/fs/fscache/object-list.c
+++ b/fs/fscache/object-list.c
@@ -329,7 +329,7 @@
config = 0;
rcu_read_lock();
- confkey = user_key_payload(key);
+ confkey = user_key_payload_rcu(key);
if (!confkey) {
/* key was revoked */
rcu_read_unlock();
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index ff72ac6..77f1e25 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1226,7 +1226,7 @@
* We set the bdi here to the queue backing, file systems can
* overwrite this in ->fill_super()
*/
- s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
+ s->s_bdi = bdev_get_queue(s->s_bdev)->backing_dev_info;
return 0;
}
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index 5e659ee..4e5c610 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -488,8 +488,10 @@
EXPORT_SYMBOL(jbd2_journal_free_reserved);
/**
- * int jbd2_journal_start_reserved(handle_t *handle) - start reserved handle
+ * int jbd2_journal_start_reserved() - start reserved handle
* @handle: handle to start
+ * @type: for handle statistics
+ * @line_no: for handle statistics
*
* Start handle that has been previously reserved with jbd2_journal_reserve().
* This attaches @handle to the running transaction (or creates one if there's
@@ -619,6 +621,7 @@
* int jbd2_journal_restart() - restart a handle .
* @handle: handle to restart
* @nblocks: nr credits requested
+ * @gfp_mask: memory allocation flags (for start_this_handle)
*
* Restart a handle for a multi-transaction filesystem
* operation.
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index 78219d5..d6512cd 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -275,7 +275,7 @@
{
struct kernfs_open_file *of = kernfs_of(file);
const struct kernfs_ops *ops;
- size_t len;
+ ssize_t len;
char *buf;
if (of->atomic_write_len) {
diff --git a/fs/mbcache.c b/fs/mbcache.c
index c5bd19f..27e6bf6 100644
--- a/fs/mbcache.c
+++ b/fs/mbcache.c
@@ -93,6 +93,7 @@
entry->e_key = key;
entry->e_block = block;
entry->e_reusable = reusable;
+ entry->e_referenced = 0;
head = mb_cache_entry_head(cache, key);
hlist_bl_lock(head);
hlist_bl_for_each_entry(dup, dup_node, head, e_hash_list) {
diff --git a/fs/namei.c b/fs/namei.c
index 2af3818..339f7c7 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2153,6 +2153,9 @@
int retval = 0;
const char *s = nd->name->name;
+ if (!*s)
+ flags &= ~LOOKUP_RCU;
+
nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT;
nd->depth = 0;
@@ -2903,11 +2906,6 @@
if (error)
return error;
error = dir->i_op->create(dir, dentry, mode, want_excl);
- if (error)
- return error;
- error = security_inode_post_create(dir, dentry, mode);
- if (error)
- return error;
if (!error)
fsnotify_create(dir, dentry);
return error;
@@ -3723,13 +3721,6 @@
return error;
error = dir->i_op->mknod(dir, dentry, mode, dev);
- if (error)
- return error;
-
- error = security_inode_post_create(dir, dentry, mode);
- if (error)
- return error;
-
if (!error)
fsnotify_create(dir, dentry);
return error;
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index bd81bcf..1ac1593 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -787,10 +787,8 @@
spin_lock(&dreq->lock);
- if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
- dreq->flags = 0;
+ if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
dreq->error = hdr->error;
- }
if (dreq->error == 0) {
nfs_direct_good_bytes(dreq, hdr);
if (nfs_write_need_commit(hdr)) {
diff --git a/fs/nfs/io.c b/fs/nfs/io.c
index 1fc5d1c..d18ccc1 100644
--- a/fs/nfs/io.c
+++ b/fs/nfs/io.c
@@ -98,7 +98,7 @@
{
if (!test_bit(NFS_INO_ODIRECT, &nfsi->flags)) {
set_bit(NFS_INO_ODIRECT, &nfsi->flags);
- nfs_wb_all(inode);
+ nfs_sync_mapping(inode->i_mapping);
}
}
diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
index c444285..eaac878 100644
--- a/fs/nfs/nfs4idmap.c
+++ b/fs/nfs/nfs4idmap.c
@@ -316,7 +316,7 @@
if (ret < 0)
goto out_up;
- payload = user_key_payload(rkey);
+ payload = user_key_payload_rcu(rkey);
if (IS_ERR_OR_NULL(payload)) {
ret = PTR_ERR(payload);
goto out_up;
@@ -567,9 +567,13 @@
struct idmap_msg *im;
struct idmap *idmap = (struct idmap *)aux;
struct key *key = cons->key;
- int ret = -ENOMEM;
+ int ret = -ENOKEY;
+
+ if (!aux)
+ goto out1;
/* msg and im are freed in idmap_pipe_destroy_msg */
+ ret = -ENOMEM;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
goto out1;
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index b7a07ba..b8e4474 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -2145,7 +2145,7 @@
nfs_pageio_reset_write_mds(desc);
mirror->pg_recoalesce = 1;
}
- hdr->release(hdr);
+ hdr->completion_ops->completion(hdr);
}
static enum pnfs_try_status
@@ -2256,7 +2256,7 @@
nfs_pageio_reset_read_mds(desc);
mirror->pg_recoalesce = 1;
}
- hdr->release(hdr);
+ hdr->completion_ops->completion(hdr);
}
/*
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 9905735..9a3b382 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -1806,6 +1806,8 @@
set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags);
next:
nfs_unlock_and_release_request(req);
+ /* Latency breaker */
+ cond_resched();
}
nfss = NFS_SERVER(data->inode);
if (atomic_long_read(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index c95d369..ff158f0 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -1068,7 +1068,7 @@
sb->s_time_gran = 1;
sb->s_max_links = NILFS_LINK_MAX;
- sb->s_bdi = &bdev_get_queue(sb->s_bdev)->backing_dev_info;
+ sb->s_bdi = bdev_get_queue(sb->s_bdev)->backing_dev_info;
err = load_nilfs(nilfs, sb);
if (err)
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 8dce409..785fcc2 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -2485,6 +2485,15 @@
ret = ocfs2_inode_lock_full(inode, ret_bh, ex, OCFS2_LOCK_NONBLOCK);
if (ret == -EAGAIN) {
unlock_page(page);
+ /*
+ * If we can't get inode lock immediately, we should not return
+ * directly here, since this will lead to a softlockup problem.
+ * The method is to get a blocking lock and immediately unlock
+ * before returning, this can avoid CPU resource waste due to
+ * lots of retries, and benefits fairness in getting lock.
+ */
+ if (ocfs2_inode_lock(inode, ret_bh, ex) == 0)
+ ocfs2_inode_unlock(inode, ex);
ret = AOP_TRUNCATED_PAGE;
}
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index f241b4e..a1be6ba 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -434,10 +434,14 @@
struct dentry *dentry = file->f_path.dentry;
struct file *realfile = od->realfile;
+ /* Nothing to sync for lower */
+ if (!OVL_TYPE_UPPER(ovl_path_type(dentry)))
+ return 0;
+
/*
* Need to check if we started out being a lower dir, but got copied up
*/
- if (!od->is_upper && OVL_TYPE_UPPER(ovl_path_type(dentry))) {
+ if (!od->is_upper) {
struct inode *inode = file_inode(file);
realfile = lockless_dereference(od->upperfile);
diff --git a/fs/pipe.c b/fs/pipe.c
index 9faecf1..3434553 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -609,12 +609,17 @@
static bool too_many_pipe_buffers_soft(unsigned long user_bufs)
{
- return pipe_user_pages_soft && user_bufs >= pipe_user_pages_soft;
+ return pipe_user_pages_soft && user_bufs > pipe_user_pages_soft;
}
static bool too_many_pipe_buffers_hard(unsigned long user_bufs)
{
- return pipe_user_pages_hard && user_bufs >= pipe_user_pages_hard;
+ return pipe_user_pages_hard && user_bufs > pipe_user_pages_hard;
+}
+
+static bool is_unprivileged_user(void)
+{
+ return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
}
struct pipe_inode_info *alloc_pipe_info(void)
@@ -633,12 +638,12 @@
user_bufs = account_pipe_buffers(user, 0, pipe_bufs);
- if (too_many_pipe_buffers_soft(user_bufs)) {
+ if (too_many_pipe_buffers_soft(user_bufs) && is_unprivileged_user()) {
user_bufs = account_pipe_buffers(user, pipe_bufs, 1);
pipe_bufs = 1;
}
- if (too_many_pipe_buffers_hard(user_bufs))
+ if (too_many_pipe_buffers_hard(user_bufs) && is_unprivileged_user())
goto out_revert_acct;
pipe->bufs = kcalloc(pipe_bufs, sizeof(struct pipe_buffer),
@@ -1069,7 +1074,7 @@
if (nr_pages > pipe->buffers &&
(too_many_pipe_buffers_hard(user_bufs) ||
too_many_pipe_buffers_soft(user_bufs)) &&
- !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) {
+ is_unprivileged_user()) {
ret = -EPERM;
goto out_revert_acct;
}
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index 5c89a07..df7e079 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -507,23 +507,15 @@
return -EFAULT;
} else {
if (kern_addr_valid(start)) {
- unsigned long n;
-
/*
* Using bounce buffer to bypass the
* hardened user copy kernel text checks.
*/
- memcpy(buf, (char *) start, tsz);
- n = copy_to_user(buffer, buf, tsz);
- /*
- * We cannot distinguish between fault on source
- * and fault on destination. When this happens
- * we clear too and hope it will trigger the
- * EFAULT again.
- */
- if (n) {
- if (clear_user(buffer + tsz - n,
- n))
+ if (probe_kernel_read(buf, (void *) start, tsz)) {
+ if (clear_user(buffer, tsz))
+ return -EFAULT;
+ } else {
+ if (copy_to_user(buffer, buf, tsz))
return -EFAULT;
}
} else {
diff --git a/fs/reiserfs/lbalance.c b/fs/reiserfs/lbalance.c
index 249594a..f5cebd70 100644
--- a/fs/reiserfs/lbalance.c
+++ b/fs/reiserfs/lbalance.c
@@ -475,7 +475,7 @@
* 'cpy_bytes'; create new item header;
* n_ih = new item_header;
*/
- memcpy(&n_ih, ih, SHORT_KEY_SIZE);
+ memcpy(&n_ih.ih_key, &ih->ih_key, KEY_SIZE);
/* Endian safe, both le */
n_ih.ih_version = ih->ih_version;
diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h
index 2adcde1..5dcf3ab 100644
--- a/fs/reiserfs/reiserfs.h
+++ b/fs/reiserfs/reiserfs.h
@@ -1326,7 +1326,6 @@
#define KEY_NOT_FOUND 0
#define KEY_SIZE (sizeof(struct reiserfs_key))
-#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32))
/* return values for search_by_key and clones */
#define ITEM_FOUND 1
diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c
index 5ac0b0b..2879d12 100644
--- a/fs/sdcardfs/file.c
+++ b/fs/sdcardfs/file.c
@@ -62,6 +62,7 @@
int err;
struct file *lower_file;
struct dentry *dentry = file->f_path.dentry;
+ struct inode *inode = d_inode(dentry);
/* check disk space */
if (!check_min_free_space(dentry, count, 0)) {
@@ -73,10 +74,12 @@
err = vfs_write(lower_file, buf, count, ppos);
/* update our inode times+sizes upon a successful lower write */
if (err >= 0) {
- fsstack_copy_inode_size(d_inode(dentry),
- file_inode(lower_file));
- fsstack_copy_attr_times(d_inode(dentry),
- file_inode(lower_file));
+ if (sizeof(loff_t) > sizeof(long))
+ inode_lock(inode);
+ fsstack_copy_inode_size(inode, file_inode(lower_file));
+ fsstack_copy_attr_times(inode, file_inode(lower_file));
+ if (sizeof(loff_t) > sizeof(long))
+ inode_unlock(inode);
}
return err;
@@ -391,6 +394,7 @@
{
int err;
struct file *file = iocb->ki_filp, *lower_file;
+ struct inode *inode = file->f_path.dentry->d_inode;
lower_file = sdcardfs_lower_file(file);
if (!lower_file->f_op->write_iter) {
@@ -405,10 +409,12 @@
fput(lower_file);
/* update upper inode times/sizes as needed */
if (err >= 0 || err == -EIOCBQUEUED) {
- fsstack_copy_inode_size(file->f_path.dentry->d_inode,
- file_inode(lower_file));
- fsstack_copy_attr_times(file->f_path.dentry->d_inode,
- file_inode(lower_file));
+ if (sizeof(loff_t) > sizeof(long))
+ inode_lock(inode);
+ fsstack_copy_inode_size(inode, file_inode(lower_file));
+ fsstack_copy_attr_times(inode, file_inode(lower_file));
+ if (sizeof(loff_t) > sizeof(long))
+ inode_lock(inode);
}
out:
return err;
diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c
index 137d876..fafc09c 100644
--- a/fs/sdcardfs/inode.c
+++ b/fs/sdcardfs/inode.c
@@ -629,6 +629,8 @@
struct inode tmp;
struct sdcardfs_inode_data *top = top_data_get(SDCARDFS_I(inode));
+ if (IS_ERR(mnt))
+ return PTR_ERR(mnt);
if (!top)
return -EINVAL;
@@ -645,7 +647,7 @@
*/
copy_attrs(&tmp, inode);
tmp.i_uid = make_kuid(&init_user_ns, top->d_uid);
- tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, top));
+ tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, inode->i_sb, top));
tmp.i_mode = (inode->i_mode & S_IFMT)
| get_mode(mnt, SDCARDFS_I(inode), top);
data_put(top);
@@ -724,7 +726,7 @@
*/
copy_attrs(&tmp, inode);
tmp.i_uid = make_kuid(&init_user_ns, top->d_uid);
- tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, top));
+ tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, dentry->d_sb, top));
tmp.i_mode = (inode->i_mode & S_IFMT)
| get_mode(mnt, SDCARDFS_I(inode), top);
tmp.i_size = i_size_read(inode);
@@ -826,6 +828,7 @@
{
struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
struct sdcardfs_inode_data *top = top_data_get(info);
+ struct super_block *sb = inode->i_sb;
if (!top)
return -EINVAL;
@@ -835,7 +838,7 @@
stat->mode = (inode->i_mode & S_IFMT) | get_mode(mnt, info, top);
stat->nlink = inode->i_nlink;
stat->uid = make_kuid(&init_user_ns, top->d_uid);
- stat->gid = make_kgid(&init_user_ns, get_gid(mnt, top));
+ stat->gid = make_kgid(&init_user_ns, get_gid(mnt, sb, top));
stat->rdev = inode->i_rdev;
stat->size = lower_stat->size;
stat->atime = lower_stat->atime;
diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c
index 37d4864..e4fd3fb 100644
--- a/fs/sdcardfs/main.c
+++ b/fs/sdcardfs/main.c
@@ -33,6 +33,7 @@
Opt_userid,
Opt_reserved_mb,
Opt_gid_derivation,
+ Opt_default_normal,
Opt_err,
};
@@ -45,6 +46,7 @@
{Opt_userid, "userid=%d"},
{Opt_multiuser, "multiuser"},
{Opt_gid_derivation, "derive_gid"},
+ {Opt_default_normal, "default_normal"},
{Opt_reserved_mb, "reserved_mb=%u"},
{Opt_err, NULL}
};
@@ -68,6 +70,7 @@
opts->reserved_mb = 0;
/* by default, gid derivation is off */
opts->gid_derivation = false;
+ opts->default_normal = false;
*debug = 0;
@@ -122,6 +125,9 @@
case Opt_gid_derivation:
opts->gid_derivation = true;
break;
+ case Opt_default_normal:
+ opts->default_normal = true;
+ break;
/* unknown option */
default:
if (!silent)
@@ -175,6 +181,7 @@
return 0;
vfsopts->mask = option;
break;
+ case Opt_default_normal:
case Opt_multiuser:
case Opt_userid:
case Opt_fsuid:
diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h
index eda8e7a..610466a 100644
--- a/fs/sdcardfs/sdcardfs.h
+++ b/fs/sdcardfs/sdcardfs.h
@@ -221,6 +221,7 @@
userid_t fs_user_id;
bool multiuser;
bool gid_derivation;
+ bool default_normal;
unsigned int reserved_mb;
};
@@ -424,11 +425,13 @@
}
static inline int get_gid(struct vfsmount *mnt,
+ struct super_block *sb,
struct sdcardfs_inode_data *data)
{
- struct sdcardfs_vfsmount_options *opts = mnt->data;
+ struct sdcardfs_vfsmount_options *vfsopts = mnt->data;
+ struct sdcardfs_sb_info *sbi = SDCARDFS_SB(sb);
- if (opts->gid == AID_SDCARD_RW)
+ if (vfsopts->gid == AID_SDCARD_RW && !sbi->options.default_normal)
/* As an optimization, certain trusted system components only run
* as owner but operate across all users. Since we're now handing
* out the sdcard_rw GID only to trusted apps, we're okay relaxing
@@ -437,7 +440,7 @@
*/
return AID_SDCARD_RW;
else
- return multiuser_get_uid(data->userid, opts->gid);
+ return multiuser_get_uid(data->userid, vfsopts->gid);
}
static inline int get_mode(struct vfsmount *mnt,
diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c
index 72d89b9..cffcdb1 100644
--- a/fs/sdcardfs/super.c
+++ b/fs/sdcardfs/super.c
@@ -307,6 +307,8 @@
seq_printf(m, ",userid=%u", opts->fs_user_id);
if (opts->gid_derivation)
seq_puts(m, ",derive_gid");
+ if (opts->default_normal)
+ seq_puts(m, ",default_normal");
if (opts->reserved_mb != 0)
seq_printf(m, ",reserved=%uMB", opts->reserved_mb);
diff --git a/fs/super.c b/fs/super.c
index 2987fe3..847d82d 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1030,7 +1030,7 @@
* We set the bdi here to the queue backing, file systems can
* overwrite this in ->fill_super()
*/
- s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
+ s->s_bdi = bdev_get_queue(s->s_bdev)->backing_dev_info;
return 0;
}
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index d9f9615..3979d76 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -270,7 +270,8 @@
}
static int __ubifs_setxattr(struct inode *host, const char *name,
- const void *value, size_t size, int flags)
+ const void *value, size_t size, int flags,
+ bool check_lock)
{
struct inode *inode;
struct ubifs_info *c = host->i_sb->s_fs_info;
@@ -279,7 +280,8 @@
union ubifs_key key;
int err;
- ubifs_assert(inode_is_locked(host));
+ if (check_lock)
+ ubifs_assert(inode_is_locked(host));
if (size > UBIFS_MAX_INO_DATA)
return -ERANGE;
@@ -548,7 +550,8 @@
}
strcpy(name, XATTR_SECURITY_PREFIX);
strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
- err = __ubifs_setxattr(inode, name, xattr->value, xattr->value_len, 0);
+ err = __ubifs_setxattr(inode, name, xattr->value,
+ xattr->value_len, 0, false);
kfree(name);
if (err < 0)
break;
@@ -594,7 +597,8 @@
name = xattr_full_name(handler, name);
if (value)
- return __ubifs_setxattr(inode, name, value, size, flags);
+ return __ubifs_setxattr(inode, name, value, size, flags,
+ true);
else
return __ubifs_removexattr(inode, name);
}
diff --git a/fs/xattr.c b/fs/xattr.c
index 932b906..1b00bab 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -130,7 +130,7 @@
return -EPERM;
}
- return inode_permission(inode, mask);
+ return inode_permission2(ERR_PTR(-EOPNOTSUPP), inode, mask);
}
int
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 3f45d98..7a04b03 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -744,7 +744,7 @@
int nmaps,
const struct xfs_buf_ops *ops)
{
- if (bdi_read_congested(target->bt_bdi))
+ if (bdi_read_congested(target->bt_bdev->bd_bdi))
return;
xfs_buf_read_map(target, map, nmaps,
@@ -1782,7 +1782,6 @@
btp->bt_mount = mp;
btp->bt_dev = bdev->bd_dev;
btp->bt_bdev = bdev;
- btp->bt_bdi = blk_get_backing_dev_info(bdev);
if (xfs_setsize_buftarg_early(btp, bdev))
goto error_free;
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
index f961b19..c26b36a 100644
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -107,7 +107,6 @@
typedef struct xfs_buftarg {
dev_t bt_dev;
struct block_device *bt_bdev;
- struct backing_dev_info *bt_bdi;
struct xfs_mount *bt_mount;
unsigned int bt_meta_sectorsize;
size_t bt_meta_sectormask;
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index 4df64a1..e02a3d9 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -27,6 +27,8 @@
* __kprobes_text_start, __kprobes_text_end
* __entry_text_start, __entry_text_end
* __ctors_start, __ctors_end
+ * __irqentry_text_start, __irqentry_text_end
+ * __softirqentry_text_start, __softirqentry_text_end
*/
extern char _text[], _stext[], _etext[];
extern char _data[], _sdata[], _edata[];
@@ -39,6 +41,8 @@
extern char __kprobes_text_start[], __kprobes_text_end[];
extern char __entry_text_start[], __entry_text_end[];
extern char __start_rodata[], __end_rodata[];
+extern char __irqentry_text_start[], __irqentry_text_end[];
+extern char __softirqentry_text_start[], __softirqentry_text_end[];
/* Start and end of .ctors section - used for constructor calls. */
extern char __ctors_start[], __ctors_end[];
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 2e6000a..3a396a9 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -499,25 +499,17 @@
*(.entry.text) \
VMLINUX_SYMBOL(__entry_text_end) = .;
-#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN)
#define IRQENTRY_TEXT \
ALIGN_FUNCTION(); \
VMLINUX_SYMBOL(__irqentry_text_start) = .; \
*(.irqentry.text) \
VMLINUX_SYMBOL(__irqentry_text_end) = .;
-#else
-#define IRQENTRY_TEXT
-#endif
-#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN)
#define SOFTIRQENTRY_TEXT \
ALIGN_FUNCTION(); \
VMLINUX_SYMBOL(__softirqentry_text_start) = .; \
*(.softirqentry.text) \
VMLINUX_SYMBOL(__softirqentry_text_end) = .;
-#else
-#define SOFTIRQENTRY_TEXT
-#endif
/* Section used for early init (in .S files) */
#define HEAD_TEXT *(.head.text)
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index 2660588..d3de3b8 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -205,7 +205,6 @@
unsigned int keylen);
unsigned int reqsize;
- bool has_setkey;
struct crypto_tfm base;
};
@@ -399,11 +398,6 @@
int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
unsigned int keylen);
-static inline bool crypto_ahash_has_setkey(struct crypto_ahash *tfm)
-{
- return tfm->has_setkey;
-}
-
/**
* crypto_ahash_finup() - update and finalize message digest
* @req: reference to the ahash_request handle that holds all information
@@ -475,7 +469,12 @@
*/
static inline int crypto_ahash_import(struct ahash_request *req, const void *in)
{
- return crypto_ahash_reqtfm(req)->import(req, in);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+
+ if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+ return -ENOKEY;
+
+ return tfm->import(req, in);
}
/**
@@ -492,7 +491,12 @@
*/
static inline int crypto_ahash_init(struct ahash_request *req)
{
- return crypto_ahash_reqtfm(req)->init(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+
+ if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+ return -ENOKEY;
+
+ return tfm->init(req);
}
/**
@@ -845,7 +849,12 @@
*/
static inline int crypto_shash_import(struct shash_desc *desc, const void *in)
{
- return crypto_shash_alg(desc->tfm)->import(desc, in);
+ struct crypto_shash *tfm = desc->tfm;
+
+ if (crypto_shash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+ return -ENOKEY;
+
+ return crypto_shash_alg(tfm)->import(desc, in);
}
/**
@@ -861,7 +870,12 @@
*/
static inline int crypto_shash_init(struct shash_desc *desc)
{
- return crypto_shash_alg(desc->tfm)->init(desc);
+ struct crypto_shash *tfm = desc->tfm;
+
+ if (crypto_shash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+ return -ENOKEY;
+
+ return crypto_shash_alg(tfm)->init(desc);
}
/**
diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
index cac5735..5203560 100644
--- a/include/crypto/internal/hash.h
+++ b/include/crypto/internal/hash.h
@@ -88,6 +88,8 @@
return alg->setkey != shash_no_setkey;
}
+bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg);
+
int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn,
struct hash_alg_common *alg,
struct crypto_instance *inst);
diff --git a/include/crypto/poly1305.h b/include/crypto/poly1305.h
index 894df59..d586f74 100644
--- a/include/crypto/poly1305.h
+++ b/include/crypto/poly1305.h
@@ -30,8 +30,6 @@
};
int crypto_poly1305_init(struct shash_desc *desc);
-int crypto_poly1305_setkey(struct crypto_shash *tfm,
- const u8 *key, unsigned int keylen);
unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
const u8 *src, unsigned int srclen);
int crypto_poly1305_update(struct shash_desc *desc,
diff --git a/include/crypto/speck.h b/include/crypto/speck.h
new file mode 100644
index 0000000..73cfc95
--- /dev/null
+++ b/include/crypto/speck.h
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Common values for the Speck algorithm
+ */
+
+#ifndef _CRYPTO_SPECK_H
+#define _CRYPTO_SPECK_H
+
+#include <linux/types.h>
+
+/* Speck128 */
+
+#define SPECK128_BLOCK_SIZE 16
+
+#define SPECK128_128_KEY_SIZE 16
+#define SPECK128_128_NROUNDS 32
+
+#define SPECK128_192_KEY_SIZE 24
+#define SPECK128_192_NROUNDS 33
+
+#define SPECK128_256_KEY_SIZE 32
+#define SPECK128_256_NROUNDS 34
+
+struct speck128_tfm_ctx {
+ u64 round_keys[SPECK128_256_NROUNDS];
+ int nrounds;
+};
+
+void crypto_speck128_encrypt(const struct speck128_tfm_ctx *ctx,
+ u8 *out, const u8 *in);
+
+void crypto_speck128_decrypt(const struct speck128_tfm_ctx *ctx,
+ u8 *out, const u8 *in);
+
+int crypto_speck128_setkey(struct speck128_tfm_ctx *ctx, const u8 *key,
+ unsigned int keysize);
+
+/* Speck64 */
+
+#define SPECK64_BLOCK_SIZE 8
+
+#define SPECK64_96_KEY_SIZE 12
+#define SPECK64_96_NROUNDS 26
+
+#define SPECK64_128_KEY_SIZE 16
+#define SPECK64_128_NROUNDS 27
+
+struct speck64_tfm_ctx {
+ u32 round_keys[SPECK64_128_NROUNDS];
+ int nrounds;
+};
+
+void crypto_speck64_encrypt(const struct speck64_tfm_ctx *ctx,
+ u8 *out, const u8 *in);
+
+void crypto_speck64_decrypt(const struct speck64_tfm_ctx *ctx,
+ u8 *out, const u8 *in);
+
+int crypto_speck64_setkey(struct speck64_tfm_ctx *ctx, const u8 *key,
+ unsigned int keysize);
+
+#endif /* _CRYPTO_SPECK_H */
diff --git a/include/dt-bindings/clock/mdm-clocks-9607.h b/include/dt-bindings/clock/mdm-clocks-9607.h
new file mode 100644
index 0000000..c2c5f26
--- /dev/null
+++ b/include/dt-bindings/clock/mdm-clocks-9607.h
@@ -0,0 +1,156 @@
+/*
+ * 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 __MDM_CLOCKS_9607_H
+#define __MDM_CLOCKS_9607_H
+
+/*PLL Sources */
+#define clk_gpll0_clk_src 0x5933b69f
+#define clk_gpll0_ao_clk_src 0x6b2fb034
+#define clk_gpll2_clk_src 0x7c34503b
+#define clk_gpll1_clk_src 0x916f8847
+
+#define clk_a7sspll 0x0b2e5cbd
+
+/*RPM and Voter clocks */
+#define clk_pcnoc_clk 0xc1296d0f
+#define clk_pcnoc_a_clk 0x9bcffee4
+#define clk_pcnoc_msmbus_clk 0x2b53b688
+#define clk_pcnoc_msmbus_a_clk 0x9753a54f
+#define clk_pcnoc_keepalive_a_clk 0x9464f720
+#define clk_pcnoc_usb_clk 0x57adc448
+#define clk_pcnoc_usb_a_clk 0x11d6a74e
+#define clk_bimc_clk 0x4b80bf00
+#define clk_bimc_a_clk 0x4b25668a
+#define clk_bimc_msmbus_clk 0xd212feea
+#define clk_bimc_msmbus_a_clk 0x71d1a499
+#define clk_bimc_usb_clk 0x9bd2b2bf
+#define clk_bimc_usb_a_clk 0xea410834
+#define clk_qdss_clk 0x1492202a
+#define clk_qdss_a_clk 0xdd121669
+#define clk_qpic_clk 0x3ce6f7bb
+#define clk_qpic_a_clk 0xd70ccb7c
+#define clk_xo_clk_src 0x23f5649f
+#define clk_xo_a_clk_src 0x2fdd2c7c
+#define clk_xo_otg_clk 0x79bca5cc
+#define clk_xo_lpm_clk 0x2be48257
+#define clk_xo_pil_mss_clk 0xe97a8354
+#define clk_bb_clk1 0xf5304268
+#define clk_bb_clk1_pin 0x6dd0a779
+
+/* SRCs */
+#define clk_apss_ahb_clk_src 0x36f8495f
+#define clk_emac_0_125m_clk_src 0x955db353
+#define clk_blsp1_qup1_i2c_apps_clk_src 0x17f78f5e
+#define clk_blsp1_qup1_spi_apps_clk_src 0xf534c4fa
+#define clk_blsp1_qup2_i2c_apps_clk_src 0x8de71c79
+#define clk_blsp1_qup2_spi_apps_clk_src 0x33cf809a
+#define clk_blsp1_qup3_i2c_apps_clk_src 0xf161b902
+#define clk_blsp1_qup3_spi_apps_clk_src 0x5e95683f
+#define clk_blsp1_qup4_i2c_apps_clk_src 0xb2ecce68
+#define clk_blsp1_qup4_spi_apps_clk_src 0xddb5bbdb
+#define clk_blsp1_qup5_i2c_apps_clk_src 0x71ea7804
+#define clk_blsp1_qup5_spi_apps_clk_src 0x9752f35f
+#define clk_blsp1_qup6_i2c_apps_clk_src 0x28806803
+#define clk_blsp1_qup6_spi_apps_clk_src 0x44a1edc4
+#define clk_blsp1_uart1_apps_clk_src 0xf8146114
+#define clk_blsp1_uart2_apps_clk_src 0xfc9c2f73
+#define clk_blsp1_uart3_apps_clk_src 0x600497f2
+#define clk_blsp1_uart4_apps_clk_src 0x56bff15c
+#define clk_blsp1_uart5_apps_clk_src 0x218ef697
+#define clk_blsp1_uart6_apps_clk_src 0x8fbdbe4c
+#define clk_crypto_clk_src 0x37a21414
+#define clk_gp1_clk_src 0xad85b97a
+#define clk_gp2_clk_src 0xfb1f0065
+#define clk_gp3_clk_src 0x63b693d6
+#define clk_pdm2_clk_src 0x31e494fd
+#define clk_sdcc1_apps_clk_src 0xd4975db2
+#define clk_sdcc2_apps_clk_src 0xfc46c821
+#define clk_emac_0_sys_25m_clk_src 0x92fe3614
+#define clk_emac_0_tx_clk_src 0x0487ec76
+#define clk_usb_hs_system_clk_src 0x28385546
+#define clk_usb_hsic_clk_src 0x141b01df
+#define clk_usb_hsic_io_cal_clk_src 0xc83584bd
+#define clk_usb_hsic_system_clk_src 0x52ef7224
+
+/*Branch*/
+#define clk_gcc_apss_ahb_clk 0x2b0d39ff
+#define clk_gcc_apss_axi_clk 0x1d47f4ff
+#define clk_gcc_prng_ahb_clk 0x397e7eaa
+#define clk_gcc_qdss_dap_clk 0x7fa9aa73
+#define clk_gcc_apss_tcu_clk 0xaf56a329
+#define clk_gcc_blsp1_ahb_clk 0x8caa5b4f
+#define clk_gcc_blsp1_qup1_i2c_apps_clk 0xc303fae9
+#define clk_gcc_blsp1_qup1_spi_apps_clk 0x759a76b0
+#define clk_gcc_blsp1_qup2_i2c_apps_clk 0x1076f220
+#define clk_gcc_blsp1_qup2_spi_apps_clk 0x3e77d48f
+#define clk_gcc_blsp1_qup3_i2c_apps_clk 0x9e25ac82
+#define clk_gcc_blsp1_qup3_spi_apps_clk 0xfb978880
+#define clk_gcc_blsp1_qup4_i2c_apps_clk 0xd7f40f6f
+#define clk_gcc_blsp1_qup4_spi_apps_clk 0x80f8722f
+#define clk_gcc_blsp1_qup5_i2c_apps_clk 0xacae5604
+#define clk_gcc_blsp1_qup5_spi_apps_clk 0xbf3e15d7
+#define clk_gcc_blsp1_qup6_i2c_apps_clk 0x5c6ad820
+#define clk_gcc_blsp1_qup6_spi_apps_clk 0x780d9f85
+#define clk_gcc_blsp1_uart1_apps_clk 0xc7c62f90
+#define clk_gcc_blsp1_uart2_apps_clk 0xf8a61c96
+#define clk_gcc_blsp1_uart3_apps_clk 0xc3298bd7
+#define clk_gcc_blsp1_uart4_apps_clk 0x26be16c0
+#define clk_gcc_blsp1_uart5_apps_clk 0x28a6bc74
+#define clk_gcc_blsp1_uart6_apps_clk 0x28fd3466
+#define clk_gcc_boot_rom_ahb_clk 0xde2adeb1
+#define clk_gcc_crypto_ahb_clk 0x94de4919
+#define clk_gcc_crypto_axi_clk 0xd4415c9b
+#define clk_gcc_crypto_clk 0x00d390d2
+#define clk_gcc_gp1_clk 0x057f7b69
+#define clk_gcc_gp2_clk 0x9bf83ffd
+#define clk_gcc_gp3_clk 0xec6539ee
+#define clk_gcc_mss_cfg_ahb_clk 0x111cde81
+#define clk_gcc_mss_q6_bimc_axi_clk 0x67544d62
+#define clk_gcc_pdm2_clk 0x99d55711
+#define clk_gcc_pdm_ahb_clk 0x365664f6
+#define clk_gcc_sdcc1_ahb_clk 0x691e0caa
+#define clk_gcc_sdcc1_apps_clk 0x9ad6fb96
+#define clk_gcc_sdcc2_ahb_clk 0x23d5727f
+#define clk_gcc_sdcc2_apps_clk 0x861b20ac
+#define clk_gcc_emac_0_125m_clk 0xe556de53
+#define clk_gcc_emac_0_ahb_clk 0x6a741d38
+#define clk_gcc_emac_0_axi_clk 0xf2b04fb4
+#define clk_gcc_emac_0_rx_clk 0x869a4e5c
+#define clk_gcc_emac_0_sys_25m_clk 0x5812832b
+#define clk_gcc_emac_0_sys_clk 0x34fb62b0
+#define clk_gcc_emac_0_tx_clk 0x331d3573
+#define clk_gcc_smmu_cfg_clk 0x75eaefa5
+#define clk_gcc_usb2a_phy_sleep_clk 0x6caa736f
+#define clk_gcc_usb_hs_phy_cfg_ahb_clk 0xe13808fd
+#define clk_gcc_usb_hs_ahb_clk 0x72ce8032
+#define clk_gcc_usb_hs_system_clk 0xa11972e5
+#define clk_gcc_usb_hsic_ahb_clk 0x3ec2631a
+#define clk_gcc_usb_hsic_clk 0x8de18b0e
+#define clk_gcc_usb_hsic_io_cal_clk 0xbc21f776
+#define clk_gcc_usb_hsic_io_cal_sleep_clk 0x20e09a22
+#define clk_gcc_usb_hsic_system_clk 0x145e9366
+#define clk_gcc_usb2_hs_phy_only_clk 0x0047179d
+#define clk_gcc_qusb2_phy_clk 0x996884d5
+/* DEBUG */
+#define clk_gcc_debug_mux 0x8121ac15
+#define clk_apss_debug_pri_mux 0xc691ff55
+#define clk_apc0_m_clk 0xce1e9473
+#define clk_apc1_m_clk 0x990fbaf7
+#define clk_apc2_m_clk 0x252cd4ae
+#define clk_apc3_m_clk 0x78c64486
+#define clk_l2_m_clk 0x4bedf4d0
+
+#define clk_wcnss_m_clk 0x709f430b
+
+#endif
diff --git a/include/dt-bindings/clock/mdm-clocks-9650.h b/include/dt-bindings/clock/mdm-clocks-9650.h
new file mode 100644
index 0000000..d62a806
--- /dev/null
+++ b/include/dt-bindings/clock/mdm-clocks-9650.h
@@ -0,0 +1,160 @@
+/*
+ * 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_CLOCKS_9650_H
+#define __MSM_CLOCKS_9650_H
+
+/* RPM controlled clocks */
+#define clk_xo 0xf13dfee3
+#define clk_xo_a_clk 0xd939b99b
+#define clk_ce_clk 0xd8bc64e1
+#define clk_ce_a_clk 0x4dfefd47
+#define clk_pcnoc_clk 0xc1296d0f
+#define clk_pcnoc_a_clk 0x9bcffee4
+#define clk_bimc_clk 0x4b80bf00
+#define clk_bimc_a_clk 0x4b25668a
+#define clk_snoc_clk 0x2c341aa0
+#define clk_snoc_a_clk 0x8fcef2af
+#define clk_ipa_clk 0xfa685cda
+#define clk_ipa_a_clk 0xeeec2919
+#define clk_qpic_clk 0x3ce6f7bb
+#define clk_qpic_a_clk 0xd70ccb7c
+#define clk_qdss_clk 0x1492202a
+#define clk_qdss_a_clk 0xdd121669
+#define clk_bimc_msmbus_clk 0xd212feea
+#define clk_bimc_msmbus_a_clk 0x71d1a499
+#define clk_mcd_ce_clk 0x7ad13979
+#define clk_pcnoc_keepalive_a_clk 0x9464f720
+#define clk_pcnoc_msmbus_clk 0x2b53b688
+#define clk_pcnoc_msmbus_a_clk 0x9753a54f
+#define clk_pcnoc_pm_clk 0x5e636b5d
+#define clk_pcnoc_sps_clk 0x23d3f584
+#define clk_qcedev_ce_clk 0x2e7f9cee
+#define clk_qcrypto_ce_clk 0xd8cd060b
+#define clk_qseecom_ce_clk 0xea036e4b
+#define clk_scm_ce_clk 0xfd35bb87
+#define clk_snoc_msmbus_clk 0xe6900bb6
+#define clk_snoc_msmbus_a_clk 0x5d4683bd
+#define clk_cxo_dwc3_clk 0xf79c19f6
+#define clk_cxo_lpm_clk 0x94adbf3d
+#define clk_cxo_otg_clk 0x4eec0bb9
+#define clk_div_clk1 0xaa1157a6
+#define clk_div_clk1_ao 0x6b943d68
+#define clk_ln_bb_clk 0x3ab0b36d
+#define clk_ln_bb_a_clk 0xc7257ea8
+#define clk_rf_clk1 0xaabeea5a
+#define clk_rf_clk1_ao 0x72a10cb8
+#define clk_rf_clk1_pin 0x8f463562
+#define clk_rf_clk1_pin_ao 0x62549ff6
+#define clk_rf_clk2 0x24a30992
+#define clk_rf_clk2_ao 0x944d8bbd
+#define clk_rf_clk2_pin 0xa7c5602a
+#define clk_rf_clk2_pin_ao 0x2d75eb4d
+#define clk_rf_clk3 0xb673936b
+#define clk_rf_clk3_ao 0x038bb968
+#define clk_rf_clk3_pin 0x726f53f5
+#define clk_rf_clk3_pin_ao 0x76f9240f
+
+/* APSS controlled clocks */
+#define clk_gpll0 0x1ebe3bc4
+#define clk_gpll0_ao 0xa1368304
+#define clk_gpll0_out_msscc 0x7d794829
+#define clk_apss_ahb_clk_src 0x36f8495f
+#define clk_usb30_master_clk_src 0xc6262f89
+#define clk_blsp1_qup1_i2c_apps_clk_src 0x17f78f5e
+#define clk_blsp1_qup1_spi_apps_clk_src 0xf534c4fa
+#define clk_blsp1_qup2_i2c_apps_clk_src 0x8de71c79
+#define clk_blsp1_qup2_spi_apps_clk_src 0x33cf809a
+#define clk_blsp1_qup3_i2c_apps_clk_src 0xf161b902
+#define clk_blsp1_qup3_spi_apps_clk_src 0x5e95683f
+#define clk_blsp1_qup4_i2c_apps_clk_src 0xb2ecce68
+#define clk_blsp1_qup4_spi_apps_clk_src 0xddb5bbdb
+#define clk_blsp1_uart1_apps_clk_src 0xf8146114
+#define clk_blsp1_uart2_apps_clk_src 0xfc9c2f73
+#define clk_blsp1_uart3_apps_clk_src 0x600497f2
+#define clk_blsp1_uart4_apps_clk_src 0x56bff15c
+#define clk_gp1_clk_src 0xad85b97a
+#define clk_gp2_clk_src 0xfb1f0065
+#define clk_gp3_clk_src 0x63b693d6
+#define clk_pcie_aux_clk_src 0xebc50566
+#define clk_pdm2_clk_src 0x31e494fd
+#define clk_sdcc1_apps_clk_src 0xd4975db2
+#define clk_usb30_mock_utmi_clk_src 0xa024a976
+#define clk_usb3_aux_clk_src 0xfde7ae09
+#define clk_gcc_pcie_phy_reset 0x9bc3c959
+#define clk_gcc_qusb2a_phy_reset 0x2a9dfa9f
+#define clk_gcc_usb3phy_phy_reset 0xb1a4f885
+#define clk_gcc_usb3_phy_reset 0x03d559f1
+#define clk_gpll0_out_main_cgc 0xb0298998
+#define clk_gcc_blsp1_ahb_clk 0x8caa5b4f
+#define clk_gcc_blsp1_qup1_i2c_apps_clk 0xc303fae9
+#define clk_gcc_blsp1_qup1_spi_apps_clk 0x759a76b0
+#define clk_gcc_blsp1_qup2_i2c_apps_clk 0x1076f220
+#define clk_gcc_blsp1_qup2_spi_apps_clk 0x3e77d48f
+#define clk_gcc_blsp1_qup3_i2c_apps_clk 0x9e25ac82
+#define clk_gcc_blsp1_qup3_spi_apps_clk 0xfb978880
+#define clk_gcc_blsp1_qup4_i2c_apps_clk 0xd7f40f6f
+#define clk_gcc_blsp1_qup4_spi_apps_clk 0x80f8722f
+#define clk_gcc_blsp1_uart1_apps_clk 0xc7c62f90
+#define clk_gcc_blsp1_uart2_apps_clk 0xf8a61c96
+#define clk_gcc_blsp1_uart3_apps_clk 0xc3298bd7
+#define clk_gcc_blsp1_uart4_apps_clk 0x26be16c0
+#define clk_gcc_boot_rom_ahb_clk 0xde2adeb1
+#define clk_gcc_dcc_clk 0xd1000c50
+#define clk_gpll0_out_main_div2_cgc 0xc76ac7ae
+#define clk_gcc_gp1_clk 0x057f7b69
+#define clk_gcc_gp2_clk 0x9bf83ffd
+#define clk_gcc_gp3_clk 0xec6539ee
+#define clk_gcc_mss_q6_bimc_axi_clk 0x67544d62
+#define clk_gcc_pcie_axi_clk 0xb833d9e3
+#define clk_gcc_pcie_axi_mstr_clk 0x54d09178
+#define clk_gcc_pcie_cfg_ahb_clk 0xddc9a515
+#define clk_gcc_pcie_pipe_clk 0x8be62558
+#define clk_gcc_pcie_sleep_clk 0x8b8bfc3b
+#define clk_gcc_pdm2_clk 0x99d55711
+#define clk_gcc_pdm_ahb_clk 0x365664f6
+#define clk_gcc_prng_ahb_clk 0x397e7eaa
+#define clk_gcc_sdcc1_ahb_clk 0x691e0caa
+#define clk_gcc_sdcc1_apps_clk 0x9ad6fb96
+#define clk_gcc_apss_tcu_clk 0xaf56a329
+#define clk_gcc_pcie_axi_tbu_clk 0xab70f06e
+#define clk_gcc_pcie_ref_clk 0x63fca50a
+#define clk_gcc_usb_ss_ref_clk 0xb85dadfa
+#define clk_gcc_qusb_ref_clk 0x16e35a90
+#define clk_gcc_smmu_cfg_clk 0x75eaefa5
+#define clk_gcc_usb3_axi_tbu_clk 0x18779c6e
+#define clk_gcc_sys_noc_usb3_axi_clk 0x94d26800
+#define clk_gcc_usb30_master_clk 0xb3b4e2cb
+#define clk_gcc_usb30_mock_utmi_clk 0xa800b65a
+#define clk_gcc_usb30_sleep_clk 0xd0b65c92
+#define clk_gcc_usb3_aux_clk 0x555d16b2
+#define clk_gcc_usb3_pipe_clk 0x26f8a97a
+#define clk_gcc_usb_phy_cfg_ahb_clk 0xccb7e26f
+#define clk_gcc_mss_cfg_ahb_clk 0x111cde81
+
+/* a7pll */
+#define clk_a7pll_clk 0x3dd5dd94
+
+/* clock_debug controlled clocks */
+#define clk_gcc_debug_mux 0x8121ac15
+
+/* Audio External Clocks */
+#define clk_audio_lpass_mclk 0x575ec22b
+
+/* sdx20 */
+#define clk_gcc_pcie_aux_clk 0x06d8e933
+#define clk_pcie_aux_phy_clk_src 0x672e340c
+#define clk_pcie20_phy_aux_clk 0x613dfb19
+#define clk_pcie_aux_mux_clk 0x3e75325b
+
+#endif
diff --git a/include/dt-bindings/clock/mdm-clocks-hwio-9607.h b/include/dt-bindings/clock/mdm-clocks-hwio-9607.h
new file mode 100644
index 0000000..e8bb4e0
--- /dev/null
+++ b/include/dt-bindings/clock/mdm-clocks-hwio-9607.h
@@ -0,0 +1,227 @@
+/*
+ * 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.
+ */
+
+#ifndef __MDM_CLOCKS_9607_HWIO_H
+#define __MDM_CLOCKS_9607_HWIO_H
+
+#define GPLL0_MODE 0x21000
+#define GPLL0_STATUS 0x21024
+#define GPLL1_MODE 0x20000
+#define GPLL1_STATUS 0x2001C
+#define GPLL2_MODE 0x25000
+#define GPLL2_STATUS 0x25024
+#define APCS_GPLL_ENA_VOTE 0x45000
+#define APCS_MODE 0x00018
+#define APSS_AHB_CMD_RCGR 0x46000
+#define PRNG_AHB_CBCR 0x13004
+#define EMAC_0_125M_CMD_RCGR 0x4E028
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR 0x200C
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR 0x2024
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR 0x3000
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR 0x3014
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR 0x4000
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR 0x4024
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR 0x5000
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR 0x5024
+#define BLSP1_QUP5_I2C_APPS_CMD_RCGR 0x6000
+#define BLSP1_QUP5_SPI_APPS_CMD_RCGR 0x6024
+#define BLSP1_QUP6_I2C_APPS_CMD_RCGR 0x7000
+#define BLSP1_QUP6_SPI_APPS_CMD_RCGR 0x7024
+#define BLSP1_UART1_APPS_CMD_RCGR 0x2044
+#define BLSP1_UART2_APPS_CMD_RCGR 0x3034
+#define BLSP1_UART3_APPS_CMD_RCGR 0x4044
+#define BLSP1_UART4_APPS_CMD_RCGR 0x5044
+#define BLSP1_UART5_APPS_CMD_RCGR 0x6044
+#define BLSP1_UART6_APPS_CMD_RCGR 0x7044
+#define CRYPTO_CMD_RCGR 0x16004
+#define GP1_CMD_RCGR 0x8004
+#define GP2_CMD_RCGR 0x9004
+#define GP3_CMD_RCGR 0xA004
+#define PDM2_CMD_RCGR 0x44010
+#define QPIC_CMD_RCGR 0x3F004
+#define SDCC1_APPS_CMD_RCGR 0x42004
+#define SDCC2_APPS_CMD_RCGR 0x43004
+#define EMAC_0_SYS_25M_CMD_RCGR 0x4E03C
+#define EMAC_0_TX_CMD_RCGR 0x4E014
+#define USB_HS_SYSTEM_CMD_RCGR 0x41010
+#define USB_HSIC_CMD_RCGR 0x3D018
+#define USB_HSIC_IO_CAL_CMD_RCGR 0x3D030
+#define USB_HSIC_SYSTEM_CMD_RCGR 0x3D000
+#define BIMC_PCNOC_AXI_CBCR 0x31024
+#define BLSP1_AHB_CBCR 0x1008
+#define APCS_CLOCK_BRANCH_ENA_VOTE 0x45004
+#define BLSP1_QUP1_I2C_APPS_CBCR 0x2008
+#define BLSP1_QUP1_SPI_APPS_CBCR 0x2004
+#define BLSP1_QUP2_I2C_APPS_CBCR 0x3010
+#define BLSP1_QUP2_SPI_APPS_CBCR 0x300C
+#define BLSP1_QUP3_I2C_APPS_CBCR 0x4020
+#define BLSP1_QUP3_SPI_APPS_CBCR 0x401C
+#define BLSP1_QUP4_I2C_APPS_CBCR 0x5020
+#define BLSP1_QUP4_SPI_APPS_CBCR 0x501C
+#define BLSP1_QUP5_I2C_APPS_CBCR 0x6020
+#define BLSP1_QUP5_SPI_APPS_CBCR 0x601C
+#define BLSP1_QUP6_I2C_APPS_CBCR 0x7020
+#define BLSP1_QUP6_SPI_APPS_CBCR 0x701C
+#define BLSP1_UART1_APPS_CBCR 0x203C
+#define BLSP1_UART2_APPS_CBCR 0x302C
+#define BLSP1_UART3_APPS_CBCR 0x403C
+#define BLSP1_UART4_APPS_CBCR 0x503C
+#define BLSP1_UART5_APPS_CBCR 0x603C
+#define BLSP1_UART6_APPS_CBCR 0x703C
+#define APSS_AHB_CBCR 0x4601C
+#define APSS_AXI_CBCR 0x46020
+#define BOOT_ROM_AHB_CBCR 0x1300C
+#define CRYPTO_AHB_CBCR 0x16024
+#define CRYPTO_AXI_CBCR 0x16020
+#define CRYPTO_CBCR 0x1601C
+#define GP1_CBCR 0x8000
+#define GP2_CBCR 0x9000
+#define GP3_CBCR 0xA000
+#define MSS_CFG_AHB_CBCR 0x49000
+#define MSS_Q6_BIMC_AXI_CBCR 0x49004
+#define PCNOC_APSS_AHB_CBCR 0x27030
+#define PDM2_CBCR 0x4400C
+#define PDM_AHB_CBCR 0x44004
+#define QPIC_AHB_CBCR 0x3F01C
+#define QPIC_CBCR 0x3F018
+#define QPIC_SYSTEM_CBCR 0x3F020
+#define SDCC1_AHB_CBCR 0x4201C
+#define SDCC1_APPS_CBCR 0x42018
+#define SDCC2_AHB_CBCR 0x4301C
+#define SDCC2_APPS_CBCR 0x43018
+#define EMAC_0_125M_CBCR 0x4E010
+#define EMAC_0_AHB_CBCR 0x4E000
+#define EMAC_0_AXI_CBCR 0x4E008
+#define EMAC_0_RX_CBCR 0x4E030
+#define EMAC_0_SYS_25M_CBCR 0x4E038
+#define EMAC_0_SYS_CBCR 0x4E034
+#define EMAC_0_TX_CBCR 0x4E00C
+#define APSS_TCU_CBCR 0x12018
+#define SMMU_CFG_CBCR 0x12038
+#define QDSS_DAP_CBCR 0x29084
+#define APCS_SMMU_CLOCK_BRANCH_ENA_VOTE 0x4500C
+#define USB2A_PHY_SLEEP_CBCR 0x4102C
+#define USB_HS_PHY_CFG_AHB_CBCR 0x41030
+#define USB_HS_AHB_CBCR 0x41008
+#define USB_HS_SYSTEM_CBCR 0x41004
+#define USB_HS_BCR 0x41000
+#define USB_HSIC_AHB_CBCR 0x3D04C
+#define USB_HSIC_CBCR 0x3D050
+#define USB_HSIC_IO_CAL_CBCR 0x3D054
+#define USB_HSIC_IO_CAL_SLEEP_CBCR 0x3D058
+#define USB_HSIC_SYSTEM_CBCR 0x3D048
+#define USB_HS_HSIC_BCR 0x3D05C
+#define USB2_HS_PHY_ONLY_BCR 0x41034
+#define QUSB2_PHY_BCR 0x4103C
+#define GCC_DEBUG_CLK_CTL 0x74000
+#define CLOCK_FRQ_MEASURE_CTL 0x74004
+#define CLOCK_FRQ_MEASURE_STATUS 0x74008
+#define PLLTEST_PAD_CFG 0x7400C
+#define GCC_XO_DIV4_CBCR 0x30034
+
+#define xo_source_val 0
+#define xo_a_source_val 0
+#define gpll0_source_val 1
+#define gpll2_source_val 1
+#define emac_0_125m_clk_source_val 1
+#define emac_0_tx_clk_source_val 2
+
+#define F(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .src_clk = &s##_clk_src.c, \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+ | BVAL(10, 8, s##_source_val), \
+ }
+
+#define F_EXT(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+ | BVAL(10, 8, s##_source_val), \
+ }
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+
+enum vdd_dig_levels {
+ VDD_DIG_NONE,
+ VDD_DIG_LOWER,
+ VDD_DIG_LOW,
+ VDD_DIG_NOMINAL,
+ VDD_DIG_HIGH,
+ VDD_DIG_NUM
+};
+
+static int vdd_corner[] = {
+ RPM_REGULATOR_LEVEL_NONE, /* VDD_DIG_NONE */
+ RPM_REGULATOR_LEVEL_SVS, /* VDD_DIG_LOWER */
+ RPM_REGULATOR_LEVEL_SVS_PLUS, /*VDD_DIG_LOW*/
+ RPM_REGULATOR_LEVEL_NOM, /* VDD_DIG_NOMINAL */
+ RPM_REGULATOR_LEVEL_TURBO, /* VDD_DIG_HIGH */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+
+#define VDD_STROMER_FMAX_MAP1(l1, f1) \
+ .vdd_class = &vdd_stromer_pll, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+
+
+#define RPM_MISC_CLK_TYPE 0x306b6c63
+#define RPM_BUS_CLK_TYPE 0x316b6c63
+#define RPM_MEM_CLK_TYPE 0x326b6c63
+#define RPM_SMD_KEY_ENABLE 0x62616E45
+#define RPM_QPIC_CLK_TYPE 0x63697071
+
+#define XO_ID 0x0
+#define QDSS_ID 0x1
+#define PCNOC_ID 0x0
+#define BIMC_ID 0x0
+#define QPIC_ID 0x0
+
+/* XO clock */
+#define BB_CLK1_ID 1
+#define RF_CLK2_ID 5
+
+#endif
diff --git a/include/dt-bindings/clock/msm-clocks-8909.h b/include/dt-bindings/clock/msm-clocks-8909.h
new file mode 100644
index 0000000..b46c724
--- /dev/null
+++ b/include/dt-bindings/clock/msm-clocks-8909.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2014-2018, 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_CLOCKS_8909_H
+#define __MSM_CLOCKS_8909_H
+
+/* GPLLs */
+#define clk_gpll0_clk_src 0x5933b69f
+#define clk_gpll0_ao_clk_src 0x6b2fb034
+#define clk_gpll1_clk_src 0x916f8847
+#define clk_gpll2_clk_src 0x7c34503b
+
+/* SR2PLL */
+#define clk_a7sspll 0xf761da94
+
+/* SRCs */
+#define clk_apss_ahb_clk_src 0x36f8495f
+#define clk_blsp1_qup1_i2c_apps_clk_src 0x17f78f5e
+#define clk_blsp1_qup1_spi_apps_clk_src 0xf534c4fa
+#define clk_blsp1_qup2_i2c_apps_clk_src 0x8de71c79
+#define clk_blsp1_qup2_spi_apps_clk_src 0x33cf809a
+#define clk_blsp1_qup3_i2c_apps_clk_src 0xf161b902
+#define clk_blsp1_qup3_spi_apps_clk_src 0x5e95683f
+#define clk_blsp1_qup4_i2c_apps_clk_src 0xb2ecce68
+#define clk_blsp1_qup4_spi_apps_clk_src 0xddb5bbdb
+#define clk_blsp1_qup5_i2c_apps_clk_src 0x71ea7804
+#define clk_blsp1_qup5_spi_apps_clk_src 0x9752f35f
+#define clk_blsp1_qup6_i2c_apps_clk_src 0x28806803
+#define clk_blsp1_qup6_spi_apps_clk_src 0x44a1edc4
+#define clk_blsp1_uart1_apps_clk_src 0xf8146114
+#define clk_blsp1_uart2_apps_clk_src 0xfc9c2f73
+#define clk_byte0_clk_src 0x75cc885b
+#define clk_cci_clk_src 0x822f3d97
+#define clk_cpp_clk_src 0x8382f56d
+#define clk_camss_top_ahb_clk_src 0xf92304fb
+#define clk_camss_gp0_clk_src 0x43b063e9
+#define clk_camss_gp1_clk_src 0xa3315f1b
+#define clk_crypto_clk_src 0x37a21414
+#define clk_csi0_clk_src 0x227e65bc
+#define clk_csi1_clk_src 0x6a2a6c36
+#define clk_csi0phytimer_clk_src 0xc8a309be
+#define clk_csi1phytimer_clk_src 0x7c0fe23a
+#define clk_esc0_clk_src 0xb41d7c38
+#define clk_gfx3d_clk_src 0x917f76ef
+#define clk_gp1_clk_src 0xad85b97a
+#define clk_gp2_clk_src 0xfb1f0065
+#define clk_gp3_clk_src 0x63b693d6
+#define clk_jpeg0_clk_src 0x9a0a0ac3
+#define clk_mdp_clk_src 0x6dc1f8f1
+#define clk_mclk0_clk_src 0x266b3853
+#define clk_mclk1_clk_src 0xa73cad0c
+#define clk_pclk0_clk_src 0xccac1f35
+#define clk_pdm2_clk_src 0x31e494fd
+#define clk_sdcc1_apps_clk_src 0xd4975db2
+#define clk_sdcc2_apps_clk_src 0xfc46c821
+#define clk_usb_hs_system_clk_src 0x28385546
+#define clk_gcc_qusb2_phy_clk 0x996884d5
+#define clk_gcc_usb2_hs_phy_only_clk 0x0047179d
+#define clk_vsync_clk_src 0xecb43940
+#define clk_vfe0_clk_src 0xa0c2bd8f
+#define clk_vcodec0_clk_src 0xbc193019
+
+/* BRANCHEs*/
+#define clk_gcc_apss_ahb_clk 0x2b0d39ff
+#define clk_gcc_blsp1_ahb_clk 0x8caa5b4f
+#define clk_gcc_boot_rom_ahb_clk 0xde2adeb1
+#define clk_gcc_crypto_ahb_clk 0x94de4919
+#define clk_gcc_crypto_axi_clk 0xd4415c9b
+#define clk_gcc_crypto_clk 0x00d390d2
+#define clk_gcc_prng_ahb_clk 0x397e7eaa
+#define clk_gcc_apss_tcu_clk 0xaf56a329
+#define clk_gcc_gfx_tbu_clk 0x18bb9a90
+#define clk_gcc_gtcu_ahb_clk 0xb432168e
+#define clk_gcc_jpeg_tbu_clk 0xcf8fd944
+#define clk_gcc_mdp_tbu_clk 0x82287f76
+#define clk_gcc_smmu_cfg_clk 0x75eaefa5
+#define clk_gcc_venus_tbu_clk 0x7e0b97ce
+#define clk_gcc_vfe_tbu_clk 0x061f2f95
+#define clk_gcc_blsp1_qup1_i2c_apps_clk 0xc303fae9
+#define clk_gcc_blsp1_qup1_spi_apps_clk 0x759a76b0
+#define clk_gcc_blsp1_qup2_i2c_apps_clk 0x1076f220
+#define clk_gcc_blsp1_qup2_spi_apps_clk 0x3e77d48f
+#define clk_gcc_blsp1_qup3_i2c_apps_clk 0x9e25ac82
+#define clk_gcc_blsp1_qup3_spi_apps_clk 0xfb978880
+#define clk_gcc_blsp1_qup4_i2c_apps_clk 0xd7f40f6f
+#define clk_gcc_blsp1_qup4_spi_apps_clk 0x80f8722f
+#define clk_gcc_blsp1_qup5_i2c_apps_clk 0xacae5604
+#define clk_gcc_blsp1_qup5_spi_apps_clk 0xbf3e15d7
+#define clk_gcc_blsp1_qup6_i2c_apps_clk 0x5c6ad820
+#define clk_gcc_blsp1_qup6_spi_apps_clk 0x780d9f85
+#define clk_gcc_blsp1_uart1_apps_clk 0xc7c62f90
+#define clk_gcc_blsp1_uart2_apps_clk 0xf8a61c96
+#define clk_gcc_camss_cci_ahb_clk 0xa81c11ba
+#define clk_gcc_camss_cci_clk 0xb7dd8824
+#define clk_gcc_camss_csi0_ahb_clk 0x175d672a
+#define clk_gcc_camss_csi0_clk 0x6b01b3e1
+#define clk_gcc_camss_csi0phy_clk 0x06a41ff7
+#define clk_gcc_camss_csi0pix_clk 0x61a8a930
+#define clk_gcc_camss_csi0rdi_clk 0x7053c7ae
+#define clk_gcc_camss_csi1_ahb_clk 0x2c2dc261
+#define clk_gcc_camss_csi1_clk 0x1aba4a8c
+#define clk_gcc_camss_csi1phy_clk 0x0fd1d1fa
+#define clk_gcc_camss_csi1pix_clk 0x87fc98d8
+#define clk_gcc_camss_csi1rdi_clk 0x6ac996fe
+#define clk_gcc_camss_csi_vfe0_clk 0xcc73453c
+#define clk_gcc_camss_gp0_clk 0xd2bc3892
+#define clk_gcc_camss_gp1_clk 0xe4c013e1
+#define clk_gcc_camss_ispif_ahb_clk 0x3c0a858f
+#define clk_gcc_camss_jpeg0_clk 0x1ed3f032
+#define clk_gcc_camss_jpeg_ahb_clk 0x3bfa7603
+#define clk_gcc_camss_jpeg_axi_clk 0x3e278896
+#define clk_gcc_camss_mclk0_clk 0x80902deb
+#define clk_gcc_camss_mclk1_clk 0x5002d85f
+#define clk_gcc_camss_micro_ahb_clk 0xfbbee8cf
+#define clk_gcc_camss_csi0phytimer_clk 0xf8897589
+#define clk_gcc_camss_csi1phytimer_clk 0x4d26438f
+#define clk_gcc_camss_ahb_clk 0x9894b414
+#define clk_gcc_camss_top_ahb_clk 0x4e814a78
+#define clk_gcc_camss_cpp_ahb_clk 0x4ac95e14
+#define clk_gcc_camss_cpp_clk 0x7118a0de
+#define clk_gcc_camss_vfe0_clk 0xaaa3cd97
+#define clk_gcc_camss_vfe_ahb_clk 0x4050f47a
+#define clk_gcc_camss_vfe_axi_clk 0x77fe2384
+#define clk_gcc_oxili_gmem_clk 0x5620913a
+#define clk_gcc_gp1_clk 0x057f7b69
+#define clk_gcc_gp2_clk 0x9bf83ffd
+#define clk_gcc_gp3_clk 0xec6539ee
+#define clk_gcc_mdss_ahb_clk 0xbfb92ed3
+#define clk_gcc_mdss_axi_clk 0x668f51de
+#define clk_gcc_mdss_byte0_clk 0x35da7862
+#define clk_gcc_mdss_esc0_clk 0xaec5cb25
+#define clk_gcc_mdss_mdp_clk 0x22f3521f
+#define clk_gcc_mdss_pclk0_clk 0xcc5c5c77
+#define clk_gcc_mdss_vsync_clk 0x32a09f1f
+#define clk_gcc_mss_cfg_ahb_clk 0x111cde81
+#define clk_gcc_mss_q6_bimc_axi_clk 0x67544d62
+#define clk_gcc_oxili_ahb_clk 0xd15c8a00
+#define clk_gcc_oxili_gfx3d_clk 0x49a51fd9
+#define clk_gcc_pdm2_clk 0x99d55711
+#define clk_gcc_pdm_ahb_clk 0x365664f6
+#define clk_gcc_sdcc1_ahb_clk 0x691e0caa
+#define clk_gcc_sdcc1_apps_clk 0x9ad6fb96
+#define clk_gcc_sdcc2_ahb_clk 0x23d5727f
+#define clk_gcc_sdcc2_apps_clk 0x861b20ac
+#define clk_gcc_usb2a_phy_sleep_clk 0x6caa736f
+#define clk_gcc_usb_hs_phy_cfg_ahb_clk 0xe13808fd
+#define clk_gcc_usb_hs_ahb_clk 0x72ce8032
+#define clk_gcc_usb_hs_system_clk 0xa11972e5
+#define clk_gcc_venus0_ahb_clk 0x08d778c6
+#define clk_gcc_venus0_axi_clk 0xcdf4c8f6
+#define clk_gcc_venus0_vcodec0_clk 0xf76a02bb
+#define clk_gcc_venus0_core0_vcodec0_clk 0x83a7f549
+#define clk_gcc_gfx_tcu_clk 0x59505e55
+#define clk_gcc_gtcu_ahb_bridge_clk 0x19d2c5fe
+#define clk_gcc_bimc_gpu_clk 0x19922503
+#define clk_gcc_bimc_gfx_clk 0x3edd69ad
+#define clk_gcc_snoc_qosgen_clk 0x37d40ce2
+
+#define clk_pixel_clk_src 0x8b6f83d8
+#define clk_byte_clk_src 0x3a911c53
+#define clk_dsi_pll0_byte_clk_src 0x44539836
+#define clk_dsi_pll0_pixel_clk_src 0x5767c287
+
+/* RPM */
+#define clk_pcnoc_clk 0xc1296d0f
+#define clk_pcnoc_a_clk 0x9bcffee4
+#define clk_pcnoc_msmbus_clk 0x2b53b688
+#define clk_pcnoc_msmbus_a_clk 0x9753a54f
+#define clk_pcnoc_keepalive_a_clk 0x9464f720
+#define clk_pcnoc_usb_a_clk 0x11d6a74e
+#define clk_snoc_clk 0x2c341aa0
+#define clk_snoc_a_clk 0x8fcef2af
+#define clk_snoc_msmbus_clk 0xe6900bb6
+#define clk_snoc_msmbus_a_clk 0x5d4683bd
+#define clk_snoc_mmnoc_axi_clk 0xfedd4bd5
+#define clk_snoc_mmnoc_ahb_clk 0xd2149dbb
+#define clk_snoc_usb_a_clk 0x34b7821b
+#define clk_snoc_mm_msmbus_clk 0x5e221ca4
+#define clk_snoc_mm_msmbus_a_clk 0x5950f9ea
+#define clk_bimc_clk 0x4b80bf00
+#define clk_bimc_a_clk 0x4b25668a
+#define clk_bimc_acpu_a_clk 0x4446311b
+#define clk_bimc_msmbus_clk 0xd212feea
+#define clk_bimc_msmbus_a_clk 0x71d1a499
+#define clk_bimc_usb_a_clk 0xea410834
+#define clk_qdss_clk 0x1492202a
+#define clk_qdss_a_clk 0xdd121669
+#define clk_xo_clk_src 0x23f5649f
+#define clk_xo_a_clk_src 0x2fdd2c7c
+#define clk_xo_otg_clk 0x79bca5cc
+#define clk_xo_lpm_clk 0x2be48257
+#define clk_xo_pil_mss_clk 0xe97a8354
+#define clk_xo_pil_pronto_clk 0x89dae6d0
+#define clk_xo_wlan_clk 0x0116b76f
+
+#define clk_qpic_clk 0x3ce6f7bb
+#define clk_qpic_a_clk 0xd70ccb7c
+#define clk_bb_clk1 0xf5304268
+#define clk_bb_clk1_pin 0x6dd0a779
+#define clk_bb_clk2 0xfe15cb87
+#define clk_bb_clk2_pin 0x498938e5
+#define clk_bb_clk3 0x3a9e99a8
+#define clk_bb_clk3_pin 0x3a96c14c
+#define clk_rf_clk1 0xaabeea5a
+#define clk_rf_clk1_pin 0x8f463562
+#define clk_rf_clk2 0x24a30992
+#define clk_rf_clk2_pin 0xa7c5602a
+
+/* DEBUG */
+#define clk_gcc_debug_mux 0x8121ac15
+#define clk_rpm_debug_mux 0x25cd1f3a
+#define clk_wcnss_m_clk 0x709f430b
+#define clk_apss_debug_pri_mux 0xc691ff55
+#define clk_apss_debug_sec_mux 0xc0b680f9
+#define clk_apss_debug_ter_mux 0x32041c48
+#define clk_apc0_m_clk 0xce1e9473
+#define clk_apc1_m_clk 0x990fbaf7
+#define clk_apc2_m_clk 0x252cd4ae
+#define clk_apc3_m_clk 0x78c64486
+#define clk_l2_m_clk 0x4bedf4d0
+
+#define clk_audio_ap_clk 0x312ac429
+#define clk_audio_pmi_clk 0xb7ba2274
+
+#define clk_audio_lpass_mclk 0x575ec22b
+
+/* GCC block resets */
+#define GCC_USB_HS_BCR 0
+#define GCC_USB2_HS_PHY_ONLY_BCR 1
+#define GCC_QUSB2_PHY_BCR 2
+
+#endif
diff --git a/include/dt-bindings/clock/msm-clocks-8952.h b/include/dt-bindings/clock/msm-clocks-8952.h
index e8afdba..4547751 100644
--- a/include/dt-bindings/clock/msm-clocks-8952.h
+++ b/include/dt-bindings/clock/msm-clocks-8952.h
@@ -339,6 +339,7 @@
#define clk_audio_ap_clk 0x312ac429
#define clk_audio_pmi_clk 0xb7ba2274
+#define clk_audio_ap_clk2 0xf0fbaf5b
#define clk_audio_lpass_mclk 0x575ec22b
/* GCC block resets */
diff --git a/include/dt-bindings/clock/msm-clocks-8953.h b/include/dt-bindings/clock/msm-clocks-8953.h
index 6bfca0b..9550a41 100644
--- a/include/dt-bindings/clock/msm-clocks-8953.h
+++ b/include/dt-bindings/clock/msm-clocks-8953.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -313,6 +313,12 @@
#define clk_cpu_debug_pri_mux 0x61a2945f
#define clk_debug_cpu_clk 0x0e696b2b
+#define clk_apcs_c0_pll 0xfbc57bbd
+#define clk_apcs_c1_pll 0x17d32f1e
+#define clk_apcs_cci_pll 0x09affb3c
+#define clk_a53ssmux_cci 0x15560bd5
+#define clk_a53_cci_clk 0x4cdbbe58
+
#define clk_audio_ap_clk 0x312ac429
#define clk_audio_pmi_clk 0xb7ba2274
#define clk_audio_ap_clk2 0xf0fbaf5b
diff --git a/include/dt-bindings/clock/msm-clocks-a7.h b/include/dt-bindings/clock/msm-clocks-a7.h
new file mode 100644
index 0000000..6438b70
--- /dev/null
+++ b/include/dt-bindings/clock/msm-clocks-a7.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015, 2018 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_CLOCKS_A7_H
+#define __MSM_CLOCKS_A7_H
+
+#define clk_a7ssmux 0x3ea882af
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,cpucc-sdm845.h b/include/dt-bindings/clock/qcom,cpucc-sdm845.h
index f039284..bbfb849 100644
--- a/include/dt-bindings/clock/qcom,cpucc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,cpucc-sdm845.h
@@ -30,5 +30,6 @@
#define L3_MISC_VOTE_CLK 13
#define CPU4_PWRCL_CLK 14
#define CPU5_PWRCL_CLK 15
+#define L3_GPU_VOTE_CLK 16
#endif
diff --git a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
index 36d34b1..1018b0e 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
@@ -126,4 +126,7 @@
#define GCC_USB_PHY_CFG_AHB2PHY_BCR 18
#define GCC_EMAC_BCR 19
+/* Dummy clocks for rate measurement */
+#define MEASURE_ONLY_IPA_2X_CLK 0
+
#endif
diff --git a/include/keys/user-type.h b/include/keys/user-type.h
index c56fef4..e098cbe 100644
--- a/include/keys/user-type.h
+++ b/include/keys/user-type.h
@@ -48,9 +48,14 @@
extern long user_read(const struct key *key,
char __user *buffer, size_t buflen);
-static inline const struct user_key_payload *user_key_payload(const struct key *key)
+static inline const struct user_key_payload *user_key_payload_rcu(const struct key *key)
{
- return (struct user_key_payload *)rcu_dereference_key(key);
+ return (struct user_key_payload *)dereference_key_rcu(key);
+}
+
+static inline struct user_key_payload *user_key_payload_locked(const struct key *key)
+{
+ return (struct user_key_payload *)dereference_key_locked((struct key *)key);
}
#endif /* CONFIG_KEYS */
diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h
index c357f27..0691068 100644
--- a/include/linux/backing-dev-defs.h
+++ b/include/linux/backing-dev-defs.h
@@ -10,6 +10,7 @@
#include <linux/flex_proportions.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
+#include <linux/kref.h>
struct page;
struct device;
@@ -20,6 +21,7 @@
*/
enum wb_state {
WB_registered, /* bdi_register() was done */
+ WB_shutting_down, /* wb_shutdown() in progress */
WB_writeback_running, /* Writeback is in progress */
WB_has_dirty_io, /* Dirty inodes on ->b_{dirty|io|more_io} */
};
@@ -53,7 +55,9 @@
atomic_t refcnt; /* nr of attached wb's and blkg */
#ifdef CONFIG_CGROUP_WRITEBACK
- struct backing_dev_info *bdi; /* the associated bdi */
+ struct backing_dev_info *__bdi; /* the associated bdi, set to NULL
+ * on bdi unregistration. For memcg-wb
+ * internal use only! */
int blkcg_id; /* ID of the associated blkcg */
struct rb_node rb_node; /* on bdi->cgwb_congestion_tree */
#endif
@@ -142,6 +146,7 @@
char *name;
+ struct kref refcnt; /* Reference counter for the structure */
unsigned int min_ratio;
unsigned int max_ratio, max_prop_frac;
@@ -156,7 +161,6 @@
#ifdef CONFIG_CGROUP_WRITEBACK
struct radix_tree_root cgwb_tree; /* radix tree of active cgroup wbs */
struct rb_root cgwb_congested_tree; /* their congested states */
- atomic_t usage_cnt; /* counts both cgwbs and cgwb_contested's */
#else
struct bdi_writeback_congested *wb_congested;
#endif
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 43b93a9..c52a48c 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -18,7 +18,14 @@
#include <linux/slab.h>
int __must_check bdi_init(struct backing_dev_info *bdi);
-void bdi_exit(struct backing_dev_info *bdi);
+
+static inline struct backing_dev_info *bdi_get(struct backing_dev_info *bdi)
+{
+ kref_get(&bdi->refcnt);
+ return bdi;
+}
+
+void bdi_put(struct backing_dev_info *bdi);
__printf(3, 4)
int bdi_register(struct backing_dev_info *bdi, struct device *parent,
@@ -29,6 +36,7 @@
int __must_check bdi_setup_and_register(struct backing_dev_info *, char *);
void bdi_destroy(struct backing_dev_info *bdi);
+struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id);
void wb_start_writeback(struct bdi_writeback *wb, long nr_pages,
bool range_cyclic, enum wb_reason reason);
@@ -183,7 +191,7 @@
sb = inode->i_sb;
#ifdef CONFIG_BLOCK
if (sb_is_blkdev_sb(sb))
- return blk_get_backing_dev_info(I_BDEV(inode));
+ return I_BDEV(inode)->bd_bdi;
#endif
return sb->s_bdi;
}
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 8a7a15c..2b8b6e0 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -81,12 +81,6 @@
struct bio_set *bi_pool;
/*
- * When using dircet-io (O_DIRECT), we can't get the inode from a bio
- * by walking bio->bi_io_vec->bv_page->mapping->host
- * since the page is anon.
- */
- struct inode *bi_dio_inode;
- /*
* We can inline a number of vecs at the end of the bio, to avoid
* double allocations for a small number of bio_vecs. This member
* MUST obviously be kept at the very end of the bio.
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 0693c3e..b0f981a 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -345,7 +345,7 @@
*/
struct delayed_work delay_work;
- struct backing_dev_info backing_dev_info;
+ struct backing_dev_info *backing_dev_info;
/*
* The queue owner gets to use this for whatever they like.
@@ -1031,7 +1031,6 @@
extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
extern void blk_queue_flush_queueable(struct request_queue *q, bool queueable);
extern void blk_queue_write_cache(struct request_queue *q, bool enabled, bool fua);
-extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *);
extern int blk_rq_map_sg_no_cluster(struct request_queue *q, struct request *rq,
@@ -1743,43 +1742,26 @@
#define BLK_IO_LAT_HIST_ZERO 2
struct io_latency_state {
- u_int64_t latency_y_axis_read[ARRAY_SIZE(latency_x_axis_us) + 1];
- u_int64_t latency_reads_elems;
- u_int64_t latency_y_axis_write[ARRAY_SIZE(latency_x_axis_us) + 1];
- u_int64_t latency_writes_elems;
+ u_int64_t latency_y_axis[ARRAY_SIZE(latency_x_axis_us) + 1];
+ u_int64_t latency_elems;
+ u_int64_t latency_sum;
};
static inline void
-blk_update_latency_hist(struct io_latency_state *s,
- int read,
- u_int64_t delta_us)
+blk_update_latency_hist(struct io_latency_state *s, u_int64_t delta_us)
{
int i;
- for (i = 0; i < ARRAY_SIZE(latency_x_axis_us); i++) {
- if (delta_us < (u_int64_t)latency_x_axis_us[i]) {
- if (read)
- s->latency_y_axis_read[i]++;
- else
- s->latency_y_axis_write[i]++;
+ for (i = 0; i < ARRAY_SIZE(latency_x_axis_us); i++)
+ if (delta_us < (u_int64_t)latency_x_axis_us[i])
break;
- }
- }
- if (i == ARRAY_SIZE(latency_x_axis_us)) {
- /* Overflowed the histogram */
- if (read)
- s->latency_y_axis_read[i]++;
- else
- s->latency_y_axis_write[i]++;
- }
- if (read)
- s->latency_reads_elems++;
- else
- s->latency_writes_elems++;
+ s->latency_y_axis[i]++;
+ s->latency_elems++;
+ s->latency_sum += delta_us;
}
-void blk_zero_latency_hist(struct io_latency_state *s);
-ssize_t blk_latency_hist_show(struct io_latency_state *s, char *buf);
+ssize_t blk_latency_hist_show(char* name, struct io_latency_state *s,
+ char *buf, int buf_size);
#else /* CONFIG_BLOCK */
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 7995940..193c40e 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -56,6 +56,9 @@
atomic_t refcnt;
atomic_t usercnt;
struct work_struct work;
+#ifdef CONFIG_SECURITY
+ void *security;
+#endif
};
struct bpf_map_type_list {
@@ -189,6 +192,9 @@
struct bpf_map **used_maps;
struct bpf_prog *prog;
struct user_struct *user;
+#ifdef CONFIG_SECURITY
+ void *security;
+#endif
union {
struct work_struct work;
struct rcu_head rcu;
@@ -241,6 +247,9 @@
void bpf_register_prog_type(struct bpf_prog_type_list *tl);
void bpf_register_map_type(struct bpf_map_type_list *tl);
+extern const struct file_operations bpf_map_fops;
+extern const struct file_operations bpf_prog_fops;
+
struct bpf_prog *bpf_prog_get(u32 ufd);
struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type);
struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i);
@@ -258,11 +267,11 @@
extern int sysctl_unprivileged_bpf_disabled;
-int bpf_map_new_fd(struct bpf_map *map);
+int bpf_map_new_fd(struct bpf_map *map, int flags);
int bpf_prog_new_fd(struct bpf_prog *prog);
int bpf_obj_pin_user(u32 ufd, const char __user *pathname);
-int bpf_obj_get_user(const char __user *pathname);
+int bpf_obj_get_user(const char __user *pathname, int flags);
int bpf_percpu_hash_copy(struct bpf_map *map, void *key, void *value);
int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value);
@@ -277,6 +286,8 @@
void *key, void *value, u64 map_flags);
void bpf_fd_array_map_clear(struct bpf_map *map);
+int bpf_get_file_flag(int flags);
+
/* memcpy that is used with 8-byte aligned pointers, power-of-8 size and
* forced to use 'long' read/writes to try to atomically copy long counters.
* Best-effort only. No barriers here, since it _will_ race with concurrent
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index 928e5ca..3a8c897 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -66,18 +66,22 @@
/*
* Force always-inline if the user requests it so via the .config,
- * or if gcc is too old:
+ * or if gcc is too old.
+ * GCC does not warn about unused static inline functions for
+ * -Wunused-function. This turns out to avoid the need for complex #ifdef
+ * directives. Suppress the warning in clang as well by using "unused"
+ * function attribute, which is redundant but not harmful for gcc.
*/
#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) || \
!defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4)
-#define inline inline __attribute__((always_inline)) notrace
-#define __inline__ __inline__ __attribute__((always_inline)) notrace
-#define __inline __inline __attribute__((always_inline)) notrace
+#define inline inline __attribute__((always_inline,unused)) notrace
+#define __inline__ __inline__ __attribute__((always_inline,unused)) notrace
+#define __inline __inline __attribute__((always_inline,unused)) notrace
#else
/* A lot of inline functions can cause havoc with function tracing */
-#define inline inline notrace
-#define __inline__ __inline__ notrace
-#define __inline __inline notrace
+#define inline inline __attribute__((unused)) notrace
+#define __inline__ __inline__ __attribute__((unused)) notrace
+#define __inline __inline __attribute__((unused)) notrace
#endif
#define __always_inline inline __attribute__((always_inline))
@@ -187,6 +191,10 @@
#endif /* __CHECKER__ */
#endif /* GCC_VERSION >= 40300 */
+#if GCC_VERSION >= 40400
+#define __optimize(level) __attribute__((__optimize__(level)))
+#endif /* GCC_VERSION >= 40400 */
+
#if GCC_VERSION >= 40500
#ifndef __CHECKER__
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index cf0fa5d..5ce911d 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -469,6 +469,10 @@
# define __native_word(t) (sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))
#endif
+#ifndef __optimize
+# define __optimize(level)
+#endif
+
/* Compile time object size, -1 for unknown */
#ifndef __compiletime_object_size
# define __compiletime_object_size(obj) -1
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 23beb58..45d5522 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -941,5 +941,6 @@
struct sched_domain;
unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu);
-unsigned long cpufreq_scale_max_freq_capacity(int cpu);
+unsigned long cpufreq_scale_max_freq_capacity(struct sched_domain *sd, int cpu);
+unsigned long cpufreq_scale_min_freq_capacity(struct sched_domain *sd, int cpu);
#endif /* _LINUX_CPUFREQ_H */
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 7cee555..6666ea0 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/uaccess.h>
+#include <linux/completion.h>
/*
* Autoloaded crypto modules should only use a prefixed name to avoid allowing
@@ -103,8 +104,16 @@
#define CRYPTO_ALG_INTERNAL 0x00002000
/*
+ * Set if the algorithm has a ->setkey() method but can be used without
+ * calling it first, i.e. there is a default key.
+ */
+#define CRYPTO_ALG_OPTIONAL_KEY 0x00004000
+
+/*
* Transform masks and values (for crt_flags).
*/
+#define CRYPTO_TFM_NEED_KEY 0x00000001
+
#define CRYPTO_TFM_REQ_MASK 0x000fff00
#define CRYPTO_TFM_RES_MASK 0xfff00000
@@ -465,6 +474,45 @@
} CRYPTO_MINALIGN_ATTR;
/*
+ * A helper struct for waiting for completion of async crypto ops
+ */
+struct crypto_wait {
+ struct completion completion;
+ int err;
+};
+
+/*
+ * Macro for declaring a crypto op async wait object on stack
+ */
+#define DECLARE_CRYPTO_WAIT(_wait) \
+ struct crypto_wait _wait = { \
+ COMPLETION_INITIALIZER_ONSTACK((_wait).completion), 0 }
+
+/*
+ * Async ops completion helper functioons
+ */
+void crypto_req_done(struct crypto_async_request *req, int err);
+
+static inline int crypto_wait_req(int err, struct crypto_wait *wait)
+{
+ switch (err) {
+ case -EINPROGRESS:
+ case -EBUSY:
+ wait_for_completion(&wait->completion);
+ reinit_completion(&wait->completion);
+ err = wait->err;
+ break;
+ };
+
+ return err;
+}
+
+static inline void crypto_init_wait(struct crypto_wait *wait)
+{
+ init_completion(&wait->completion);
+}
+
+/*
* Algorithm registration interface.
*/
int crypto_register_alg(struct crypto_alg *alg);
diff --git a/include/linux/efi.h b/include/linux/efi.h
index cba7177..5e204a5 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1427,7 +1427,7 @@
unsigned long *load_addr,
unsigned long *load_size);
-efi_status_t efi_parse_options(char *cmdline);
+efi_status_t efi_parse_options(char const *cmdline);
efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg,
struct screen_info *si, efi_guid_t *proto,
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index e46e7d1..58aecb6 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -32,9 +32,17 @@
/* 0, 1(node nid), 2(meta nid) are reserved node id */
#define F2FS_RESERVED_NODE_NUM 3
-#define F2FS_ROOT_INO(sbi) (sbi->root_ino_num)
-#define F2FS_NODE_INO(sbi) (sbi->node_ino_num)
-#define F2FS_META_INO(sbi) (sbi->meta_ino_num)
+#define F2FS_ROOT_INO(sbi) ((sbi)->root_ino_num)
+#define F2FS_NODE_INO(sbi) ((sbi)->node_ino_num)
+#define F2FS_META_INO(sbi) ((sbi)->meta_ino_num)
+
+#define F2FS_MAX_QUOTAS 3
+
+#define F2FS_IO_SIZE(sbi) (1 << (sbi)->write_io_size_bits) /* Blocks */
+#define F2FS_IO_SIZE_KB(sbi) (1 << ((sbi)->write_io_size_bits + 2)) /* KB */
+#define F2FS_IO_SIZE_BYTES(sbi) (1 << ((sbi)->write_io_size_bits + 12)) /* B */
+#define F2FS_IO_SIZE_BITS(sbi) ((sbi)->write_io_size_bits) /* power of 2 */
+#define F2FS_IO_SIZE_MASK(sbi) (F2FS_IO_SIZE(sbi) - 1)
/* This flag is used by node and meta inodes, and by recovery */
#define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO)
@@ -52,10 +60,17 @@
#define VERSION_LEN 256
#define MAX_VOLUME_NAME 512
+#define MAX_PATH_LEN 64
+#define MAX_DEVICES 8
/*
* For superblock
*/
+struct f2fs_device {
+ __u8 path[MAX_PATH_LEN];
+ __le32 total_segments;
+} __packed;
+
struct f2fs_super_block {
__le32 magic; /* Magic Number */
__le16 major_ver; /* Major Version */
@@ -94,12 +109,17 @@
__le32 feature; /* defined features */
__u8 encryption_level; /* versioning level for encryption */
__u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */
- __u8 reserved[871]; /* valid reserved region */
+ struct f2fs_device devs[MAX_DEVICES]; /* device list */
+ __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */
+ __u8 reserved[315]; /* valid reserved region */
} __packed;
/*
* For checkpoint
*/
+#define CP_NOCRC_RECOVERY_FLAG 0x00000200
+#define CP_TRIMMED_FLAG 0x00000100
+#define CP_NAT_BITS_FLAG 0x00000080
#define CP_CRC_RECOVERY_FLAG 0x00000040
#define CP_FASTBOOT_FLAG 0x00000020
#define CP_FSCK_FLAG 0x00000010
@@ -146,7 +166,7 @@
*/
#define F2FS_ORPHANS_PER_BLOCK 1020
-#define GET_ORPHAN_BLOCKS(n) ((n + F2FS_ORPHANS_PER_BLOCK - 1) / \
+#define GET_ORPHAN_BLOCKS(n) (((n) + F2FS_ORPHANS_PER_BLOCK - 1) / \
F2FS_ORPHANS_PER_BLOCK)
struct f2fs_orphan_block {
@@ -168,8 +188,11 @@
} __packed;
#define F2FS_NAME_LEN 255
-#define F2FS_INLINE_XATTR_ADDRS 50 /* 200 bytes for inline xattrs */
+/* 200 bytes for inline xattrs by default */
+#define DEFAULT_INLINE_XATTR_ADDRS 50
#define DEF_ADDRS_PER_INODE 923 /* Address Pointers in an Inode */
+#define CUR_ADDRS_PER_INODE(inode) (DEF_ADDRS_PER_INODE - \
+ get_extra_isize(inode))
#define DEF_NIDS_PER_INODE 5 /* Node IDs in an Inode */
#define ADDRS_PER_INODE(inode) addrs_per_inode(inode)
#define ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */
@@ -189,9 +212,8 @@
#define F2FS_INLINE_DENTRY 0x04 /* file inline dentry flag */
#define F2FS_DATA_EXIST 0x08 /* file inline data exist flag */
#define F2FS_INLINE_DOTS 0x10 /* file having implicit dot dentries */
-
-#define MAX_INLINE_DATA (sizeof(__le32) * (DEF_ADDRS_PER_INODE - \
- F2FS_INLINE_XATTR_ADDRS - 1))
+#define F2FS_EXTRA_ATTR 0x20 /* file having extra attribute */
+#define F2FS_PIN_FILE 0x40 /* file should not be gced */
struct f2fs_inode {
__le16 i_mode; /* file mode */
@@ -209,7 +231,13 @@
__le32 i_ctime_nsec; /* change time in nano scale */
__le32 i_mtime_nsec; /* modification time in nano scale */
__le32 i_generation; /* file version (for NFS) */
- __le32 i_current_depth; /* only for directory depth */
+ union {
+ __le32 i_current_depth; /* only for directory depth */
+ __le16 i_gc_failures; /*
+ * # of gc failures on pinned file.
+ * only for regular files.
+ */
+ };
__le32 i_xattr_nid; /* nid to save xattr */
__le32 i_flags; /* file attributes */
__le32 i_pino; /* parent inode number */
@@ -219,8 +247,18 @@
struct f2fs_extent i_ext; /* caching a largest extent */
- __le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */
-
+ union {
+ struct {
+ __le16 i_extra_isize; /* extra inode attribute size */
+ __le16 i_inline_xattr_size; /* inline xattr size, unit: 4 bytes */
+ __le32 i_projid; /* project id */
+ __le32 i_inode_checksum;/* inode meta checksum */
+ __le64 i_crtime; /* creation time */
+ __le32 i_crtime_nsec; /* creation time in nano scale */
+ __le32 i_extra_end[0]; /* for attribute size calculation */
+ } __packed;
+ __le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */
+ };
__le32 i_nid[DEF_NIDS_PER_INODE]; /* direct(2), indirect(2),
double_indirect(1) node id */
} __packed;
@@ -264,6 +302,7 @@
* For NAT entries
*/
#define NAT_ENTRY_PER_BLOCK (PAGE_SIZE / sizeof(struct f2fs_nat_entry))
+#define NAT_ENTRY_BITMAP_SIZE ((NAT_ENTRY_PER_BLOCK + 7) / 8)
struct f2fs_nat_entry {
__u8 version; /* latest version of cached nat entry */
@@ -439,7 +478,7 @@
#define F2FS_SLOT_LEN 8
#define F2FS_SLOT_LEN_BITS 3
-#define GET_DENTRY_SLOTS(x) ((x + F2FS_SLOT_LEN - 1) >> F2FS_SLOT_LEN_BITS)
+#define GET_DENTRY_SLOTS(x) (((x) + F2FS_SLOT_LEN - 1) >> F2FS_SLOT_LEN_BITS)
/* MAX level for dir lookup */
#define MAX_DIR_HASH_DEPTH 63
@@ -448,7 +487,7 @@
#define MAX_DIR_BUCKETS (1 << ((MAX_DIR_HASH_DEPTH / 2) - 1))
/*
- * space utilization of regular dentry and inline dentry
+ * space utilization of regular dentry and inline dentry (w/o extra reservation)
* regular dentry inline dentry
* bitmap 1 * 27 = 27 1 * 23 = 23
* reserved 1 * 3 = 3 1 * 7 = 7
@@ -484,24 +523,6 @@
__u8 filename[NR_DENTRY_IN_BLOCK][F2FS_SLOT_LEN];
} __packed;
-/* for inline dir */
-#define NR_INLINE_DENTRY (MAX_INLINE_DATA * BITS_PER_BYTE / \
- ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
- BITS_PER_BYTE + 1))
-#define INLINE_DENTRY_BITMAP_SIZE ((NR_INLINE_DENTRY + \
- BITS_PER_BYTE - 1) / BITS_PER_BYTE)
-#define INLINE_RESERVED_SIZE (MAX_INLINE_DATA - \
- ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
- NR_INLINE_DENTRY + INLINE_DENTRY_BITMAP_SIZE))
-
-/* inline directory entry structure */
-struct f2fs_inline_dentry {
- __u8 dentry_bitmap[INLINE_DENTRY_BITMAP_SIZE];
- __u8 reserved[INLINE_RESERVED_SIZE];
- struct f2fs_dir_entry dentry[NR_INLINE_DENTRY];
- __u8 filename[NR_INLINE_DENTRY][F2FS_SLOT_LEN];
-} __packed;
-
/* file types used in inode_info->flags */
enum {
F2FS_FT_UNKNOWN,
@@ -517,4 +538,6 @@
#define S_SHIFT 12
+#define F2FS_DEF_PROJID 0 /* default project ID */
+
#endif /* _LINUX_F2FS_FS_H */
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index 6e84b2cae..442b54a 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -9,6 +9,7 @@
#include <linux/compiler.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
+#include <linux/nospec.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/fs.h>
@@ -81,8 +82,10 @@
{
struct fdtable *fdt = rcu_dereference_raw(files->fdt);
- if (fd < fdt->max_fds)
+ if (fd < fdt->max_fds) {
+ fd = array_index_nospec(fd, fdt->max_fds);
return rcu_dereference_raw(fdt->fd[fd]);
+ }
return NULL;
}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4f6ec47..4abfa9c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -475,6 +475,7 @@
int bd_invalidated;
struct gendisk * bd_disk;
struct request_queue * bd_queue;
+ struct backing_dev_info *bd_bdi;
struct list_head bd_list;
/*
* Private data. You must have bd_claim'ed the block_device
@@ -1857,6 +1858,7 @@
#else
#define S_DAX 0 /* Make all the DAX code disappear */
#endif
+#define S_ENCRYPTED 16384 /* Encrypted file (using fs/crypto/) */
/*
* Note that nosuid etc flags are inode-specific: setting some file-system
@@ -1895,6 +1897,7 @@
#define IS_AUTOMOUNT(inode) ((inode)->i_flags & S_AUTOMOUNT)
#define IS_NOSEC(inode) ((inode)->i_flags & S_NOSEC)
#define IS_DAX(inode) ((inode)->i_flags & S_DAX)
+#define IS_ENCRYPTED(inode) ((inode)->i_flags & S_ENCRYPTED)
#define IS_WHITEOUT(inode) (S_ISCHR(inode->i_mode) && \
(inode)->i_rdev == WHITEOUT_DEV)
@@ -2398,6 +2401,7 @@
#ifdef CONFIG_BLOCK
extern int register_blkdev(unsigned int, const char *);
extern void unregister_blkdev(unsigned int, const char *);
+extern void bdev_unhash_inode(dev_t dev);
extern struct block_device *bdget(dev_t);
extern struct block_device *bdgrab(struct block_device *bdev);
extern void bd_set_size(struct block_device *, loff_t size);
@@ -2925,8 +2929,6 @@
wake_up_bit(&inode->i_state, __I_DIO_WAKEUP);
}
-struct inode *dio_bio_get_inode(struct bio *bio);
-
extern void inode_set_flags(struct inode *inode, unsigned int flags,
unsigned int mask);
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
new file mode 100644
index 0000000..8641e56
--- /dev/null
+++ b/include/linux/fscrypt.h
@@ -0,0 +1,290 @@
+/*
+ * fscrypt.h: declarations for per-file encryption
+ *
+ * Filesystems that implement per-file encryption include this header
+ * file with the __FS_HAS_ENCRYPTION set according to whether that filesystem
+ * is being built with encryption support or not.
+ *
+ * Copyright (C) 2015, Google, Inc.
+ *
+ * Written by Michael Halcrow, 2015.
+ * Modified by Jaegeuk Kim, 2015.
+ */
+#ifndef _LINUX_FSCRYPT_H
+#define _LINUX_FSCRYPT_H
+
+#include <linux/key.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/bio.h>
+#include <linux/dcache.h>
+#include <crypto/skcipher.h>
+#include <uapi/linux/fs.h>
+
+#define FS_CRYPTO_BLOCK_SIZE 16
+
+struct fscrypt_info;
+
+struct fscrypt_ctx {
+ union {
+ struct {
+ struct page *bounce_page; /* Ciphertext page */
+ struct page *control_page; /* Original page */
+ } w;
+ struct {
+ struct bio *bio;
+ struct work_struct work;
+ } r;
+ struct list_head free_list; /* Free list */
+ };
+ u8 flags; /* Flags */
+};
+
+/**
+ * For encrypted symlinks, the ciphertext length is stored at the beginning
+ * of the string in little-endian format.
+ */
+struct fscrypt_symlink_data {
+ __le16 len;
+ char encrypted_path[1];
+} __packed;
+
+struct fscrypt_str {
+ unsigned char *name;
+ u32 len;
+};
+
+struct fscrypt_name {
+ const struct qstr *usr_fname;
+ struct fscrypt_str disk_name;
+ u32 hash;
+ u32 minor_hash;
+ struct fscrypt_str crypto_buf;
+};
+
+#define FSTR_INIT(n, l) { .name = n, .len = l }
+#define FSTR_TO_QSTR(f) QSTR_INIT((f)->name, (f)->len)
+#define fname_name(p) ((p)->disk_name.name)
+#define fname_len(p) ((p)->disk_name.len)
+
+/*
+ * fscrypt superblock flags
+ */
+#define FS_CFLG_OWN_PAGES (1U << 1)
+
+/*
+ * crypto opertions for filesystems
+ */
+struct fscrypt_operations {
+ unsigned int flags;
+ const char *key_prefix;
+ int (*get_context)(struct inode *, void *, size_t);
+ int (*set_context)(struct inode *, const void *, size_t, void *);
+ bool (*dummy_context)(struct inode *);
+ bool (*empty_dir)(struct inode *);
+ unsigned (*max_namelen)(struct inode *);
+};
+
+static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
+{
+ if (inode->i_sb->s_cop->dummy_context &&
+ inode->i_sb->s_cop->dummy_context(inode))
+ return true;
+ return false;
+}
+
+static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
+ u32 filenames_mode)
+{
+ if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC &&
+ filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS)
+ return true;
+
+ if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS &&
+ filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
+ return true;
+
+ return false;
+}
+
+static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
+{
+ if (str->len == 1 && str->name[0] == '.')
+ return true;
+
+ if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
+ return true;
+
+ return false;
+}
+
+#if __FS_HAS_ENCRYPTION
+
+static inline struct page *fscrypt_control_page(struct page *page)
+{
+ return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
+}
+
+static inline bool fscrypt_has_encryption_key(const struct inode *inode)
+{
+ return (inode->i_crypt_info != NULL);
+}
+
+#include <linux/fscrypt_supp.h>
+
+#else /* !__FS_HAS_ENCRYPTION */
+
+static inline struct page *fscrypt_control_page(struct page *page)
+{
+ WARN_ON_ONCE(1);
+ return ERR_PTR(-EINVAL);
+}
+
+static inline bool fscrypt_has_encryption_key(const struct inode *inode)
+{
+ return 0;
+}
+
+#include <linux/fscrypt_notsupp.h>
+#endif /* __FS_HAS_ENCRYPTION */
+
+/**
+ * fscrypt_require_key - require an inode's encryption key
+ * @inode: the inode we need the key for
+ *
+ * If the inode is encrypted, set up its encryption key if not already done.
+ * Then require that the key be present and return -ENOKEY otherwise.
+ *
+ * No locks are needed, and the key will live as long as the struct inode --- so
+ * it won't go away from under you.
+ *
+ * Return: 0 on success, -ENOKEY if the key is missing, or another -errno code
+ * if a problem occurred while setting up the encryption key.
+ */
+static inline int fscrypt_require_key(struct inode *inode)
+{
+ if (IS_ENCRYPTED(inode)) {
+ int err = fscrypt_get_encryption_info(inode);
+
+ if (err)
+ return err;
+ if (!fscrypt_has_encryption_key(inode))
+ return -ENOKEY;
+ }
+ return 0;
+}
+
+/**
+ * fscrypt_prepare_link - prepare to link an inode into a possibly-encrypted directory
+ * @old_dentry: an existing dentry for the inode being linked
+ * @dir: the target directory
+ * @dentry: negative dentry for the target filename
+ *
+ * A new link can only be added to an encrypted directory if the directory's
+ * encryption key is available --- since otherwise we'd have no way to encrypt
+ * the filename. Therefore, we first set up the directory's encryption key (if
+ * not already done) and return an error if it's unavailable.
+ *
+ * We also verify that the link will not violate the constraint that all files
+ * in an encrypted directory tree use the same encryption policy.
+ *
+ * Return: 0 on success, -ENOKEY if the directory's encryption key is missing,
+ * -EPERM if the link would result in an inconsistent encryption policy, or
+ * another -errno code.
+ */
+static inline int fscrypt_prepare_link(struct dentry *old_dentry,
+ struct inode *dir,
+ struct dentry *dentry)
+{
+ if (IS_ENCRYPTED(dir))
+ return __fscrypt_prepare_link(d_inode(old_dentry), dir);
+ return 0;
+}
+
+/**
+ * fscrypt_prepare_rename - prepare for a rename between possibly-encrypted directories
+ * @old_dir: source directory
+ * @old_dentry: dentry for source file
+ * @new_dir: target directory
+ * @new_dentry: dentry for target location (may be negative unless exchanging)
+ * @flags: rename flags (we care at least about %RENAME_EXCHANGE)
+ *
+ * Prepare for ->rename() where the source and/or target directories may be
+ * encrypted. A new link can only be added to an encrypted directory if the
+ * directory's encryption key is available --- since otherwise we'd have no way
+ * to encrypt the filename. A rename to an existing name, on the other hand,
+ * *is* cryptographically possible without the key. However, we take the more
+ * conservative approach and just forbid all no-key renames.
+ *
+ * We also verify that the rename will not violate the constraint that all files
+ * in an encrypted directory tree use the same encryption policy.
+ *
+ * Return: 0 on success, -ENOKEY if an encryption key is missing, -EPERM if the
+ * rename would cause inconsistent encryption policies, or another -errno code.
+ */
+static inline int fscrypt_prepare_rename(struct inode *old_dir,
+ struct dentry *old_dentry,
+ struct inode *new_dir,
+ struct dentry *new_dentry,
+ unsigned int flags)
+{
+ if (IS_ENCRYPTED(old_dir) || IS_ENCRYPTED(new_dir))
+ return __fscrypt_prepare_rename(old_dir, old_dentry,
+ new_dir, new_dentry, flags);
+ return 0;
+}
+
+/**
+ * fscrypt_prepare_lookup - prepare to lookup a name in a possibly-encrypted directory
+ * @dir: directory being searched
+ * @dentry: filename being looked up
+ * @flags: lookup flags
+ *
+ * Prepare for ->lookup() in a directory which may be encrypted. Lookups can be
+ * done with or without the directory's encryption key; without the key,
+ * filenames are presented in encrypted form. Therefore, we'll try to set up
+ * the directory's encryption key, but even without it the lookup can continue.
+ *
+ * To allow invalidating stale dentries if the directory's encryption key is
+ * added later, we also install a custom ->d_revalidate() method and use the
+ * DCACHE_ENCRYPTED_WITH_KEY flag to indicate whether a given dentry is a
+ * plaintext name (flag set) or a ciphertext name (flag cleared).
+ *
+ * Return: 0 on success, -errno if a problem occurred while setting up the
+ * encryption key
+ */
+static inline int fscrypt_prepare_lookup(struct inode *dir,
+ struct dentry *dentry,
+ unsigned int flags)
+{
+ if (IS_ENCRYPTED(dir))
+ return __fscrypt_prepare_lookup(dir, dentry);
+ return 0;
+}
+
+/**
+ * fscrypt_prepare_setattr - prepare to change a possibly-encrypted inode's attributes
+ * @dentry: dentry through which the inode is being changed
+ * @attr: attributes to change
+ *
+ * Prepare for ->setattr() on a possibly-encrypted inode. On an encrypted file,
+ * most attribute changes are allowed even without the encryption key. However,
+ * without the encryption key we do have to forbid truncates. This is needed
+ * because the size being truncated to may not be a multiple of the filesystem
+ * block size, and in that case we'd have to decrypt the final block, zero the
+ * portion past i_size, and re-encrypt it. (We *could* allow truncating to a
+ * filesystem block boundary, but it's simpler to just forbid all truncates ---
+ * and we already forbid all other contents modifications without the key.)
+ *
+ * Return: 0 on success, -ENOKEY if the key is missing, or another -errno code
+ * if a problem occurred while setting up the encryption key.
+ */
+static inline int fscrypt_prepare_setattr(struct dentry *dentry,
+ struct iattr *attr)
+{
+ if (attr->ia_valid & ATTR_SIZE)
+ return fscrypt_require_key(d_inode(dentry));
+ return 0;
+}
+
+#endif /* _LINUX_FSCRYPT_H */
diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h
new file mode 100644
index 0000000..c4c6bf2
--- /dev/null
+++ b/include/linux/fscrypt_notsupp.h
@@ -0,0 +1,210 @@
+/*
+ * fscrypt_notsupp.h
+ *
+ * This stubs out the fscrypt functions for filesystems configured without
+ * encryption support.
+ *
+ * Do not include this file directly. Use fscrypt.h instead!
+ */
+#ifndef _LINUX_FSCRYPT_H
+#error "Incorrect include of linux/fscrypt_notsupp.h!"
+#endif
+
+#ifndef _LINUX_FSCRYPT_NOTSUPP_H
+#define _LINUX_FSCRYPT_NOTSUPP_H
+
+/* crypto.c */
+static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode,
+ gfp_t gfp_flags)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline void fscrypt_release_ctx(struct fscrypt_ctx *ctx)
+{
+ return;
+}
+
+static inline struct page *fscrypt_encrypt_page(const struct inode *inode,
+ struct page *page,
+ unsigned int len,
+ unsigned int offs,
+ u64 lblk_num, gfp_t gfp_flags)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline int fscrypt_decrypt_page(const struct inode *inode,
+ struct page *page,
+ unsigned int len, unsigned int offs,
+ u64 lblk_num)
+{
+ return -EOPNOTSUPP;
+}
+
+
+static inline void fscrypt_restore_control_page(struct page *page)
+{
+ return;
+}
+
+static inline void fscrypt_set_d_op(struct dentry *dentry)
+{
+ return;
+}
+
+static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry)
+{
+ return;
+}
+
+/* policy.c */
+static inline int fscrypt_ioctl_set_policy(struct file *filp,
+ const void __user *arg)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int fscrypt_has_permitted_context(struct inode *parent,
+ struct inode *child)
+{
+ return 0;
+}
+
+static inline int fscrypt_inherit_context(struct inode *parent,
+ struct inode *child,
+ void *fs_data, bool preload)
+{
+ return -EOPNOTSUPP;
+}
+
+/* keyinfo.c */
+static inline int fscrypt_get_encryption_info(struct inode *inode)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void fscrypt_put_encryption_info(struct inode *inode,
+ struct fscrypt_info *ci)
+{
+ return;
+}
+
+ /* fname.c */
+static inline int fscrypt_setup_filename(struct inode *dir,
+ const struct qstr *iname,
+ int lookup, struct fscrypt_name *fname)
+{
+ if (IS_ENCRYPTED(dir))
+ return -EOPNOTSUPP;
+
+ memset(fname, 0, sizeof(struct fscrypt_name));
+ fname->usr_fname = iname;
+ fname->disk_name.name = (unsigned char *)iname->name;
+ fname->disk_name.len = iname->len;
+ return 0;
+}
+
+static inline void fscrypt_free_filename(struct fscrypt_name *fname)
+{
+ return;
+}
+
+static inline u32 fscrypt_fname_encrypted_size(const struct inode *inode,
+ u32 ilen)
+{
+ /* never happens */
+ WARN_ON(1);
+ return 0;
+}
+
+static inline int fscrypt_fname_alloc_buffer(const struct inode *inode,
+ u32 ilen,
+ struct fscrypt_str *crypto_str)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str)
+{
+ return;
+}
+
+static inline int fscrypt_fname_disk_to_usr(struct inode *inode,
+ u32 hash, u32 minor_hash,
+ const struct fscrypt_str *iname,
+ struct fscrypt_str *oname)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int fscrypt_fname_usr_to_disk(struct inode *inode,
+ const struct qstr *iname,
+ struct fscrypt_str *oname)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline bool fscrypt_match_name(const struct fscrypt_name *fname,
+ const u8 *de_name, u32 de_name_len)
+{
+ /* Encryption support disabled; use standard comparison */
+ if (de_name_len != fname->disk_name.len)
+ return false;
+ return !memcmp(de_name, fname->disk_name.name, fname->disk_name.len);
+}
+
+/* bio.c */
+static inline void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx,
+ struct bio *bio)
+{
+ return;
+}
+
+static inline void fscrypt_pullback_bio_page(struct page **page, bool restore)
+{
+ return;
+}
+
+static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
+ sector_t pblk, unsigned int len)
+{
+ return -EOPNOTSUPP;
+}
+
+/* hooks.c */
+
+static inline int fscrypt_file_open(struct inode *inode, struct file *filp)
+{
+ if (IS_ENCRYPTED(inode))
+ return -EOPNOTSUPP;
+ return 0;
+}
+
+static inline int __fscrypt_prepare_link(struct inode *inode,
+ struct inode *dir)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int __fscrypt_prepare_rename(struct inode *old_dir,
+ struct dentry *old_dentry,
+ struct inode *new_dir,
+ struct dentry *new_dentry,
+ unsigned int flags)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int __fscrypt_prepare_lookup(struct inode *dir,
+ struct dentry *dentry)
+{
+ return -EOPNOTSUPP;
+}
+
+#endif /* _LINUX_FSCRYPT_NOTSUPP_H */
diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h
new file mode 100644
index 0000000..2db5e970
--- /dev/null
+++ b/include/linux/fscrypt_supp.h
@@ -0,0 +1,156 @@
+/*
+ * fscrypt_supp.h
+ *
+ * Do not include this file directly. Use fscrypt.h instead!
+ */
+#ifndef _LINUX_FSCRYPT_H
+#error "Incorrect include of linux/fscrypt_supp.h!"
+#endif
+
+#ifndef _LINUX_FSCRYPT_SUPP_H
+#define _LINUX_FSCRYPT_SUPP_H
+
+/* crypto.c */
+extern struct kmem_cache *fscrypt_info_cachep;
+extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t);
+extern void fscrypt_release_ctx(struct fscrypt_ctx *);
+extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *,
+ unsigned int, unsigned int,
+ u64, gfp_t);
+extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int,
+ unsigned int, u64);
+extern void fscrypt_restore_control_page(struct page *);
+
+extern const struct dentry_operations fscrypt_d_ops;
+
+static inline void fscrypt_set_d_op(struct dentry *dentry)
+{
+ d_set_d_op(dentry, &fscrypt_d_ops);
+}
+
+static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry)
+{
+ spin_lock(&dentry->d_lock);
+ dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY;
+ spin_unlock(&dentry->d_lock);
+}
+
+/* policy.c */
+extern int fscrypt_ioctl_set_policy(struct file *, const void __user *);
+extern int fscrypt_ioctl_get_policy(struct file *, void __user *);
+extern int fscrypt_has_permitted_context(struct inode *, struct inode *);
+extern int fscrypt_inherit_context(struct inode *, struct inode *,
+ void *, bool);
+/* keyinfo.c */
+extern int fscrypt_get_encryption_info(struct inode *);
+extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *);
+
+/* fname.c */
+extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
+ int lookup, struct fscrypt_name *);
+
+static inline void fscrypt_free_filename(struct fscrypt_name *fname)
+{
+ kfree(fname->crypto_buf.name);
+}
+
+extern u32 fscrypt_fname_encrypted_size(const struct inode *, u32);
+extern int fscrypt_fname_alloc_buffer(const struct inode *, u32,
+ struct fscrypt_str *);
+extern void fscrypt_fname_free_buffer(struct fscrypt_str *);
+extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32,
+ const struct fscrypt_str *, struct fscrypt_str *);
+extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *,
+ struct fscrypt_str *);
+
+#define FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE 32
+
+/* Extracts the second-to-last ciphertext block; see explanation below */
+#define FSCRYPT_FNAME_DIGEST(name, len) \
+ ((name) + round_down((len) - FS_CRYPTO_BLOCK_SIZE - 1, \
+ FS_CRYPTO_BLOCK_SIZE))
+
+#define FSCRYPT_FNAME_DIGEST_SIZE FS_CRYPTO_BLOCK_SIZE
+
+/**
+ * fscrypt_digested_name - alternate identifier for an on-disk filename
+ *
+ * When userspace lists an encrypted directory without access to the key,
+ * filenames whose ciphertext is longer than FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE
+ * bytes are shown in this abbreviated form (base64-encoded) rather than as the
+ * full ciphertext (base64-encoded). This is necessary to allow supporting
+ * filenames up to NAME_MAX bytes, since base64 encoding expands the length.
+ *
+ * To make it possible for filesystems to still find the correct directory entry
+ * despite not knowing the full on-disk name, we encode any filesystem-specific
+ * 'hash' and/or 'minor_hash' which the filesystem may need for its lookups,
+ * followed by the second-to-last ciphertext block of the filename. Due to the
+ * use of the CBC-CTS encryption mode, the second-to-last ciphertext block
+ * depends on the full plaintext. (Note that ciphertext stealing causes the
+ * last two blocks to appear "flipped".) This makes accidental collisions very
+ * unlikely: just a 1 in 2^128 chance for two filenames to collide even if they
+ * share the same filesystem-specific hashes.
+ *
+ * However, this scheme isn't immune to intentional collisions, which can be
+ * created by anyone able to create arbitrary plaintext filenames and view them
+ * without the key. Making the "digest" be a real cryptographic hash like
+ * SHA-256 over the full ciphertext would prevent this, although it would be
+ * less efficient and harder to implement, especially since the filesystem would
+ * need to calculate it for each directory entry examined during a search.
+ */
+struct fscrypt_digested_name {
+ u32 hash;
+ u32 minor_hash;
+ u8 digest[FSCRYPT_FNAME_DIGEST_SIZE];
+};
+
+/**
+ * fscrypt_match_name() - test whether the given name matches a directory entry
+ * @fname: the name being searched for
+ * @de_name: the name from the directory entry
+ * @de_name_len: the length of @de_name in bytes
+ *
+ * Normally @fname->disk_name will be set, and in that case we simply compare
+ * that to the name stored in the directory entry. The only exception is that
+ * if we don't have the key for an encrypted directory and a filename in it is
+ * very long, then we won't have the full disk_name and we'll instead need to
+ * match against the fscrypt_digested_name.
+ *
+ * Return: %true if the name matches, otherwise %false.
+ */
+static inline bool fscrypt_match_name(const struct fscrypt_name *fname,
+ const u8 *de_name, u32 de_name_len)
+{
+ if (unlikely(!fname->disk_name.name)) {
+ const struct fscrypt_digested_name *n =
+ (const void *)fname->crypto_buf.name;
+ if (WARN_ON_ONCE(fname->usr_fname->name[0] != '_'))
+ return false;
+ if (de_name_len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE)
+ return false;
+ return !memcmp(FSCRYPT_FNAME_DIGEST(de_name, de_name_len),
+ n->digest, FSCRYPT_FNAME_DIGEST_SIZE);
+ }
+
+ if (de_name_len != fname->disk_name.len)
+ return false;
+ return !memcmp(de_name, fname->disk_name.name, fname->disk_name.len);
+}
+
+/* bio.c */
+extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *);
+extern void fscrypt_pullback_bio_page(struct page **, bool);
+extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t,
+ unsigned int);
+
+/* hooks.c */
+extern int fscrypt_file_open(struct inode *inode, struct file *filp);
+extern int __fscrypt_prepare_link(struct inode *inode, struct inode *dir);
+extern int __fscrypt_prepare_rename(struct inode *old_dir,
+ struct dentry *old_dentry,
+ struct inode *new_dir,
+ struct dentry *new_dentry,
+ unsigned int flags);
+extern int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry);
+
+#endif /* _LINUX_FSCRYPT_SUPP_H */
diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
deleted file mode 100644
index 9b57c19..0000000
--- a/include/linux/fscrypto.h
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * General per-file encryption definition
- *
- * Copyright (C) 2015, Google, Inc.
- *
- * Written by Michael Halcrow, 2015.
- * Modified by Jaegeuk Kim, 2015.
- */
-
-#ifndef _LINUX_FSCRYPTO_H
-#define _LINUX_FSCRYPTO_H
-
-#include <linux/key.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/bio.h>
-#include <linux/dcache.h>
-#include <crypto/skcipher.h>
-#include <uapi/linux/fs.h>
-
-#define FS_KEY_DERIVATION_NONCE_SIZE 16
-#define FS_ENCRYPTION_CONTEXT_FORMAT_V1 1
-
-#define FS_POLICY_FLAGS_PAD_4 0x00
-#define FS_POLICY_FLAGS_PAD_8 0x01
-#define FS_POLICY_FLAGS_PAD_16 0x02
-#define FS_POLICY_FLAGS_PAD_32 0x03
-#define FS_POLICY_FLAGS_PAD_MASK 0x03
-#define FS_POLICY_FLAGS_VALID 0x03
-
-/* Encryption algorithms */
-#define FS_ENCRYPTION_MODE_INVALID 0
-#define FS_ENCRYPTION_MODE_AES_256_XTS 1
-#define FS_ENCRYPTION_MODE_AES_256_GCM 2
-#define FS_ENCRYPTION_MODE_AES_256_CBC 3
-#define FS_ENCRYPTION_MODE_AES_256_CTS 4
-#define FS_ENCRYPTION_MODE_PRIVATE 127
-
-/**
- * Encryption context for inode
- *
- * Protector format:
- * 1 byte: Protector format (1 = this version)
- * 1 byte: File contents encryption mode
- * 1 byte: File names encryption mode
- * 1 byte: Flags
- * 8 bytes: Master Key descriptor
- * 16 bytes: Encryption Key derivation nonce
- */
-struct fscrypt_context {
- u8 format;
- u8 contents_encryption_mode;
- u8 filenames_encryption_mode;
- u8 flags;
- u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
- u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
-} __packed;
-
-/* Encryption parameters */
-#define FS_XTS_TWEAK_SIZE 16
-#define FS_AES_128_ECB_KEY_SIZE 16
-#define FS_AES_256_GCM_KEY_SIZE 32
-#define FS_AES_256_CBC_KEY_SIZE 32
-#define FS_AES_256_CTS_KEY_SIZE 32
-#define FS_AES_256_XTS_KEY_SIZE 64
-#define FS_MAX_KEY_SIZE 64
-
-#define FS_KEY_DESC_PREFIX "fscrypt:"
-#define FS_KEY_DESC_PREFIX_SIZE 8
-
-/* This is passed in from userspace into the kernel keyring */
-struct fscrypt_key {
- u32 mode;
- u8 raw[FS_MAX_KEY_SIZE];
- u32 size;
-} __packed;
-
-struct fscrypt_info {
- u8 ci_data_mode;
- u8 ci_filename_mode;
- u8 ci_flags;
- struct crypto_skcipher *ci_ctfm;
- u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE];
- u8 ci_raw_key[FS_MAX_KEY_SIZE];
-};
-
-#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001
-#define FS_WRITE_PATH_FL 0x00000002
-
-struct fscrypt_ctx {
- union {
- struct {
- struct page *bounce_page; /* Ciphertext page */
- struct page *control_page; /* Original page */
- } w;
- struct {
- struct bio *bio;
- struct work_struct work;
- } r;
- struct list_head free_list; /* Free list */
- };
- u8 flags; /* Flags */
- u8 mode; /* Encryption mode for tfm */
-};
-
-struct fscrypt_completion_result {
- struct completion completion;
- int res;
-};
-
-#define DECLARE_FS_COMPLETION_RESULT(ecr) \
- struct fscrypt_completion_result ecr = { \
- COMPLETION_INITIALIZER((ecr).completion), 0 }
-
-#define FS_FNAME_NUM_SCATTER_ENTRIES 4
-#define FS_CRYPTO_BLOCK_SIZE 16
-#define FS_FNAME_CRYPTO_DIGEST_SIZE 32
-
-/**
- * For encrypted symlinks, the ciphertext length is stored at the beginning
- * of the string in little-endian format.
- */
-struct fscrypt_symlink_data {
- __le16 len;
- char encrypted_path[1];
-} __packed;
-
-/**
- * This function is used to calculate the disk space required to
- * store a filename of length l in encrypted symlink format.
- */
-static inline u32 fscrypt_symlink_data_len(u32 l)
-{
- if (l < FS_CRYPTO_BLOCK_SIZE)
- l = FS_CRYPTO_BLOCK_SIZE;
- return (l + sizeof(struct fscrypt_symlink_data) - 1);
-}
-
-struct fscrypt_str {
- unsigned char *name;
- u32 len;
-};
-
-struct fscrypt_name {
- const struct qstr *usr_fname;
- struct fscrypt_str disk_name;
- u32 hash;
- u32 minor_hash;
- struct fscrypt_str crypto_buf;
-};
-
-#define FSTR_INIT(n, l) { .name = n, .len = l }
-#define FSTR_TO_QSTR(f) QSTR_INIT((f)->name, (f)->len)
-#define fname_name(p) ((p)->disk_name.name)
-#define fname_len(p) ((p)->disk_name.len)
-
-/*
- * crypto opertions for filesystems
- */
-struct fscrypt_operations {
- int (*get_context)(struct inode *, void *, size_t);
- int (*key_prefix)(struct inode *, u8 **);
- int (*prepare_context)(struct inode *);
- int (*set_context)(struct inode *, const void *, size_t, void *);
- int (*dummy_context)(struct inode *);
- bool (*is_encrypted)(struct inode *);
- bool (*empty_dir)(struct inode *);
- unsigned (*max_namelen)(struct inode *);
-};
-
-static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
-{
- if (inode->i_sb->s_cop->dummy_context &&
- inode->i_sb->s_cop->dummy_context(inode))
- return true;
- return false;
-}
-
-static inline bool fscrypt_valid_contents_enc_mode(u32 mode)
-{
- return (mode == FS_ENCRYPTION_MODE_AES_256_XTS ||
- mode == FS_ENCRYPTION_MODE_PRIVATE);
-}
-
-static inline bool fscrypt_valid_filenames_enc_mode(u32 mode)
-{
- return (mode == FS_ENCRYPTION_MODE_AES_256_CTS);
-}
-
-static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
-{
- if (str->len == 1 && str->name[0] == '.')
- return true;
-
- if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
- return true;
-
- return false;
-}
-
-static inline struct page *fscrypt_control_page(struct page *page)
-{
-#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
- return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
-#else
- WARN_ON_ONCE(1);
- return ERR_PTR(-EINVAL);
-#endif
-}
-
-static inline int fscrypt_has_encryption_key(struct inode *inode)
-{
-#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
- return (inode->i_crypt_info != NULL);
-#else
- return 0;
-#endif
-}
-
-static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry)
-{
-#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
- spin_lock(&dentry->d_lock);
- dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY;
- spin_unlock(&dentry->d_lock);
-#endif
-}
-
-#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
-extern const struct dentry_operations fscrypt_d_ops;
-#endif
-
-static inline void fscrypt_set_d_op(struct dentry *dentry)
-{
-#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
- d_set_d_op(dentry, &fscrypt_d_ops);
-#endif
-}
-
-#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
-/* crypto.c */
-extern struct kmem_cache *fscrypt_info_cachep;
-int fscrypt_initialize(void);
-
-extern struct fscrypt_ctx *fscrypt_get_ctx(struct inode *, gfp_t);
-extern void fscrypt_release_ctx(struct fscrypt_ctx *);
-extern struct page *fscrypt_encrypt_page(struct inode *, struct page *, gfp_t);
-extern int fscrypt_decrypt_page(struct page *);
-extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *);
-extern void fscrypt_pullback_bio_page(struct page **, bool);
-extern void fscrypt_restore_control_page(struct page *);
-extern int fscrypt_zeroout_range(struct inode *, pgoff_t, sector_t,
- unsigned int);
-/* policy.c */
-extern int fscrypt_process_policy(struct file *, const struct fscrypt_policy *);
-extern int fscrypt_get_policy(struct inode *, struct fscrypt_policy *);
-extern int fscrypt_has_permitted_context(struct inode *, struct inode *);
-extern int fscrypt_inherit_context(struct inode *, struct inode *,
- void *, bool);
-/* keyinfo.c */
-extern int fscrypt_get_encryption_info(struct inode *);
-extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *);
-extern int fs_using_hardware_encryption(struct inode *inode);
-
-/* fname.c */
-extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
- int lookup, struct fscrypt_name *);
-extern void fscrypt_free_filename(struct fscrypt_name *);
-extern u32 fscrypt_fname_encrypted_size(struct inode *, u32);
-extern int fscrypt_fname_alloc_buffer(struct inode *, u32,
- struct fscrypt_str *);
-extern void fscrypt_fname_free_buffer(struct fscrypt_str *);
-extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32,
- const struct fscrypt_str *, struct fscrypt_str *);
-extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *,
- struct fscrypt_str *);
-#endif
-
-/* crypto.c */
-static inline struct fscrypt_ctx *fscrypt_notsupp_get_ctx(struct inode *i,
- gfp_t f)
-{
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void fscrypt_notsupp_release_ctx(struct fscrypt_ctx *c)
-{
- return;
-}
-
-static inline struct page *fscrypt_notsupp_encrypt_page(struct inode *i,
- struct page *p, gfp_t f)
-{
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline int fscrypt_notsupp_decrypt_page(struct page *p)
-{
- return -EOPNOTSUPP;
-}
-
-static inline void fscrypt_notsupp_decrypt_bio_pages(struct fscrypt_ctx *c,
- struct bio *b)
-{
- return;
-}
-
-static inline void fscrypt_notsupp_pullback_bio_page(struct page **p, bool b)
-{
- return;
-}
-
-static inline void fscrypt_notsupp_restore_control_page(struct page *p)
-{
- return;
-}
-
-static inline int fscrypt_notsupp_zeroout_range(struct inode *i, pgoff_t p,
- sector_t s, unsigned int f)
-{
- return -EOPNOTSUPP;
-}
-
-/* policy.c */
-static inline int fscrypt_notsupp_process_policy(struct file *f,
- const struct fscrypt_policy *p)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int fscrypt_notsupp_get_policy(struct inode *i,
- struct fscrypt_policy *p)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int fscrypt_notsupp_has_permitted_context(struct inode *p,
- struct inode *i)
-{
- return 0;
-}
-
-static inline int fscrypt_notsupp_inherit_context(struct inode *p,
- struct inode *i, void *v, bool b)
-{
- return -EOPNOTSUPP;
-}
-
-/* keyinfo.c */
-static inline int fscrypt_notsupp_get_encryption_info(struct inode *i)
-{
- return -EOPNOTSUPP;
-}
-
-static inline void fscrypt_notsupp_put_encryption_info(struct inode *i,
- struct fscrypt_info *f)
-{
- return;
-}
-
-static inline int fs_notsupp_using_hardware_encryption(struct inode *inode)
-{
- return -EOPNOTSUPP;
-}
-
- /* fname.c */
-static inline int fscrypt_notsupp_setup_filename(struct inode *dir,
- const struct qstr *iname,
- int lookup, struct fscrypt_name *fname)
-{
- if (dir->i_sb->s_cop->is_encrypted(dir))
- return -EOPNOTSUPP;
-
- memset(fname, 0, sizeof(struct fscrypt_name));
- fname->usr_fname = iname;
- fname->disk_name.name = (unsigned char *)iname->name;
- fname->disk_name.len = iname->len;
- return 0;
-}
-
-static inline void fscrypt_notsupp_free_filename(struct fscrypt_name *fname)
-{
- return;
-}
-
-static inline u32 fscrypt_notsupp_fname_encrypted_size(struct inode *i, u32 s)
-{
- /* never happens */
- WARN_ON(1);
- return 0;
-}
-
-static inline int fscrypt_notsupp_fname_alloc_buffer(struct inode *inode,
- u32 ilen, struct fscrypt_str *crypto_str)
-{
- return -EOPNOTSUPP;
-}
-
-static inline void fscrypt_notsupp_fname_free_buffer(struct fscrypt_str *c)
-{
- return;
-}
-
-static inline int fscrypt_notsupp_fname_disk_to_usr(struct inode *inode,
- u32 hash, u32 minor_hash,
- const struct fscrypt_str *iname,
- struct fscrypt_str *oname)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int fscrypt_notsupp_fname_usr_to_disk(struct inode *inode,
- const struct qstr *iname,
- struct fscrypt_str *oname)
-{
- return -EOPNOTSUPP;
-}
-#endif /* _LINUX_FSCRYPTO_H */
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index e5f03a4d..ff51592 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -213,12 +213,20 @@
static inline void fsnotify_open(struct file *file)
{
struct path *path = &file->f_path;
+ struct path lower_path;
struct inode *inode = path->dentry->d_inode;
+
__u32 mask = FS_OPEN;
if (S_ISDIR(inode->i_mode))
mask |= FS_ISDIR;
+ if (path->dentry->d_op && path->dentry->d_op->d_canonical_path) {
+ path->dentry->d_op->d_canonical_path(path, &lower_path);
+ fsnotify_parent(&lower_path, NULL, mask);
+ fsnotify(lower_path.dentry->d_inode, mask, &lower_path, FSNOTIFY_EVENT_PATH, NULL, 0);
+ path_put(&lower_path);
+ }
fsnotify_parent(path, NULL, mask);
fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
}
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index b3d34d3..f4c0d36 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -734,7 +734,8 @@
static inline void time_hardirqs_off(unsigned long a0, unsigned long a1) { }
#endif
-#ifdef CONFIG_PREEMPT_TRACER
+#if defined(CONFIG_PREEMPT_TRACER) || \
+ (defined(CONFIG_DEBUG_PREEMPT) && defined(CONFIG_PREEMPTIRQ_EVENTS))
extern void trace_preempt_on(unsigned long a0, unsigned long a1);
extern void trace_preempt_off(unsigned long a0, unsigned long a1);
#else
diff --git a/include/linux/hdcp_qseecom.h b/include/linux/hdcp_qseecom.h
index 20f5cba..08f30a46 100644
--- a/include/linux/hdcp_qseecom.h
+++ b/include/linux/hdcp_qseecom.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -181,11 +181,9 @@
/**
* struct hdcp_client_ops - call back functions to display transport layer
* @wakeup: wake up display transport layer with a new command
- * @notify_lvl_change notify of encryption level changes
*/
struct hdcp_client_ops {
int (*wakeup)(struct hdcp_wakeup_data *data);
- void (*notify_lvl_change)(void *client_ctx, int min_lvl);
};
/**
@@ -219,6 +217,4 @@
bool hdcp1_check_if_supported_load_app(void);
int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb);
int hdcp1_set_enc(bool enable);
-void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp);
-void hdcp1_notify_topology(void);
#endif /* __HDCP_QSEECOM_H */
diff --git a/include/linux/init.h b/include/linux/init.h
index e30104c..8e346d1 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -4,6 +4,13 @@
#include <linux/compiler.h>
#include <linux/types.h>
+/* Built-in __init functions needn't be compiled with retpoline */
+#if defined(RETPOLINE) && !defined(MODULE)
+#define __noretpoline __attribute__((indirect_branch("keep")))
+#else
+#define __noretpoline
+#endif
+
/* These macros are used to mark some functions or
* initialized data (doesn't apply to uninitialized data)
* as `initialization' functions. The kernel can take this
@@ -39,7 +46,7 @@
/* These are for everybody (although not all archs will actually
discard it in modules) */
-#define __init __section(.init.text) __cold notrace __latent_entropy
+#define __init __section(.init.text) __cold notrace __latent_entropy __noretpoline
#define __initdata __section(.init.data)
#define __initconst __section(.init.rodata)
#define __exitdata __section(.exit.data)
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 3562047..d6d31a0 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -14,11 +14,11 @@
#include <linux/hrtimer.h>
#include <linux/kref.h>
#include <linux/workqueue.h>
-#include <linux/sched.h>
#include <linux/atomic.h>
#include <asm/ptrace.h>
#include <asm/irq.h>
+#include <asm/sections.h>
/*
* These correspond to the IORESOURCE_IRQ_* defines in
@@ -499,13 +499,6 @@
return this_cpu_read(ksoftirqd);
}
-static inline bool ksoftirqd_running_on(int cpu)
-{
- struct task_struct *tsk = per_cpu(ksoftirqd, cpu);
-
- return tsk && (tsk->state == TASK_RUNNING);
-}
-
/* Tasklets --- multithreaded analogue of BHs.
Main feature differing them of generic softirqs: tasklet
@@ -714,7 +707,6 @@
extern int arch_probe_nr_irqs(void);
extern int arch_early_irq_init(void);
-#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN)
/*
* We want to know which function is an entrypoint of a hardirq or a softirq.
*/
@@ -722,16 +714,4 @@
#define __softirq_entry \
__attribute__((__section__(".softirqentry.text")))
-/* Limits of hardirq entrypoints */
-extern char __irqentry_text_start[];
-extern char __irqentry_text_end[];
-/* Limits of softirq entrypoints */
-extern char __softirqentry_text_start[];
-extern char __softirqentry_text_end[];
-
-#else
-#define __irq_entry
-#define __softirq_entry
-#endif
-
#endif
diff --git a/include/linux/ipa.h b/include/linux/ipa.h
index 46ee6da..4951e0b 100644
--- a/include/linux/ipa.h
+++ b/include/linux/ipa.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -1668,7 +1668,7 @@
static inline int ipa_cfg_ep_conn_track(u32 clnt_hdl,
const struct ipa_ep_cfg_conn_track *ep_conn_track)
{
- return -EPERM
+ return -EPERM;
}
static inline int ipa_cfg_ep_hdr(u32 clnt_hdl,
diff --git a/include/linux/ipa_wdi3.h b/include/linux/ipa_wdi3.h
index aed8c59..6f00711 100644
--- a/include/linux/ipa_wdi3.h
+++ b/include/linux/ipa_wdi3.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -24,15 +24,49 @@
(IPA_HW_WDI3_TCL_DATA_CMD_ER_DESC_SIZE) : \
(IPA_HW_WDI3_IPA2FW_ER_DESC_SIZE))
+#define IPA_WDI_MAX_SUPPORTED_SYS_PIPE 3
+
+enum ipa_wdi_version {
+ IPA_WDI_1,
+ IPA_WDI_2,
+ IPA_WDI_3
+};
+
/**
- * struct ipa_wdi3_hdr_info - Header to install on IPA HW
+ * struct ipa_wdi_init_in_params - wdi init input parameters
+ *
+ * @wdi_version: wdi version
+ * @notify: uc ready callback
+ * @priv: uc ready callback cookie
+ */
+struct ipa_wdi_init_in_params {
+ enum ipa_wdi_version wdi_version;
+ ipa_uc_ready_cb notify;
+ void *priv;
+ ipa_wdi_meter_notifier_cb wdi_notify;
+};
+
+/**
+ * struct ipa_wdi_init_out_params - wdi init output parameters
+ *
+ * @is_uC_ready: is uC ready. No API should be called until uC
+ is ready.
+ * @is_smmu_enable: is smmu enabled
+ */
+struct ipa_wdi_init_out_params {
+ bool is_uC_ready;
+ bool is_smmu_enabled;
+};
+
+/**
+ * struct ipa_wdi_hdr_info - Header to install on IPA HW
*
* @hdr: header to install on IPA HW
* @hdr_len: length of header
* @dst_mac_addr_offset: destination mac address offset
* @hdr_type: layer two header type
*/
-struct ipa_wdi3_hdr_info {
+struct ipa_wdi_hdr_info {
u8 *hdr;
u8 hdr_len;
u8 dst_mac_addr_offset;
@@ -40,7 +74,7 @@
};
/**
- * struct ipa_wdi3_reg_intf_in_params - parameters for uC offload
+ * struct ipa_wdi_reg_intf_in_params - parameters for uC offload
* interface registration
*
* @netdev_name: network interface name
@@ -49,16 +83,17 @@
* @meta_data: meta data if any
* @meta_data_mask: meta data mask
*/
-struct ipa_wdi3_reg_intf_in_params {
+struct ipa_wdi_reg_intf_in_params {
const char *netdev_name;
- struct ipa_wdi3_hdr_info hdr_info[IPA_IP_MAX];
+ struct ipa_wdi_hdr_info hdr_info[IPA_IP_MAX];
+ enum ipa_client_type alt_dst_pipe;
u8 is_meta_data_valid;
u32 meta_data;
u32 meta_data_mask;
};
/**
- * struct ipa_wdi3_setup_info - WDI3 TX/Rx configuration
+ * struct ipa_wdi_pipe_setup_info - WDI TX/Rx configuration
* @ipa_ep_cfg: ipa endpoint configuration
* @client: type of "client"
* @transfer_ring_base_pa: physical address of the base of the transfer ring
@@ -71,20 +106,20 @@
will update the headpointer of the event ring
* @num_pkt_buffers: Number of pkt buffers allocated. The size of the event
ring and the transfer ring has to be atleast ( num_pkt_buffers + 1)
- * @pkt_offset: packet offset (wdi3 header length)
+ * @pkt_offset: packet offset (wdi header length)
* @desc_format_template[IPA_HW_WDI3_MAX_ER_DESC_SIZE]: Holds a cached
template of the desc format
*/
-struct ipa_wdi3_setup_info {
+struct ipa_wdi_pipe_setup_info {
struct ipa_ep_cfg ipa_ep_cfg;
enum ipa_client_type client;
- dma_addr_t transfer_ring_base_pa;
+ phys_addr_t transfer_ring_base_pa;
u32 transfer_ring_size;
- dma_addr_t transfer_ring_doorbell_pa;
+ phys_addr_t transfer_ring_doorbell_pa;
- dma_addr_t event_ring_base_pa;
+ phys_addr_t event_ring_base_pa;
u32 event_ring_size;
- dma_addr_t event_ring_doorbell_pa;
+ phys_addr_t event_ring_doorbell_pa;
u16 num_pkt_buffers;
u16 pkt_offset;
@@ -93,40 +128,87 @@
};
/**
- * struct ipa_wdi3_conn_in_params - information provided by
+ * struct ipa_wdi_pipe_setup_info_smmu - WDI TX/Rx configuration
+ * @ipa_ep_cfg: ipa endpoint configuration
+ * @client: type of "client"
+ * @transfer_ring_base_pa: physical address of the base of the transfer ring
+ * @transfer_ring_size: size of the transfer ring
+ * @transfer_ring_doorbell_pa: physical address of the doorbell that
+ IPA uC will update the tailpointer of the transfer ring
+ * @event_ring_base_pa: physical address of the base of the event ring
+ * @event_ring_size: event ring size
+ * @event_ring_doorbell_pa: physical address of the doorbell that IPA uC
+ will update the headpointer of the event ring
+ * @num_pkt_buffers: Number of pkt buffers allocated. The size of the event
+ ring and the transfer ring has to be atleast ( num_pkt_buffers + 1)
+ * @pkt_offset: packet offset (wdi header length)
+ * @desc_format_template[IPA_HW_WDI3_MAX_ER_DESC_SIZE]: Holds a cached
+ template of the desc format
+ */
+struct ipa_wdi_pipe_setup_info_smmu {
+ struct ipa_ep_cfg ipa_ep_cfg;
+ enum ipa_client_type client;
+ struct sg_table transfer_ring_base;
+ u32 transfer_ring_size;
+ phys_addr_t transfer_ring_doorbell_pa;
+
+ struct sg_table event_ring_base;
+ u32 event_ring_size;
+ phys_addr_t event_ring_doorbell_pa;
+ u16 num_pkt_buffers;
+
+ u16 pkt_offset;
+
+ u32 desc_format_template[IPA_HW_WDI3_MAX_ER_DESC_SIZE];
+};
+
+/**
+ * struct ipa_wdi_conn_in_params - information provided by
* uC offload client
* @notify: client callback function
* @priv: client cookie
+ * @is_smmu_enabled: if smmu is enabled
+ * @num_sys_pipe_needed: number of sys pipe needed
+ * @sys_in: parameters to setup sys pipe in mcc mode
* @tx: parameters to connect TX pipe(from IPA to WLAN)
+ * @tx_smmu: smmu parameters to connect TX pipe(from IPA to WLAN)
* @rx: parameters to connect RX pipe(from WLAN to IPA)
+ * @rx_smmu: smmu parameters to connect RX pipe(from WLAN to IPA)
*/
-struct ipa_wdi3_conn_in_params {
+struct ipa_wdi_conn_in_params {
ipa_notify_cb notify;
void *priv;
- struct ipa_wdi3_setup_info tx;
- struct ipa_wdi3_setup_info rx;
+ bool is_smmu_enabled;
+ u8 num_sys_pipe_needed;
+ struct ipa_sys_connect_params sys_in[IPA_WDI_MAX_SUPPORTED_SYS_PIPE];
+ union {
+ struct ipa_wdi_pipe_setup_info tx;
+ struct ipa_wdi_pipe_setup_info_smmu tx_smmu;
+ } u_tx;
+ union {
+ struct ipa_wdi_pipe_setup_info rx;
+ struct ipa_wdi_pipe_setup_info_smmu rx_smmu;
+ } u_rx;
};
/**
- * struct ipa_wdi3_conn_out_params - information provided
+ * struct ipa_wdi_conn_out_params - information provided
* to WLAN driver
* @tx_uc_db_pa: physical address of IPA uC doorbell for TX
- * @tx_uc_db_va: virtual address of IPA uC doorbell for TX
* @rx_uc_db_pa: physical address of IPA uC doorbell for RX
*/
-struct ipa_wdi3_conn_out_params {
- dma_addr_t tx_uc_db_pa;
- void __iomem *tx_uc_db_va;
- dma_addr_t rx_uc_db_pa;
+struct ipa_wdi_conn_out_params {
+ phys_addr_t tx_uc_db_pa;
+ phys_addr_t rx_uc_db_pa;
};
/**
- * struct ipa_wdi3_perf_profile - To set BandWidth profile
+ * struct ipa_wdi_perf_profile - To set BandWidth profile
*
* @client: type of client
* @max_supported_bw_mbps: maximum bandwidth needed (in Mbps)
*/
-struct ipa_wdi3_perf_profile {
+struct ipa_wdi_perf_profile {
enum ipa_client_type client;
u32 max_supported_bw_mbps;
};
@@ -134,117 +216,193 @@
#if defined CONFIG_IPA || defined CONFIG_IPA3
/**
- * ipa_wdi3_reg_intf - Client should call this function to
- * init WDI3 IPA offload data path
+ * ipa_wdi_init - Client should call this function to
+ * init WDI IPA offload data path
*
* Note: Should not be called from atomic context and only
* after checking IPA readiness using ipa_register_ipa_ready_cb()
*
* @Return 0 on success, negative on failure
*/
-int ipa_wdi3_reg_intf(
- struct ipa_wdi3_reg_intf_in_params *in);
+int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
+ struct ipa_wdi_init_out_params *out);
/**
- * ipa_wdi3_dereg_intf - Client Driver should call this
+ * ipa_wdi_cleanup - Client should call this function to
+ * clean up WDI IPA offload data path
+ *
+ * @Return 0 on success, negative on failure
+ */
+int ipa_wdi_cleanup(void);
+
+/**
+ * ipa_wdi_reg_intf - Client should call this function to
+ * register interface
+ *
+ * Note: Should not be called from atomic context
+ *
+ * @Return 0 on success, negative on failure
+ */
+int ipa_wdi_reg_intf(
+ struct ipa_wdi_reg_intf_in_params *in);
+
+/**
+ * ipa_wdi_dereg_intf - Client Driver should call this
* function to deregister before unload and after disconnect
*
* @Return 0 on success, negative on failure
*/
-int ipa_wdi3_dereg_intf(const char *netdev_name);
+int ipa_wdi_dereg_intf(const char *netdev_name);
/**
- * ipa_wdi3_conn_pipes - Client should call this
+ * ipa_wdi_conn_pipes - Client should call this
* function to connect pipes
*
* @in: [in] input parameters from client
* @out: [out] output params to client
*
- * Note: Should not be called from atomic context and only
- * after checking IPA readiness using ipa_register_ipa_ready_cb()
+ * Note: Should not be called from atomic context
*
* @Return 0 on success, negative on failure
*/
-int ipa_wdi3_conn_pipes(struct ipa_wdi3_conn_in_params *in,
- struct ipa_wdi3_conn_out_params *out);
+int ipa_wdi_conn_pipes(struct ipa_wdi_conn_in_params *in,
+ struct ipa_wdi_conn_out_params *out);
/**
- * ipa_wdi3_disconn_pipes() - Client should call this
+ * ipa_wdi_disconn_pipes() - Client should call this
* function to disconnect pipes
*
* Note: Should not be called from atomic context
*
* Returns: 0 on success, negative on failure
*/
-int ipa_wdi3_disconn_pipes(void);
+int ipa_wdi_disconn_pipes(void);
/**
- * ipa_wdi3_enable_pipes() - Client should call this
+ * ipa_wdi_enable_pipes() - Client should call this
* function to enable IPA offload data path
*
* Note: Should not be called from atomic context
*
* Returns: 0 on success, negative on failure
*/
-int ipa_wdi3_enable_pipes(void);
+int ipa_wdi_enable_pipes(void);
/**
- * ipa_wdi3_disable_pipes() - Client should call this
+ * ipa_wdi_disable_pipes() - Client should call this
* function to disable IPA offload data path
*
* Note: Should not be called from atomic context
*
* Returns: 0 on success, negative on failure
*/
-int ipa_wdi3_disable_pipes(void);
+int ipa_wdi_disable_pipes(void);
/**
- * ipa_wdi3_set_perf_profile() - Client should call this function to
+ * ipa_wdi_set_perf_profile() - Client should call this function to
* set IPA clock bandwidth based on data rates
*
* @profile: [in] BandWidth profile to use
*
* Returns: 0 on success, negative on failure
*/
-int ipa_wdi3_set_perf_profile(struct ipa_wdi3_perf_profile *profile);
+int ipa_wdi_set_perf_profile(struct ipa_wdi_perf_profile *profile);
+/**
+ * ipa_wdi_create_smmu_mapping() - Create smmu mapping
+ *
+ * @num_buffers: number of buffers
+ *
+ * @info: wdi buffer info
+ */
+int ipa_wdi_create_smmu_mapping(u32 num_buffers,
+ struct ipa_wdi_buffer_info *info);
+
+/**
+ * ipa_wdi_release_smmu_mapping() - Release smmu mapping
+ *
+ * @num_buffers: number of buffers
+ *
+ * @info: wdi buffer info
+ */
+int ipa_wdi_release_smmu_mapping(u32 num_buffers,
+ struct ipa_wdi_buffer_info *info);
+
+/**
+ * ipa_wdi_get_stats() - Query WDI statistics
+ * @stats: [inout] stats blob from client populated by driver
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * @note Cannot be called from atomic context
+ *
+ */
+int ipa_wdi_get_stats(struct IpaHwStatsWDIInfoData_t *stats);
#else /* (CONFIG_IPA || CONFIG_IPA3) */
-static inline int ipa_wdi3_reg_intf(
- struct ipa_wdi3_reg_intf_in_params *in)
+static inline int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
+ struct ipa_wdi_init_out_params *out)
{
return -EPERM;
}
-static inline int ipa_wdi3_dereg_intf(const char *netdev_name)
+static inline int ipa_wdi_cleanup(void)
{
return -EPERM;
}
-static inline int ipa_wdi3_conn_pipes(struct ipa_wdi3_conn_in_params *in,
- struct ipa_wdi3_conn_out_params *out)
+static inline int ipa_wdi_reg_intf(
+ struct ipa_wdi_reg_intf_in_params *in)
{
return -EPERM;
}
-static inline int ipa_wdi3_disconn_pipes(void)
+static inline int ipa_wdi_dereg_intf(const char *netdev_name)
{
return -EPERM;
}
-static inline int ipa_wdi3_enable_pipes(void)
+static inline int ipa_wdi_conn_pipes(struct ipa_wdi_conn_in_params *in,
+ struct ipa_wdi_conn_out_params *out)
{
return -EPERM;
}
-static inline int ipa_wdi3_disable_pipes(void)
+static inline int ipa_wdi_disconn_pipes(void)
{
return -EPERM;
}
-static inline int ipa_wdi3_set_perf_profile(
- struct ipa_wdi3_perf_profile *profile)
+static inline int ipa_wdi_enable_pipes(void)
+{
+ return -EPERM;
+}
+
+static inline int ipa_wdi_disable_pipes(void)
+{
+ return -EPERM;
+}
+
+static inline int ipa_wdi_set_perf_profile(
+ struct ipa_wdi_perf_profile *profile)
+{
+ return -EPERM;
+}
+
+static inline int ipa_wdi_create_smmu_mapping(u32 num_buffers,
+ struct ipa_wdi_buffer_info *info)
+{
+ return -EPERM;
+}
+
+static inline int ipa_wdi_release_smmu_mapping(u32 num_buffers,
+ struct ipa_wdi_buffer_info *info)
+{
+ return -EPERM;
+}
+
+static inline int ipa_wdi_get_stats(struct IpaHwStatsWDIInfoData_t *stats)
{
return -EPERM;
}
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 11ff751..c695ae6 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -66,6 +66,7 @@
} stable_secret;
__s32 use_oif_addrs_only;
__s32 keep_addr_on_down;
+ __s32 accept_ra_prefix_route;
struct ctl_table_header *sysctl_header;
};
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index dfaa1f4..d073470 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -418,26 +418,41 @@
#define JI_WAIT_DATA (1 << __JI_WAIT_DATA)
/**
- * struct jbd_inode is the structure linking inodes in ordered mode
- * present in a transaction so that we can sync them during commit.
+ * struct jbd_inode - The jbd_inode type is the structure linking inodes in
+ * ordered mode present in a transaction so that we can sync them during commit.
*/
struct jbd2_inode {
- /* Which transaction does this inode belong to? Either the running
- * transaction or the committing one. [j_list_lock] */
+ /**
+ * @i_transaction:
+ *
+ * Which transaction does this inode belong to? Either the running
+ * transaction or the committing one. [j_list_lock]
+ */
transaction_t *i_transaction;
- /* Pointer to the running transaction modifying inode's data in case
- * there is already a committing transaction touching it. [j_list_lock] */
+ /**
+ * @i_next_transaction:
+ *
+ * Pointer to the running transaction modifying inode's data in case
+ * there is already a committing transaction touching it. [j_list_lock]
+ */
transaction_t *i_next_transaction;
- /* List of inodes in the i_transaction [j_list_lock] */
+ /**
+ * @i_list: List of inodes in the i_transaction [j_list_lock]
+ */
struct list_head i_list;
- /* VFS inode this inode belongs to [constant during the lifetime
- * of the structure] */
+ /**
+ * @i_vfs_inode:
+ *
+ * VFS inode this inode belongs to [constant for lifetime of structure]
+ */
struct inode *i_vfs_inode;
- /* Flags of inode [j_list_lock] */
+ /**
+ * @i_flags: Flags of inode [j_list_lock]
+ */
unsigned long i_flags;
};
@@ -447,12 +462,20 @@
* struct handle_s - The handle_s type is the concrete type associated with
* handle_t.
* @h_transaction: Which compound transaction is this update a part of?
+ * @h_journal: Which journal handle belongs to - used iff h_reserved set.
+ * @h_rsv_handle: Handle reserved for finishing the logical operation.
* @h_buffer_credits: Number of remaining buffers we are allowed to dirty.
- * @h_ref: Reference count on this handle
- * @h_err: Field for caller's use to track errors through large fs operations
- * @h_sync: flag for sync-on-close
- * @h_jdata: flag to force data journaling
- * @h_aborted: flag indicating fatal error on handle
+ * @h_ref: Reference count on this handle.
+ * @h_err: Field for caller's use to track errors through large fs operations.
+ * @h_sync: Flag for sync-on-close.
+ * @h_jdata: Flag to force data journaling.
+ * @h_reserved: Flag for handle for reserved credits.
+ * @h_aborted: Flag indicating fatal error on handle.
+ * @h_type: For handle statistics.
+ * @h_line_no: For handle statistics.
+ * @h_start_jiffies: Handle Start time.
+ * @h_requested_credits: Holds @h_buffer_credits after handle is started.
+ * @saved_alloc_context: Saved context while transaction is open.
**/
/* Docbook can't yet cope with the bit fields, but will leave the documentation
@@ -462,32 +485,23 @@
struct jbd2_journal_handle
{
union {
- /* Which compound transaction is this update a part of? */
transaction_t *h_transaction;
/* Which journal handle belongs to - used iff h_reserved set */
journal_t *h_journal;
};
- /* Handle reserved for finishing the logical operation */
handle_t *h_rsv_handle;
-
- /* Number of remaining buffers we are allowed to dirty: */
int h_buffer_credits;
-
- /* Reference count on this handle */
int h_ref;
-
- /* Field for caller's use to track errors through large fs */
- /* operations */
int h_err;
/* Flags [no locking] */
- unsigned int h_sync: 1; /* sync-on-close */
- unsigned int h_jdata: 1; /* force data journaling */
- unsigned int h_reserved: 1; /* handle with reserved credits */
- unsigned int h_aborted: 1; /* fatal error on handle */
- unsigned int h_type: 8; /* for handle statistics */
- unsigned int h_line_no: 16; /* for handle statistics */
+ unsigned int h_sync: 1;
+ unsigned int h_jdata: 1;
+ unsigned int h_reserved: 1;
+ unsigned int h_aborted: 1;
+ unsigned int h_type: 8;
+ unsigned int h_line_no: 16;
unsigned long h_start_jiffies;
unsigned int h_requested_credits;
@@ -727,228 +741,253 @@
/**
* struct journal_s - The journal_s type is the concrete type associated with
* journal_t.
- * @j_flags: General journaling state flags
- * @j_errno: Is there an outstanding uncleared error on the journal (from a
- * prior abort)?
- * @j_sb_buffer: First part of superblock buffer
- * @j_superblock: Second part of superblock buffer
- * @j_format_version: Version of the superblock format
- * @j_state_lock: Protect the various scalars in the journal
- * @j_barrier_count: Number of processes waiting to create a barrier lock
- * @j_barrier: The barrier lock itself
- * @j_running_transaction: The current running transaction..
- * @j_committing_transaction: the transaction we are pushing to disk
- * @j_checkpoint_transactions: a linked circular list of all transactions
- * waiting for checkpointing
- * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction
- * to start committing, or for a barrier lock to be released
- * @j_wait_done_commit: Wait queue for waiting for commit to complete
- * @j_wait_commit: Wait queue to trigger commit
- * @j_wait_updates: Wait queue to wait for updates to complete
- * @j_wait_reserved: Wait queue to wait for reserved buffer credits to drop
- * @j_checkpoint_mutex: Mutex for locking against concurrent checkpoints
- * @j_head: Journal head - identifies the first unused block in the journal
- * @j_tail: Journal tail - identifies the oldest still-used block in the
- * journal.
- * @j_free: Journal free - how many free blocks are there in the journal?
- * @j_first: The block number of the first usable block
- * @j_last: The block number one beyond the last usable block
- * @j_dev: Device where we store the journal
- * @j_blocksize: blocksize for the location where we store the journal.
- * @j_blk_offset: starting block offset for into the device where we store the
- * journal
- * @j_fs_dev: Device which holds the client fs. For internal journal this will
- * be equal to j_dev
- * @j_reserved_credits: Number of buffers reserved from the running transaction
- * @j_maxlen: Total maximum capacity of the journal region on disk.
- * @j_list_lock: Protects the buffer lists and internal buffer state.
- * @j_inode: Optional inode where we store the journal. If present, all journal
- * block numbers are mapped into this inode via bmap().
- * @j_tail_sequence: Sequence number of the oldest transaction in the log
- * @j_transaction_sequence: Sequence number of the next transaction to grant
- * @j_commit_sequence: Sequence number of the most recently committed
- * transaction
- * @j_commit_request: Sequence number of the most recent transaction wanting
- * commit
- * @j_uuid: Uuid of client object.
- * @j_task: Pointer to the current commit thread for this journal
- * @j_max_transaction_buffers: Maximum number of metadata buffers to allow in a
- * single compound commit transaction
- * @j_commit_interval: What is the maximum transaction lifetime before we begin
- * a commit?
- * @j_commit_timer: The timer used to wakeup the commit thread
- * @j_revoke_lock: Protect the revoke table
- * @j_revoke: The revoke table - maintains the list of revoked blocks in the
- * current transaction.
- * @j_revoke_table: alternate revoke tables for j_revoke
- * @j_wbuf: array of buffer_heads for jbd2_journal_commit_transaction
- * @j_wbufsize: maximum number of buffer_heads allowed in j_wbuf, the
- * number that will fit in j_blocksize
- * @j_last_sync_writer: most recent pid which did a synchronous write
- * @j_history_lock: Protect the transactions statistics history
- * @j_proc_entry: procfs entry for the jbd statistics directory
- * @j_stats: Overall statistics
- * @j_private: An opaque pointer to fs-private information.
- * @j_trans_commit_map: Lockdep entity to track transaction commit dependencies
*/
-
struct journal_s
{
- /* General journaling state flags [j_state_lock] */
+ /**
+ * @j_flags: General journaling state flags [j_state_lock]
+ */
unsigned long j_flags;
- /*
+ /**
+ * @j_errno:
+ *
* Is there an outstanding uncleared error on the journal (from a prior
* abort)? [j_state_lock]
*/
int j_errno;
- /* The superblock buffer */
+ /**
+ * @j_sb_buffer: The first part of the superblock buffer.
+ */
struct buffer_head *j_sb_buffer;
+
+ /**
+ * @j_superblock: The second part of the superblock buffer.
+ */
journal_superblock_t *j_superblock;
- /* Version of the superblock format */
+ /**
+ * @j_format_version: Version of the superblock format.
+ */
int j_format_version;
- /*
- * Protect the various scalars in the journal
+ /**
+ * @j_state_lock: Protect the various scalars in the journal.
*/
rwlock_t j_state_lock;
- /*
+ /**
+ * @j_barrier_count:
+ *
* Number of processes waiting to create a barrier lock [j_state_lock]
*/
int j_barrier_count;
- /* The barrier lock itself */
+ /**
+ * @j_barrier: The barrier lock itself.
+ */
struct mutex j_barrier;
- /*
+ /**
+ * @j_running_transaction:
+ *
* Transactions: The current running transaction...
* [j_state_lock] [caller holding open handle]
*/
transaction_t *j_running_transaction;
- /*
+ /**
+ * @j_committing_transaction:
+ *
* the transaction we are pushing to disk
* [j_state_lock] [caller holding open handle]
*/
transaction_t *j_committing_transaction;
- /*
+ /**
+ * @j_checkpoint_transactions:
+ *
* ... and a linked circular list of all transactions waiting for
* checkpointing. [j_list_lock]
*/
transaction_t *j_checkpoint_transactions;
- /*
+ /**
+ * @j_wait_transaction_locked:
+ *
* Wait queue for waiting for a locked transaction to start committing,
- * or for a barrier lock to be released
+ * or for a barrier lock to be released.
*/
wait_queue_head_t j_wait_transaction_locked;
- /* Wait queue for waiting for commit to complete */
+ /**
+ * @j_wait_done_commit: Wait queue for waiting for commit to complete.
+ */
wait_queue_head_t j_wait_done_commit;
- /* Wait queue to trigger commit */
+ /**
+ * @j_wait_commit: Wait queue to trigger commit.
+ */
wait_queue_head_t j_wait_commit;
- /* Wait queue to wait for updates to complete */
+ /**
+ * @j_wait_updates: Wait queue to wait for updates to complete.
+ */
wait_queue_head_t j_wait_updates;
- /* Wait queue to wait for reserved buffer credits to drop */
+ /**
+ * @j_wait_reserved:
+ *
+ * Wait queue to wait for reserved buffer credits to drop.
+ */
wait_queue_head_t j_wait_reserved;
- /* Semaphore for locking against concurrent checkpoints */
+ /**
+ * @j_checkpoint_mutex:
+ *
+ * Semaphore for locking against concurrent checkpoints.
+ */
struct mutex j_checkpoint_mutex;
- /*
+ /**
+ * @j_chkpt_bhs:
+ *
* List of buffer heads used by the checkpoint routine. This
* was moved from jbd2_log_do_checkpoint() to reduce stack
* usage. Access to this array is controlled by the
- * j_checkpoint_mutex. [j_checkpoint_mutex]
+ * @j_checkpoint_mutex. [j_checkpoint_mutex]
*/
struct buffer_head *j_chkpt_bhs[JBD2_NR_BATCH];
-
- /*
+
+ /**
+ * @j_head:
+ *
* Journal head: identifies the first unused block in the journal.
* [j_state_lock]
*/
unsigned long j_head;
- /*
+ /**
+ * @j_tail:
+ *
* Journal tail: identifies the oldest still-used block in the journal.
* [j_state_lock]
*/
unsigned long j_tail;
- /*
+ /**
+ * @j_free:
+ *
* Journal free: how many free blocks are there in the journal?
* [j_state_lock]
*/
unsigned long j_free;
- /*
- * Journal start and end: the block numbers of the first usable block
- * and one beyond the last usable block in the journal. [j_state_lock]
+ /**
+ * @j_first:
+ *
+ * The block number of the first usable block in the journal
+ * [j_state_lock].
*/
unsigned long j_first;
+
+ /**
+ * @j_last:
+ *
+ * The block number one beyond the last usable block in the journal
+ * [j_state_lock].
+ */
unsigned long j_last;
- /*
- * Device, blocksize and starting block offset for the location where we
- * store the journal.
+ /**
+ * @j_dev: Device where we store the journal.
*/
struct block_device *j_dev;
+
+ /**
+ * @j_blocksize: Block size for the location where we store the journal.
+ */
int j_blocksize;
+
+ /**
+ * @j_blk_offset:
+ *
+ * Starting block offset into the device where we store the journal.
+ */
unsigned long long j_blk_offset;
+
+ /**
+ * @j_devname: Journal device name.
+ */
char j_devname[BDEVNAME_SIZE+24];
- /*
+ /**
+ * @j_fs_dev:
+ *
* Device which holds the client fs. For internal journal this will be
* equal to j_dev.
*/
struct block_device *j_fs_dev;
- /* Total maximum capacity of the journal region on disk. */
+ /**
+ * @j_maxlen: Total maximum capacity of the journal region on disk.
+ */
unsigned int j_maxlen;
- /* Number of buffers reserved from the running transaction */
+ /**
+ * @j_reserved_credits:
+ *
+ * Number of buffers reserved from the running transaction.
+ */
atomic_t j_reserved_credits;
- /*
- * Protects the buffer lists and internal buffer state.
+ /**
+ * @j_list_lock: Protects the buffer lists and internal buffer state.
*/
spinlock_t j_list_lock;
- /* Optional inode where we store the journal. If present, all */
- /* journal block numbers are mapped into this inode via */
- /* bmap(). */
+ /**
+ * @j_inode:
+ *
+ * Optional inode where we store the journal. If present, all
+ * journal block numbers are mapped into this inode via bmap().
+ */
struct inode *j_inode;
- /*
+ /**
+ * @j_tail_sequence:
+ *
* Sequence number of the oldest transaction in the log [j_state_lock]
*/
tid_t j_tail_sequence;
- /*
+ /**
+ * @j_transaction_sequence:
+ *
* Sequence number of the next transaction to grant [j_state_lock]
*/
tid_t j_transaction_sequence;
- /*
+ /**
+ * @j_commit_sequence:
+ *
* Sequence number of the most recently committed transaction
* [j_state_lock].
*/
tid_t j_commit_sequence;
- /*
+ /**
+ * @j_commit_request:
+ *
* Sequence number of the most recent transaction wanting commit
* [j_state_lock]
*/
tid_t j_commit_request;
- /*
+ /**
+ * @j_uuid:
+ *
* Journal uuid: identifies the object (filesystem, LVM volume etc)
* backed by this journal. This will eventually be replaced by an array
* of uuids, allowing us to index multiple devices within a single
@@ -956,85 +995,151 @@
*/
__u8 j_uuid[16];
- /* Pointer to the current commit thread for this journal */
+ /**
+ * @j_task: Pointer to the current commit thread for this journal.
+ */
struct task_struct *j_task;
- /*
+ /**
+ * @j_max_transaction_buffers:
+ *
* Maximum number of metadata buffers to allow in a single compound
- * commit transaction
+ * commit transaction.
*/
int j_max_transaction_buffers;
- /*
+ /**
+ * @j_commit_interval:
+ *
* What is the maximum transaction lifetime before we begin a commit?
*/
unsigned long j_commit_interval;
- /* The timer used to wakeup the commit thread: */
+ /**
+ * @j_commit_timer: The timer used to wakeup the commit thread.
+ */
struct timer_list j_commit_timer;
- /*
- * The revoke table: maintains the list of revoked blocks in the
- * current transaction. [j_revoke_lock]
+ /**
+ * @j_revoke_lock: Protect the revoke table.
*/
spinlock_t j_revoke_lock;
+
+ /**
+ * @j_revoke:
+ *
+ * The revoke table - maintains the list of revoked blocks in the
+ * current transaction.
+ */
struct jbd2_revoke_table_s *j_revoke;
+
+ /**
+ * @j_revoke_table: Alternate revoke tables for j_revoke.
+ */
struct jbd2_revoke_table_s *j_revoke_table[2];
- /*
- * array of bhs for jbd2_journal_commit_transaction
+ /**
+ * @j_wbuf: Array of bhs for jbd2_journal_commit_transaction.
*/
struct buffer_head **j_wbuf;
+
+ /**
+ * @j_wbufsize:
+ *
+ * Size of @j_wbuf array.
+ */
int j_wbufsize;
- /*
- * this is the pid of hte last person to run a synchronous operation
- * through the journal
+ /**
+ * @j_last_sync_writer:
+ *
+ * The pid of the last person to run a synchronous operation
+ * through the journal.
*/
pid_t j_last_sync_writer;
- /*
- * the average amount of time in nanoseconds it takes to commit a
+ /**
+ * @j_average_commit_time:
+ *
+ * The average amount of time in nanoseconds it takes to commit a
* transaction to disk. [j_state_lock]
*/
u64 j_average_commit_time;
- /*
- * minimum and maximum times that we should wait for
- * additional filesystem operations to get batched into a
- * synchronous handle in microseconds
+ /**
+ * @j_min_batch_time:
+ *
+ * Minimum time that we should wait for additional filesystem operations
+ * to get batched into a synchronous handle in microseconds.
*/
u32 j_min_batch_time;
+
+ /**
+ * @j_max_batch_time:
+ *
+ * Maximum time that we should wait for additional filesystem operations
+ * to get batched into a synchronous handle in microseconds.
+ */
u32 j_max_batch_time;
- /* This function is called when a transaction is closed */
+ /**
+ * @j_commit_callback:
+ *
+ * This function is called when a transaction is closed.
+ */
void (*j_commit_callback)(journal_t *,
transaction_t *);
/*
* Journal statistics
*/
+
+ /**
+ * @j_history_lock: Protect the transactions statistics history.
+ */
spinlock_t j_history_lock;
+
+ /**
+ * @j_proc_entry: procfs entry for the jbd statistics directory.
+ */
struct proc_dir_entry *j_proc_entry;
+
+ /**
+ * @j_stats: Overall statistics.
+ */
struct transaction_stats_s j_stats;
- /* Failed journal commit ID */
+ /**
+ * @j_failed_commit: Failed journal commit ID.
+ */
unsigned int j_failed_commit;
- /*
+ /**
+ * @j_private:
+ *
* An opaque pointer to fs-private information. ext3 puts its
- * superblock pointer here
+ * superblock pointer here.
*/
void *j_private;
- /* Reference to checksum algorithm driver via cryptoapi */
+ /**
+ * @j_chksum_driver:
+ *
+ * Reference to checksum algorithm driver via cryptoapi.
+ */
struct crypto_shash *j_chksum_driver;
- /* Precomputed journal UUID checksum for seeding other checksums */
+ /**
+ * @j_csum_seed:
+ *
+ * Precomputed journal UUID checksum for seeding other checksums.
+ */
__u32 j_csum_seed;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
- /*
+ /**
+ * @j_trans_commit_map:
+ *
* Lockdep entity to track transaction commit dependencies. Handles
* hold this "lock" for read, when we wait for commit, we acquire the
* "lock" for writing. This matches the properties of jbd2 journalling
diff --git a/include/linux/kaiser.h b/include/linux/kaiser.h
index 58c55b1..b56c190 100644
--- a/include/linux/kaiser.h
+++ b/include/linux/kaiser.h
@@ -32,7 +32,7 @@
{
}
static inline int kaiser_add_mapping(unsigned long addr,
- unsigned long size, unsigned long flags)
+ unsigned long size, u64 flags)
{
return 0;
}
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
index 820c0ad..b37afd1 100644
--- a/include/linux/kasan.h
+++ b/include/linux/kasan.h
@@ -30,16 +30,10 @@
}
/* Enable reporting bugs after kasan_disable_current() */
-static inline void kasan_enable_current(void)
-{
- current->kasan_depth++;
-}
+extern void kasan_enable_current(void);
/* Disable reporting bugs for current task */
-static inline void kasan_disable_current(void)
-{
- current->kasan_depth--;
-}
+extern void kasan_disable_current(void);
void kasan_unpoison_shadow(const void *address, size_t size);
@@ -52,7 +46,7 @@
void kasan_cache_create(struct kmem_cache *cache, size_t *size,
unsigned long *flags);
void kasan_cache_shrink(struct kmem_cache *cache);
-void kasan_cache_destroy(struct kmem_cache *cache);
+void kasan_cache_shutdown(struct kmem_cache *cache);
void kasan_poison_slab(struct page *page);
void kasan_unpoison_object_data(struct kmem_cache *cache, void *object);
@@ -81,6 +75,9 @@
static inline void kasan_unpoison_slab(const void *ptr) { ksize(ptr); }
size_t kasan_metadata_size(struct kmem_cache *cache);
+bool kasan_save_enable_multi_shot(void);
+void kasan_restore_multi_shot(bool enabled);
+
#else /* CONFIG_KASAN */
static inline void kasan_unpoison_shadow(const void *address, size_t size) {}
@@ -98,7 +95,7 @@
size_t *size,
unsigned long *flags) {}
static inline void kasan_cache_shrink(struct kmem_cache *cache) {}
-static inline void kasan_cache_destroy(struct kmem_cache *cache) {}
+static inline void kasan_cache_shutdown(struct kmem_cache *cache) {}
static inline void kasan_poison_slab(struct page *page) {}
static inline void kasan_unpoison_object_data(struct kmem_cache *cache,
diff --git a/include/linux/kbuild.h b/include/linux/kbuild.h
index 22a7219..4e80f3a 100644
--- a/include/linux/kbuild.h
+++ b/include/linux/kbuild.h
@@ -2,14 +2,14 @@
#define __LINUX_KBUILD_H
#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+ asm volatile("\n.ascii \"->" #sym " %0 " #val "\"" : : "i" (val))
-#define BLANK() asm volatile("\n->" : : )
+#define BLANK() asm volatile("\n.ascii \"->\"" : : )
#define OFFSET(sym, str, mem) \
DEFINE(sym, offsetof(struct str, mem))
#define COMMENT(x) \
- asm volatile("\n->#" x)
+ asm volatile("\n.ascii \"->#" x "\"")
#endif
diff --git a/include/linux/kcov.h b/include/linux/kcov.h
index 2883ac9..87e2a44 100644
--- a/include/linux/kcov.h
+++ b/include/linux/kcov.h
@@ -7,19 +7,23 @@
#ifdef CONFIG_KCOV
-void kcov_task_init(struct task_struct *t);
-void kcov_task_exit(struct task_struct *t);
-
enum kcov_mode {
/* Coverage collection is not enabled yet. */
KCOV_MODE_DISABLED = 0,
+ /* KCOV was initialized, but tracing mode hasn't been chosen yet. */
+ KCOV_MODE_INIT = 1,
/*
* Tracing coverage collection mode.
* Covered PCs are collected in a per-task buffer.
*/
- KCOV_MODE_TRACE = 1,
+ KCOV_MODE_TRACE_PC = 2,
+ /* Collecting comparison operands mode. */
+ KCOV_MODE_TRACE_CMP = 3,
};
+void kcov_task_init(struct task_struct *t);
+void kcov_task_exit(struct task_struct *t);
+
#else
static inline void kcov_task_init(struct task_struct *t) {}
diff --git a/include/linux/key.h b/include/linux/key.h
index ed9b44f..7e2d143 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -369,7 +369,10 @@
return key_read_state(key) < 0;
}
-#define rcu_dereference_key(KEY) \
+#define dereference_key_rcu(KEY) \
+ (rcu_dereference((KEY)->payload.rcu_data0))
+
+#define dereference_key_locked(KEY) \
(rcu_dereference_protected((KEY)->payload.rcu_data0, \
rwsem_is_locked(&((struct key *)(KEY))->sem)))
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index 74de8b6..5c8b65a 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -108,6 +108,8 @@
extern int __must_check kobject_move(struct kobject *, struct kobject *);
extern struct kobject *kobject_get(struct kobject *kobj);
+extern struct kobject * __must_check kobject_get_unless_zero(
+ struct kobject *kobj);
extern void kobject_put(struct kobject *kobj);
extern const void *kobject_namespace(struct kobject *kobj);
diff --git a/include/linux/llist.h b/include/linux/llist.h
index fd4ca0b..ac67961 100644
--- a/include/linux/llist.h
+++ b/include/linux/llist.h
@@ -88,6 +88,23 @@
container_of(ptr, type, member)
/**
+ * member_address_is_nonnull - check whether the member address is not NULL
+ * @ptr: the object pointer (struct type * that contains the llist_node)
+ * @member: the name of the llist_node within the struct.
+ *
+ * This macro is conceptually the same as
+ * &ptr->member != NULL
+ * but it works around the fact that compilers can decide that taking a member
+ * address is never a NULL pointer.
+ *
+ * Real objects that start at a high address and have a member at NULL are
+ * unlikely to exist, but such pointers may be returned e.g. by the
+ * container_of() macro.
+ */
+#define member_address_is_nonnull(ptr, member) \
+ ((uintptr_t)(ptr) + offsetof(typeof(*(ptr)), member) != 0)
+
+/**
* llist_for_each - iterate over some deleted entries of a lock-less list
* @pos: the &struct llist_node to use as a loop cursor
* @node: the first entry of deleted list entries
@@ -121,7 +138,7 @@
*/
#define llist_for_each_entry(pos, node, member) \
for ((pos) = llist_entry((node), typeof(*(pos)), member); \
- &(pos)->member != NULL; \
+ member_address_is_nonnull(pos, member); \
(pos) = llist_entry((pos)->member.next, typeof(*(pos)), member))
/**
@@ -143,7 +160,7 @@
*/
#define llist_for_each_entry_safe(pos, n, node, member) \
for (pos = llist_entry((node), typeof(*pos), member); \
- &pos->member != NULL && \
+ member_address_is_nonnull(pos, member) && \
(n = llist_entry(pos->member.next, typeof(*n), member), true); \
pos = n)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 580cc10..be65c03 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1328,7 +1328,40 @@
* @inode we wish to get the security context of.
* @ctx is a pointer in which to place the allocated security context.
* @ctxlen points to the place to put the length of @ctx.
- * This is the main security structure.
+ *
+ * Security hooks for using the eBPF maps and programs functionalities through
+ * eBPF syscalls.
+ *
+ * @bpf:
+ * Do a initial check for all bpf syscalls after the attribute is copied
+ * into the kernel. The actual security module can implement their own
+ * rules to check the specific cmd they need.
+ *
+ * @bpf_map:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF maps.
+ *
+ * @map: bpf map that we want to access
+ * @mask: the access flags
+ *
+ * @bpf_prog:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF programs.
+ *
+ * @prog: bpf prog that userspace want to use.
+ *
+ * @bpf_map_alloc_security:
+ * Initialize the security field inside bpf map.
+ *
+ * @bpf_map_free_security:
+ * Clean up the security information stored inside bpf map.
+ *
+ * @bpf_prog_alloc_security:
+ * Initialize the security field inside bpf program.
+ *
+ * @bpf_prog_free_security:
+ * Clean up the security information stored inside bpf prog.
+ *
*/
union security_list_options {
@@ -1419,8 +1452,6 @@
size_t *len);
int (*inode_create)(struct inode *dir, struct dentry *dentry,
umode_t mode);
- int (*inode_post_create)(struct inode *dir, struct dentry *dentry,
- umode_t mode);
int (*inode_link)(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry);
int (*inode_unlink)(struct inode *dir, struct dentry *dentry);
@@ -1654,6 +1685,17 @@
struct audit_context *actx);
void (*audit_rule_free)(void *lsmrule);
#endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_BPF_SYSCALL
+ int (*bpf)(int cmd, union bpf_attr *attr,
+ unsigned int size);
+ int (*bpf_map)(struct bpf_map *map, fmode_t fmode);
+ int (*bpf_prog)(struct bpf_prog *prog);
+ int (*bpf_map_alloc_security)(struct bpf_map *map);
+ void (*bpf_map_free_security)(struct bpf_map *map);
+ int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
+ void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
+#endif /* CONFIG_BPF_SYSCALL */
};
struct security_hook_heads {
@@ -1708,7 +1750,6 @@
struct list_head inode_free_security;
struct list_head inode_init_security;
struct list_head inode_create;
- struct list_head inode_post_create;
struct list_head inode_link;
struct list_head inode_unlink;
struct list_head inode_symlink;
@@ -1869,6 +1910,15 @@
struct list_head audit_rule_match;
struct list_head audit_rule_free;
#endif /* CONFIG_AUDIT */
+#ifdef CONFIG_BPF_SYSCALL
+ struct list_head bpf;
+ struct list_head bpf_map;
+ struct list_head bpf_prog;
+ struct list_head bpf_map_alloc_security;
+ struct list_head bpf_map_free_security;
+ struct list_head bpf_prog_alloc_security;
+ struct list_head bpf_prog_free_security;
+#endif /* CONFIG_BPF_SYSCALL */
};
/*
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 089c18b..2d4d24f 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -610,7 +610,8 @@
#ifdef CONFIG_BLOCK
int latency_hist_enabled;
- struct io_latency_state io_lat_s;
+ struct io_latency_state io_lat_read;
+ struct io_latency_state io_lat_write;
#endif
bool sdr104_wa;
diff --git a/include/linux/module.h b/include/linux/module.h
index 0c3207d..fd9e121 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -127,13 +127,13 @@
/* Each module must use one module_init(). */
#define module_init(initfn) \
- static inline initcall_t __inittest(void) \
+ static inline initcall_t __maybe_unused __inittest(void) \
{ return initfn; } \
int init_module(void) __attribute__((alias(#initfn)));
/* This is only required if you want to be unloadable. */
#define module_exit(exitfn) \
- static inline exitcall_t __exittest(void) \
+ static inline exitcall_t __maybe_unused __exittest(void) \
{ return exitfn; } \
void cleanup_module(void) __attribute__((alias(#exitfn)));
@@ -791,6 +791,15 @@
static inline void module_bug_cleanup(struct module *mod) {}
#endif /* CONFIG_GENERIC_BUG */
+#ifdef RETPOLINE
+extern bool retpoline_module_ok(bool has_retpoline);
+#else
+static inline bool retpoline_module_ok(bool has_retpoline)
+{
+ return true;
+}
+#endif
+
#ifdef CONFIG_MODULE_SIG
static inline bool module_sig_ok(struct module *module)
{
diff --git a/include/linux/msm_hdcp.h b/include/linux/msm_hdcp.h
new file mode 100644
index 0000000..e25d242
--- /dev/null
+++ b/include/linux/msm_hdcp.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2018, 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_HDCP_H
+#define __MSM_HDCP_H
+#include <linux/types.h>
+#include "video/msm_hdmi_hdcp_mgr.h"
+
+void msm_hdcp_notify_topology(struct device *dev);
+void msm_hdcp_cache_repeater_topology(struct device *dev,
+ struct HDCP_V2V1_MSG_TOPOLOGY *tp);
+void msm_hdcp_register_cb(struct device *dev, void *ctx,
+ void (*cb)(void *ctx, int data));
+
+#endif /* __MSM_HDCP_H */
+
+
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
index 3aa56e3..b5b43f9 100644
--- a/include/linux/mtd/map.h
+++ b/include/linux/mtd/map.h
@@ -270,75 +270,67 @@
#define INVALIDATE_CACHED_RANGE(map, from, size) \
do { if (map->inval_cache) map->inval_cache(map, from, size); } while (0)
+#define map_word_equal(map, val1, val2) \
+({ \
+ int i, ret = 1; \
+ for (i = 0; i < map_words(map); i++) \
+ if ((val1).x[i] != (val2).x[i]) { \
+ ret = 0; \
+ break; \
+ } \
+ ret; \
+})
-static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2)
-{
- int i;
+#define map_word_and(map, val1, val2) \
+({ \
+ map_word r; \
+ int i; \
+ for (i = 0; i < map_words(map); i++) \
+ r.x[i] = (val1).x[i] & (val2).x[i]; \
+ r; \
+})
- for (i = 0; i < map_words(map); i++) {
- if (val1.x[i] != val2.x[i])
- return 0;
- }
+#define map_word_clr(map, val1, val2) \
+({ \
+ map_word r; \
+ int i; \
+ for (i = 0; i < map_words(map); i++) \
+ r.x[i] = (val1).x[i] & ~(val2).x[i]; \
+ r; \
+})
- return 1;
-}
+#define map_word_or(map, val1, val2) \
+({ \
+ map_word r; \
+ int i; \
+ for (i = 0; i < map_words(map); i++) \
+ r.x[i] = (val1).x[i] | (val2).x[i]; \
+ r; \
+})
-static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2)
-{
- map_word r;
- int i;
+#define map_word_andequal(map, val1, val2, val3) \
+({ \
+ int i, ret = 1; \
+ for (i = 0; i < map_words(map); i++) { \
+ if (((val1).x[i] & (val2).x[i]) != (val2).x[i]) { \
+ ret = 0; \
+ break; \
+ } \
+ } \
+ ret; \
+})
- for (i = 0; i < map_words(map); i++)
- r.x[i] = val1.x[i] & val2.x[i];
-
- return r;
-}
-
-static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2)
-{
- map_word r;
- int i;
-
- for (i = 0; i < map_words(map); i++)
- r.x[i] = val1.x[i] & ~val2.x[i];
-
- return r;
-}
-
-static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
-{
- map_word r;
- int i;
-
- for (i = 0; i < map_words(map); i++)
- r.x[i] = val1.x[i] | val2.x[i];
-
- return r;
-}
-
-static inline int map_word_andequal(struct map_info *map, map_word val1, map_word val2, map_word val3)
-{
- int i;
-
- for (i = 0; i < map_words(map); i++) {
- if ((val1.x[i] & val2.x[i]) != val3.x[i])
- return 0;
- }
-
- return 1;
-}
-
-static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
-{
- int i;
-
- for (i = 0; i < map_words(map); i++) {
- if (val1.x[i] & val2.x[i])
- return 1;
- }
-
- return 0;
-}
+#define map_word_bitsset(map, val1, val2) \
+({ \
+ int i, ret = 0; \
+ for (i = 0; i < map_words(map); i++) { \
+ if ((val1).x[i] & (val2).x[i]) { \
+ ret = 1; \
+ break; \
+ } \
+ } \
+ ret; \
+})
static inline map_word map_word_load(struct map_info *map, const void *ptr)
{
diff --git a/include/linux/nospec.h b/include/linux/nospec.h
new file mode 100644
index 0000000..fbc98e2
--- /dev/null
+++ b/include/linux/nospec.h
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2018 Linus Torvalds. All rights reserved.
+// Copyright(c) 2018 Alexei Starovoitov. All rights reserved.
+// Copyright(c) 2018 Intel Corporation. All rights reserved.
+
+#ifndef _LINUX_NOSPEC_H
+#define _LINUX_NOSPEC_H
+
+/**
+ * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ *
+ * When @index is out of bounds (@index >= @size), the sign bit will be
+ * set. Extend the sign bit to all bits and invert, giving a result of
+ * zero for an out of bounds index, or ~0 if within bounds [0, @size).
+ */
+#ifndef array_index_mask_nospec
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+ unsigned long size)
+{
+ /*
+ * Always calculate and emit the mask even if the compiler
+ * thinks the mask is not needed. The compiler does not take
+ * into account the value of @index under speculation.
+ */
+ OPTIMIZER_HIDE_VAR(index);
+ return ~(long)(index | (size - 1UL - index)) >> (BITS_PER_LONG - 1);
+}
+#endif
+
+/*
+ * Warn developers about inappropriate array_index_nospec() usage.
+ *
+ * Even if the CPU speculates past the WARN_ONCE branch, the
+ * sign bit of @index is taken into account when generating the
+ * mask.
+ *
+ * This warning is compiled out when the compiler can infer that
+ * @index and @size are less than LONG_MAX.
+ */
+#define array_index_mask_nospec_check(index, size) \
+({ \
+ if (WARN_ONCE(index > LONG_MAX || size > LONG_MAX, \
+ "array_index_nospec() limited to range of [0, LONG_MAX]\n")) \
+ _mask = 0; \
+ else \
+ _mask = array_index_mask_nospec(index, size); \
+ _mask; \
+})
+
+/*
+ * array_index_nospec - sanitize an array index after a bounds check
+ *
+ * For a code sequence like:
+ *
+ * if (index < size) {
+ * index = array_index_nospec(index, size);
+ * val = array[index];
+ * }
+ *
+ * ...if the CPU speculates past the bounds check then
+ * array_index_nospec() will clamp the index within the range of [0,
+ * size).
+ */
+#define array_index_nospec(index, size) \
+({ \
+ typeof(index) _i = (index); \
+ typeof(size) _s = (size); \
+ unsigned long _mask = array_index_mask_nospec_check(_i, _s); \
+ \
+ BUILD_BUG_ON(sizeof(_i) > sizeof(long)); \
+ BUILD_BUG_ON(sizeof(_s) > sizeof(long)); \
+ \
+ _i &= _mask; \
+ _i; \
+})
+#endif /* _LINUX_NOSPEC_H */
diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
index 7adad20..e19efac 100644
--- a/include/linux/pci-ecam.h
+++ b/include/linux/pci-ecam.h
@@ -59,7 +59,7 @@
/* default ECAM ops */
extern struct pci_ecam_ops pci_generic_ecam_ops;
-#ifdef CONFIG_PCI_HOST_GENERIC
+#ifdef CONFIG_PCI_HOST_COMMON
/* for DT-based PCI controllers that support ECAM */
int pci_host_common_probe(struct platform_device *pdev,
struct pci_ecam_ops *ops);
diff --git a/include/linux/pfk.h b/include/linux/pfk.h
deleted file mode 100644
index 82ee741..0000000
--- a/include/linux/pfk.h
+++ /dev/null
@@ -1,57 +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 PFK_H_
-#define PFK_H_
-
-#include <linux/bio.h>
-
-struct ice_crypto_setting;
-
-#ifdef CONFIG_PFK
-
-int pfk_load_key_start(const struct bio *bio,
- struct ice_crypto_setting *ice_setting, bool *is_pfe, bool);
-int pfk_load_key_end(const struct bio *bio, bool *is_pfe);
-int pfk_remove_key(const unsigned char *key, size_t key_size);
-bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2);
-void pfk_clear_on_reset(void);
-
-#else
-static inline int pfk_load_key_start(const struct bio *bio,
- struct ice_crypto_setting *ice_setting, bool *is_pfe, bool async)
-{
- return -ENODEV;
-}
-
-static inline int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
-{
- return -ENODEV;
-}
-
-static inline int pfk_remove_key(const unsigned char *key, size_t key_size)
-{
- return -ENODEV;
-}
-
-static inline bool pfk_allow_merge_bio(const struct bio *bio1,
- const struct bio *bio2)
-{
- return true;
-}
-
-static inline void pfk_clear_on_reset(void)
-{}
-
-#endif /* CONFIG_PFK */
-
-#endif /* PFK_H */
diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h
index e38f471..05c6d20 100644
--- a/include/linux/ptr_ring.h
+++ b/include/linux/ptr_ring.h
@@ -351,6 +351,8 @@
static inline void **__ptr_ring_init_queue_alloc(unsigned int size, gfp_t gfp)
{
+ if (size * sizeof(void *) > KMALLOC_MAX_SIZE)
+ return NULL;
return kcalloc(size, sizeof(void *), gfp);
}
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 9a079a6..a083370 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -133,8 +133,11 @@
VADC_VCOIN = 0x85,
VADC_DIE_TEMP = 6,
VADC_CHG_TEMP = 7,
+ VADC_USB_IN_I_PM5 = 7,
VADC_USB_IN = 8,
+ VADC_USB_IN_V_DIV_16_PM5 = 8,
VADC_IREG_FB = 9,
+ VADC_CHG_TEMP_PM5 = 9,
/* External input connection */
VADC_BAT_THERM = 0xa,
VADC_BAT_ID = 0xb,
@@ -156,6 +159,7 @@
VADC_ATEST2 = 0x1b,
VADC_ATEST3 = 0x1c,
VADC_ATEST4 = 0x1d,
+ VADC_MID_CHG_DIV_6 = 0x1e,
VADC_OFF = 0xff,
/* PU1 is 30K pull up */
VADC_BAT_THERM_PU1 = 0x2a,
@@ -222,6 +226,13 @@
VADC_ATEST3_DIV_3 = 0x9c,
VADC_ATEST4_DIV_3 = 0x9d,
VADC_REFRESH_MAX_NUM = 0xffff,
+ /*Current and synchronous channels*/
+ VADC_ISNS_INT_EXT_PM5 = 0xa1,
+ VADC_ISNS_PAR_PM5 = 0xa5,
+ VADC_V_I_INT_EXT_VDATA_PM5 = 0xb0,
+ VADC_V_I_INT_EXT_IDATA_PM5 = 0xb1,
+ VADC_V_I_PAR_VDATA_PM5 = 0xb4,
+ VADC_V_I_PAR_IDATA_PM5 = 0xb5,
};
/**
@@ -388,6 +399,9 @@
* %SCALE_DIE_TEMP: Conversion for die temp.
* %SCALE_I_DEFAULT: Default scaling to convert raw adc code to current (uA).
* %SCALE_USBIN_I: Conversion for USB input current.
+ * %SCALE_BATT_THERM_TEMP_QRD: Conversion to temperature(decidegC) based on btm
+ * parameters for QRD.
+ * %SCALE_SMB1390_DIE_TEMP: Conversion for SMB1390 die temp
* %SCALE_NONE: Do not use this scaling type.
*/
enum qpnp_adc_scale_fn_type {
@@ -410,6 +424,8 @@
SCALE_DIE_TEMP,
SCALE_I_DEFAULT,
SCALE_USBIN_I,
+ SCALE_BATT_THERM_TEMP_QRD,
+ SCALE_SMB1390_DIE_TEMP,
SCALE_NONE,
};
@@ -1432,6 +1448,23 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
/**
+ * qpnp_adc_batt_therm_qrd() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. Returns the temperature in decidegC for QRD.
+ * @dev: Structure device for qpnp vadc
+ * @adc_code: pre-calibrated digital output of the ADC.
+ * @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: physical result to be stored.
+ */
+int32_t qpnp_adc_batt_therm_qrd(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
* qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset. Returns the temperature in decidegC.
@@ -1692,6 +1725,25 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
/**
+ * qpnp_adc_scale_die_temp_1390() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. The voltage measured by HKADC is related to
+ * the junction temperature according to
+ * V_adc = 1.496 – 0.00381*Tj
+ * @dev: Structure device for qpnp vadc
+ * @adc_code: pre-calibrated digital output of the ADC.
+ * @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: physical result to be stored.
+ */
+int32_t qpnp_adc_scale_die_temp_1390(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
* qpnp_get_vadc() - Clients need to register with the vadc using the
* corresponding device instance it wants to read the channels
* from. Read the bindings document on how to pass the phandle
@@ -2033,6 +2085,12 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
+static inline int32_t qpnp_adc_batt_therm_qrd(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
static inline int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *vadc,
int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
@@ -2123,6 +2181,12 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_die_temp_1390(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
static inline struct qpnp_vadc_chip *qpnp_get_vadc(struct device *dev,
const char *name)
{ return ERR_PTR(-ENXIO); }
diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
index 8933742..c1206c6 100644
--- a/include/linux/qpnp/qpnp-revid.h
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -162,6 +162,9 @@
#define PM8950_V2P0_REV4 0x02
+/* PM8953 */
+#define PM8953_SUBTYPE 0x16
+
/* PMI8950 */
#define PMI8950_SUBTYPE 0x11
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 290e2b2..8933c9f 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2754,11 +2754,6 @@
return 0;
}
-static inline void
-sched_set_cpu_cstate(int cpu, int cstate, int wakeup_energy, int wakeup_latency)
-{
-}
-
#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);
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
index 3e97574..0f57407 100644
--- a/include/linux/sched/sysctl.h
+++ b/include/linux/sched/sysctl.h
@@ -21,7 +21,6 @@
extern unsigned int sysctl_sched_child_runs_first;
extern unsigned int sysctl_sched_is_big_little;
extern unsigned int sysctl_sched_sync_hint_enable;
-extern unsigned int sysctl_sched_initial_task_util;
extern unsigned int sysctl_sched_cstate_aware;
extern unsigned int sysctl_sched_capacity_margin;
extern unsigned int sysctl_sched_capacity_margin_down;
diff --git a/include/linux/security.h b/include/linux/security.h
index 02e05de..3632428 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -30,7 +30,6 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/fs.h>
-#include <linux/bio.h>
struct linux_binprm;
struct cred;
@@ -257,8 +256,6 @@
const struct qstr *qstr, const char **name,
void **value, size_t *len);
int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode);
-int security_inode_post_create(struct inode *dir, struct dentry *dentry,
- umode_t mode);
int security_inode_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry);
int security_inode_unlink(struct inode *dir, struct dentry *dentry);
@@ -307,7 +304,6 @@
struct fown_struct *fown, int sig);
int security_file_receive(struct file *file);
int security_file_open(struct file *file, const struct cred *cred);
-
int security_task_create(unsigned long clone_flags);
void security_task_free(struct task_struct *task);
int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
@@ -641,13 +637,6 @@
return 0;
}
-static inline int security_inode_post_create(struct inode *dir,
- struct dentry *dentry,
- umode_t mode)
-{
- return 0;
-}
-
static inline int security_inode_link(struct dentry *old_dentry,
struct inode *dir,
struct dentry *new_dentry)
@@ -1673,6 +1662,54 @@
#endif
+#ifdef CONFIG_BPF_SYSCALL
+union bpf_attr;
+struct bpf_map;
+struct bpf_prog;
+struct bpf_prog_aux;
+#ifdef CONFIG_SECURITY
+extern int security_bpf(int cmd, union bpf_attr *attr, unsigned int size);
+extern int security_bpf_map(struct bpf_map *map, fmode_t fmode);
+extern int security_bpf_prog(struct bpf_prog *prog);
+extern int security_bpf_map_alloc(struct bpf_map *map);
+extern void security_bpf_map_free(struct bpf_map *map);
+extern int security_bpf_prog_alloc(struct bpf_prog_aux *aux);
+extern void security_bpf_prog_free(struct bpf_prog_aux *aux);
+#else
+static inline int security_bpf(int cmd, union bpf_attr *attr,
+ unsigned int size)
+{
+ return 0;
+}
+
+static inline int security_bpf_map(struct bpf_map *map, fmode_t fmode)
+{
+ return 0;
+}
+
+static inline int security_bpf_prog(struct bpf_prog *prog)
+{
+ return 0;
+}
+
+static inline int security_bpf_map_alloc(struct bpf_map *map)
+{
+ return 0;
+}
+
+static inline void security_bpf_map_free(struct bpf_map *map)
+{ }
+
+static inline int security_bpf_prog_alloc(struct bpf_prog_aux *aux)
+{
+ return 0;
+}
+
+static inline void security_bpf_prog_free(struct bpf_prog_aux *aux)
+{ }
+#endif /* CONFIG_SECURITY */
+#endif /* CONFIG_BPF_SYSCALL */
+
#ifdef CONFIG_SECURITY
static inline char *alloc_secdata(void)
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 53af941..4b5dc54 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -601,7 +601,7 @@
int (*framer_handover)(struct slim_controller *ctrl,
struct slim_framer *new_framer);
int (*port_xfer)(struct slim_controller *ctrl,
- u8 pn, phys_addr_t iobuf, u32 len,
+ u8 pn, void *buf, u32 len,
struct completion *comp);
enum slim_port_err (*port_xfer_status)(struct slim_controller *ctr,
u8 pn, phys_addr_t *done_buf, u32 *done_len);
@@ -869,7 +869,7 @@
* Client will call slim_port_get_xfer_status to get error and/or number of
* bytes transferred if used asynchronously.
*/
-extern int slim_port_xfer(struct slim_device *sb, u32 ph, phys_addr_t iobuf,
+extern int slim_port_xfer(struct slim_device *sb, u32 ph, void *buf,
u32 len, struct completion *comp);
/*
diff --git a/include/linux/string.h b/include/linux/string.h
index 4691e7f..b7e8f42 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -123,6 +123,7 @@
extern const char *kstrdup_const(const char *s, gfp_t gfp);
extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
+extern char *kmemdup_nul(const char *s, size_t len, gfp_t gfp);
extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
extern void argv_free(char **argv);
diff --git a/include/linux/sw_sync.h b/include/linux/sw_sync.h
new file mode 100644
index 0000000..69f1391
--- /dev/null
+++ b/include/linux/sw_sync.h
@@ -0,0 +1,59 @@
+/*
+ * include/linux/sw_sync.h
+ *
+ * Copyright (C) 2012 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_SW_SYNC_H
+#define _LINUX_SW_SYNC_H
+
+#include <linux/types.h>
+#include <linux/kconfig.h>
+#include <linux/sync.h>
+#include <uapi/linux/sw_sync.h>
+
+struct sw_sync_timeline {
+ struct sync_timeline obj;
+
+ u32 value;
+};
+
+struct sw_sync_pt {
+ struct sync_pt pt;
+
+ u32 value;
+};
+
+#if IS_ENABLED(CONFIG_SW_SYNC)
+struct sw_sync_timeline *sw_sync_timeline_create(const char *name);
+void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc);
+
+struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value);
+#else
+static inline struct sw_sync_timeline *sw_sync_timeline_create(const char *name)
+{
+ return NULL;
+}
+
+static inline void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc)
+{
+}
+
+static inline struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj,
+ u32 value)
+{
+ return NULL;
+}
+#endif /* IS_ENABLED(CONFIG_SW_SYNC) */
+
+#endif /* _LINUX_SW_SYNC_H */
diff --git a/include/linux/sync.h b/include/linux/sync.h
new file mode 100644
index 0000000..a443b52
--- /dev/null
+++ b/include/linux/sync.h
@@ -0,0 +1,349 @@
+/*
+ * include/linux/sync.h
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * 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_SYNC_H
+#define _LINUX_SYNC_H
+
+#include <linux/types.h>
+#include <linux/kref.h>
+#include <linux/ktime.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+#include <uapi/linux/sync.h>
+
+struct sync_timeline;
+struct sync_pt;
+struct sync_fence;
+struct seq_file;
+
+/**
+ * struct sync_timeline_ops - sync object implementation ops
+ * @driver_name: name of the implementation
+ * @dup: duplicate a sync_pt
+ * @has_signaled: returns:
+ * 1 if pt has signaled
+ * 0 if pt has not signaled
+ * <0 on error
+ * @compare: returns:
+ * 1 if b will signal before a
+ * 0 if a and b will signal at the same time
+ * -1 if a will signal before b
+ * @free_pt: called before sync_pt is freed
+ * @release_obj: called before sync_timeline is freed
+ * @print_obj: deprecated
+ * @print_pt: deprecated
+ * @fill_driver_data: write implementation specific driver data to data.
+ * should return an error if there is not enough room
+ * as specified by size. This information is returned
+ * to userspace by SYNC_IOC_FENCE_INFO.
+ * @timeline_value_str: fill str with the value of the sync_timeline's counter
+ * @pt_value_str: fill str with the value of the sync_pt
+ */
+struct sync_timeline_ops {
+ const char *driver_name;
+
+ /* required */
+ struct sync_pt * (*dup)(struct sync_pt *pt);
+
+ /* required */
+ int (*has_signaled)(struct sync_pt *pt);
+
+ /* required */
+ int (*compare)(struct sync_pt *a, struct sync_pt *b);
+
+ /* optional */
+ void (*free_pt)(struct sync_pt *sync_pt);
+
+ /* optional */
+ void (*release_obj)(struct sync_timeline *sync_timeline);
+
+ /* deprecated */
+ void (*print_obj)(struct seq_file *s,
+ struct sync_timeline *sync_timeline);
+
+ /* deprecated */
+ void (*print_pt)(struct seq_file *s, struct sync_pt *sync_pt);
+
+ /* optional */
+ int (*fill_driver_data)(struct sync_pt *syncpt, void *data, int size);
+
+ /* optional */
+ void (*timeline_value_str)(struct sync_timeline *timeline, char *str,
+ int size);
+
+ /* optional */
+ void (*pt_value_str)(struct sync_pt *pt, char *str, int size);
+
+ /* optional */
+ void (*pt_log)(struct sync_pt *pt);
+};
+
+/**
+ * struct sync_timeline - sync object
+ * @kref: reference count on fence.
+ * @ops: ops that define the implementation of the sync_timeline
+ * @name: name of the sync_timeline. Useful for debugging
+ * @destroyed: set when sync_timeline is destroyed
+ * @child_list_head: list of children sync_pts for this sync_timeline
+ * @child_list_lock: lock protecting @child_list_head, destroyed, and
+ * sync_pt.status
+ * @active_list_head: list of active (unsignaled/errored) sync_pts
+ * @sync_timeline_list: membership in global sync_timeline_list
+ */
+struct sync_timeline {
+ struct kref kref;
+ const struct sync_timeline_ops *ops;
+ char name[64];
+
+ /* protected by child_list_lock */
+ bool destroyed;
+
+ struct list_head child_list_head;
+ spinlock_t child_list_lock;
+
+ struct list_head active_list_head;
+ spinlock_t active_list_lock;
+
+ struct list_head sync_timeline_list;
+};
+
+/**
+ * struct sync_pt - sync point
+ * @parent: sync_timeline to which this sync_pt belongs
+ * @child_list: membership in sync_timeline.child_list_head
+ * @active_list: membership in sync_timeline.active_list_head
+ * @signaled_list: membership in temporary signaled_list on stack
+ * @fence: sync_fence to which the sync_pt belongs
+ * @pt_list: membership in sync_fence.pt_list_head
+ * @status: 1: signaled, 0:active, <0: error
+ * @timestamp: time which sync_pt status transitioned from active to
+ * signaled or error.
+ */
+struct sync_pt {
+ struct sync_timeline *parent;
+ struct list_head child_list;
+
+ struct list_head active_list;
+ struct list_head signaled_list;
+
+ struct sync_fence *fence;
+ struct list_head pt_list;
+
+ /* protected by parent->active_list_lock */
+ int status;
+
+ ktime_t timestamp;
+};
+
+/**
+ * struct sync_fence - sync fence
+ * @file: file representing this fence
+ * @kref: reference count on fence.
+ * @name: name of sync_fence. Useful for debugging
+ * @pt_list_head: list of sync_pts in the fence. immutable once fence
+ * is created
+ * @waiter_list_head: list of asynchronous waiters on this fence
+ * @waiter_list_lock: lock protecting @waiter_list_head and @status
+ * @status: 1: signaled, 0:active, <0: error
+ *
+ * @wq: wait queue for fence signaling
+ * @sync_fence_list: membership in global fence list
+ */
+struct sync_fence {
+ struct file *file;
+ struct kref kref;
+ char name[64];
+
+ /* this list is immutable once the fence is created */
+ struct list_head pt_list_head;
+
+ struct list_head waiter_list_head;
+ spinlock_t waiter_list_lock; /* also protects status */
+ int status;
+
+ wait_queue_head_t wq;
+
+ struct list_head sync_fence_list;
+};
+
+struct sync_fence_waiter;
+typedef void (*sync_callback_t)(struct sync_fence *fence,
+ struct sync_fence_waiter *waiter);
+
+/**
+ * struct sync_fence_waiter - metadata for asynchronous waiter on a fence
+ * @waiter_list: membership in sync_fence.waiter_list_head
+ * @callback: function pointer to call when fence signals
+ * @callback_data: pointer to pass to @callback
+ */
+struct sync_fence_waiter {
+ struct list_head waiter_list;
+
+ sync_callback_t callback;
+};
+
+static inline void sync_fence_waiter_init(struct sync_fence_waiter *waiter,
+ sync_callback_t callback)
+{
+ waiter->callback = callback;
+}
+
+/*
+ * API for sync_timeline implementers
+ */
+
+/**
+ * sync_timeline_create() - creates a sync object
+ * @ops: specifies the implementation ops for the object
+ * @size: size to allocate for this obj
+ * @name: sync_timeline name
+ *
+ * Creates a new sync_timeline which will use the implementation specified by
+ * @ops. @size bytes will be allocated allowing for implementation specific
+ * data to be kept after the generic sync_timeline struct.
+ */
+struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops,
+ int size, const char *name);
+
+/**
+ * sync_timeline_destroy() - destroys a sync object
+ * @obj: sync_timeline to destroy
+ *
+ * A sync implementation should call this when the @obj is going away
+ * (i.e. module unload.) @obj won't actually be freed until all its children
+ * sync_pts are freed.
+ */
+void sync_timeline_destroy(struct sync_timeline *obj);
+
+/**
+ * sync_timeline_signal() - signal a status change on a sync_timeline
+ * @obj: sync_timeline to signal
+ *
+ * A sync implementation should call this any time one of it's sync_pts
+ * has signaled or has an error condition.
+ */
+void sync_timeline_signal(struct sync_timeline *obj);
+
+/**
+ * sync_pt_create() - creates a sync pt
+ * @parent: sync_pt's parent sync_timeline
+ * @size: size to allocate for this pt
+ *
+ * Creates a new sync_pt as a child of @parent. @size bytes will be
+ * allocated allowing for implementation specific data to be kept after
+ * the generic sync_timeline struct.
+ */
+struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size);
+
+/**
+ * sync_pt_free() - frees a sync pt
+ * @pt: sync_pt to free
+ *
+ * This should only be called on sync_pts which have been created but
+ * not added to a fence.
+ */
+void sync_pt_free(struct sync_pt *pt);
+
+/**
+ * sync_fence_create() - creates a sync fence
+ * @name: name of fence to create
+ * @pt: sync_pt to add to the fence
+ *
+ * Creates a fence containg @pt. Once this is called, the fence takes
+ * ownership of @pt.
+ */
+struct sync_fence *sync_fence_create(const char *name, struct sync_pt *pt);
+
+/*
+ * API for sync_fence consumers
+ */
+
+/**
+ * sync_fence_merge() - merge two fences
+ * @name: name of new fence
+ * @a: fence a
+ * @b: fence b
+ *
+ * Creates a new fence which contains copies of all the sync_pts in both
+ * @a and @b. @a and @b remain valid, independent fences.
+ */
+struct sync_fence *sync_fence_merge(const char *name,
+ struct sync_fence *a, struct sync_fence *b);
+
+/**
+ * sync_fence_fdget() - get a fence from an fd
+ * @fd: fd referencing a fence
+ *
+ * Ensures @fd references a valid fence, increments the refcount of the backing
+ * file, and returns the fence.
+ */
+struct sync_fence *sync_fence_fdget(int fd);
+
+/**
+ * sync_fence_put() - puts a reference of a sync fence
+ * @fence: fence to put
+ *
+ * Puts a reference on @fence. If this is the last reference, the fence and
+ * all it's sync_pts will be freed
+ */
+void sync_fence_put(struct sync_fence *fence);
+
+/**
+ * sync_fence_install() - installs a fence into a file descriptor
+ * @fence: fence to install
+ * @fd: file descriptor in which to install the fence
+ *
+ * Installs @fence into @fd. @fd's should be acquired through
+ * get_unused_fd_flags(O_CLOEXEC).
+ */
+void sync_fence_install(struct sync_fence *fence, int fd);
+
+/**
+ * sync_fence_wait_async() - registers and async wait on the fence
+ * @fence: fence to wait on
+ * @waiter: waiter callback struck
+ *
+ * Returns 1 if @fence has already signaled.
+ *
+ * Registers a callback to be called when @fence signals or has an error.
+ * @waiter should be initialized with sync_fence_waiter_init().
+ */
+int sync_fence_wait_async(struct sync_fence *fence,
+ struct sync_fence_waiter *waiter);
+
+/**
+ * sync_fence_cancel_async() - cancels an async wait
+ * @fence: fence to wait on
+ * @waiter: waiter callback struck
+ *
+ * returns 0 if waiter was removed from fence's async waiter list.
+ * returns -ENOENT if waiter was not found on fence's async waiter list.
+ *
+ * Cancels a previously registered async wait. Will fail gracefully if
+ * @waiter was never registered or if @fence has already signaled @waiter.
+ */
+int sync_fence_cancel_async(struct sync_fence *fence,
+ struct sync_fence_waiter *waiter);
+
+/**
+ * sync_fence_wait() - wait on fence
+ * @fence: fence to wait on
+ * @tiemout: timeout in ms
+ *
+ * Wait for @fence to be signaled or have an error. Waits indefinitely
+ * if @timeout < 0
+ */
+int sync_fence_wait(struct sync_fence *fence, long timeout);
+
+#endif /* _LINUX_SYNC_H */
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index f50b717c..fc11641 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -219,8 +219,9 @@
} rack;
u16 advmss; /* Advertised MSS */
u8 rate_app_limited:1, /* rate_{delivered,interval_us} limited? */
+ fastopen_connect:1, /* FASTOPEN_CONNECT sockopt */
is_sack_reneg:1, /* in recovery from loss with SACK reneg? */
- unused:6;
+ unused:5;
u8 nonagle : 4,/* Disable Nagle algorithm? */
thin_lto : 1,/* Use linear timeouts for thin streams */
thin_dupack : 1,/* Fast retransmit on first dupack */
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
new file mode 100644
index 0000000..a2b3dfc
--- /dev/null
+++ b/include/linux/tee_drv.h
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ *
+ * 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 __TEE_DRV_H
+#define __TEE_DRV_H
+
+#include <linux/types.h>
+#include <linux/idr.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/tee.h>
+
+/*
+ * The file describes the API provided by the generic TEE driver to the
+ * specific TEE driver.
+ */
+
+#define TEE_SHM_MAPPED BIT(0) /* Memory mapped by the kernel */
+#define TEE_SHM_DMA_BUF BIT(1) /* Memory with dma-buf handle */
+#define TEE_SHM_EXT_DMA_BUF BIT(2) /* Memory with dma-buf handle */
+#define TEE_SHM_REGISTER BIT(3) /* Memory registered in secure world */
+#define TEE_SHM_USER_MAPPED BIT(4) /* Memory mapped in user space */
+#define TEE_SHM_POOL BIT(5) /* Memory allocated from pool */
+
+struct device;
+struct tee_device;
+struct tee_shm;
+struct tee_shm_pool;
+
+/**
+ * struct tee_context - driver specific context on file pointer data
+ * @teedev: pointer to this drivers struct tee_device
+ * @list_shm: List of shared memory object owned by this context
+ * @data: driver specific context data, managed by the driver
+ * @refcount: reference counter for this structure
+ * @releasing: flag that indicates if context is being released right now.
+ * It is needed to break circular dependency on context during
+ * shared memory release.
+ */
+struct tee_context {
+ struct tee_device *teedev;
+ struct list_head list_shm;
+ void *data;
+ struct kref refcount;
+ bool releasing;
+};
+
+struct tee_param_memref {
+ size_t shm_offs;
+ size_t size;
+ struct tee_shm *shm;
+};
+
+struct tee_param_value {
+ u64 a;
+ u64 b;
+ u64 c;
+};
+
+struct tee_param {
+ u64 attr;
+ union {
+ struct tee_param_memref memref;
+ struct tee_param_value value;
+ } u;
+};
+
+/**
+ * struct tee_driver_ops - driver operations vtable
+ * @get_version: returns version of driver
+ * @open: called when the device file is opened
+ * @release: release this open file
+ * @open_session: open a new session
+ * @close_session: close a session
+ * @invoke_func: invoke a trusted function
+ * @cancel_req: request cancel of an ongoing invoke or open
+ * @supp_revc: called for supplicant to get a command
+ * @supp_send: called for supplicant to send a response
+ * @shm_register: register shared memory buffer in TEE
+ * @shm_unregister: unregister shared memory buffer in TEE
+ */
+struct tee_driver_ops {
+ void (*get_version)(struct tee_device *teedev,
+ struct tee_ioctl_version_data *vers);
+ int (*open)(struct tee_context *ctx);
+ void (*release)(struct tee_context *ctx);
+ int (*open_session)(struct tee_context *ctx,
+ struct tee_ioctl_open_session_arg *arg,
+ struct tee_param *param);
+ int (*close_session)(struct tee_context *ctx, u32 session);
+ int (*invoke_func)(struct tee_context *ctx,
+ struct tee_ioctl_invoke_arg *arg,
+ struct tee_param *param);
+ int (*cancel_req)(struct tee_context *ctx, u32 cancel_id, u32 session);
+ int (*supp_recv)(struct tee_context *ctx, u32 *func, u32 *num_params,
+ struct tee_param *param);
+ int (*supp_send)(struct tee_context *ctx, u32 ret, u32 num_params,
+ struct tee_param *param);
+ int (*shm_register)(struct tee_context *ctx, struct tee_shm *shm,
+ struct page **pages, size_t num_pages,
+ unsigned long start);
+ int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm);
+};
+
+/**
+ * struct tee_desc - Describes the TEE driver to the subsystem
+ * @name: name of driver
+ * @ops: driver operations vtable
+ * @owner: module providing the driver
+ * @flags: Extra properties of driver, defined by TEE_DESC_* below
+ */
+#define TEE_DESC_PRIVILEGED 0x1
+struct tee_desc {
+ const char *name;
+ const struct tee_driver_ops *ops;
+ struct module *owner;
+ u32 flags;
+};
+
+/**
+ * tee_device_alloc() - Allocate a new struct tee_device instance
+ * @teedesc: Descriptor for this driver
+ * @dev: Parent device for this device
+ * @pool: Shared memory pool, NULL if not used
+ * @driver_data: Private driver data for this device
+ *
+ * Allocates a new struct tee_device instance. The device is
+ * removed by tee_device_unregister().
+ *
+ * @returns a pointer to a 'struct tee_device' or an ERR_PTR on failure
+ */
+struct tee_device *tee_device_alloc(const struct tee_desc *teedesc,
+ struct device *dev,
+ struct tee_shm_pool *pool,
+ void *driver_data);
+
+/**
+ * tee_device_register() - Registers a TEE device
+ * @teedev: Device to register
+ *
+ * tee_device_unregister() need to be called to remove the @teedev if
+ * this function fails.
+ *
+ * @returns < 0 on failure
+ */
+int tee_device_register(struct tee_device *teedev);
+
+/**
+ * tee_device_unregister() - Removes a TEE device
+ * @teedev: Device to unregister
+ *
+ * This function should be called to remove the @teedev even if
+ * tee_device_register() hasn't been called yet. Does nothing if
+ * @teedev is NULL.
+ */
+void tee_device_unregister(struct tee_device *teedev);
+
+/**
+ * struct tee_shm - shared memory object
+ * @teedev: device used to allocate the object
+ * @ctx: context using the object, if NULL the context is gone
+ * @link link element
+ * @paddr: physical address of the shared memory
+ * @kaddr: virtual address of the shared memory
+ * @size: size of shared memory
+ * @offset: offset of buffer in user space
+ * @pages: locked pages from userspace
+ * @num_pages: number of locked pages
+ * @dmabuf: dmabuf used to for exporting to user space
+ * @flags: defined by TEE_SHM_* in tee_drv.h
+ * @id: unique id of a shared memory object on this device
+ *
+ * This pool is only supposed to be accessed directly from the TEE
+ * subsystem and from drivers that implements their own shm pool manager.
+ */
+struct tee_shm {
+ struct tee_device *teedev;
+ struct tee_context *ctx;
+ struct list_head link;
+ phys_addr_t paddr;
+ void *kaddr;
+ size_t size;
+ unsigned int offset;
+ struct page **pages;
+ size_t num_pages;
+ struct dma_buf *dmabuf;
+ u32 flags;
+ int id;
+};
+
+/**
+ * struct tee_shm_pool_mgr - shared memory manager
+ * @ops: operations
+ * @private_data: private data for the shared memory manager
+ */
+struct tee_shm_pool_mgr {
+ const struct tee_shm_pool_mgr_ops *ops;
+ void *private_data;
+};
+
+/**
+ * struct tee_shm_pool_mgr_ops - shared memory pool manager operations
+ * @alloc: called when allocating shared memory
+ * @free: called when freeing shared memory
+ * @destroy_poolmgr: called when destroying the pool manager
+ */
+struct tee_shm_pool_mgr_ops {
+ int (*alloc)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm,
+ size_t size);
+ void (*free)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm);
+ void (*destroy_poolmgr)(struct tee_shm_pool_mgr *poolmgr);
+};
+
+/**
+ * tee_shm_pool_alloc() - Create a shared memory pool from shm managers
+ * @priv_mgr: manager for driver private shared memory allocations
+ * @dmabuf_mgr: manager for dma-buf shared memory allocations
+ *
+ * Allocation with the flag TEE_SHM_DMA_BUF set will use the range supplied
+ * in @dmabuf, others will use the range provided by @priv.
+ *
+ * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure.
+ */
+struct tee_shm_pool *tee_shm_pool_alloc(struct tee_shm_pool_mgr *priv_mgr,
+ struct tee_shm_pool_mgr *dmabuf_mgr);
+
+/*
+ * tee_shm_pool_mgr_alloc_res_mem() - Create a shm manager for reserved
+ * memory
+ * @vaddr: Virtual address of start of pool
+ * @paddr: Physical address of start of pool
+ * @size: Size in bytes of the pool
+ *
+ * @returns pointer to a 'struct tee_shm_pool_mgr' or an ERR_PTR on failure.
+ */
+struct tee_shm_pool_mgr *tee_shm_pool_mgr_alloc_res_mem(unsigned long vaddr,
+ phys_addr_t paddr,
+ size_t size,
+ int min_alloc_order);
+
+/**
+ * tee_shm_pool_mgr_destroy() - Free a shared memory manager
+ */
+static inline void tee_shm_pool_mgr_destroy(struct tee_shm_pool_mgr *poolm)
+{
+ poolm->ops->destroy_poolmgr(poolm);
+}
+
+/**
+ * struct tee_shm_pool_mem_info - holds information needed to create a shared
+ * memory pool
+ * @vaddr: Virtual address of start of pool
+ * @paddr: Physical address of start of pool
+ * @size: Size in bytes of the pool
+ */
+struct tee_shm_pool_mem_info {
+ unsigned long vaddr;
+ phys_addr_t paddr;
+ size_t size;
+};
+
+/**
+ * tee_shm_pool_alloc_res_mem() - Create a shared memory pool from reserved
+ * memory range
+ * @priv_info: Information for driver private shared memory pool
+ * @dmabuf_info: Information for dma-buf shared memory pool
+ *
+ * Start and end of pools will must be page aligned.
+ *
+ * Allocation with the flag TEE_SHM_DMA_BUF set will use the range supplied
+ * in @dmabuf, others will use the range provided by @priv.
+ *
+ * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure.
+ */
+struct tee_shm_pool *
+tee_shm_pool_alloc_res_mem(struct tee_shm_pool_mem_info *priv_info,
+ struct tee_shm_pool_mem_info *dmabuf_info);
+
+/**
+ * tee_shm_pool_free() - Free a shared memory pool
+ * @pool: The shared memory pool to free
+ *
+ * The must be no remaining shared memory allocated from this pool when
+ * this function is called.
+ */
+void tee_shm_pool_free(struct tee_shm_pool *pool);
+
+/**
+ * tee_get_drvdata() - Return driver_data pointer
+ * @returns the driver_data pointer supplied to tee_register().
+ */
+void *tee_get_drvdata(struct tee_device *teedev);
+
+/**
+ * tee_shm_alloc() - Allocate shared memory
+ * @ctx: Context that allocates the shared memory
+ * @size: Requested size of shared memory
+ * @flags: Flags setting properties for the requested shared memory.
+ *
+ * Memory allocated as global shared memory is automatically freed when the
+ * TEE file pointer is closed. The @flags field uses the bits defined by
+ * TEE_SHM_* above. TEE_SHM_MAPPED must currently always be set. If
+ * TEE_SHM_DMA_BUF global shared memory will be allocated and associated
+ * with a dma-buf handle, else driver private memory.
+ *
+ * @returns a pointer to 'struct tee_shm'
+ */
+struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags);
+
+/**
+ * tee_shm_priv_alloc() - Allocate shared memory privately
+ * @dev: Device that allocates the shared memory
+ * @size: Requested size of shared memory
+ *
+ * Allocates shared memory buffer that is not associated with any client
+ * context. Such buffers are owned by TEE driver and used for internal calls.
+ *
+ * @returns a pointer to 'struct tee_shm'
+ */
+struct tee_shm *tee_shm_priv_alloc(struct tee_device *teedev, size_t size);
+
+/**
+ * tee_shm_register() - Register shared memory buffer
+ * @ctx: Context that registers the shared memory
+ * @addr: Address is userspace of the shared buffer
+ * @length: Length of the shared buffer
+ * @flags: Flags setting properties for the requested shared memory.
+ *
+ * @returns a pointer to 'struct tee_shm'
+ */
+struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
+ size_t length, u32 flags);
+
+/**
+ * tee_shm_is_registered() - Check if shared memory object in registered in TEE
+ * @shm: Shared memory handle
+ * @returns true if object is registered in TEE
+ */
+static inline bool tee_shm_is_registered(struct tee_shm *shm)
+{
+ return shm && (shm->flags & TEE_SHM_REGISTER);
+}
+
+/**
+ * tee_shm_free() - Free shared memory
+ * @shm: Handle to shared memory to free
+ */
+void tee_shm_free(struct tee_shm *shm);
+
+/**
+ * tee_shm_put() - Decrease reference count on a shared memory handle
+ * @shm: Shared memory handle
+ */
+void tee_shm_put(struct tee_shm *shm);
+
+/**
+ * tee_shm_va2pa() - Get physical address of a virtual address
+ * @shm: Shared memory handle
+ * @va: Virtual address to tranlsate
+ * @pa: Returned physical address
+ * @returns 0 on success and < 0 on failure
+ */
+int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa);
+
+/**
+ * tee_shm_pa2va() - Get virtual address of a physical address
+ * @shm: Shared memory handle
+ * @pa: Physical address to tranlsate
+ * @va: Returned virtual address
+ * @returns 0 on success and < 0 on failure
+ */
+int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va);
+
+/**
+ * tee_shm_get_va() - Get virtual address of a shared memory plus an offset
+ * @shm: Shared memory handle
+ * @offs: Offset from start of this shared memory
+ * @returns virtual address of the shared memory + offs if offs is within
+ * the bounds of this shared memory, else an ERR_PTR
+ */
+void *tee_shm_get_va(struct tee_shm *shm, size_t offs);
+
+/**
+ * tee_shm_get_pa() - Get physical address of a shared memory plus an offset
+ * @shm: Shared memory handle
+ * @offs: Offset from start of this shared memory
+ * @pa: Physical address to return
+ * @returns 0 if offs is within the bounds of this shared memory, else an
+ * error code.
+ */
+int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa);
+
+/**
+ * tee_shm_get_size() - Get size of shared memory buffer
+ * @shm: Shared memory handle
+ * @returns size of shared memory
+ */
+static inline size_t tee_shm_get_size(struct tee_shm *shm)
+{
+ return shm->size;
+}
+
+/**
+ * tee_shm_get_pages() - Get list of pages that hold shared buffer
+ * @shm: Shared memory handle
+ * @num_pages: Number of pages will be stored there
+ * @returns pointer to pages array
+ */
+static inline struct page **tee_shm_get_pages(struct tee_shm *shm,
+ size_t *num_pages)
+{
+ *num_pages = shm->num_pages;
+ return shm->pages;
+}
+
+/**
+ * tee_shm_get_page_offset() - Get shared buffer offset from page start
+ * @shm: Shared memory handle
+ * @returns page offset of shared buffer
+ */
+static inline size_t tee_shm_get_page_offset(struct tee_shm *shm)
+{
+ return shm->offset;
+}
+
+/**
+ * tee_shm_get_id() - Get id of a shared memory object
+ * @shm: Shared memory handle
+ * @returns id
+ */
+static inline int tee_shm_get_id(struct tee_shm *shm)
+{
+ return shm->id;
+}
+
+/**
+ * tee_shm_get_from_id() - Find shared memory object and increase reference
+ * count
+ * @ctx: Context owning the shared memory
+ * @id: Id of shared memory object
+ * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure
+ */
+struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id);
+
+static inline bool tee_param_is_memref(struct tee_param *param)
+{
+ switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#endif /*__TEE_DRV_H*/
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 52bc890..33c1dae 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -393,6 +393,8 @@
* temperature.
* @set_trip_temp: a pointer to a function that sets the trip temperature on
* hardware.
+ * @get_trip_temp: a pointer to a function that gets the trip temperature on
+ * hardware.
*/
struct thermal_zone_of_device_ops {
int (*get_temp)(void *, int *);
@@ -400,6 +402,7 @@
int (*set_trips)(void *, int, int);
int (*set_emul_temp)(void *, int);
int (*set_trip_temp)(void *, int, int);
+ int (*get_trip_temp)(void *, int, int *);
};
/**
diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h
index 2c225d4..dfc80b7 100644
--- a/include/linux/timekeeper_internal.h
+++ b/include/linux/timekeeper_internal.h
@@ -51,7 +51,7 @@
* @clock_was_set_seq: The sequence number of clock was set events
* @cs_was_changed_seq: The sequence number of clocksource change events
* @next_leap_ktime: CLOCK_MONOTONIC time value of a pending leap-second
- * @raw_time: Monotonic raw base time in timespec64 format
+ * @raw_sec: CLOCK_MONOTONIC_RAW time in seconds
* @cycle_interval: Number of clock cycles in one NTP interval
* @xtime_interval: Number of clock shifted nano seconds in one NTP
* interval.
@@ -93,7 +93,7 @@
unsigned int clock_was_set_seq;
u8 cs_was_changed_seq;
ktime_t next_leap_ktime;
- struct timespec64 raw_time;
+ u64 raw_sec;
/* The following members are for timekeeping internal use */
cycle_t cycle_interval;
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 6acd229..3f3a7e4 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -481,6 +481,7 @@
* @bam2bam_func_enabled; Indicates function using bam2bam is enabled or not.
* @extra_buf_alloc: Extra allocation size for AXI prefetch so that out of
* boundary access is protected.
+ * @is_chipidea: True if ChipIdea device controller
*
* Gadgets have a mostly-portable "gadget driver" implementing device
* functions, handling all usb configurations and interfaces. Gadget
@@ -537,6 +538,7 @@
bool bam2bam_func_enabled;
u32 extra_buf_alloc;
bool l1_supported;
+ bool is_chipidea;
};
#define work_to_gadget(w) (container_of((w), struct usb_gadget, work))
@@ -1133,7 +1135,7 @@
const char *ep_name);
#ifdef CONFIG_USB_DWC3_MSM
-int msm_ep_config(struct usb_ep *ep);
+int msm_ep_config(struct usb_ep *ep, struct usb_request *request);
int msm_ep_unconfig(struct usb_ep *ep);
void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enable);
int msm_data_fifo_config(struct usb_ep *ep, unsigned long addr, u32 size,
@@ -1145,7 +1147,7 @@
u32 size, u8 dst_pipe_idx)
{ return -ENODEV; }
-static inline int msm_ep_config(struct usb_ep *ep)
+static inline int msm_ep_config(struct usb_ep *ep, struct usb_request *request)
{ return -ENODEV; }
static inline int msm_ep_unconfig(struct usb_ep *ep)
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index d070109..3a28749 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -664,6 +664,7 @@
#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
+#ifdef CONFIG_USB
#ifdef CONFIG_PM
extern void usb_root_hub_lost_power(struct usb_device *rhdev);
extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
@@ -675,7 +676,15 @@
return;
}
#endif /* CONFIG_PM */
-
+#else /* CONFIG_USB */
+extern int usb_add_hcd(struct usb_hcd *hcd,
+ unsigned int irqnum, unsigned long irqflags)
+{
+ return 0;
+}
+extern void usb_remove_hcd(struct usb_hcd *hcd) {}
+extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd) {}
+#endif /* CONFIG_USB */
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 18b738c..b7ccd4e 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -273,8 +273,10 @@
unsigned int vbus_state;
unsigned int usb_irq_count;
int pm_qos_latency;
+ unsigned int notify_current_mA;
struct pm_qos_request pm_qos_req_dma;
struct delayed_work perf_vote_work;
+ struct work_struct notify_chg_current_work;
};
struct ci13xxx_platform_data {
@@ -292,14 +294,9 @@
#ifdef CONFIG_USB_BAM
void msm_bam_set_usb_host_dev(struct device *dev);
-bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable);
int msm_do_bam_disable_enable(enum usb_ctrl ctrl);
#else
static inline void msm_bam_set_usb_host_dev(struct device *dev) {}
-static inline bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable)
-{
- return true;
-}
int msm_do_bam_disable_enable(enum usb_ctrl ctrl) { return true; }
#endif
#ifdef CONFIG_USB_CI13XXX_MSM
diff --git a/include/linux/usb_bam.h b/include/linux/usb_bam.h
index 84d7549..e5d4c04 100644
--- a/include/linux/usb_bam.h
+++ b/include/linux/usb_bam.h
@@ -426,7 +426,7 @@
*
* @return true when producer granted, false when prodcuer is released.
*/
-bool usb_bam_get_prod_granted(enum usb_ctrl bam_type, u8 idx);
+bool usb_bam_get_prod_granted(enum usb_ctrl bam_type);
/* Allocates memory for data fifo and descriptor fifos. */
int usb_bam_alloc_fifos(enum usb_ctrl cur_bam, u8 idx);
@@ -519,7 +519,7 @@
return -ENODEV;
}
-static inline bool usb_bam_get_prod_granted(enum usb_ctrl bam_type, u8 idx)
+static inline bool usb_bam_get_prod_granted(enum usb_ctrl bam_type)
{
return false;
}
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 797100e..9a8eb83 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -224,6 +224,7 @@
static inline void inode_detach_wb(struct inode *inode)
{
if (inode->i_wb) {
+ WARN_ON_ONCE(!(inode->i_state & I_CLEAR));
wb_put(inode->i_wb);
inode->i_wb = NULL;
}
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 6f5da29..95679cb 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -29,6 +29,13 @@
} u;
};
#endif
-
+#ifdef CONFIG_MSM_AVTIMER
+struct avtimer_fptr_t {
+ int (*fptr_avtimer_open)(void);
+ int (*fptr_avtimer_enable)(int enable);
+ int (*fptr_avtimer_get_time)(uint64_t *avtimer_tick);
+};
+void msm_isp_set_avtimer_fptr(struct avtimer_fptr_t avtimer_func);
+#endif
#endif
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d5e79f1..520c4c3 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -61,6 +61,9 @@
/* Indicate backport support for per chain rssi scan */
#define CFG80211_SCAN_PER_CHAIN_RSSI_SUPPORT 1
+/* Indicate backport support for external authentication*/
+#define CFG80211_EXTERNAL_AUTH_SUPPORT 1
+
/**
* DOC: Introduction
*
@@ -1878,11 +1881,16 @@
* @ASSOC_REQ_DISABLE_HT: Disable HT (802.11n)
* @ASSOC_REQ_DISABLE_VHT: Disable VHT
* @ASSOC_REQ_USE_RRM: Declare RRM capability in this association
+ * @CONNECT_REQ_EXTERNAL_AUTH_SUPPORT: User space indicates external
+ * authentication capability. Drivers can offload authentication to
+ * userspace if this flag is set. Only applicable for cfg80211_connect()
+ * request (connect callback).
*/
enum cfg80211_assoc_req_flags {
- ASSOC_REQ_DISABLE_HT = BIT(0),
- ASSOC_REQ_DISABLE_VHT = BIT(1),
- ASSOC_REQ_USE_RRM = BIT(2),
+ ASSOC_REQ_DISABLE_HT = BIT(0),
+ ASSOC_REQ_DISABLE_VHT = BIT(1),
+ ASSOC_REQ_USE_RRM = BIT(2),
+ CONNECT_REQ_EXTERNAL_AUTH_SUPPORT = BIT(3),
};
/**
@@ -2554,6 +2562,33 @@
};
/**
+ * struct cfg80211_external_auth_params - Trigger External authentication.
+ *
+ * Commonly used across the external auth request and event interfaces.
+ *
+ * @action: action type / trigger for external authentication. Only significant
+ * for the authentication request event interface (driver to user space).
+ * @bssid: BSSID of the peer with which the authentication has
+ * to happen. Used by both the authentication request event and
+ * authentication response command interface.
+ * @ssid: SSID of the AP. Used by both the authentication request event and
+ * authentication response command interface.
+ * @key_mgmt_suite: AKM suite of the respective authentication. Used by the
+ * authentication request event interface.
+ * @status: status code, %WLAN_STATUS_SUCCESS for successful authentication,
+ * use %WLAN_STATUS_UNSPECIFIED_FAILURE if user space cannot give you
+ * the real status code for failures. Used only for the authentication
+ * response command interface (user space to driver).
+ */
+struct cfg80211_external_auth_params {
+ enum nl80211_external_auth_action action;
+ u8 bssid[ETH_ALEN] __aligned(2);
+ struct cfg80211_ssid ssid;
+ unsigned int key_mgmt_suite;
+ u16 status;
+};
+
+/**
* struct cfg80211_ops - backend description for wireless configuration
*
* This struct is registered by fullmac card drivers and/or wireless stacks
@@ -2862,6 +2897,9 @@
* All other parameters must be ignored.
*
* @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
+ *
+ * @external_auth: indicates result of offloaded authentication processing from
+ * user space
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3146,6 +3184,8 @@
int (*set_multicast_to_unicast)(struct wiphy *wiphy,
struct net_device *dev,
const bool enabled);
+ int (*external_auth)(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_external_auth_params *params);
};
/*
@@ -3937,6 +3977,9 @@
* @conn: (private) cfg80211 software SME connection state machine data
* @connect_keys: (private) keys to set after connection is established
* @conn_bss_type: connecting/connected BSS type
+ * @conn_owner_nlportid: (private) connection owner socket port ID
+ * @disconnect_wk: (private) auto-disconnect work
+ * @disconnect_bssid: (private) the BSSID to use for auto-disconnect
* @ibss_fixed: (private) IBSS is using fixed BSSID
* @ibss_dfs_possible: (private) IBSS may change to a DFS channel
* @event_list: (private) list for internal event processing
@@ -3968,6 +4011,10 @@
struct cfg80211_conn *conn;
struct cfg80211_cached_keys *connect_keys;
enum ieee80211_bss_type conn_bss_type;
+ u32 conn_owner_nlportid;
+
+ struct work_struct disconnect_wk;
+ u8 disconnect_bssid[ETH_ALEN];
struct list_head event_list;
spinlock_t event_lock;
@@ -6078,6 +6125,17 @@
*/
bool cfg80211_is_gratuitous_arp_unsolicited_na(struct sk_buff *skb);
+/**
+ * cfg80211_external_auth_request - userspace request for authentication
+ * @netdev: network device
+ * @params: External authentication parameters
+ * @gfp: allocation flags
+ * Returns: 0 on success, < 0 on error
+ */
+int cfg80211_external_auth_request(struct net_device *netdev,
+ struct cfg80211_external_auth_params *params,
+ gfp_t gfp);
+
/* Logging, debugging and troubleshooting/diagnostic helpers. */
/* wiphy_printk helpers, similar to dev_printk */
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index 0464b20..a2f3a49 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -212,7 +212,11 @@
transparent:1,
mc_all:1,
nodefrag:1;
- __u8 bind_address_no_port:1;
+ __u8 bind_address_no_port:1,
+ defer_connect:1; /* Indicates that fastopen_connect is set
+ * and cookie exists so we defer connect
+ * until first data frame is written
+ */
__u8 rcv_tos;
__u8 convert_csum;
int uc_index;
diff --git a/include/net/red.h b/include/net/red.h
index 76e0b5f..3618cdf 100644
--- a/include/net/red.h
+++ b/include/net/red.h
@@ -167,6 +167,17 @@
v->qcount = -1;
}
+static inline bool red_check_params(u32 qth_min, u32 qth_max, u8 Wlog)
+{
+ if (fls(qth_min) + Wlog > 32)
+ return false;
+ if (fls(qth_max) + Wlog > 32)
+ return false;
+ if (qth_max < qth_min)
+ return false;
+ return true;
+}
+
static inline void red_set_parms(struct red_parms *p,
u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog,
u8 Scell_log, u8 *stab, u32 max_P)
@@ -178,7 +189,7 @@
p->qth_max = qth_max << Wlog;
p->Wlog = Wlog;
p->Plog = Plog;
- if (delta < 0)
+ if (delta <= 0)
delta = 1;
p->qth_delta = delta;
if (!max_P) {
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 61d9ce8..579ded2 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -433,7 +433,8 @@
if (asoc->user_frag)
frag = min_t(int, frag, asoc->user_frag);
- frag = SCTP_TRUNC4(min_t(int, frag, SCTP_MAX_CHUNK_LEN));
+ frag = SCTP_TRUNC4(min_t(int, frag, SCTP_MAX_CHUNK_LEN -
+ sizeof(struct sctp_data_chunk)));
return frag;
}
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 448aec0..e7ac114 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1522,6 +1522,9 @@
struct tcp_fastopen_cookie *foc,
struct dst_entry *dst);
void tcp_fastopen_init_key_once(bool publish);
+bool tcp_fastopen_cookie_check(struct sock *sk, u16 *mss,
+ struct tcp_fastopen_cookie *cookie);
+bool tcp_fastopen_defer_connect(struct sock *sk, int *err);
#define TCP_FASTOPEN_KEY_LENGTH 16
/* Fastopen key context */
diff --git a/include/soc/qcom/clock-alpha-pll.h b/include/soc/qcom/clock-alpha-pll.h
index f8130f1..20f8a2f 100644
--- a/include/soc/qcom/clock-alpha-pll.h
+++ b/include/soc/qcom/clock-alpha-pll.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -27,6 +27,7 @@
u32 alpha_en_mask; /* alpha_en bit */
u32 output_mask; /* pllout_* bits */
u32 post_div_mask;
+ u32 cal_l_val_mask;
u32 test_ctl_lo_mask;
u32 test_ctl_hi_mask;
@@ -61,6 +62,7 @@
u32 config_ctl_val; /* config register init value */
u32 test_ctl_lo_val; /* test control settings */
u32 test_ctl_hi_val;
+ u32 cal_l_val; /* Calibration L value */
struct alpha_pll_vco_tbl *vco_tbl;
u32 num_vco;
diff --git a/include/soc/qcom/msm_tz_smmu.h b/include/soc/qcom/msm_tz_smmu.h
index 43a3069..1ae1dd9 100644
--- a/include/soc/qcom/msm_tz_smmu.h
+++ b/include/soc/qcom/msm_tz_smmu.h
@@ -102,6 +102,29 @@
{
return -EINVAL;
}
+
+static inline size_t msm_secure_smmu_unmap(struct iommu_domain *domain,
+ unsigned long iova,
+ size_t size)
+{
+ return -EINVAL;
+}
+
+static inline size_t msm_secure_smmu_map_sg(struct iommu_domain *domain,
+ unsigned long iova,
+ struct scatterlist *sg,
+ unsigned int nents, int prot)
+{
+ return -EINVAL;
+}
+
+static inline int msm_secure_smmu_map(struct iommu_domain *domain,
+ unsigned long iova,
+ phys_addr_t paddr, size_t size, int prot)
+{
+ return -EINVAL;
+}
+
#endif /* CONFIG_MSM_TZ_SMMU */
#endif /* __MSM_TZ_SMMU_H__ */
diff --git a/include/soc/qcom/secure_buffer.h b/include/soc/qcom/secure_buffer.h
index d9a526d..75f017c 100644
--- a/include/soc/qcom/secure_buffer.h
+++ b/include/soc/qcom/secure_buffer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -41,6 +41,7 @@
VMID_CP_CAMERA_PREVIEW = 0x1D,
VMID_CP_SPSS_SP_SHARED = 0x22,
VMID_CP_SPSS_HLOS_SHARED = 0x24,
+ VMID_CP_CDSP = 0x2A,
VMID_LAST,
VMID_INVAL = -1
};
diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h
index a872c9a..280a6d9 100644
--- a/include/soc/qcom/socinfo.h
+++ b/include/soc/qcom/socinfo.h
@@ -106,6 +106,8 @@
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,qcs605")
#define early_machine_is_sda670() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sda670")
+#define early_machine_is_sdm710() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm670")
#define early_machine_is_msm8953() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8953")
#define early_machine_is_msm8937() \
@@ -118,6 +120,8 @@
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm439")
#define early_machine_is_sdm429() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm429")
+#define early_machine_is_mdm9650() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,mdm9650")
#else
#define of_board_is_sim() 0
#define of_board_is_rumi() 0
@@ -160,12 +164,14 @@
#define early_machine_is_sdm670() 0
#define early_machine_is_qcs605() 0
#define early_machine_is_sda670() 0
+#define early_machine_is_sdm710() 0
#define early_machine_is_msm8953() 0
#define early_machine_is_msm8937() 0
#define early_machine_is_sdm450() 0
#define early_machine_is_sdm632() 0
#define early_machine_is_sdm439() 0
#define early_machine_is_sdm429() 0
+#define early_machine_is_mdm9650() 0
#endif
#define PLATFORM_SUBTYPE_MDM 1
@@ -230,6 +236,7 @@
MSM_CPU_SDM670,
MSM_CPU_QCS605,
MSM_CPU_SDA670,
+ MSM_CPU_SDM710,
MSM_CPU_8953,
MSM_CPU_SDM450,
MSM_CPU_SDM632,
@@ -237,6 +244,7 @@
MSM_CPU_8937,
MSM_CPU_SDM439,
MSM_CPU_SDM429,
+ MSM_CPU_9650,
};
struct msm_soc_info {
diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h
index f730b91..9e1aa1a 100644
--- a/include/sound/rawmidi.h
+++ b/include/sound/rawmidi.h
@@ -78,6 +78,7 @@
size_t xruns; /* over/underruns counter */
/* misc */
spinlock_t lock;
+ struct mutex realloc_mutex;
wait_queue_head_t sleep;
/* event handler (new bytes, input only) */
void (*event)(struct snd_rawmidi_substream *substream);
diff --git a/include/trace/events/clk.h b/include/trace/events/clk.h
index ad19e73..cd9c6db 100644
--- a/include/trace/events/clk.h
+++ b/include/trace/events/clk.h
@@ -134,12 +134,12 @@
TP_STRUCT__entry(
__string( name, core->name )
- __string( pname, parent->name )
+ __string( pname, parent ? parent->name : "none" )
),
TP_fast_assign(
__assign_str(name, core->name);
- __assign_str(pname, parent->name);
+ __assign_str(pname, parent ? parent->name : "none");
),
TP_printk("%s %s", __get_str(name), __get_str(pname))
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
index 903a091..e88465a 100644
--- a/include/trace/events/f2fs.h
+++ b/include/trace/events/f2fs.h
@@ -6,8 +6,8 @@
#include <linux/tracepoint.h>
-#define show_dev(entry) MAJOR(entry->dev), MINOR(entry->dev)
-#define show_dev_ino(entry) show_dev(entry), (unsigned long)entry->ino
+#define show_dev(dev) MAJOR(dev), MINOR(dev)
+#define show_dev_ino(entry) show_dev(entry->dev), (unsigned long)entry->ino
TRACE_DEFINE_ENUM(NODE);
TRACE_DEFINE_ENUM(DATA);
@@ -15,6 +15,8 @@
TRACE_DEFINE_ENUM(META_FLUSH);
TRACE_DEFINE_ENUM(INMEM);
TRACE_DEFINE_ENUM(INMEM_DROP);
+TRACE_DEFINE_ENUM(INMEM_INVALIDATE);
+TRACE_DEFINE_ENUM(INMEM_REVOKE);
TRACE_DEFINE_ENUM(IPU);
TRACE_DEFINE_ENUM(OPU);
TRACE_DEFINE_ENUM(CURSEG_HOT_DATA);
@@ -42,6 +44,7 @@
TRACE_DEFINE_ENUM(CP_SYNC);
TRACE_DEFINE_ENUM(CP_RECOVERY);
TRACE_DEFINE_ENUM(CP_DISCARD);
+TRACE_DEFINE_ENUM(CP_TRIMMED);
#define show_block_type(type) \
__print_symbolic(type, \
@@ -51,32 +54,40 @@
{ META_FLUSH, "META_FLUSH" }, \
{ INMEM, "INMEM" }, \
{ INMEM_DROP, "INMEM_DROP" }, \
+ { INMEM_INVALIDATE, "INMEM_INVALIDATE" }, \
{ INMEM_REVOKE, "INMEM_REVOKE" }, \
{ IPU, "IN-PLACE" }, \
{ OPU, "OUT-OF-PLACE" })
-#define F2FS_BIO_FLAG_MASK(t) (t & (REQ_RAHEAD | WRITE_FLUSH_FUA))
-#define F2FS_BIO_EXTRA_MASK(t) (t & (REQ_META | REQ_PRIO))
+#define F2FS_OP_FLAGS (REQ_RAHEAD | REQ_SYNC | REQ_META | REQ_PRIO | \
+ REQ_PREFLUSH | REQ_FUA)
+#define F2FS_BIO_FLAG_MASK(t) (t & F2FS_OP_FLAGS)
-#define show_bio_type(op_flags) show_bio_op_flags(op_flags), \
- show_bio_extra(op_flags)
+#define show_bio_type(op,op_flags) show_bio_op(op), \
+ show_bio_op_flags(op_flags)
+
+#define show_bio_op(op) \
+ __print_symbolic(op, \
+ { REQ_OP_READ, "READ" }, \
+ { REQ_OP_WRITE, "WRITE" }, \
+ { REQ_OP_DISCARD, "DISCARD" }, \
+ { REQ_OP_SECURE_ERASE, "SECURE_ERASE" }, \
+ { REQ_OP_WRITE_SAME, "WRITE_SAME" })
#define show_bio_op_flags(flags) \
- __print_symbolic(F2FS_BIO_FLAG_MASK(flags), \
- { 0, "WRITE" }, \
- { REQ_RAHEAD, "READAHEAD" }, \
- { READ_SYNC, "READ_SYNC" }, \
- { WRITE_SYNC, "WRITE_SYNC" }, \
- { WRITE_FLUSH, "WRITE_FLUSH" }, \
- { WRITE_FUA, "WRITE_FUA" }, \
- { WRITE_FLUSH_FUA, "WRITE_FLUSH_FUA" })
+ __print_flags(F2FS_BIO_FLAG_MASK(flags), "|", \
+ { REQ_RAHEAD, "R" }, \
+ { REQ_SYNC, "S" }, \
+ { REQ_META, "M" }, \
+ { REQ_PRIO, "P" }, \
+ { REQ_PREFLUSH, "PF" }, \
+ { REQ_FUA, "FUA" })
-#define show_bio_extra(type) \
- __print_symbolic(F2FS_BIO_EXTRA_MASK(type), \
- { REQ_META, "(M)" }, \
- { REQ_PRIO, "(P)" }, \
- { REQ_META | REQ_PRIO, "(MP)" }, \
- { 0, " \b" })
+#define show_block_temp(temp) \
+ __print_symbolic(temp, \
+ { HOT, "HOT" }, \
+ { WARM, "WARM" }, \
+ { COLD, "COLD" })
#define show_data_type(type) \
__print_symbolic(type, \
@@ -109,12 +120,27 @@
{ GC_CB, "Cost-Benefit" })
#define show_cpreason(type) \
- __print_symbolic(type, \
+ __print_flags(type, "|", \
{ CP_UMOUNT, "Umount" }, \
{ CP_FASTBOOT, "Fastboot" }, \
{ CP_SYNC, "Sync" }, \
{ CP_RECOVERY, "Recovery" }, \
- { CP_DISCARD, "Discard" })
+ { CP_DISCARD, "Discard" }, \
+ { CP_UMOUNT, "Umount" }, \
+ { CP_TRIMMED, "Trimmed" })
+
+#define show_fsync_cpreason(type) \
+ __print_symbolic(type, \
+ { CP_NO_NEEDED, "no needed" }, \
+ { CP_NON_REGULAR, "non regular" }, \
+ { CP_HARDLINK, "hardlink" }, \
+ { CP_SB_NEED_CP, "sb needs cp" }, \
+ { CP_WRONG_PINO, "wrong pino" }, \
+ { CP_NO_SPC_ROLL, "no space roll forward" }, \
+ { CP_NODE_NEED_CP, "node needs cp" }, \
+ { CP_FASTBOOT_MODE, "fastboot mode" }, \
+ { CP_SPEC_LOG_NUM, "log type is 2" }, \
+ { CP_RECOVER_DIR, "dir needs recovery" })
struct victim_sel_policy;
struct f2fs_map_blocks;
@@ -190,14 +216,14 @@
TRACE_EVENT(f2fs_sync_file_exit,
- TP_PROTO(struct inode *inode, int need_cp, int datasync, int ret),
+ TP_PROTO(struct inode *inode, int cp_reason, int datasync, int ret),
- TP_ARGS(inode, need_cp, datasync, ret),
+ TP_ARGS(inode, cp_reason, datasync, ret),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
- __field(int, need_cp)
+ __field(int, cp_reason)
__field(int, datasync)
__field(int, ret)
),
@@ -205,15 +231,15 @@
TP_fast_assign(
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
- __entry->need_cp = need_cp;
+ __entry->cp_reason = cp_reason;
__entry->datasync = datasync;
__entry->ret = ret;
),
- TP_printk("dev = (%d,%d), ino = %lu, checkpoint is %s, "
+ TP_printk("dev = (%d,%d), ino = %lu, cp_reason: %s, "
"datasync = %d, ret = %d",
show_dev_ino(__entry),
- __entry->need_cp ? "needed" : "not needed",
+ show_fsync_cpreason(__entry->cp_reason),
__entry->datasync,
__entry->ret)
);
@@ -237,7 +263,7 @@
),
TP_printk("dev = (%d,%d), superblock is %s, wait = %d",
- show_dev(__entry),
+ show_dev(__entry->dev),
__entry->dirty ? "dirty" : "not dirty",
__entry->wait)
);
@@ -307,6 +333,13 @@
TP_ARGS(inode, ret)
);
+DEFINE_EVENT(f2fs__inode_exit, f2fs_drop_inode,
+
+ TP_PROTO(struct inode *inode, int ret),
+
+ TP_ARGS(inode, ret)
+);
+
DEFINE_EVENT(f2fs__inode, f2fs_truncate,
TP_PROTO(struct inode *inode),
@@ -516,14 +549,14 @@
TRACE_EVENT(f2fs_background_gc,
- TP_PROTO(struct super_block *sb, long wait_ms,
+ TP_PROTO(struct super_block *sb, unsigned int wait_ms,
unsigned int prefree, unsigned int free),
TP_ARGS(sb, wait_ms, prefree, free),
TP_STRUCT__entry(
__field(dev_t, dev)
- __field(long, wait_ms)
+ __field(unsigned int, wait_ms)
__field(unsigned int, prefree)
__field(unsigned int, free)
),
@@ -535,13 +568,120 @@
__entry->free = free;
),
- TP_printk("dev = (%d,%d), wait_ms = %ld, prefree = %u, free = %u",
- show_dev(__entry),
+ TP_printk("dev = (%d,%d), wait_ms = %u, prefree = %u, free = %u",
+ show_dev(__entry->dev),
__entry->wait_ms,
__entry->prefree,
__entry->free)
);
+TRACE_EVENT(f2fs_gc_begin,
+
+ TP_PROTO(struct super_block *sb, bool sync, bool background,
+ long long dirty_nodes, long long dirty_dents,
+ long long dirty_imeta, unsigned int free_sec,
+ unsigned int free_seg, int reserved_seg,
+ unsigned int prefree_seg),
+
+ TP_ARGS(sb, sync, background, dirty_nodes, dirty_dents, dirty_imeta,
+ free_sec, free_seg, reserved_seg, prefree_seg),
+
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(bool, sync)
+ __field(bool, background)
+ __field(long long, dirty_nodes)
+ __field(long long, dirty_dents)
+ __field(long long, dirty_imeta)
+ __field(unsigned int, free_sec)
+ __field(unsigned int, free_seg)
+ __field(int, reserved_seg)
+ __field(unsigned int, prefree_seg)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = sb->s_dev;
+ __entry->sync = sync;
+ __entry->background = background;
+ __entry->dirty_nodes = dirty_nodes;
+ __entry->dirty_dents = dirty_dents;
+ __entry->dirty_imeta = dirty_imeta;
+ __entry->free_sec = free_sec;
+ __entry->free_seg = free_seg;
+ __entry->reserved_seg = reserved_seg;
+ __entry->prefree_seg = prefree_seg;
+ ),
+
+ TP_printk("dev = (%d,%d), sync = %d, background = %d, nodes = %lld, "
+ "dents = %lld, imeta = %lld, free_sec:%u, free_seg:%u, "
+ "rsv_seg:%d, prefree_seg:%u",
+ show_dev(__entry->dev),
+ __entry->sync,
+ __entry->background,
+ __entry->dirty_nodes,
+ __entry->dirty_dents,
+ __entry->dirty_imeta,
+ __entry->free_sec,
+ __entry->free_seg,
+ __entry->reserved_seg,
+ __entry->prefree_seg)
+);
+
+TRACE_EVENT(f2fs_gc_end,
+
+ TP_PROTO(struct super_block *sb, int ret, int seg_freed,
+ int sec_freed, long long dirty_nodes,
+ long long dirty_dents, long long dirty_imeta,
+ unsigned int free_sec, unsigned int free_seg,
+ int reserved_seg, unsigned int prefree_seg),
+
+ TP_ARGS(sb, ret, seg_freed, sec_freed, dirty_nodes, dirty_dents,
+ dirty_imeta, free_sec, free_seg, reserved_seg, prefree_seg),
+
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(int, ret)
+ __field(int, seg_freed)
+ __field(int, sec_freed)
+ __field(long long, dirty_nodes)
+ __field(long long, dirty_dents)
+ __field(long long, dirty_imeta)
+ __field(unsigned int, free_sec)
+ __field(unsigned int, free_seg)
+ __field(int, reserved_seg)
+ __field(unsigned int, prefree_seg)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = sb->s_dev;
+ __entry->ret = ret;
+ __entry->seg_freed = seg_freed;
+ __entry->sec_freed = sec_freed;
+ __entry->dirty_nodes = dirty_nodes;
+ __entry->dirty_dents = dirty_dents;
+ __entry->dirty_imeta = dirty_imeta;
+ __entry->free_sec = free_sec;
+ __entry->free_seg = free_seg;
+ __entry->reserved_seg = reserved_seg;
+ __entry->prefree_seg = prefree_seg;
+ ),
+
+ TP_printk("dev = (%d,%d), ret = %d, seg_freed = %d, sec_freed = %d, "
+ "nodes = %lld, dents = %lld, imeta = %lld, free_sec:%u, "
+ "free_seg:%u, rsv_seg:%d, prefree_seg:%u",
+ show_dev(__entry->dev),
+ __entry->ret,
+ __entry->seg_freed,
+ __entry->sec_freed,
+ __entry->dirty_nodes,
+ __entry->dirty_dents,
+ __entry->dirty_imeta,
+ __entry->free_sec,
+ __entry->free_seg,
+ __entry->reserved_seg,
+ __entry->prefree_seg)
+);
+
TRACE_EVENT(f2fs_get_victim,
TP_PROTO(struct super_block *sb, int type, int gc_type,
@@ -557,6 +697,7 @@
__field(int, alloc_mode)
__field(int, gc_mode)
__field(unsigned int, victim)
+ __field(unsigned int, cost)
__field(unsigned int, ofs_unit)
__field(unsigned int, pre_victim)
__field(unsigned int, prefree)
@@ -570,26 +711,114 @@
__entry->alloc_mode = p->alloc_mode;
__entry->gc_mode = p->gc_mode;
__entry->victim = p->min_segno;
+ __entry->cost = p->min_cost;
__entry->ofs_unit = p->ofs_unit;
__entry->pre_victim = pre_victim;
__entry->prefree = prefree;
__entry->free = free;
),
- TP_printk("dev = (%d,%d), type = %s, policy = (%s, %s, %s), victim = %u "
- "ofs_unit = %u, pre_victim_secno = %d, prefree = %u, free = %u",
- show_dev(__entry),
+ TP_printk("dev = (%d,%d), type = %s, policy = (%s, %s, %s), "
+ "victim = %u, cost = %u, ofs_unit = %u, "
+ "pre_victim_secno = %d, prefree = %u, free = %u",
+ show_dev(__entry->dev),
show_data_type(__entry->type),
show_gc_type(__entry->gc_type),
show_alloc_mode(__entry->alloc_mode),
show_victim_policy(__entry->gc_mode),
__entry->victim,
+ __entry->cost,
__entry->ofs_unit,
(int)__entry->pre_victim,
__entry->prefree,
__entry->free)
);
+TRACE_EVENT(f2fs_lookup_start,
+
+ TP_PROTO(struct inode *dir, struct dentry *dentry, unsigned int flags),
+
+ TP_ARGS(dir, dentry, flags),
+
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(ino_t, ino)
+ __field(const char *, name)
+ __field(unsigned int, flags)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = dir->i_sb->s_dev;
+ __entry->ino = dir->i_ino;
+ __entry->name = dentry->d_name.name;
+ __entry->flags = flags;
+ ),
+
+ TP_printk("dev = (%d,%d), pino = %lu, name:%s, flags:%u",
+ show_dev_ino(__entry),
+ __entry->name,
+ __entry->flags)
+);
+
+TRACE_EVENT(f2fs_lookup_end,
+
+ TP_PROTO(struct inode *dir, struct dentry *dentry, nid_t ino,
+ int err),
+
+ TP_ARGS(dir, dentry, ino, err),
+
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(ino_t, ino)
+ __field(const char *, name)
+ __field(nid_t, cino)
+ __field(int, err)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = dir->i_sb->s_dev;
+ __entry->ino = dir->i_ino;
+ __entry->name = dentry->d_name.name;
+ __entry->cino = ino;
+ __entry->err = err;
+ ),
+
+ TP_printk("dev = (%d,%d), pino = %lu, name:%s, ino:%u, err:%d",
+ show_dev_ino(__entry),
+ __entry->name,
+ __entry->cino,
+ __entry->err)
+);
+
+TRACE_EVENT(f2fs_readdir,
+
+ TP_PROTO(struct inode *dir, loff_t start_pos, loff_t end_pos, int err),
+
+ TP_ARGS(dir, start_pos, end_pos, err),
+
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(ino_t, ino)
+ __field(loff_t, start)
+ __field(loff_t, end)
+ __field(int, err)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = dir->i_sb->s_dev;
+ __entry->ino = dir->i_ino;
+ __entry->start = start_pos;
+ __entry->end = end_pos;
+ __entry->err = err;
+ ),
+
+ TP_printk("dev = (%d,%d), ino = %lu, start_pos:%llu, end_pos:%llu, err:%d",
+ show_dev_ino(__entry),
+ __entry->start,
+ __entry->end,
+ __entry->err)
+);
+
TRACE_EVENT(f2fs_fallocate,
TP_PROTO(struct inode *inode, int mode,
@@ -715,7 +944,7 @@
),
TP_printk("dev = (%d,%d), nid = %u, ofs_in_node = %u, count = %llu",
- show_dev(__entry),
+ show_dev(__entry->dev),
(unsigned int)__entry->nid,
__entry->ofs_in_node,
(unsigned long long)__entry->count)
@@ -735,6 +964,7 @@
__field(block_t, new_blkaddr)
__field(int, op)
__field(int, op_flags)
+ __field(int, temp)
__field(int, type)
),
@@ -746,16 +976,18 @@
__entry->new_blkaddr = fio->new_blkaddr;
__entry->op = fio->op;
__entry->op_flags = fio->op_flags;
+ __entry->temp = fio->temp;
__entry->type = fio->type;
),
TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, "
- "oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s%s, type = %s",
+ "oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s(%s), type = %s_%s",
show_dev_ino(__entry),
(unsigned long)__entry->index,
(unsigned long long)__entry->old_blkaddr,
(unsigned long long)__entry->new_blkaddr,
- show_bio_type(__entry->op_flags),
+ show_bio_type(__entry->op, __entry->op_flags),
+ show_block_temp(__entry->temp),
show_block_type(__entry->type))
);
@@ -768,7 +1000,7 @@
TP_CONDITION(page->mapping)
);
-DEFINE_EVENT_CONDITION(f2fs__submit_page_bio, f2fs_submit_page_mbio,
+DEFINE_EVENT_CONDITION(f2fs__submit_page_bio, f2fs_submit_page_write,
TP_PROTO(struct page *page, struct f2fs_io_info *fio),
@@ -777,15 +1009,15 @@
TP_CONDITION(page->mapping)
);
-DECLARE_EVENT_CLASS(f2fs__submit_bio,
+DECLARE_EVENT_CLASS(f2fs__bio,
- TP_PROTO(struct super_block *sb, struct f2fs_io_info *fio,
- struct bio *bio),
+ TP_PROTO(struct super_block *sb, int type, struct bio *bio),
- TP_ARGS(sb, fio, bio),
+ TP_ARGS(sb, type, bio),
TP_STRUCT__entry(
__field(dev_t, dev)
+ __field(dev_t, target)
__field(int, op)
__field(int, op_flags)
__field(int, type)
@@ -795,37 +1027,55 @@
TP_fast_assign(
__entry->dev = sb->s_dev;
- __entry->op = fio->op;
- __entry->op_flags = fio->op_flags;
- __entry->type = fio->type;
+ __entry->target = bio->bi_bdev->bd_dev;
+ __entry->op = bio_op(bio);
+ __entry->op_flags = bio->bi_opf;
+ __entry->type = type;
__entry->sector = bio->bi_iter.bi_sector;
__entry->size = bio->bi_iter.bi_size;
),
- TP_printk("dev = (%d,%d), rw = %s%s, %s, sector = %lld, size = %u",
- show_dev(__entry),
- show_bio_type(__entry->op_flags),
+ TP_printk("dev = (%d,%d)/(%d,%d), rw = %s(%s), %s, sector = %lld, size = %u",
+ show_dev(__entry->target),
+ show_dev(__entry->dev),
+ show_bio_type(__entry->op, __entry->op_flags),
show_block_type(__entry->type),
(unsigned long long)__entry->sector,
__entry->size)
);
-DEFINE_EVENT_CONDITION(f2fs__submit_bio, f2fs_submit_write_bio,
+DEFINE_EVENT_CONDITION(f2fs__bio, f2fs_prepare_write_bio,
- TP_PROTO(struct super_block *sb, struct f2fs_io_info *fio,
- struct bio *bio),
+ TP_PROTO(struct super_block *sb, int type, struct bio *bio),
- TP_ARGS(sb, fio, bio),
+ TP_ARGS(sb, type, bio),
TP_CONDITION(bio)
);
-DEFINE_EVENT_CONDITION(f2fs__submit_bio, f2fs_submit_read_bio,
+DEFINE_EVENT_CONDITION(f2fs__bio, f2fs_prepare_read_bio,
- TP_PROTO(struct super_block *sb, struct f2fs_io_info *fio,
- struct bio *bio),
+ TP_PROTO(struct super_block *sb, int type, struct bio *bio),
- TP_ARGS(sb, fio, bio),
+ TP_ARGS(sb, type, bio),
+
+ TP_CONDITION(bio)
+);
+
+DEFINE_EVENT_CONDITION(f2fs__bio, f2fs_submit_read_bio,
+
+ TP_PROTO(struct super_block *sb, int type, struct bio *bio),
+
+ TP_ARGS(sb, type, bio),
+
+ TP_CONDITION(bio)
+);
+
+DEFINE_EVENT_CONDITION(f2fs__bio, f2fs_submit_write_bio,
+
+ TP_PROTO(struct super_block *sb, int type, struct bio *bio),
+
+ TP_ARGS(sb, type, bio),
TP_CONDITION(bio)
);
@@ -1084,16 +1334,16 @@
),
TP_printk("dev = (%d,%d), checkpoint for %s, state = %s",
- show_dev(__entry),
+ show_dev(__entry->dev),
show_cpreason(__entry->reason),
__entry->msg)
);
-TRACE_EVENT(f2fs_issue_discard,
+DECLARE_EVENT_CLASS(f2fs_discard,
- TP_PROTO(struct super_block *sb, block_t blkstart, block_t blklen),
+ TP_PROTO(struct block_device *dev, block_t blkstart, block_t blklen),
- TP_ARGS(sb, blkstart, blklen),
+ TP_ARGS(dev, blkstart, blklen),
TP_STRUCT__entry(
__field(dev_t, dev)
@@ -1102,40 +1352,85 @@
),
TP_fast_assign(
- __entry->dev = sb->s_dev;
+ __entry->dev = dev->bd_dev;
__entry->blkstart = blkstart;
__entry->blklen = blklen;
),
TP_printk("dev = (%d,%d), blkstart = 0x%llx, blklen = 0x%llx",
- show_dev(__entry),
+ show_dev(__entry->dev),
(unsigned long long)__entry->blkstart,
(unsigned long long)__entry->blklen)
);
+DEFINE_EVENT(f2fs_discard, f2fs_queue_discard,
+
+ TP_PROTO(struct block_device *dev, block_t blkstart, block_t blklen),
+
+ TP_ARGS(dev, blkstart, blklen)
+);
+
+DEFINE_EVENT(f2fs_discard, f2fs_issue_discard,
+
+ TP_PROTO(struct block_device *dev, block_t blkstart, block_t blklen),
+
+ TP_ARGS(dev, blkstart, blklen)
+);
+
+DEFINE_EVENT(f2fs_discard, f2fs_remove_discard,
+
+ TP_PROTO(struct block_device *dev, block_t blkstart, block_t blklen),
+
+ TP_ARGS(dev, blkstart, blklen)
+);
+
+TRACE_EVENT(f2fs_issue_reset_zone,
+
+ TP_PROTO(struct block_device *dev, block_t blkstart),
+
+ TP_ARGS(dev, blkstart),
+
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(block_t, blkstart)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = dev->bd_dev;
+ __entry->blkstart = blkstart;
+ ),
+
+ TP_printk("dev = (%d,%d), reset zone at block = 0x%llx",
+ show_dev(__entry->dev),
+ (unsigned long long)__entry->blkstart)
+);
+
TRACE_EVENT(f2fs_issue_flush,
- TP_PROTO(struct super_block *sb, unsigned int nobarrier,
- unsigned int flush_merge),
+ TP_PROTO(struct block_device *dev, unsigned int nobarrier,
+ unsigned int flush_merge, int ret),
- TP_ARGS(sb, nobarrier, flush_merge),
+ TP_ARGS(dev, nobarrier, flush_merge, ret),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(unsigned int, nobarrier)
__field(unsigned int, flush_merge)
+ __field(int, ret)
),
TP_fast_assign(
- __entry->dev = sb->s_dev;
+ __entry->dev = dev->bd_dev;
__entry->nobarrier = nobarrier;
__entry->flush_merge = flush_merge;
+ __entry->ret = ret;
),
- TP_printk("dev = (%d,%d), %s %s",
- show_dev(__entry),
+ TP_printk("dev = (%d,%d), %s %s, ret = %d",
+ show_dev(__entry->dev),
__entry->nobarrier ? "skip (nobarrier)" : "issue",
- __entry->flush_merge ? " with flush_merge" : "")
+ __entry->flush_merge ? " with flush_merge" : "",
+ __entry->ret)
);
TRACE_EVENT(f2fs_lookup_extent_tree_start,
@@ -1248,7 +1543,7 @@
),
TP_printk("dev = (%d,%d), shrunk: node_cnt = %u, tree_cnt = %u",
- show_dev(__entry),
+ show_dev(__entry->dev),
__entry->node_cnt,
__entry->tree_cnt)
);
@@ -1295,7 +1590,7 @@
),
TP_printk("dev = (%d,%d), %s, dirty count = %lld",
- show_dev(__entry),
+ show_dev(__entry->dev),
show_file_type(__entry->type),
__entry->count)
);
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index 8cfb1d7..a29c76f 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -858,322 +858,6 @@
__entry->freq)
);
-DECLARE_EVENT_CLASS(kpm_module,
-
- TP_PROTO(unsigned int managed_cpus, unsigned int max_cpus),
-
- TP_ARGS(managed_cpus, max_cpus),
-
- TP_STRUCT__entry(
- __field(u32, managed_cpus)
- __field(u32, max_cpus)
- ),
-
- TP_fast_assign(
- __entry->managed_cpus = managed_cpus;
- __entry->max_cpus = max_cpus;
- ),
-
- TP_printk("managed:%x max_cpus=%u", (unsigned int)__entry->managed_cpus,
- (unsigned int)__entry->max_cpus)
-);
-
-DEFINE_EVENT(kpm_module, set_max_cpus,
- TP_PROTO(unsigned int managed_cpus, unsigned int max_cpus),
- TP_ARGS(managed_cpus, max_cpus)
-);
-
-DEFINE_EVENT(kpm_module, reevaluate_hotplug,
- TP_PROTO(unsigned int managed_cpus, unsigned int max_cpus),
- TP_ARGS(managed_cpus, max_cpus)
-);
-
-DECLARE_EVENT_CLASS(kpm_module2,
-
- TP_PROTO(unsigned int cpu, unsigned int enter_cycle_cnt,
- unsigned int exit_cycle_cnt,
- unsigned int io_busy, u64 iowait),
-
- TP_ARGS(cpu, enter_cycle_cnt, exit_cycle_cnt, io_busy, iowait),
-
- TP_STRUCT__entry(
- __field(u32, cpu)
- __field(u32, enter_cycle_cnt)
- __field(u32, exit_cycle_cnt)
- __field(u32, io_busy)
- __field(u64, iowait)
- ),
-
- TP_fast_assign(
- __entry->cpu = cpu;
- __entry->enter_cycle_cnt = enter_cycle_cnt;
- __entry->exit_cycle_cnt = exit_cycle_cnt;
- __entry->io_busy = io_busy;
- __entry->iowait = iowait;
- ),
-
- TP_printk("CPU:%u enter_cycles=%u exit_cycles=%u io_busy=%u iowait=%lu",
- (unsigned int)__entry->cpu,
- (unsigned int)__entry->enter_cycle_cnt,
- (unsigned int)__entry->exit_cycle_cnt,
- (unsigned int)__entry->io_busy,
- (unsigned long)__entry->iowait)
-);
-
-DEFINE_EVENT(kpm_module2, track_iowait,
- TP_PROTO(unsigned int cpu, unsigned int enter_cycle_cnt,
- unsigned int exit_cycle_cnt, unsigned int io_busy, u64 iowait),
- TP_ARGS(cpu, enter_cycle_cnt, exit_cycle_cnt, io_busy, iowait)
-);
-
-DECLARE_EVENT_CLASS(cpu_modes,
-
- TP_PROTO(unsigned int cpu, unsigned int max_load,
- unsigned int single_enter_cycle_cnt,
- unsigned int single_exit_cycle_cnt,
- unsigned int total_load, unsigned int multi_enter_cycle_cnt,
- unsigned int multi_exit_cycle_cnt,
- unsigned int perf_cl_peak_enter_cycle_cnt,
- unsigned int perf_cl_peak_exit_cycle_cnt,
- unsigned int mode,
- unsigned int cpu_cnt),
-
- TP_ARGS(cpu, max_load, single_enter_cycle_cnt, single_exit_cycle_cnt,
- total_load, multi_enter_cycle_cnt, multi_exit_cycle_cnt,
- perf_cl_peak_enter_cycle_cnt, perf_cl_peak_exit_cycle_cnt, mode,
- cpu_cnt),
-
- TP_STRUCT__entry(
- __field(u32, cpu)
- __field(u32, max_load)
- __field(u32, single_enter_cycle_cnt)
- __field(u32, single_exit_cycle_cnt)
- __field(u32, total_load)
- __field(u32, multi_enter_cycle_cnt)
- __field(u32, multi_exit_cycle_cnt)
- __field(u32, perf_cl_peak_enter_cycle_cnt)
- __field(u32, perf_cl_peak_exit_cycle_cnt)
- __field(u32, mode)
- __field(u32, cpu_cnt)
- ),
-
- TP_fast_assign(
- __entry->cpu = cpu;
- __entry->max_load = max_load;
- __entry->single_enter_cycle_cnt = single_enter_cycle_cnt;
- __entry->single_exit_cycle_cnt = single_exit_cycle_cnt;
- __entry->total_load = total_load;
- __entry->multi_enter_cycle_cnt = multi_enter_cycle_cnt;
- __entry->multi_exit_cycle_cnt = multi_exit_cycle_cnt;
- __entry->perf_cl_peak_enter_cycle_cnt =
- perf_cl_peak_enter_cycle_cnt;
- __entry->perf_cl_peak_exit_cycle_cnt =
- perf_cl_peak_exit_cycle_cnt;
- __entry->mode = mode;
- __entry->cpu_cnt = cpu_cnt;
- ),
-
- TP_printk("%u:%4u:%4u:%4u:%4u:%4u:%4u:%4u:%4u:%4u:%u",
- (unsigned int)__entry->cpu, (unsigned int)__entry->max_load,
- (unsigned int)__entry->single_enter_cycle_cnt,
- (unsigned int)__entry->single_exit_cycle_cnt,
- (unsigned int)__entry->total_load,
- (unsigned int)__entry->multi_enter_cycle_cnt,
- (unsigned int)__entry->multi_exit_cycle_cnt,
- (unsigned int)__entry->perf_cl_peak_enter_cycle_cnt,
- (unsigned int)__entry->perf_cl_peak_exit_cycle_cnt,
- (unsigned int)__entry->mode,
- (unsigned int)__entry->cpu_cnt)
-);
-
-DEFINE_EVENT(cpu_modes, cpu_mode_detect,
- TP_PROTO(unsigned int cpu, unsigned int max_load,
- unsigned int single_enter_cycle_cnt,
- unsigned int single_exit_cycle_cnt,
- unsigned int total_load, unsigned int multi_enter_cycle_cnt,
- unsigned int multi_exit_cycle_cnt,
- unsigned int perf_cl_peak_enter_cycle_cnt,
- unsigned int perf_cl_peak_exit_cycle_cnt,
- unsigned int mode,
- unsigned int cpu_cnt),
- TP_ARGS(cpu, max_load, single_enter_cycle_cnt, single_exit_cycle_cnt,
- total_load, multi_enter_cycle_cnt, multi_exit_cycle_cnt,
- perf_cl_peak_enter_cycle_cnt, perf_cl_peak_exit_cycle_cnt,
- mode, cpu_cnt)
-);
-
-DECLARE_EVENT_CLASS(timer_status,
- TP_PROTO(unsigned int cpu, unsigned int single_enter_cycles,
- unsigned int single_enter_cycle_cnt,
- unsigned int single_exit_cycles,
- unsigned int single_exit_cycle_cnt,
- unsigned int multi_enter_cycles,
- unsigned int multi_enter_cycle_cnt,
- unsigned int multi_exit_cycles,
- unsigned int multi_exit_cycle_cnt, unsigned int timer_rate,
- unsigned int mode),
- TP_ARGS(cpu, single_enter_cycles, single_enter_cycle_cnt,
- single_exit_cycles, single_exit_cycle_cnt, multi_enter_cycles,
- multi_enter_cycle_cnt, multi_exit_cycles,
- multi_exit_cycle_cnt, timer_rate, mode),
-
- TP_STRUCT__entry(
- __field(unsigned int, cpu)
- __field(unsigned int, single_enter_cycles)
- __field(unsigned int, single_enter_cycle_cnt)
- __field(unsigned int, single_exit_cycles)
- __field(unsigned int, single_exit_cycle_cnt)
- __field(unsigned int, multi_enter_cycles)
- __field(unsigned int, multi_enter_cycle_cnt)
- __field(unsigned int, multi_exit_cycles)
- __field(unsigned int, multi_exit_cycle_cnt)
- __field(unsigned int, timer_rate)
- __field(unsigned int, mode)
- ),
-
- TP_fast_assign(
- __entry->cpu = cpu;
- __entry->single_enter_cycles = single_enter_cycles;
- __entry->single_enter_cycle_cnt = single_enter_cycle_cnt;
- __entry->single_exit_cycles = single_exit_cycles;
- __entry->single_exit_cycle_cnt = single_exit_cycle_cnt;
- __entry->multi_enter_cycles = multi_enter_cycles;
- __entry->multi_enter_cycle_cnt = multi_enter_cycle_cnt;
- __entry->multi_exit_cycles = multi_exit_cycles;
- __entry->multi_exit_cycle_cnt = multi_exit_cycle_cnt;
- __entry->timer_rate = timer_rate;
- __entry->mode = mode;
- ),
-
- TP_printk("%u:%4u:%4u:%4u:%4u:%4u:%4u:%4u:%4u:%4u:%4u",
- (unsigned int) __entry->cpu,
- (unsigned int) __entry->single_enter_cycles,
- (unsigned int) __entry->single_enter_cycle_cnt,
- (unsigned int) __entry->single_exit_cycles,
- (unsigned int) __entry->single_exit_cycle_cnt,
- (unsigned int) __entry->multi_enter_cycles,
- (unsigned int) __entry->multi_enter_cycle_cnt,
- (unsigned int) __entry->multi_exit_cycles,
- (unsigned int) __entry->multi_exit_cycle_cnt,
- (unsigned int) __entry->timer_rate,
- (unsigned int) __entry->mode)
-);
-
-DEFINE_EVENT(timer_status, single_mode_timeout,
- TP_PROTO(unsigned int cpu, unsigned int single_enter_cycles,
- unsigned int single_enter_cycle_cnt,
- unsigned int single_exit_cycles,
- unsigned int single_exit_cycle_cnt,
- unsigned int multi_enter_cycles,
- unsigned int multi_enter_cycle_cnt,
- unsigned int multi_exit_cycles,
- unsigned int multi_exit_cycle_cnt, unsigned int timer_rate,
- unsigned int mode),
- TP_ARGS(cpu, single_enter_cycles, single_enter_cycle_cnt,
- single_exit_cycles, single_exit_cycle_cnt, multi_enter_cycles,
- multi_enter_cycle_cnt, multi_exit_cycles, multi_exit_cycle_cnt,
- timer_rate, mode)
-);
-
-DEFINE_EVENT(timer_status, single_cycle_exit_timer_start,
- TP_PROTO(unsigned int cpu, unsigned int single_enter_cycles,
- unsigned int single_enter_cycle_cnt,
- unsigned int single_exit_cycles,
- unsigned int single_exit_cycle_cnt,
- unsigned int multi_enter_cycles,
- unsigned int multi_enter_cycle_cnt,
- unsigned int multi_exit_cycles,
- unsigned int multi_exit_cycle_cnt, unsigned int timer_rate,
- unsigned int mode),
- TP_ARGS(cpu, single_enter_cycles, single_enter_cycle_cnt,
- single_exit_cycles, single_exit_cycle_cnt, multi_enter_cycles,
- multi_enter_cycle_cnt, multi_exit_cycles, multi_exit_cycle_cnt,
- timer_rate, mode)
-);
-
-DEFINE_EVENT(timer_status, single_cycle_exit_timer_stop,
- TP_PROTO(unsigned int cpu, unsigned int single_enter_cycles,
- unsigned int single_enter_cycle_cnt,
- unsigned int single_exit_cycles,
- unsigned int single_exit_cycle_cnt,
- unsigned int multi_enter_cycles,
- unsigned int multi_enter_cycle_cnt,
- unsigned int multi_exit_cycles,
- unsigned int multi_exit_cycle_cnt, unsigned int timer_rate,
- unsigned int mode),
- TP_ARGS(cpu, single_enter_cycles, single_enter_cycle_cnt,
- single_exit_cycles, single_exit_cycle_cnt, multi_enter_cycles,
- multi_enter_cycle_cnt, multi_exit_cycles, multi_exit_cycle_cnt,
- timer_rate, mode)
-);
-
-DECLARE_EVENT_CLASS(perf_cl_peak_timer_status,
- TP_PROTO(unsigned int cpu, unsigned int perf_cl_peak_enter_cycles,
- unsigned int perf_cl_peak_enter_cycle_cnt,
- unsigned int perf_cl_peak_exit_cycles,
- unsigned int perf_cl_peak_exit_cycle_cnt,
- unsigned int timer_rate,
- unsigned int mode),
- TP_ARGS(cpu, perf_cl_peak_enter_cycles, perf_cl_peak_enter_cycle_cnt,
- perf_cl_peak_exit_cycles, perf_cl_peak_exit_cycle_cnt,
- timer_rate, mode),
-
- TP_STRUCT__entry(
- __field(unsigned int, cpu)
- __field(unsigned int, perf_cl_peak_enter_cycles)
- __field(unsigned int, perf_cl_peak_enter_cycle_cnt)
- __field(unsigned int, perf_cl_peak_exit_cycles)
- __field(unsigned int, perf_cl_peak_exit_cycle_cnt)
- __field(unsigned int, timer_rate)
- __field(unsigned int, mode)
- ),
-
- TP_fast_assign(
- __entry->cpu = cpu;
- __entry->perf_cl_peak_enter_cycles = perf_cl_peak_enter_cycles;
- __entry->perf_cl_peak_enter_cycle_cnt =
- perf_cl_peak_enter_cycle_cnt;
- __entry->perf_cl_peak_exit_cycles = perf_cl_peak_exit_cycles;
- __entry->perf_cl_peak_exit_cycle_cnt =
- perf_cl_peak_exit_cycle_cnt;
- __entry->timer_rate = timer_rate;
- __entry->mode = mode;
- ),
-
- TP_printk("%u:%4u:%4u:%4u:%4u:%4u:%4u",
- (unsigned int) __entry->cpu,
- (unsigned int) __entry->perf_cl_peak_enter_cycles,
- (unsigned int) __entry->perf_cl_peak_enter_cycle_cnt,
- (unsigned int) __entry->perf_cl_peak_exit_cycles,
- (unsigned int) __entry->perf_cl_peak_exit_cycle_cnt,
- (unsigned int) __entry->timer_rate,
- (unsigned int) __entry->mode)
-);
-
-DEFINE_EVENT(perf_cl_peak_timer_status, perf_cl_peak_exit_timer_start,
- TP_PROTO(unsigned int cpu, unsigned int perf_cl_peak_enter_cycles,
- unsigned int perf_cl_peak_enter_cycle_cnt,
- unsigned int perf_cl_peak_exit_cycles,
- unsigned int perf_cl_peak_exit_cycle_cnt,
- unsigned int timer_rate,
- unsigned int mode),
- TP_ARGS(cpu, perf_cl_peak_enter_cycles, perf_cl_peak_enter_cycle_cnt,
- perf_cl_peak_exit_cycles, perf_cl_peak_exit_cycle_cnt,
- timer_rate, mode)
-);
-
-
-DEFINE_EVENT(perf_cl_peak_timer_status, perf_cl_peak_exit_timer_stop,
- TP_PROTO(unsigned int cpu, unsigned int perf_cl_peak_enter_cycles,
- unsigned int perf_cl_peak_enter_cycle_cnt,
- unsigned int perf_cl_peak_exit_cycles,
- unsigned int perf_cl_peak_exit_cycle_cnt,
- unsigned int timer_rate,
- unsigned int mode),
- TP_ARGS(cpu, perf_cl_peak_enter_cycles, perf_cl_peak_enter_cycle_cnt,
- perf_cl_peak_exit_cycles, perf_cl_peak_exit_cycle_cnt,
- timer_rate, mode)
-);
#endif /* _TRACE_POWER_H */
diff --git a/include/trace/events/preemptirq.h b/include/trace/events/preemptirq.h
new file mode 100644
index 0000000..f5024c5
--- /dev/null
+++ b/include/trace/events/preemptirq.h
@@ -0,0 +1,70 @@
+#ifdef CONFIG_PREEMPTIRQ_EVENTS
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM preemptirq
+
+#if !defined(_TRACE_PREEMPTIRQ_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_PREEMPTIRQ_H
+
+#include <linux/ktime.h>
+#include <linux/tracepoint.h>
+#include <linux/string.h>
+#include <asm/sections.h>
+
+DECLARE_EVENT_CLASS(preemptirq_template,
+
+ TP_PROTO(unsigned long ip, unsigned long parent_ip),
+
+ TP_ARGS(ip, parent_ip),
+
+ TP_STRUCT__entry(
+ __field(u32, caller_offs)
+ __field(u32, parent_offs)
+ ),
+
+ TP_fast_assign(
+ __entry->caller_offs = (u32)(ip - (unsigned long)_stext);
+ __entry->parent_offs = (u32)(parent_ip - (unsigned long)_stext);
+ ),
+
+ TP_printk("caller=%pF parent=%pF",
+ (void *)((unsigned long)(_stext) + __entry->caller_offs),
+ (void *)((unsigned long)(_stext) + __entry->parent_offs))
+);
+
+#ifndef CONFIG_PROVE_LOCKING
+DEFINE_EVENT(preemptirq_template, irq_disable,
+ TP_PROTO(unsigned long ip, unsigned long parent_ip),
+ TP_ARGS(ip, parent_ip));
+
+DEFINE_EVENT(preemptirq_template, irq_enable,
+ TP_PROTO(unsigned long ip, unsigned long parent_ip),
+ TP_ARGS(ip, parent_ip));
+#endif
+
+#ifdef CONFIG_DEBUG_PREEMPT
+DEFINE_EVENT(preemptirq_template, preempt_disable,
+ TP_PROTO(unsigned long ip, unsigned long parent_ip),
+ TP_ARGS(ip, parent_ip));
+
+DEFINE_EVENT(preemptirq_template, preempt_enable,
+ TP_PROTO(unsigned long ip, unsigned long parent_ip),
+ TP_ARGS(ip, parent_ip));
+#endif
+
+#endif /* _TRACE_PREEMPTIRQ_H */
+
+#include <trace/define_trace.h>
+
+#else /* !CONFIG_PREEMPTIRQ_EVENTS */
+
+#define trace_irq_enable(...)
+#define trace_irq_disable(...)
+#define trace_preempt_enable(...)
+#define trace_preempt_disable(...)
+#define trace_irq_enable_rcuidle(...)
+#define trace_irq_disable_rcuidle(...)
+#define trace_preempt_enable_rcuidle(...)
+#define trace_preempt_disable_rcuidle(...)
+
+#endif
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 63f2baf..23a3b9a 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -643,160 +643,118 @@
#ifdef CONFIG_SMP
TRACE_EVENT(sched_cpu_util,
- TP_PROTO(struct task_struct *p, int cpu, int task_util, unsigned long curr_util, unsigned long new_cum_util, int sync),
+ TP_PROTO(int cpu),
- TP_ARGS(p, cpu, task_util, curr_util, new_cum_util, sync),
+ TP_ARGS(cpu),
TP_STRUCT__entry(
- __array(char, comm, TASK_COMM_LEN )
- __field(int, pid )
__field(unsigned int, cpu )
- __field(int, task_util )
__field(unsigned int, nr_running )
- __field(long, cpu_util )
+ __field(long, cpu_util )
__field(long, cpu_util_cum )
- __field(long, new_cum_util )
__field(unsigned int, capacity_curr )
__field(unsigned int, capacity )
- __field(unsigned long, curr_util )
- __field(int, sync )
+ __field(unsigned int, capacity_orig )
__field(int, idle_state )
- __field(unsigned int, irqload )
- __field(int, high_irqload )
- __field(int, task_in_cum_demand )
+ __field(u64, irqload )
),
TP_fast_assign(
- memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
- __entry->pid = p->pid;
__entry->cpu = cpu;
- __entry->task_util = task_util;
__entry->nr_running = cpu_rq(cpu)->nr_running;
__entry->cpu_util = cpu_util(cpu);
__entry->cpu_util_cum = cpu_util_cum(cpu, 0);
- __entry->new_cum_util = new_cum_util;
- __entry->task_in_cum_demand = task_in_cum_window_demand(cpu_rq(cpu), p);
__entry->capacity_curr = capacity_curr_of(cpu);
__entry->capacity = capacity_of(cpu);
- __entry->curr_util = curr_util;
- __entry->sync = sync;
+ __entry->capacity_orig = capacity_orig_of(cpu);
__entry->idle_state = idle_get_state_idx(cpu_rq(cpu));
__entry->irqload = sched_irqload(cpu);
- __entry->high_irqload = sched_cpu_high_irqload(cpu);
),
- TP_printk("comm=%s pid=%d cpu=%d task_util=%d nr_running=%d cpu_util=%ld cpu_util_cum=%ld new_cum_util=%ld task_in_cum=%d capacity_curr=%u capacity=%u curr_util=%ld sync=%d idle_state=%d irqload=%u high_irqload=%u",
- __entry->comm, __entry->pid, __entry->cpu, __entry->task_util, __entry->nr_running, __entry->cpu_util, __entry->cpu_util_cum, __entry->new_cum_util, __entry->task_in_cum_demand, __entry->capacity_curr, __entry->capacity, __entry->curr_util, __entry->sync, __entry->idle_state, __entry->irqload, __entry->high_irqload)
+ TP_printk("cpu=%d nr_running=%d cpu_util=%ld cpu_util_cum=%ld capacity_curr=%u capacity=%u capacity_orig=%u idle_state=%d irqload=%llu",
+ __entry->cpu, __entry->nr_running, __entry->cpu_util, __entry->cpu_util_cum, __entry->capacity_curr, __entry->capacity, __entry->capacity_orig, __entry->idle_state, __entry->irqload)
);
-TRACE_EVENT(sched_energy_diff_packing,
+TRACE_EVENT(sched_energy_diff,
- TP_PROTO(struct task_struct *p, unsigned long task_util,
- int targeted_cpus, int nrg_pack, int nrg_spread),
+ TP_PROTO(struct task_struct *p, int prev_cpu, unsigned int prev_energy,
+ int next_cpu, unsigned int next_energy,
+ int backup_cpu, unsigned int backup_energy),
- TP_ARGS(p, task_util, targeted_cpus, nrg_pack, nrg_spread),
+ TP_ARGS(p, prev_cpu, prev_energy, next_cpu, next_energy,
+ backup_cpu, backup_energy),
TP_STRUCT__entry(
- __array(char, comm, TASK_COMM_LEN )
- __field(int, pid )
- __field(unsigned long, task_util )
- __field(int, targeted_cpus )
- __field(int, nrg_pack )
- __field(int, nrg_spread )
+ __field(int, pid )
+ __field(int, prev_cpu )
+ __field(int, prev_energy )
+ __field(int, next_cpu )
+ __field(int, next_energy )
+ __field(int, backup_cpu )
+ __field(int, backup_energy )
),
TP_fast_assign(
- memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
__entry->pid = p->pid;
- __entry->task_util = task_util;
- __entry->targeted_cpus = targeted_cpus;
- __entry->nrg_pack = nrg_pack;
- __entry->nrg_spread = nrg_spread;
+ __entry->prev_cpu = prev_cpu;
+ __entry->prev_energy = prev_energy;
+ __entry->next_cpu = next_cpu;
+ __entry->next_energy = next_energy;
+ __entry->backup_cpu = backup_cpu;
+ __entry->backup_energy = backup_energy;
),
- TP_printk("comm=%s pid=%d task_util=%lu targeted_cpus=%d nrg_pack=%d nrg_spread=%d nrg_diff=%d",
- __entry->comm, __entry->pid, __entry->task_util,
- __entry->targeted_cpus, __entry->nrg_pack,
- __entry->nrg_spread, __entry->nrg_pack - __entry->nrg_spread)
+ TP_printk("pid=%d prev_cpu=%d prev_energy=%u next_cpu=%d next_energy=%u backup_cpu=%d backup_energy=%u",
+ __entry->pid, __entry->prev_cpu, __entry->prev_energy,
+ __entry->next_cpu, __entry->next_energy,
+ __entry->backup_cpu, __entry->backup_energy)
);
-DECLARE_EVENT_CLASS(sched_task_util,
+TRACE_EVENT(sched_task_util,
- TP_PROTO(struct task_struct *p, int task_cpu, unsigned long task_util, int nominated_cpu, int target_cpu, int ediff, bool need_idle),
+ TP_PROTO(struct task_struct *p, int next_cpu, int backup_cpu,
+ int target_cpu, bool sync, bool need_idle,
+ bool placement_boost, int rtg_cpu),
- TP_ARGS(p, task_cpu, task_util, nominated_cpu, target_cpu, ediff, need_idle),
+ TP_ARGS(p, next_cpu, backup_cpu, target_cpu, sync, need_idle,
+ placement_boost, rtg_cpu),
TP_STRUCT__entry(
- __array(char, comm, TASK_COMM_LEN )
__field(int, pid )
- __field(int, task_cpu )
- __field(unsigned long, task_util )
- __field(unsigned long, cpu_util_freq )
- __field(int, nominated_cpu )
+ __array(char, comm, TASK_COMM_LEN )
+ __field(unsigned long, util )
+ __field(int, prev_cpu )
+ __field(int, next_cpu )
+ __field(int, backup_cpu )
__field(int, target_cpu )
- __field(int, ediff )
+ __field(bool, sync )
__field(bool, need_idle )
+ __field(bool, placement_boost )
+ __field(int, rtg_cpu )
__field(u64, latency )
),
TP_fast_assign(
- memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
__entry->pid = p->pid;
- __entry->task_cpu = task_cpu;
- __entry->task_util = task_util;
- __entry->cpu_util_freq = cpu_util_freq(target_cpu, NULL);
- __entry->nominated_cpu = nominated_cpu;
+ memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
+ __entry->util = task_util(p);
+ __entry->prev_cpu = task_cpu(p);
+ __entry->next_cpu = next_cpu;
+ __entry->backup_cpu = backup_cpu;
__entry->target_cpu = target_cpu;
- __entry->ediff = ediff;
+ __entry->sync = sync;
__entry->need_idle = need_idle;
+ __entry->placement_boost = placement_boost;
+ __entry->rtg_cpu = rtg_cpu;
__entry->latency = p->ravg.mark_start ?
ktime_get_ns() -
p->ravg.mark_start : 0;
),
- TP_printk("comm=%s pid=%d task_cpu=%d task_util=%lu nominated_cpu=%d target_cpu=%d energy_diff=%d need_idle=%d latency=%llu",
- __entry->comm, __entry->pid, __entry->task_cpu, __entry->task_util, __entry->nominated_cpu, __entry->target_cpu, __entry->ediff, __entry->need_idle, __entry->latency)
+ TP_printk("pid=%d comm=%s util=%lu prev_cpu=%d next_cpu=%d backup_cpu=%d target_cpu=%d sync=%d need_idle=%d placement_boost=%d rtg_cpu=%d latency=%llu",
+ __entry->pid, __entry->comm, __entry->util, __entry->prev_cpu, __entry->next_cpu, __entry->backup_cpu, __entry->target_cpu, __entry->sync, __entry->need_idle, __entry->placement_boost, __entry->rtg_cpu, __entry->latency)
);
-DEFINE_EVENT(sched_task_util, sched_task_util_bias_to_waker,
- TP_PROTO(struct task_struct *p, int task_cpu, unsigned long task_util, int nominated_cpu, int target_cpu, int ediff, bool need_idle),
- TP_ARGS(p, task_cpu, task_util, nominated_cpu, target_cpu, ediff, need_idle)
-);
-
-DEFINE_EVENT(sched_task_util, sched_task_util_colocated,
- TP_PROTO(struct task_struct *p, int task_cpu, unsigned long task_util, int nominated_cpu, int target_cpu, int ediff, bool need_idle),
- TP_ARGS(p, task_cpu, task_util, nominated_cpu, target_cpu, ediff, need_idle)
-);
-
-DEFINE_EVENT(sched_task_util, sched_task_util_boosted,
- TP_PROTO(struct task_struct *p, int task_cpu, unsigned long task_util, int nominated_cpu, int target_cpu, int ediff, bool need_idle),
- TP_ARGS(p, task_cpu, task_util, nominated_cpu, target_cpu, ediff, need_idle)
-);
-
-DEFINE_EVENT(sched_task_util, sched_task_util_overutilzed,
- TP_PROTO(struct task_struct *p, int task_cpu, unsigned long task_util, int nominated_cpu, int target_cpu, int ediff, bool need_idle),
- TP_ARGS(p, task_cpu, task_util, nominated_cpu, target_cpu, ediff, need_idle)
-);
-
-DEFINE_EVENT(sched_task_util, sched_task_util_energy_diff,
- TP_PROTO(struct task_struct *p, int task_cpu, unsigned long task_util, int nominated_cpu, int target_cpu, int ediff, bool need_idle),
- TP_ARGS(p, task_cpu, task_util, nominated_cpu, target_cpu, ediff, need_idle)
-);
-
-DEFINE_EVENT(sched_task_util, sched_task_util_energy_aware,
- TP_PROTO(struct task_struct *p, int task_cpu, unsigned long task_util, int nominated_cpu, int target_cpu, int ediff, bool need_idle),
- TP_ARGS(p, task_cpu, task_util, nominated_cpu, target_cpu, ediff, need_idle)
-);
-
-DEFINE_EVENT(sched_task_util, sched_task_util_imbalance,
- TP_PROTO(struct task_struct *p, int task_cpu, unsigned long task_util, int nominated_cpu, int target_cpu, int ediff, bool need_idle),
- TP_ARGS(p, task_cpu, task_util, nominated_cpu, target_cpu, ediff, need_idle)
-);
-
-DEFINE_EVENT(sched_task_util, sched_task_util_need_idle,
- TP_PROTO(struct task_struct *p, int task_cpu, unsigned long task_util, int nominated_cpu, int target_cpu, int ediff, bool need_idle),
- TP_ARGS(p, task_cpu, task_util, nominated_cpu, target_cpu, ediff, need_idle)
-);
#endif
/*
@@ -1433,22 +1391,36 @@
);
#ifdef CONFIG_SMP
+
+#ifdef CONFIG_SCHED_WALT
+extern unsigned int sysctl_sched_use_walt_cpu_util;
+extern unsigned int sysctl_sched_use_walt_task_util;
+extern unsigned int sched_ravg_window;
+extern unsigned int walt_disabled;
+#endif
+
/*
* Tracepoint for accounting sched averages for tasks.
*/
TRACE_EVENT(sched_load_avg_task,
- TP_PROTO(struct task_struct *tsk, struct sched_avg *avg),
- TP_ARGS(tsk, avg),
+
+ TP_PROTO(struct task_struct *tsk, struct sched_avg *avg, void *_ravg),
+
+ TP_ARGS(tsk, avg, _ravg),
+
TP_STRUCT__entry(
__array( char, comm, TASK_COMM_LEN )
__field( pid_t, pid )
__field( int, cpu )
__field( unsigned long, load_avg )
__field( unsigned long, util_avg )
+ __field( unsigned long, util_avg_pelt )
+ __field( u32, util_avg_walt )
__field( u64, load_sum )
__field( u32, util_sum )
__field( u32, period_contrib )
),
+
TP_fast_assign(
memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
__entry->pid = tsk->pid;
@@ -1458,79 +1430,124 @@
__entry->load_sum = avg->load_sum;
__entry->util_sum = avg->util_sum;
__entry->period_contrib = avg->period_contrib;
+ __entry->util_avg_pelt = avg->util_avg;
+ __entry->util_avg_walt = 0;
+#ifdef CONFIG_SCHED_WALT
+ __entry->util_avg_walt = ((struct ravg*)_ravg)->demand /
+ (sched_ravg_window >> SCHED_CAPACITY_SHIFT);
+ if (!walt_disabled && sysctl_sched_use_walt_task_util)
+ __entry->util_avg = __entry->util_avg_walt;
+#endif
),
- TP_printk("comm=%s pid=%d cpu=%d load_avg=%lu util_avg=%lu load_sum=%llu"
+ TP_printk("comm=%s pid=%d cpu=%d load_avg=%lu util_avg=%lu "
+ "util_avg_pelt=%lu util_avg_walt=%u load_sum=%llu"
" util_sum=%u period_contrib=%u",
__entry->comm,
__entry->pid,
__entry->cpu,
__entry->load_avg,
__entry->util_avg,
+ __entry->util_avg_pelt,
+ __entry->util_avg_walt,
(u64)__entry->load_sum,
(u32)__entry->util_sum,
(u32)__entry->period_contrib)
);
+
/*
* Tracepoint for accounting sched averages for cpus.
*/
TRACE_EVENT(sched_load_avg_cpu,
+
TP_PROTO(int cpu, struct cfs_rq *cfs_rq),
+
TP_ARGS(cpu, cfs_rq),
+
TP_STRUCT__entry(
__field( int, cpu )
__field( unsigned long, load_avg )
__field( unsigned long, util_avg )
+ __field( unsigned long, util_avg_pelt )
+ __field( u32, util_avg_walt )
),
+
TP_fast_assign(
__entry->cpu = cpu;
__entry->load_avg = cfs_rq->avg.load_avg;
__entry->util_avg = cfs_rq->avg.util_avg;
+ __entry->util_avg_pelt = cfs_rq->avg.util_avg;
+ __entry->util_avg_walt = 0;
+#ifdef CONFIG_SCHED_WALT
+ __entry->util_avg_walt = div64_ul(cpu_rq(cpu)->prev_runnable_sum,
+ sched_ravg_window >> SCHED_CAPACITY_SHIFT);
+ if (!walt_disabled && sysctl_sched_use_walt_cpu_util)
+ __entry->util_avg = __entry->util_avg_walt;
+#endif
),
- TP_printk("cpu=%d load_avg=%lu util_avg=%lu",
- __entry->cpu, __entry->load_avg, __entry->util_avg)
+
+ TP_printk("cpu=%d load_avg=%lu util_avg=%lu "
+ "util_avg_pelt=%lu util_avg_walt=%u",
+ __entry->cpu, __entry->load_avg, __entry->util_avg,
+ __entry->util_avg_pelt, __entry->util_avg_walt)
);
+
/*
* Tracepoint for sched_tune_config settings
*/
TRACE_EVENT(sched_tune_config,
+
TP_PROTO(int boost),
+
TP_ARGS(boost),
+
TP_STRUCT__entry(
__field( int, boost )
),
+
TP_fast_assign(
__entry->boost = boost;
),
+
TP_printk("boost=%d ", __entry->boost)
);
+
/*
* Tracepoint for accounting CPU boosted utilization
*/
TRACE_EVENT(sched_boost_cpu,
+
TP_PROTO(int cpu, unsigned long util, long margin),
+
TP_ARGS(cpu, util, margin),
+
TP_STRUCT__entry(
__field( int, cpu )
__field( unsigned long, util )
__field(long, margin )
),
+
TP_fast_assign(
__entry->cpu = cpu;
__entry->util = util;
__entry->margin = margin;
),
+
TP_printk("cpu=%d util=%lu margin=%ld",
__entry->cpu,
__entry->util,
__entry->margin)
);
+
/*
* Tracepoint for schedtune_tasks_update
*/
TRACE_EVENT(sched_tune_tasks_update,
+
TP_PROTO(struct task_struct *tsk, int cpu, int tasks, int idx,
int boost, int max_boost),
+
TP_ARGS(tsk, cpu, tasks, idx, boost, max_boost),
+
TP_STRUCT__entry(
__array( char, comm, TASK_COMM_LEN )
__field( pid_t, pid )
@@ -1540,6 +1557,7 @@
__field( int, boost )
__field( int, max_boost )
),
+
TP_fast_assign(
memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
__entry->pid = tsk->pid;
@@ -1549,104 +1567,109 @@
__entry->boost = boost;
__entry->max_boost = max_boost;
),
+
TP_printk("pid=%d comm=%s "
"cpu=%d tasks=%d idx=%d boost=%d max_boost=%d",
__entry->pid, __entry->comm,
__entry->cpu, __entry->tasks, __entry->idx,
__entry->boost, __entry->max_boost)
);
+
/*
* Tracepoint for schedtune_boostgroup_update
*/
TRACE_EVENT(sched_tune_boostgroup_update,
+
TP_PROTO(int cpu, int variation, int max_boost),
+
TP_ARGS(cpu, variation, max_boost),
+
TP_STRUCT__entry(
__field( int, cpu )
__field( int, variation )
__field( int, max_boost )
),
+
TP_fast_assign(
__entry->cpu = cpu;
__entry->variation = variation;
__entry->max_boost = max_boost;
),
+
TP_printk("cpu=%d variation=%d max_boost=%d",
__entry->cpu, __entry->variation, __entry->max_boost)
);
+
/*
* Tracepoint for accounting task boosted utilization
*/
TRACE_EVENT(sched_boost_task,
+
TP_PROTO(struct task_struct *tsk, unsigned long util, long margin),
+
TP_ARGS(tsk, util, margin),
+
TP_STRUCT__entry(
__array( char, comm, TASK_COMM_LEN )
__field( pid_t, pid )
__field( unsigned long, util )
__field( long, margin )
+
),
+
TP_fast_assign(
memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
__entry->pid = tsk->pid;
__entry->util = util;
__entry->margin = margin;
),
+
TP_printk("comm=%s pid=%d util=%lu margin=%ld",
__entry->comm, __entry->pid,
__entry->util,
__entry->margin)
);
+
/*
- * Tracepoint for accounting sched group energy
+ * Tracepoint for find_best_target
*/
-TRACE_EVENT(sched_energy_diff,
- TP_PROTO(struct task_struct *tsk, int scpu, int dcpu, int udelta,
- int nrgb, int nrga, int nrgd, int capb, int capa, int capd,
- int nrgn, int nrgp),
- TP_ARGS(tsk, scpu, dcpu, udelta,
- nrgb, nrga, nrgd, capb, capa, capd,
- nrgn, nrgp),
+TRACE_EVENT(sched_find_best_target,
+
+ TP_PROTO(struct task_struct *tsk, bool prefer_idle,
+ unsigned long min_util, int start_cpu,
+ int best_idle, int best_active, int target),
+
+ TP_ARGS(tsk, prefer_idle, min_util, start_cpu,
+ best_idle, best_active, target),
+
TP_STRUCT__entry(
__array( char, comm, TASK_COMM_LEN )
- __field( pid_t, pid )
- __field( int, scpu )
- __field( int, dcpu )
- __field( int, udelta )
- __field( int, nrgb )
- __field( int, nrga )
- __field( int, nrgd )
- __field( int, capb )
- __field( int, capa )
- __field( int, capd )
- __field( int, nrgn )
- __field( int, nrgp )
+ __field( pid_t, pid )
+ __field( unsigned long, min_util )
+ __field( bool, prefer_idle )
+ __field( int, start_cpu )
+ __field( int, best_idle )
+ __field( int, best_active )
+ __field( int, target )
),
+
TP_fast_assign(
memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
__entry->pid = tsk->pid;
- __entry->scpu = scpu;
- __entry->dcpu = dcpu;
- __entry->udelta = udelta;
- __entry->nrgb = nrgb;
- __entry->nrga = nrga;
- __entry->nrgd = nrgd;
- __entry->capb = capb;
- __entry->capa = capa;
- __entry->capd = capd;
- __entry->nrgn = nrgn;
- __entry->nrgp = nrgp;
+ __entry->min_util = min_util;
+ __entry->prefer_idle = prefer_idle;
+ __entry->start_cpu = start_cpu;
+ __entry->best_idle = best_idle;
+ __entry->best_active = best_active;
+ __entry->target = target;
),
- TP_printk("pid=%d comm=%s "
- "src_cpu=%d dst_cpu=%d usage_delta=%d "
- "nrg_before=%d nrg_after=%d nrg_diff=%d "
- "cap_before=%d cap_after=%d cap_delta=%d "
- "nrg_delta=%d nrg_payoff=%d",
+
+ TP_printk("pid=%d comm=%s prefer_idle=%d start_cpu=%d "
+ "best_idle=%d best_active=%d target=%d",
__entry->pid, __entry->comm,
- __entry->scpu, __entry->dcpu, __entry->udelta,
- __entry->nrgb, __entry->nrga, __entry->nrgd,
- __entry->capb, __entry->capa, __entry->capd,
- __entry->nrgn, __entry->nrgp)
+ __entry->prefer_idle, __entry->start_cpu,
+ __entry->best_idle, __entry->best_active,
+ __entry->target)
);
TRACE_EVENT(sched_group_energy,
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index f8e92fbc..a17b435 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -426,7 +426,9 @@
header-y += stddef.h
header-y += string.h
header-y += suspend_ioctls.h
+header-y += sync.h
header-y += swab.h
+header-y += sw_sync.h
header-y += synclink.h
header-y += sync_file.h
header-y += sysctl.h
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index b2d5be9..a339bea 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -124,6 +124,10 @@
#define BPF_F_NO_PREALLOC (1U << 0)
+/* Flags for accessing BPF object */
+#define BPF_F_RDONLY (1U << 3)
+#define BPF_F_WRONLY (1U << 4)
+
union bpf_attr {
struct { /* anonymous struct used by BPF_MAP_CREATE command */
__u32 map_type; /* one of enum bpf_map_type */
@@ -157,6 +161,7 @@
struct { /* anonymous struct used by BPF_OBJ_* commands */
__aligned_u64 pathname;
__u32 bpf_fd;
+ __u32 file_flags;
};
struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index 11c0307..7683188 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -257,18 +257,47 @@
/* Policy provided via an ioctl on the topmost directory */
#define FS_KEY_DESCRIPTOR_SIZE 8
+#define FS_POLICY_FLAGS_PAD_4 0x00
+#define FS_POLICY_FLAGS_PAD_8 0x01
+#define FS_POLICY_FLAGS_PAD_16 0x02
+#define FS_POLICY_FLAGS_PAD_32 0x03
+#define FS_POLICY_FLAGS_PAD_MASK 0x03
+#define FS_POLICY_FLAGS_VALID 0x03
+
+/* Encryption algorithms */
+#define FS_ENCRYPTION_MODE_INVALID 0
+#define FS_ENCRYPTION_MODE_AES_256_XTS 1
+#define FS_ENCRYPTION_MODE_AES_256_GCM 2
+#define FS_ENCRYPTION_MODE_AES_256_CBC 3
+#define FS_ENCRYPTION_MODE_AES_256_CTS 4
+#define FS_ENCRYPTION_MODE_AES_128_CBC 5
+#define FS_ENCRYPTION_MODE_AES_128_CTS 6
+
struct fscrypt_policy {
__u8 version;
__u8 contents_encryption_mode;
__u8 filenames_encryption_mode;
__u8 flags;
__u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
-} __packed;
+};
#define FS_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct fscrypt_policy)
#define FS_IOC_GET_ENCRYPTION_PWSALT _IOW('f', 20, __u8[16])
#define FS_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct fscrypt_policy)
+/* Parameters for passing an encryption key into the kernel keyring */
+#define FS_KEY_DESC_PREFIX "fscrypt:"
+#define FS_KEY_DESC_PREFIX_SIZE 8
+
+/* Structure that userspace passes to the kernel keyring */
+#define FS_MAX_KEY_SIZE 64
+
+struct fscrypt_key {
+ __u32 mode;
+ __u8 raw[FS_MAX_KEY_SIZE];
+ __u32 size;
+};
+
/*
* Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS)
*
diff --git a/include/uapi/linux/hbtp_input.h b/include/uapi/linux/hbtp_input.h
index 3b124ff..8bc189f 100644
--- a/include/uapi/linux/hbtp_input.h
+++ b/include/uapi/linux/hbtp_input.h
@@ -9,6 +9,7 @@
#define MAX_ROI_SIZE 144
#define MAX_ACCEL_SIZE 128
+#define HBTP_FLAG_ACTIVE_BLOB 0x01
#define HBTP_EVENT_TYPE_DISPLAY "EVENT_TYPE=HBTP_DISPLAY"
struct hbtp_input_touch {
@@ -33,6 +34,13 @@
struct timeval time_val;
};
+struct hbtp_input_mt_ext {
+ __s32 num_touches;
+ struct hbtp_input_touch touches[HBTP_MAX_FINGER];
+ struct timeval time_val;
+ __u32 flag;
+};
+
struct hbtp_input_absinfo {
bool active;
__u16 code;
@@ -77,6 +85,8 @@
enum hbtp_afe_power_ctrl)
#define HBTP_SET_SENSORDATA _IOW(HBTP_INPUT_IOCTL_BASE, 207, \
struct hbtp_sensor_data)
+#define HBTP_SET_TOUCHDATA_EXT _IOW(HBTP_INPUT_IOCTL_BASE, 208, \
+ struct hbtp_input_mt_ext)
#endif /* _UAPI_HBTP_INPUT_H */
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
index c462f1d..b55dceb 100644
--- a/include/uapi/linux/ipv6.h
+++ b/include/uapi/linux/ipv6.h
@@ -185,6 +185,7 @@
DEVCONF_ADDR_GEN_MODE,
DEVCONF_DISABLE_POLICY,
DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
+ DEVCONF_ACCEPT_RA_PREFIX_ROUTE,
DEVCONF_MAX
};
diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h
index 574e22e..33b826b 100644
--- a/include/uapi/linux/kcov.h
+++ b/include/uapi/linux/kcov.h
@@ -7,4 +7,28 @@
#define KCOV_ENABLE _IO('c', 100)
#define KCOV_DISABLE _IO('c', 101)
+enum {
+ /*
+ * Tracing coverage collection mode.
+ * Covered PCs are collected in a per-task buffer.
+ * In new KCOV version the mode is chosen by calling
+ * ioctl(fd, KCOV_ENABLE, mode). In older versions the mode argument
+ * was supposed to be 0 in such a call. So, for reasons of backward
+ * compatibility, we have chosen the value KCOV_TRACE_PC to be 0.
+ */
+ KCOV_TRACE_PC = 0,
+ /* Collecting comparison operands mode. */
+ KCOV_TRACE_CMP = 1,
+};
+
+/*
+ * The format for the types of collected comparisons.
+ *
+ * Bit 0 shows whether one of the arguments is a compile-time constant.
+ * Bits 1 & 2 contain log2 of the argument size, up to 8 bytes.
+ */
+#define KCOV_CMP_CONST (1 << 0)
+#define KCOV_CMP_SIZE(n) ((n) << 1)
+#define KCOV_CMP_MASK KCOV_CMP_SIZE(3)
+
#endif /* _LINUX_KCOV_IOCTLS_H */
diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h
index 9ee2a8b..943ba9e 100644
--- a/include/uapi/linux/msm_kgsl.h
+++ b/include/uapi/linux/msm_kgsl.h
@@ -331,6 +331,7 @@
#define KGSL_PROP_MIN_ACCESS_LENGTH 0x1A
#define KGSL_PROP_UBWC_MODE 0x1B
#define KGSL_PROP_DEVICE_QTIMER 0x20
+#define KGSL_PROP_L3_PWR_CONSTRAINT 0x22
struct kgsl_shadowprop {
unsigned long gpuaddr;
@@ -1119,11 +1120,19 @@
#define KGSL_CONSTRAINT_NONE 0
#define KGSL_CONSTRAINT_PWRLEVEL 1
+/* L3 constraint Type */
+#define KGSL_CONSTRAINT_L3_NONE 2
+#define KGSL_CONSTRAINT_L3_PWRLEVEL 3
+
/* PWRLEVEL constraint level*/
/* set to min frequency */
-#define KGSL_CONSTRAINT_PWR_MIN 0
+#define KGSL_CONSTRAINT_PWR_MIN 0
/* set to max frequency */
-#define KGSL_CONSTRAINT_PWR_MAX 1
+#define KGSL_CONSTRAINT_PWR_MAX 1
+
+/* L3 PWRLEVEL constraint level */
+#define KGSL_CONSTRAINT_L3_PWR_MED 0
+#define KGSL_CONSTRAINT_L3_PWR_MAX 1
struct kgsl_device_constraint_pwrlevel {
unsigned int level;
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 3092188..9399a35 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -944,6 +944,43 @@
* does not result in a change for the current association. Currently,
* only the %NL80211_ATTR_IE data is used and updated with this command.
*
+ * @NL80211_CMD_SET_PMK: For offloaded 4-Way handshake, set the PMK or PMK-R0
+ * for the given authenticator address (specified with &NL80211_ATTR_MAC).
+ * When &NL80211_ATTR_PMKR0_NAME is set, &NL80211_ATTR_PMK specifies the
+ * PMK-R0, otherwise it specifies the PMK.
+ * @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously
+ * configured PMK for the authenticator address identified by
+ * &NL80211_ATTR_MAC.
+ * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates that the 4 way
+ * handshake was completed successfully by the driver. The BSSID is
+ * specified with &NL80211_ATTR_MAC. Drivers that support 4 way handshake
+ * offload should send this event after indicating 802.11 association with
+ * &NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed
+ * &NL80211_CMD_DISCONNECT should be indicated instead.
+ *
+ * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
+ *
+ * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host
+ * drivers that do not define separate commands for authentication and
+ * association, but rely on user space for the authentication to happen.
+ * This interface acts both as the event request (driver to user space)
+ * to trigger the authentication and command response (userspace to
+ * driver) to indicate the authentication status.
+ *
+ * User space uses the %NL80211_CMD_CONNECT command to the host driver to
+ * trigger a connection. The host driver selects a BSS and further uses
+ * this interface to offload only the authentication part to the user
+ * space. Authentication frames are passed between the driver and user
+ * space through the %NL80211_CMD_FRAME interface. Host driver proceeds
+ * further with the association after getting successful authentication
+ * status. User space indicates the authentication status through
+ * %NL80211_ATTR_STATUS_CODE attribute in %NL80211_CMD_EXTERNAL_AUTH
+ * command interface.
+ *
+ * Host driver reports this status on an authentication failure to the
+ * user space through the connect result as the user space would have
+ * initiated the connection through the connect request.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1143,6 +1180,15 @@
NL80211_CMD_UPDATE_CONNECT_PARAMS,
+ NL80211_CMD_SET_PMK,
+ NL80211_CMD_DEL_PMK,
+
+ NL80211_CMD_PORT_AUTHORIZED,
+
+ NL80211_CMD_RELOAD_REGDB,
+
+ NL80211_CMD_EXTERNAL_AUTH,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1870,6 +1916,8 @@
* and remove functions. NAN notifications will be sent in unicast to that
* socket. Without this attribute, any socket can add functions and the
* notifications will be sent to the %NL80211_MCGRP_NAN multicast group.
+ * If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the
+ * station will deauthenticate when the socket is closed.
*
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
* the TDLS link initiator.
@@ -2077,6 +2125,16 @@
* the driver or is not needed (because roaming used the Fast Transition
* protocol).
*
+ * @NL80211_ATTR_EXTERNAL_AUTH_ACTION: Identify the requested external
+ * authentication operation (u32 attribute with an
+ * &enum nl80211_external_auth_action value). This is used with the
+ * &NL80211_CMD_EXTERNAL_AUTH request event.
+ * @NL80211_ATTR_EXTERNAL_AUTH_SUPPORT: Flag attribute indicating that the user
+ * space supports external authentication. This attribute shall be used
+ * only with %NL80211_CMD_CONNECT request. The driver may offload
+ * authentication processing to user space if this capability is indicated
+ * in NL80211_CMD_CONNECT requests from the user space.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2503,6 +2561,9 @@
NL80211_ATTR_PMKR0_NAME,
NL80211_ATTR_PORT_AUTHORIZED,
+ NL80211_ATTR_EXTERNAL_AUTH_ACTION,
+ NL80211_ATTR_EXTERNAL_AUTH_SUPPORT,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -5401,4 +5462,15 @@
NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1
};
+/**
+ * nl80211_external_auth_action - Action to perform with external
+ * authentication request. Used by NL80211_ATTR_EXTERNAL_AUTH_ACTION.
+ * @NL80211_EXTERNAL_AUTH_START: Start the authentication.
+ * @NL80211_EXTERNAL_AUTH_ABORT: Abort the ongoing authentication.
+ */
+enum nl80211_external_auth_action {
+ NL80211_EXTERNAL_AUTH_START,
+ NL80211_EXTERNAL_AUTH_ABORT,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/uapi/linux/qg.h b/include/uapi/linux/qg.h
index c0b2b6e..54488ff 100644
--- a/include/uapi/linux/qg.h
+++ b/include/uapi/linux/qg.h
@@ -38,6 +38,8 @@
};
struct qg_kernel_data {
+ unsigned int seq_no;
+ unsigned int fifo_time;
unsigned int fifo_length;
struct fifo_data fifo[MAX_FIFO_LENGTH];
struct qg_param param[QG_MAX];
diff --git a/include/uapi/linux/sw_sync.h b/include/uapi/linux/sw_sync.h
new file mode 100644
index 0000000..9b5d486
--- /dev/null
+++ b/include/uapi/linux/sw_sync.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 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 _UAPI_LINUX_SW_SYNC_H
+#define _UAPI_LINUX_SW_SYNC_H
+
+#include <linux/types.h>
+
+struct sw_sync_create_fence_data {
+ __u32 value;
+ char name[32];
+ __s32 fence; /* fd of new fence */
+};
+
+#define SW_SYNC_IOC_MAGIC 'W'
+
+#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\
+ struct sw_sync_create_fence_data)
+#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
+
+#endif /* _UAPI_LINUX_SW_SYNC_H */
diff --git a/include/uapi/linux/sync.h b/include/uapi/linux/sync.h
new file mode 100644
index 0000000..e964c75
--- /dev/null
+++ b/include/uapi/linux/sync.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * 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 _UAPI_LINUX_SYNC_H
+#define _UAPI_LINUX_SYNC_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/**
+ * struct sync_merge_data - data passed to merge ioctl
+ * @fd2: file descriptor of second fence
+ * @name: name of new fence
+ * @fence: returns the fd of the new fence to userspace
+ */
+struct sync_merge_data {
+ __s32 fd2; /* fd of second fence */
+ char name[32]; /* name of new fence */
+ __s32 fence; /* fd on newly created fence */
+};
+
+/**
+ * struct sync_pt_info - detailed sync_pt information
+ * @len: length of sync_pt_info including any driver_data
+ * @obj_name: name of parent sync_timeline
+ * @driver_name: name of driver implementing the parent
+ * @status: status of the sync_pt 0:active 1:signaled <0:error
+ * @timestamp_ns: timestamp of status change in nanoseconds
+ * @driver_data: any driver dependent data
+ */
+struct sync_pt_info {
+ __u32 len;
+ char obj_name[32];
+ char driver_name[32];
+ __s32 status;
+ __u64 timestamp_ns;
+
+ __u8 driver_data[0];
+};
+
+/**
+ * struct sync_fence_info_data - data returned from fence info ioctl
+ * @len: ioctl caller writes the size of the buffer its passing in.
+ * ioctl returns length of sync_fence_data returned to userspace
+ * including pt_info.
+ * @name: name of fence
+ * @status: status of fence. 1: signaled 0:active <0:error
+ * @pt_info: a sync_pt_info struct for every sync_pt in the fence
+ */
+struct sync_fence_info_data {
+ __u32 len;
+ char name[32];
+ __s32 status;
+
+ __u8 pt_info[0];
+};
+
+#define SYNC_IOC_MAGIC '>'
+
+/**
+ * DOC: SYNC_IOC_WAIT - wait for a fence to signal
+ *
+ * pass timeout in milliseconds. Waits indefinitely timeout < 0.
+ */
+#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32)
+
+/**
+ * DOC: SYNC_IOC_MERGE - merge two fences
+ *
+ * Takes a struct sync_merge_data. Creates a new fence containing copies of
+ * the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the
+ * new fence's fd in sync_merge_data.fence
+ */
+#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
+
+/**
+ * DOC: SYNC_IOC_FENCE_INFO - get detailed information on a fence
+ *
+ * Takes a struct sync_fence_info_data with extra space allocated for pt_info.
+ * Caller should write the size of the buffer into len. On return, len is
+ * updated to reflect the total size of the sync_fence_info_data including
+ * pt_info.
+ *
+ * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence.
+ * To iterate over the sync_pt_infos, use the sync_pt_info.len field.
+ */
+#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\
+ struct sync_fence_info_data)
+
+#endif /* _UAPI_LINUX_SYNC_H */
diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h
index 73ac0db..84a3eb2 100644
--- a/include/uapi/linux/tcp.h
+++ b/include/uapi/linux/tcp.h
@@ -116,6 +116,7 @@
#define TCP_SAVE_SYN 27 /* Record SYN headers for new connections */
#define TCP_SAVED_SYN 28 /* Get SYN headers recorded for connection */
#define TCP_REPAIR_WINDOW 29 /* Get/set window parameters */
+#define TCP_FASTOPEN_CONNECT 30 /* Attempt FastOpen with connect */
struct tcp_repair_opt {
__u32 opt_code;
diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h
new file mode 100644
index 0000000..4b9eb06
--- /dev/null
+++ b/include/uapi/linux/tee.h
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TEE_H
+#define __TEE_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/*
+ * This file describes the API provided by a TEE driver to user space.
+ *
+ * Each TEE driver defines a TEE specific protocol which is used for the
+ * data passed back and forth using TEE_IOC_CMD.
+ */
+
+/* Helpers to make the ioctl defines */
+#define TEE_IOC_MAGIC 0xa4
+#define TEE_IOC_BASE 0
+
+/* Flags relating to shared memory */
+#define TEE_IOCTL_SHM_MAPPED 0x1 /* memory mapped in normal world */
+#define TEE_IOCTL_SHM_DMA_BUF 0x2 /* dma-buf handle on shared memory */
+
+#define TEE_MAX_ARG_SIZE 1024
+
+#define TEE_GEN_CAP_GP (1 << 0)/* GlobalPlatform compliant TEE */
+#define TEE_GEN_CAP_PRIVILEGED (1 << 1)/* Privileged device (for supplicant) */
+#define TEE_GEN_CAP_REG_MEM (1 << 2)/* Supports registering shared memory */
+
+/*
+ * TEE Implementation ID
+ */
+#define TEE_IMPL_ID_OPTEE 1
+
+/*
+ * OP-TEE specific capabilities
+ */
+#define TEE_OPTEE_CAP_TZ (1 << 0)
+
+/**
+ * struct tee_ioctl_version_data - TEE version
+ * @impl_id: [out] TEE implementation id
+ * @impl_caps: [out] Implementation specific capabilities
+ * @gen_caps: [out] Generic capabilities, defined by TEE_GEN_CAPS_* above
+ *
+ * Identifies the TEE implementation, @impl_id is one of TEE_IMPL_ID_* above.
+ * @impl_caps is implementation specific, for example TEE_OPTEE_CAP_*
+ * is valid when @impl_id == TEE_IMPL_ID_OPTEE.
+ */
+struct tee_ioctl_version_data {
+ __u32 impl_id;
+ __u32 impl_caps;
+ __u32 gen_caps;
+};
+
+/**
+ * TEE_IOC_VERSION - query version of TEE
+ *
+ * Takes a tee_ioctl_version_data struct and returns with the TEE version
+ * data filled in.
+ */
+#define TEE_IOC_VERSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 0, \
+ struct tee_ioctl_version_data)
+
+/**
+ * struct tee_ioctl_shm_alloc_data - Shared memory allocate argument
+ * @size: [in/out] Size of shared memory to allocate
+ * @flags: [in/out] Flags to/from allocation.
+ * @id: [out] Identifier of the shared memory
+ *
+ * The flags field should currently be zero as input. Updated by the call
+ * with actual flags as defined by TEE_IOCTL_SHM_* above.
+ * This structure is used as argument for TEE_IOC_SHM_ALLOC below.
+ */
+struct tee_ioctl_shm_alloc_data {
+ __u64 size;
+ __u32 flags;
+ __s32 id;
+};
+
+/**
+ * TEE_IOC_SHM_ALLOC - allocate shared memory
+ *
+ * Allocates shared memory between the user space process and secure OS.
+ *
+ * Returns a file descriptor on success or < 0 on failure
+ *
+ * The returned file descriptor is used to map the shared memory into user
+ * space. The shared memory is freed when the descriptor is closed and the
+ * memory is unmapped.
+ */
+#define TEE_IOC_SHM_ALLOC _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 1, \
+ struct tee_ioctl_shm_alloc_data)
+
+/**
+ * struct tee_ioctl_buf_data - Variable sized buffer
+ * @buf_ptr: [in] A __user pointer to a buffer
+ * @buf_len: [in] Length of the buffer above
+ *
+ * Used as argument for TEE_IOC_OPEN_SESSION, TEE_IOC_INVOKE,
+ * TEE_IOC_SUPPL_RECV, and TEE_IOC_SUPPL_SEND below.
+ */
+struct tee_ioctl_buf_data {
+ __u64 buf_ptr;
+ __u64 buf_len;
+};
+
+/*
+ * Attributes for struct tee_ioctl_param, selects field in the union
+ */
+#define TEE_IOCTL_PARAM_ATTR_TYPE_NONE 0 /* parameter not used */
+
+/*
+ * These defines value parameters (struct tee_ioctl_param_value)
+ */
+#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT 1
+#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT 2
+#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT 3 /* input and output */
+
+/*
+ * These defines shared memory reference parameters (struct
+ * tee_ioctl_param_memref)
+ */
+#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT 5
+#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT 6
+#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT 7 /* input and output */
+
+/*
+ * Mask for the type part of the attribute, leaves room for more types
+ */
+#define TEE_IOCTL_PARAM_ATTR_TYPE_MASK 0xff
+
+/* Meta parameter carrying extra information about the message. */
+#define TEE_IOCTL_PARAM_ATTR_META 0x100
+
+/* Mask of all known attr bits */
+#define TEE_IOCTL_PARAM_ATTR_MASK \
+ (TEE_IOCTL_PARAM_ATTR_TYPE_MASK | TEE_IOCTL_PARAM_ATTR_META)
+
+/*
+ * Matches TEEC_LOGIN_* in GP TEE Client API
+ * Are only defined for GP compliant TEEs
+ */
+#define TEE_IOCTL_LOGIN_PUBLIC 0
+#define TEE_IOCTL_LOGIN_USER 1
+#define TEE_IOCTL_LOGIN_GROUP 2
+#define TEE_IOCTL_LOGIN_APPLICATION 4
+#define TEE_IOCTL_LOGIN_USER_APPLICATION 5
+#define TEE_IOCTL_LOGIN_GROUP_APPLICATION 6
+
+/**
+ * struct tee_ioctl_param - parameter
+ * @attr: attributes
+ * @a: if a memref, offset into the shared memory object, else a value parameter
+ * @b: if a memref, size of the buffer, else a value parameter
+ * @c: if a memref, shared memory identifier, else a value parameter
+ *
+ * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in
+ * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and
+ * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE
+ * indicates that none of the members are used.
+ *
+ * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns an
+ * identifier representing the shared memory object. A memref can reference
+ * a part of a shared memory by specifying an offset (@a) and size (@b) of
+ * the object. To supply the entire shared memory object set the offset
+ * (@a) to 0 and size (@b) to the previously returned size of the object.
+ */
+struct tee_ioctl_param {
+ __u64 attr;
+ __u64 a;
+ __u64 b;
+ __u64 c;
+};
+
+#define TEE_IOCTL_UUID_LEN 16
+
+/**
+ * struct tee_ioctl_open_session_arg - Open session argument
+ * @uuid: [in] UUID of the Trusted Application
+ * @clnt_uuid: [in] UUID of client
+ * @clnt_login: [in] Login class of client, TEE_IOCTL_LOGIN_* above
+ * @cancel_id: [in] Cancellation id, a unique value to identify this request
+ * @session: [out] Session id
+ * @ret: [out] return value
+ * @ret_origin [out] origin of the return value
+ * @num_params [in] number of parameters following this struct
+ */
+struct tee_ioctl_open_session_arg {
+ __u8 uuid[TEE_IOCTL_UUID_LEN];
+ __u8 clnt_uuid[TEE_IOCTL_UUID_LEN];
+ __u32 clnt_login;
+ __u32 cancel_id;
+ __u32 session;
+ __u32 ret;
+ __u32 ret_origin;
+ __u32 num_params;
+ /* num_params tells the actual number of element in params */
+ struct tee_ioctl_param params[];
+};
+
+/**
+ * TEE_IOC_OPEN_SESSION - opens a session to a Trusted Application
+ *
+ * Takes a struct tee_ioctl_buf_data which contains a struct
+ * tee_ioctl_open_session_arg followed by any array of struct
+ * tee_ioctl_param
+ */
+#define TEE_IOC_OPEN_SESSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 2, \
+ struct tee_ioctl_buf_data)
+
+/**
+ * struct tee_ioctl_invoke_func_arg - Invokes a function in a Trusted
+ * Application
+ * @func: [in] Trusted Application function, specific to the TA
+ * @session: [in] Session id
+ * @cancel_id: [in] Cancellation id, a unique value to identify this request
+ * @ret: [out] return value
+ * @ret_origin [out] origin of the return value
+ * @num_params [in] number of parameters following this struct
+ */
+struct tee_ioctl_invoke_arg {
+ __u32 func;
+ __u32 session;
+ __u32 cancel_id;
+ __u32 ret;
+ __u32 ret_origin;
+ __u32 num_params;
+ /* num_params tells the actual number of element in params */
+ struct tee_ioctl_param params[];
+};
+
+/**
+ * TEE_IOC_INVOKE - Invokes a function in a Trusted Application
+ *
+ * Takes a struct tee_ioctl_buf_data which contains a struct
+ * tee_invoke_func_arg followed by any array of struct tee_param
+ */
+#define TEE_IOC_INVOKE _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 3, \
+ struct tee_ioctl_buf_data)
+
+/**
+ * struct tee_ioctl_cancel_arg - Cancels an open session or invoke ioctl
+ * @cancel_id: [in] Cancellation id, a unique value to identify this request
+ * @session: [in] Session id, if the session is opened, else set to 0
+ */
+struct tee_ioctl_cancel_arg {
+ __u32 cancel_id;
+ __u32 session;
+};
+
+/**
+ * TEE_IOC_CANCEL - Cancels an open session or invoke
+ */
+#define TEE_IOC_CANCEL _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 4, \
+ struct tee_ioctl_cancel_arg)
+
+/**
+ * struct tee_ioctl_close_session_arg - Closes an open session
+ * @session: [in] Session id
+ */
+struct tee_ioctl_close_session_arg {
+ __u32 session;
+};
+
+/**
+ * TEE_IOC_CLOSE_SESSION - Closes a session
+ */
+#define TEE_IOC_CLOSE_SESSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 5, \
+ struct tee_ioctl_close_session_arg)
+
+/**
+ * struct tee_iocl_supp_recv_arg - Receive a request for a supplicant function
+ * @func: [in] supplicant function
+ * @num_params [in/out] number of parameters following this struct
+ *
+ * @num_params is the number of params that tee-supplicant has room to
+ * receive when input, @num_params is the number of actual params
+ * tee-supplicant receives when output.
+ */
+struct tee_iocl_supp_recv_arg {
+ __u32 func;
+ __u32 num_params;
+ /* num_params tells the actual number of element in params */
+ struct tee_ioctl_param params[];
+};
+
+/**
+ * TEE_IOC_SUPPL_RECV - Receive a request for a supplicant function
+ *
+ * Takes a struct tee_ioctl_buf_data which contains a struct
+ * tee_iocl_supp_recv_arg followed by any array of struct tee_param
+ */
+#define TEE_IOC_SUPPL_RECV _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 6, \
+ struct tee_ioctl_buf_data)
+
+/**
+ * struct tee_iocl_supp_send_arg - Send a response to a received request
+ * @ret: [out] return value
+ * @num_params [in] number of parameters following this struct
+ */
+struct tee_iocl_supp_send_arg {
+ __u32 ret;
+ __u32 num_params;
+ /* num_params tells the actual number of element in params */
+ struct tee_ioctl_param params[];
+};
+
+/**
+ * TEE_IOC_SUPPL_SEND - Receive a request for a supplicant function
+ *
+ * Takes a struct tee_ioctl_buf_data which contains a struct
+ * tee_iocl_supp_send_arg followed by any array of struct tee_param
+ */
+#define TEE_IOC_SUPPL_SEND _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 7, \
+ struct tee_ioctl_buf_data)
+
+/**
+ * struct tee_ioctl_shm_register_data - Shared memory register argument
+ * @addr: [in] Start address of shared memory to register
+ * @length: [in/out] Length of shared memory to register
+ * @flags: [in/out] Flags to/from registration.
+ * @id: [out] Identifier of the shared memory
+ *
+ * The flags field should currently be zero as input. Updated by the call
+ * with actual flags as defined by TEE_IOCTL_SHM_* above.
+ * This structure is used as argument for TEE_IOC_SHM_REGISTER below.
+ */
+struct tee_ioctl_shm_register_data {
+ __u64 addr;
+ __u64 length;
+ __u32 flags;
+ __s32 id;
+};
+
+/**
+ * TEE_IOC_SHM_REGISTER - Register shared memory argument
+ *
+ * Registers shared memory between the user space process and secure OS.
+ *
+ * Returns a file descriptor on success or < 0 on failure
+ *
+ * The shared memory is unregisterred when the descriptor is closed.
+ */
+#define TEE_IOC_SHM_REGISTER _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 9, \
+ struct tee_ioctl_shm_register_data)
+/*
+ * Five syscalls are used when communicating with the TEE driver.
+ * open(): opens the device associated with the driver
+ * ioctl(): as described above operating on the file descriptor from open()
+ * close(): two cases
+ * - closes the device file descriptor
+ * - closes a file descriptor connected to allocated shared memory
+ * mmap(): maps shared memory into user space using information from struct
+ * tee_ioctl_shm_alloc_data
+ * munmap(): unmaps previously shared memory
+ */
+
+#endif /*__TEE_H*/
diff --git a/include/uapi/linux/usb/usb_ctrl_qti.h b/include/uapi/linux/usb/usb_ctrl_qti.h
index b02272a..2dbf14f 100644
--- a/include/uapi/linux/usb/usb_ctrl_qti.h
+++ b/include/uapi/linux/usb/usb_ctrl_qti.h
@@ -4,7 +4,7 @@
#include <linux/types.h>
#include <linux/ioctl.h>
-#define MAX_QTI_PKT_SIZE 2048
+#define MAX_QTI_PKT_SIZE 8192
#define QTI_CTRL_IOCTL_MAGIC 'r'
#define QTI_CTRL_GET_LINE_STATE _IOR(QTI_CTRL_IOCTL_MAGIC, 2, int)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 8a2a315..29c10b8 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1019,6 +1019,7 @@
/* mem2mem encoder/decoder */
#define V4L2_BUF_FLAG_LAST 0x00100000
/* Vendor extensions */
+#define V4L2_QCOM_BUF_END_OF_SUBFRAME 0x00000080
#define V4L2_QCOM_BUF_FLAG_CODECCONFIG 0x00020000
#define V4L2_QCOM_BUF_FLAG_EOSEQ 0x00040000
#define V4L2_QCOM_BUF_TIMESTAMP_INVALID 0x00080000
diff --git a/include/uapi/media/msm_camera.h b/include/uapi/media/msm_camera.h
index d282586..693fd21 100644
--- a/include/uapi/media/msm_camera.h
+++ b/include/uapi/media/msm_camera.h
@@ -14,9 +14,12 @@
#ifndef __UAPI_MSM_CAMERA_H
#define __UAPI_MSM_CAMERA_H
+#define CAM_API_V1
+
#include <linux/videodev2.h>
#include <linux/types.h>
#include <linux/ioctl.h>
+#include <linux/media.h>
#include <linux/msm_ion.h>
@@ -1986,8 +1989,7 @@
#define QCAMERA_NAME "qcamera"
#define QCAMERA_SERVER_NAME "qcamera_server"
-#define QCAMERA_DEVICE_GROUP_ID 1
-#define QCAMERA_VNODE_GROUP_ID 2
+#define QCAMERA_VNODE_GROUP_ID MEDIA_ENT_F_IO_V4L
enum msm_cam_subdev_type {
CSIPHY_DEV,
diff --git a/include/uapi/media/msm_vidc.h b/include/uapi/media/msm_vidc.h
index 59fab2f..cac2b32 100644
--- a/include/uapi/media/msm_vidc.h
+++ b/include/uapi/media/msm_vidc.h
@@ -296,6 +296,9 @@
MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST = 0x04,
MSM_VIDC_INTERLACE_FRAME_TOPFIELDFIRST = 0x08,
MSM_VIDC_INTERLACE_FRAME_BOTTOMFIELDFIRST = 0x10,
+#define MSM_VIDC_INTERLACE_FRAME_MBAFF \
+ MSM_VIDC_INTERLACE_FRAME_MBAFF
+ MSM_VIDC_INTERLACE_FRAME_MBAFF = 0x20,
};
/* enum msm_vidc_framepack_type */
diff --git a/include/uapi/media/msmb_camera.h b/include/uapi/media/msmb_camera.h
index 58aff97..8bb2f8c 100644
--- a/include/uapi/media/msmb_camera.h
+++ b/include/uapi/media/msmb_camera.h
@@ -4,6 +4,7 @@
#include <linux/videodev2.h>
#include <linux/types.h>
#include <linux/ioctl.h>
+#include <linux/media.h>
#define MSM_CAM_LOGSYNC_FILE_NAME "logsync"
#define MSM_CAM_LOGSYNC_FILE_BASEDIR "camera"
@@ -26,33 +27,36 @@
#define MSM_CAM_V4L2_IOCTL_DAEMON_DISABLED \
_IOW('V', BASE_VIDIOC_PRIVATE + 35, struct msm_v4l2_event_data)
-#define QCAMERA_DEVICE_GROUP_ID 1
-#define QCAMERA_VNODE_GROUP_ID 2
+#define QCAMERA_VNODE_GROUP_ID MEDIA_ENT_F_IO_V4L
#define MSM_CAMERA_NAME "msm_camera"
#define MSM_CONFIGURATION_NAME "msm_config"
-#define MSM_CAMERA_SUBDEV_CSIPHY 0
-#define MSM_CAMERA_SUBDEV_CSID 1
-#define MSM_CAMERA_SUBDEV_ISPIF 2
-#define MSM_CAMERA_SUBDEV_VFE 3
-#define MSM_CAMERA_SUBDEV_AXI 4
-#define MSM_CAMERA_SUBDEV_VPE 5
-#define MSM_CAMERA_SUBDEV_SENSOR 6
-#define MSM_CAMERA_SUBDEV_ACTUATOR 7
-#define MSM_CAMERA_SUBDEV_EEPROM 8
-#define MSM_CAMERA_SUBDEV_CPP 9
-#define MSM_CAMERA_SUBDEV_CCI 10
-#define MSM_CAMERA_SUBDEV_LED_FLASH 11
-#define MSM_CAMERA_SUBDEV_STROBE_FLASH 12
-#define MSM_CAMERA_SUBDEV_BUF_MNGR 13
-#define MSM_CAMERA_SUBDEV_SENSOR_INIT 14
-#define MSM_CAMERA_SUBDEV_OIS 15
-#define MSM_CAMERA_SUBDEV_FLASH 16
-#define MSM_CAMERA_SUBDEV_IR_LED 17
-#define MSM_CAMERA_SUBDEV_IR_CUT 18
-#define MSM_CAMERA_SUBDEV_EXT 19
-#define MSM_CAMERA_SUBDEV_TOF 20
-#define MSM_CAMERA_SUBDEV_LASER_LED 21
+//#define MSM_CAMERA_SUBDEV_BASE (MEDIA_ENT_F_OLD_SUBDEV_BASE + 1)
+#define MSM_CAMERA_SUBDEV_BASE (MEDIA_ENT_F_OLD_BASE + 0xF00)
+#define MSM_CAMERA_SUBDEV_CSIPHY (MSM_CAMERA_SUBDEV_BASE + 0)
+//#define MSM_CAMERA_SUBDEV_CSID (MSM_CAMERA_SUBDEV_BASE + 1)
+#define MSM_CAMERA_SUBDEV_CSID (MSM_CAMERA_SUBDEV_BASE + 13)
+#define MSM_CAMERA_SUBDEV_ISPIF (MSM_CAMERA_SUBDEV_BASE + 2)
+#define MSM_CAMERA_SUBDEV_VFE (MSM_CAMERA_SUBDEV_BASE + 3)
+#define MSM_CAMERA_SUBDEV_AXI (MSM_CAMERA_SUBDEV_BASE + 4)
+#define MSM_CAMERA_SUBDEV_VPE (MSM_CAMERA_SUBDEV_BASE + 5)
+#define MSM_CAMERA_SUBDEV_SENSOR (MSM_CAMERA_SUBDEV_BASE + 6)
+#define MSM_CAMERA_SUBDEV_ACTUATOR (MSM_CAMERA_SUBDEV_BASE + 7)
+#define MSM_CAMERA_SUBDEV_EEPROM (MSM_CAMERA_SUBDEV_BASE + 8)
+#define MSM_CAMERA_SUBDEV_CPP (MSM_CAMERA_SUBDEV_BASE + 9)
+#define MSM_CAMERA_SUBDEV_CCI (MSM_CAMERA_SUBDEV_BASE + 10)
+#define MSM_CAMERA_SUBDEV_LED_FLASH (MSM_CAMERA_SUBDEV_BASE + 11)
+#define MSM_CAMERA_SUBDEV_STROBE_FLASH (MSM_CAMERA_SUBDEV_BASE + 12)
+#define MSM_CAMERA_SUBDEV_BUF_MNGR (MSM_CAMERA_SUBDEV_BASE + 1)
+//#define MSM_CAMERA_SUBDEV_BUF_MNGR (MSM_CAMERA_SUBDEV_BASE + 13)
+#define MSM_CAMERA_SUBDEV_SENSOR_INIT (MSM_CAMERA_SUBDEV_BASE + 14)
+#define MSM_CAMERA_SUBDEV_OIS (MSM_CAMERA_SUBDEV_BASE + 15)
+#define MSM_CAMERA_SUBDEV_FLASH (MSM_CAMERA_SUBDEV_BASE + 16)
+#define MSM_CAMERA_SUBDEV_IR_LED (MSM_CAMERA_SUBDEV_BASE + 17)
+#define MSM_CAMERA_SUBDEV_IR_CUT (MSM_CAMERA_SUBDEV_BASE + 18)
+#define MSM_CAMERA_SUBDEV_EXT (MSM_CAMERA_SUBDEV_BASE + 19)
+#define MSM_CAMERA_SUBDEV_TOF (MSM_CAMERA_SUBDEV_BASE + 20)
+#define MSM_CAMERA_SUBDEV_LASER_LED (MSM_CAMERA_SUBDEV_BASE + 21)
#define MSM_MAX_CAMERA_SENSORS 5
/* The below macro is defined to put an upper limit on maximum
diff --git a/include/uapi/video/msm_hdmi_hdcp_mgr.h b/include/uapi/video/msm_hdmi_hdcp_mgr.h
index 85fa918..1c19d4a 100644
--- a/include/uapi/video/msm_hdmi_hdcp_mgr.h
+++ b/include/uapi/video/msm_hdmi_hdcp_mgr.h
@@ -1,4 +1,4 @@
-#ifndef _UAPI__HDMI_HDCP_MGR_H
+#ifndef _UAPI__MSM_HDMI_HDCP_MGR_H
#define _UAPI__MSM_HDMI_HDCP_MGR_H
enum DS_TYPE { /* type of downstream device */
diff --git a/init/initramfs.c b/init/initramfs.c
index d0b53f49..bf3af10 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -622,8 +622,11 @@
{
char *err;
- if (do_skip_initramfs)
+ if (do_skip_initramfs) {
+ if (initrd_start)
+ free_initrd();
return default_rootfs();
+ }
err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
if (err)
diff --git a/kernel/async.c b/kernel/async.c
index d2edd6e..d84d486 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -84,20 +84,24 @@
static async_cookie_t lowest_in_progress(struct async_domain *domain)
{
- struct list_head *pending;
+ struct async_entry *first = NULL;
async_cookie_t ret = ASYNC_COOKIE_MAX;
unsigned long flags;
spin_lock_irqsave(&async_lock, flags);
- if (domain)
- pending = &domain->pending;
- else
- pending = &async_global_pending;
+ if (domain) {
+ if (!list_empty(&domain->pending))
+ first = list_first_entry(&domain->pending,
+ struct async_entry, domain_list);
+ } else {
+ if (!list_empty(&async_global_pending))
+ first = list_first_entry(&async_global_pending,
+ struct async_entry, global_list);
+ }
- if (!list_empty(pending))
- ret = list_first_entry(pending, struct async_entry,
- domain_list)->cookie;
+ if (first)
+ ret = first->cookie;
spin_unlock_irqrestore(&async_lock, flags);
return ret;
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 9a1e6ed..2eb9b7f 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -16,6 +16,9 @@
#include <linux/filter.h>
#include <linux/perf_event.h>
+#define ARRAY_CREATE_FLAG_MASK \
+ (BPF_F_RDONLY | BPF_F_WRONLY)
+
static void bpf_array_free_percpu(struct bpf_array *array)
{
int i;
@@ -53,7 +56,8 @@
/* check sanity of attributes */
if (attr->max_entries == 0 || attr->key_size != 4 ||
- attr->value_size == 0 || attr->map_flags)
+ attr->value_size == 0 ||
+ attr->map_flags & ~ARRAY_CREATE_FLAG_MASK)
return ERR_PTR(-EINVAL);
if (attr->value_size >= 1 << (KMALLOC_SHIFT_MAX - 1))
diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
index ad2f0ed..27f4f2c 100644
--- a/kernel/bpf/hashtab.c
+++ b/kernel/bpf/hashtab.c
@@ -14,6 +14,8 @@
#include <linux/jhash.h>
#include <linux/filter.h>
#include "percpu_freelist.h"
+#define HTAB_CREATE_FLAG_MASK \
+ (BPF_F_NO_PREALLOC | BPF_F_RDONLY | BPF_F_WRONLY)
struct bucket {
struct hlist_head head;
@@ -148,7 +150,7 @@
int err, i;
u64 cost;
- if (attr->map_flags & ~BPF_F_NO_PREALLOC)
+ if (attr->map_flags & ~HTAB_CREATE_FLAG_MASK)
/* reserved bits should not be used */
return ERR_PTR(-EINVAL);
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
index 1ed8473..2d23c32 100644
--- a/kernel/bpf/inode.c
+++ b/kernel/bpf/inode.c
@@ -255,7 +255,7 @@
}
static void *bpf_obj_do_get(const struct filename *pathname,
- enum bpf_type *type)
+ enum bpf_type *type, int flags)
{
struct inode *inode;
struct path path;
@@ -267,7 +267,7 @@
return ERR_PTR(ret);
inode = d_backing_inode(path.dentry);
- ret = inode_permission(inode, MAY_WRITE);
+ ret = inode_permission(inode, ACC_MODE(flags));
if (ret)
goto out;
@@ -286,18 +286,23 @@
return ERR_PTR(ret);
}
-int bpf_obj_get_user(const char __user *pathname)
+int bpf_obj_get_user(const char __user *pathname, int flags)
{
enum bpf_type type = BPF_TYPE_UNSPEC;
struct filename *pname;
int ret = -ENOENT;
+ int f_flags;
void *raw;
+ f_flags = bpf_get_file_flag(flags);
+ if (f_flags < 0)
+ return f_flags;
+
pname = getname(pathname);
if (IS_ERR(pname))
return PTR_ERR(pname);
- raw = bpf_obj_do_get(pname, &type);
+ raw = bpf_obj_do_get(pname, &type, f_flags);
if (IS_ERR(raw)) {
ret = PTR_ERR(raw);
goto out;
@@ -306,7 +311,7 @@
if (type == BPF_TYPE_PROG)
ret = bpf_prog_new_fd(raw);
else if (type == BPF_TYPE_MAP)
- ret = bpf_map_new_fd(raw);
+ ret = bpf_map_new_fd(raw, f_flags);
else
goto out;
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index be85191..230aced 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -11,6 +11,9 @@
#include <linux/perf_event.h>
#include "percpu_freelist.h"
+#define STACK_CREATE_FLAG_MASK \
+ (BPF_F_RDONLY | BPF_F_WRONLY)
+
struct stack_map_bucket {
struct pcpu_freelist_node fnode;
u32 hash;
@@ -59,7 +62,7 @@
if (!capable(CAP_SYS_ADMIN))
return ERR_PTR(-EPERM);
- if (attr->map_flags)
+ if (attr->map_flags & ~STACK_CREATE_FLAG_MASK)
return ERR_PTR(-EINVAL);
/* check sanity of attributes */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 5b017fb..590ce0a 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -20,6 +20,8 @@
#include <linux/filter.h>
#include <linux/version.h>
+#define BPF_OBJ_FLAG_MASK (BPF_F_RDONLY | BPF_F_WRONLY)
+
DEFINE_PER_CPU(int, bpf_prog_active);
int sysctl_unprivileged_bpf_disabled __read_mostly;
@@ -119,6 +121,7 @@
struct bpf_map *map = container_of(work, struct bpf_map, work);
bpf_map_uncharge_memlock(map);
+ security_bpf_map_free(map);
/* implementation dependent freeing */
map->ops->map_free(map);
}
@@ -178,17 +181,54 @@
}
#endif
-static const struct file_operations bpf_map_fops = {
+static ssize_t bpf_dummy_read(struct file *filp, char __user *buf, size_t siz,
+ loff_t *ppos)
+{
+ /* We need this handler such that alloc_file() enables
+ * f_mode with FMODE_CAN_READ.
+ */
+ return -EINVAL;
+}
+
+static ssize_t bpf_dummy_write(struct file *filp, const char __user *buf,
+ size_t siz, loff_t *ppos)
+{
+ /* We need this handler such that alloc_file() enables
+ * f_mode with FMODE_CAN_WRITE.
+ */
+ return -EINVAL;
+}
+
+const struct file_operations bpf_map_fops = {
#ifdef CONFIG_PROC_FS
.show_fdinfo = bpf_map_show_fdinfo,
#endif
.release = bpf_map_release,
+ .read = bpf_dummy_read,
+ .write = bpf_dummy_write,
};
-int bpf_map_new_fd(struct bpf_map *map)
+int bpf_map_new_fd(struct bpf_map *map, int flags)
{
+ int ret;
+
+ ret = security_bpf_map(map, OPEN_FMODE(flags));
+ if (ret < 0)
+ return ret;
+
return anon_inode_getfd("bpf-map", &bpf_map_fops, map,
- O_RDWR | O_CLOEXEC);
+ flags | O_CLOEXEC);
+}
+
+int bpf_get_file_flag(int flags)
+{
+ if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY))
+ return -EINVAL;
+ if (flags & BPF_F_RDONLY)
+ return O_RDONLY;
+ if (flags & BPF_F_WRONLY)
+ return O_WRONLY;
+ return O_RDWR;
}
/* helper macro to check that unused fields 'union bpf_attr' are zero */
@@ -204,12 +244,17 @@
static int map_create(union bpf_attr *attr)
{
struct bpf_map *map;
+ int f_flags;
int err;
err = CHECK_ATTR(BPF_MAP_CREATE);
if (err)
return -EINVAL;
+ f_flags = bpf_get_file_flag(attr->map_flags);
+ if (f_flags < 0)
+ return f_flags;
+
/* find map type and init map: hashtable vs rbtree vs bloom vs ... */
map = find_and_alloc_map(attr);
if (IS_ERR(map))
@@ -218,11 +263,15 @@
atomic_set(&map->refcnt, 1);
atomic_set(&map->usercnt, 1);
- err = bpf_map_charge_memlock(map);
+ err = security_bpf_map_alloc(map);
if (err)
goto free_map_nouncharge;
- err = bpf_map_new_fd(map);
+ err = bpf_map_charge_memlock(map);
+ if (err)
+ goto free_map_sec;
+
+ err = bpf_map_new_fd(map, f_flags);
if (err < 0)
/* failed to allocate fd */
goto free_map;
@@ -231,6 +280,8 @@
free_map:
bpf_map_uncharge_memlock(map);
+free_map_sec:
+ security_bpf_map_free(map);
free_map_nouncharge:
map->ops->map_free(map);
return err;
@@ -313,6 +364,11 @@
if (IS_ERR(map))
return PTR_ERR(map);
+ if (!(f.file->f_mode & FMODE_CAN_READ)) {
+ err = -EPERM;
+ goto err_put;
+ }
+
err = -ENOMEM;
key = kmalloc(map->key_size, GFP_USER);
if (!key)
@@ -387,6 +443,11 @@
if (IS_ERR(map))
return PTR_ERR(map);
+ if (!(f.file->f_mode & FMODE_CAN_WRITE)) {
+ err = -EPERM;
+ goto err_put;
+ }
+
err = -ENOMEM;
key = kmalloc(map->key_size, GFP_USER);
if (!key)
@@ -463,6 +524,11 @@
if (IS_ERR(map))
return PTR_ERR(map);
+ if (!(f.file->f_mode & FMODE_CAN_WRITE)) {
+ err = -EPERM;
+ goto err_put;
+ }
+
err = -ENOMEM;
key = kmalloc(map->key_size, GFP_USER);
if (!key)
@@ -508,6 +574,11 @@
if (IS_ERR(map))
return PTR_ERR(map);
+ if (!(f.file->f_mode & FMODE_CAN_READ)) {
+ err = -EPERM;
+ goto err_put;
+ }
+
err = -ENOMEM;
key = kmalloc(map->key_size, GFP_USER);
if (!key)
@@ -607,6 +678,7 @@
free_used_maps(aux);
bpf_prog_uncharge_memlock(aux->prog);
+ security_bpf_prog_free(aux);
bpf_prog_free(aux->prog);
}
@@ -625,12 +697,20 @@
return 0;
}
-static const struct file_operations bpf_prog_fops = {
+const struct file_operations bpf_prog_fops = {
.release = bpf_prog_release,
+ .read = bpf_dummy_read,
+ .write = bpf_dummy_write,
};
int bpf_prog_new_fd(struct bpf_prog *prog)
{
+ int ret;
+
+ ret = security_bpf_prog(prog);
+ if (ret < 0)
+ return ret;
+
return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog,
O_RDWR | O_CLOEXEC);
}
@@ -732,10 +812,14 @@
if (!prog)
return -ENOMEM;
- err = bpf_prog_charge_memlock(prog);
+ err = security_bpf_prog_alloc(prog->aux);
if (err)
goto free_prog_nouncharge;
+ err = bpf_prog_charge_memlock(prog);
+ if (err)
+ goto free_prog_sec;
+
prog->len = attr->insn_cnt;
err = -EFAULT;
@@ -775,16 +859,18 @@
free_used_maps(prog->aux);
free_prog:
bpf_prog_uncharge_memlock(prog);
+free_prog_sec:
+ security_bpf_prog_free(prog->aux);
free_prog_nouncharge:
bpf_prog_free(prog);
return err;
}
-#define BPF_OBJ_LAST_FIELD bpf_fd
+#define BPF_OBJ_LAST_FIELD file_flags
static int bpf_obj_pin(const union bpf_attr *attr)
{
- if (CHECK_ATTR(BPF_OBJ))
+ if (CHECK_ATTR(BPF_OBJ) || attr->file_flags != 0)
return -EINVAL;
return bpf_obj_pin_user(attr->bpf_fd, u64_to_ptr(attr->pathname));
@@ -792,10 +878,12 @@
static int bpf_obj_get(const union bpf_attr *attr)
{
- if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0)
+ if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 ||
+ attr->file_flags & ~BPF_OBJ_FLAG_MASK)
return -EINVAL;
- return bpf_obj_get_user(u64_to_ptr(attr->pathname));
+ return bpf_obj_get_user(u64_to_ptr(attr->pathname),
+ attr->file_flags);
}
#ifdef CONFIG_CGROUP_BPF
@@ -918,6 +1006,10 @@
if (copy_from_user(&attr, uattr, size) != 0)
return -EFAULT;
+ err = security_bpf(cmd, &attr, size);
+ if (err < 0)
+ return err;
+
switch (cmd) {
case BPF_MAP_CREATE:
err = map_create(&attr);
diff --git a/kernel/kcov.c b/kernel/kcov.c
index f8f3f4c..154a80d 100644
--- a/kernel/kcov.c
+++ b/kernel/kcov.c
@@ -1,11 +1,16 @@
#define pr_fmt(fmt) "kcov: " fmt
#define DISABLE_BRANCH_PROFILING
+#include <linux/atomic.h>
#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/export.h>
#include <linux/types.h>
#include <linux/file.h>
#include <linux/fs.h>
+#include <linux/init.h>
#include <linux/mm.h>
+#include <linux/preempt.h>
#include <linux/printk.h>
#include <linux/sched.h>
#include <linux/slab.h>
@@ -16,13 +21,21 @@
#include <linux/kcov.h>
#include <asm/setup.h>
+/* Number of 64-bit words written per one comparison: */
+#define KCOV_WORDS_PER_CMP 4
+
/*
* kcov descriptor (one per opened debugfs file).
* State transitions of the descriptor:
* - initial state after open()
* - then there must be a single ioctl(KCOV_INIT_TRACE) call
* - then, mmap() call (several calls are allowed but not useful)
- * - then, repeated enable/disable for a task (only one task a time allowed)
+ * - then, ioctl(KCOV_ENABLE, arg), where arg is
+ * KCOV_TRACE_PC - to trace only the PCs
+ * or
+ * KCOV_TRACE_CMP - to trace only the comparison operands
+ * - then, ioctl(KCOV_DISABLE) to disable the task.
+ * Enabling/disabling ioctls can be repeated (only one task a time allowed).
*/
struct kcov {
/*
@@ -42,6 +55,36 @@
struct task_struct *t;
};
+static bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t)
+{
+ enum kcov_mode mode;
+
+ /*
+ * We are interested in code coverage as a function of a syscall inputs,
+ * so we ignore code executed in interrupts.
+ */
+ if (!in_task())
+ return false;
+ mode = READ_ONCE(t->kcov_mode);
+ /*
+ * There is some code that runs in interrupts but for which
+ * in_interrupt() returns false (e.g. preempt_schedule_irq()).
+ * READ_ONCE()/barrier() effectively provides load-acquire wrt
+ * interrupts, there are paired barrier()/WRITE_ONCE() in
+ * kcov_ioctl_locked().
+ */
+ barrier();
+ return mode == needed_mode;
+}
+
+static unsigned long canonicalize_ip(unsigned long ip)
+{
+#ifdef CONFIG_RANDOMIZE_BASE
+ ip -= kaslr_offset();
+#endif
+ return ip;
+}
+
/*
* Entry point from instrumented code.
* This is called once per basic-block/edge.
@@ -49,51 +92,139 @@
void notrace __sanitizer_cov_trace_pc(void)
{
struct task_struct *t;
- enum kcov_mode mode;
+ unsigned long *area;
+ unsigned long ip = canonicalize_ip(_RET_IP_);
+ unsigned long pos;
t = current;
- /*
- * We are interested in code coverage as a function of a syscall inputs,
- * so we ignore code executed in interrupts.
- * The checks for whether we are in an interrupt are open-coded, because
- * 1. We can't use in_interrupt() here, since it also returns true
- * when we are inside local_bh_disable() section.
- * 2. We don't want to use (in_irq() | in_serving_softirq() | in_nmi()),
- * since that leads to slower generated code (three separate tests,
- * one for each of the flags).
- */
- if (!t || (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_OFFSET
- | NMI_MASK)))
+ if (!check_kcov_mode(KCOV_MODE_TRACE_PC, t))
return;
- mode = READ_ONCE(t->kcov_mode);
- if (mode == KCOV_MODE_TRACE) {
- unsigned long *area;
- unsigned long pos;
- unsigned long ip = _RET_IP_;
-#ifdef CONFIG_RANDOMIZE_BASE
- ip -= kaslr_offset();
-#endif
-
- /*
- * There is some code that runs in interrupts but for which
- * in_interrupt() returns false (e.g. preempt_schedule_irq()).
- * READ_ONCE()/barrier() effectively provides load-acquire wrt
- * interrupts, there are paired barrier()/WRITE_ONCE() in
- * kcov_ioctl_locked().
- */
- barrier();
- area = t->kcov_area;
- /* The first word is number of subsequent PCs. */
- pos = READ_ONCE(area[0]) + 1;
- if (likely(pos < t->kcov_size)) {
- area[pos] = ip;
- WRITE_ONCE(area[0], pos);
- }
+ area = t->kcov_area;
+ /* The first 64-bit word is the number of subsequent PCs. */
+ pos = READ_ONCE(area[0]) + 1;
+ if (likely(pos < t->kcov_size)) {
+ area[pos] = ip;
+ WRITE_ONCE(area[0], pos);
}
}
EXPORT_SYMBOL(__sanitizer_cov_trace_pc);
+#ifdef CONFIG_KCOV_ENABLE_COMPARISONS
+static void write_comp_data(u64 type, u64 arg1, u64 arg2, u64 ip)
+{
+ struct task_struct *t;
+ u64 *area;
+ u64 count, start_index, end_pos, max_pos;
+
+ t = current;
+ if (!check_kcov_mode(KCOV_MODE_TRACE_CMP, t))
+ return;
+
+ ip = canonicalize_ip(ip);
+
+ /*
+ * We write all comparison arguments and types as u64.
+ * The buffer was allocated for t->kcov_size unsigned longs.
+ */
+ area = (u64 *)t->kcov_area;
+ max_pos = t->kcov_size * sizeof(unsigned long);
+
+ count = READ_ONCE(area[0]);
+
+ /* Every record is KCOV_WORDS_PER_CMP 64-bit words. */
+ start_index = 1 + count * KCOV_WORDS_PER_CMP;
+ end_pos = (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64);
+ if (likely(end_pos <= max_pos)) {
+ area[start_index] = type;
+ area[start_index + 1] = arg1;
+ area[start_index + 2] = arg2;
+ area[start_index + 3] = ip;
+ WRITE_ONCE(area[0], count + 1);
+ }
+}
+
+void notrace __sanitizer_cov_trace_cmp1(u8 arg1, u8 arg2)
+{
+ write_comp_data(KCOV_CMP_SIZE(0), arg1, arg2, _RET_IP_);
+}
+EXPORT_SYMBOL(__sanitizer_cov_trace_cmp1);
+
+void notrace __sanitizer_cov_trace_cmp2(u16 arg1, u16 arg2)
+{
+ write_comp_data(KCOV_CMP_SIZE(1), arg1, arg2, _RET_IP_);
+}
+EXPORT_SYMBOL(__sanitizer_cov_trace_cmp2);
+
+void notrace __sanitizer_cov_trace_cmp4(u32 arg1, u32 arg2)
+{
+ write_comp_data(KCOV_CMP_SIZE(2), arg1, arg2, _RET_IP_);
+}
+EXPORT_SYMBOL(__sanitizer_cov_trace_cmp4);
+
+void notrace __sanitizer_cov_trace_cmp8(u64 arg1, u64 arg2)
+{
+ write_comp_data(KCOV_CMP_SIZE(3), arg1, arg2, _RET_IP_);
+}
+EXPORT_SYMBOL(__sanitizer_cov_trace_cmp8);
+
+void notrace __sanitizer_cov_trace_const_cmp1(u8 arg1, u8 arg2)
+{
+ write_comp_data(KCOV_CMP_SIZE(0) | KCOV_CMP_CONST, arg1, arg2,
+ _RET_IP_);
+}
+EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp1);
+
+void notrace __sanitizer_cov_trace_const_cmp2(u16 arg1, u16 arg2)
+{
+ write_comp_data(KCOV_CMP_SIZE(1) | KCOV_CMP_CONST, arg1, arg2,
+ _RET_IP_);
+}
+EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp2);
+
+void notrace __sanitizer_cov_trace_const_cmp4(u32 arg1, u32 arg2)
+{
+ write_comp_data(KCOV_CMP_SIZE(2) | KCOV_CMP_CONST, arg1, arg2,
+ _RET_IP_);
+}
+EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp4);
+
+void notrace __sanitizer_cov_trace_const_cmp8(u64 arg1, u64 arg2)
+{
+ write_comp_data(KCOV_CMP_SIZE(3) | KCOV_CMP_CONST, arg1, arg2,
+ _RET_IP_);
+}
+EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp8);
+
+void notrace __sanitizer_cov_trace_switch(u64 val, u64 *cases)
+{
+ u64 i;
+ u64 count = cases[0];
+ u64 size = cases[1];
+ u64 type = KCOV_CMP_CONST;
+
+ switch (size) {
+ case 8:
+ type |= KCOV_CMP_SIZE(0);
+ break;
+ case 16:
+ type |= KCOV_CMP_SIZE(1);
+ break;
+ case 32:
+ type |= KCOV_CMP_SIZE(2);
+ break;
+ case 64:
+ type |= KCOV_CMP_SIZE(3);
+ break;
+ default:
+ return;
+ }
+ for (i = 0; i < count; i++)
+ write_comp_data(type, cases[i + 2], val, _RET_IP_);
+}
+EXPORT_SYMBOL(__sanitizer_cov_trace_switch);
+#endif /* ifdef CONFIG_KCOV_ENABLE_COMPARISONS */
+
static void kcov_get(struct kcov *kcov)
{
atomic_inc(&kcov->refcount);
@@ -130,6 +261,7 @@
/* Just to not leave dangling references behind. */
kcov_task_init(t);
kcov->t = NULL;
+ kcov->mode = KCOV_MODE_INIT;
spin_unlock(&kcov->lock);
kcov_put(kcov);
}
@@ -148,7 +280,7 @@
spin_lock(&kcov->lock);
size = kcov->size * sizeof(unsigned long);
- if (kcov->mode == KCOV_MODE_DISABLED || vma->vm_pgoff != 0 ||
+ if (kcov->mode != KCOV_MODE_INIT || vma->vm_pgoff != 0 ||
vma->vm_end - vma->vm_start != size) {
res = -EINVAL;
goto exit;
@@ -177,6 +309,7 @@
kcov = kzalloc(sizeof(*kcov), GFP_KERNEL);
if (!kcov)
return -ENOMEM;
+ kcov->mode = KCOV_MODE_DISABLED;
atomic_set(&kcov->refcount, 1);
spin_lock_init(&kcov->lock);
filep->private_data = kcov;
@@ -212,7 +345,7 @@
if (size < 2 || size > INT_MAX / sizeof(unsigned long))
return -EINVAL;
kcov->size = size;
- kcov->mode = KCOV_MODE_TRACE;
+ kcov->mode = KCOV_MODE_INIT;
return 0;
case KCOV_ENABLE:
/*
@@ -222,17 +355,27 @@
* at task exit or voluntary by KCOV_DISABLE. After that it can
* be enabled for another task.
*/
- unused = arg;
- if (unused != 0 || kcov->mode == KCOV_MODE_DISABLED ||
- kcov->area == NULL)
+ if (kcov->mode != KCOV_MODE_INIT || !kcov->area)
return -EINVAL;
if (kcov->t != NULL)
return -EBUSY;
+ if (arg == KCOV_TRACE_PC)
+ kcov->mode = KCOV_MODE_TRACE_PC;
+ else if (arg == KCOV_TRACE_CMP)
+#ifdef CONFIG_KCOV_ENABLE_COMPARISONS
+ kcov->mode = KCOV_MODE_TRACE_CMP;
+#else
+ return -ENOTSUPP;
+#endif
+ else
+ return -EINVAL;
t = current;
+ if (kcov->t != NULL || t->kcov != NULL)
+ return -EBUSY;
/* Cache in task struct for performance. */
t->kcov_size = kcov->size;
t->kcov_area = kcov->area;
- /* See comment in __sanitizer_cov_trace_pc(). */
+ /* See comment in check_kcov_mode(). */
barrier();
WRITE_ONCE(t->kcov_mode, kcov->mode);
t->kcov = kcov;
@@ -250,6 +393,7 @@
return -EINVAL;
kcov_task_init(t);
kcov->t = NULL;
+ kcov->mode = KCOV_MODE_INIT;
kcov_put(kcov);
return 0;
default:
@@ -272,6 +416,7 @@
static const struct file_operations kcov_fops = {
.open = kcov_open,
.unlocked_ioctl = kcov_ioctl,
+ .compat_ioctl = kcov_ioctl,
.mmap = kcov_mmap,
.release = kcov_close,
};
diff --git a/kernel/memremap.c b/kernel/memremap.c
index 0612323..426547a 100644
--- a/kernel/memremap.c
+++ b/kernel/memremap.c
@@ -245,7 +245,8 @@
/* pages are dead and unused, undo the arch mapping */
align_start = res->start & ~(SECTION_SIZE - 1);
- align_size = ALIGN(resource_size(res), SECTION_SIZE);
+ align_size = ALIGN(res->start + resource_size(res), SECTION_SIZE)
+ - align_start;
lock_device_hotplug();
mem_hotplug_begin();
diff --git a/kernel/module.c b/kernel/module.c
index 0e54d5b..07bfb99 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2817,6 +2817,15 @@
}
#endif /* CONFIG_LIVEPATCH */
+static void check_modinfo_retpoline(struct module *mod, struct load_info *info)
+{
+ if (retpoline_module_ok(get_modinfo(info, "retpoline")))
+ return;
+
+ pr_warn("%s: loading module not compiled with retpoline compiler.\n",
+ mod->name);
+}
+
/* Sets info->hdr and info->len. */
static int copy_module_from_user(const void __user *umod, unsigned long len,
struct load_info *info)
@@ -2969,6 +2978,8 @@
add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK);
}
+ check_modinfo_retpoline(mod, info);
+
if (get_modinfo(info, "staging")) {
add_taint_module(mod, TAINT_CRAP, LOCKDEP_STILL_OK);
pr_warn("%s: module is from the staging directory, the quality "
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 5183134..0469d80 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -597,12 +597,11 @@
#ifdef CONFIG_SMP
case PM_QOS_REQ_AFFINE_IRQ:
if (irq_can_set_affinity(req->irq)) {
- int ret = 0;
struct irq_desc *desc = irq_to_desc(req->irq);
struct cpumask *mask;
if (!desc)
- break;
+ return;
mask = desc->irq_data.common->affinity;
@@ -612,13 +611,6 @@
req->irq_notify.notify = pm_qos_irq_notify;
req->irq_notify.release = pm_qos_irq_release;
- ret = irq_set_affinity_notifier(req->irq,
- &req->irq_notify);
- if (ret) {
- WARN(1, KERN_ERR "IRQ affinity notify set failed\n");
- req->type = PM_QOS_REQ_ALL_CORES;
- cpumask_setall(&req->cpus_affine);
- }
} else {
req->type = PM_QOS_REQ_ALL_CORES;
cpumask_setall(&req->cpus_affine);
@@ -640,6 +632,24 @@
trace_pm_qos_add_request(pm_qos_class, value);
pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints,
req, PM_QOS_ADD_REQ, value);
+
+#ifdef CONFIG_SMP
+ if (req->type == PM_QOS_REQ_AFFINE_IRQ &&
+ irq_can_set_affinity(req->irq)) {
+ int ret = 0;
+
+ ret = irq_set_affinity_notifier(req->irq,
+ &req->irq_notify);
+ if (ret) {
+ WARN(1, "IRQ affinity notify set failed\n");
+ req->type = PM_QOS_REQ_ALL_CORES;
+ cpumask_setall(&req->cpus_affine);
+ pm_qos_update_target(
+ pm_qos_array[pm_qos_class]->constraints,
+ req, PM_QOS_UPDATE_REQ, value);
+ }
+ }
+#endif
}
EXPORT_SYMBOL_GPL(pm_qos_add_request);
diff --git a/kernel/relay.c b/kernel/relay.c
index 8f18d31..2603e04 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -611,7 +611,6 @@
kref_put(&chan->kref, relay_destroy_channel);
mutex_unlock(&relay_channels_mutex);
- kfree(chan);
return NULL;
}
EXPORT_SYMBOL_GPL(relay_open);
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
index 4b87c4e..38cbc0d 100644
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -28,4 +28,3 @@
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) += cpufreq_schedutil.o
obj-$(CONFIG_SCHED_CORE_CTL) += core_ctl.o
-obj-$(CONFIG_CPU_FREQ_GOV_SCHED) += cpufreq_sched.o
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 31b45b7..23a7f9c 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3233,70 +3233,6 @@
unsigned int capacity_margin_freq = 1280; /* ~20% margin */
-#ifdef CONFIG_CPU_FREQ_GOV_SCHED
-
-static inline
-unsigned long sum_capacity_reqs(unsigned long cfs_cap,
- struct sched_capacity_reqs *scr, int cpu)
-{
- unsigned long total = add_capacity_margin(cfs_cap + scr->rt, cpu);
- return total += scr->dl;
-}
-
-unsigned long boosted_cpu_util(int cpu);
-static void sched_freq_tick_pelt(int cpu)
-{
- unsigned long cpu_utilization = boosted_cpu_util(cpu);
- unsigned long capacity_curr = capacity_curr_of(cpu);
- struct sched_capacity_reqs *scr;
-
- scr = &per_cpu(cpu_sched_capacity_reqs, cpu);
- if (sum_capacity_reqs(cpu_utilization, scr, cpu) < capacity_curr)
- return;
-
- /*
- * To make free room for a task that is building up its "real"
- * utilization and to harm its performance the least, request
- * a jump to a higher OPP as soon as the margin of free capacity
- * is impacted (specified by capacity_margin_freq).
- */
- set_cfs_cpu_capacity(cpu, true, cpu_utilization);
-}
-
-#ifdef CONFIG_SCHED_WALT
-static void sched_freq_tick_walt(int cpu)
-{
- unsigned long cpu_utilization = cpu_util_freq(cpu, NULL);
-
- if (walt_disabled || !sysctl_sched_use_walt_cpu_util)
- return sched_freq_tick_pelt(cpu);
-
- cpu_utilization = cpu_utilization * SCHED_CAPACITY_SCALE /
- capacity_orig_of(cpu);
- /*
- * It is likely that the load is growing so we
- * keep the added margin in our request as an
- * extra boost.
- */
- set_cfs_cpu_capacity(cpu, true, cpu_utilization);
-
-}
-#define _sched_freq_tick(cpu) sched_freq_tick_walt(cpu)
-#else
-#define _sched_freq_tick(cpu) sched_freq_tick_pelt(cpu)
-#endif /* CONFIG_SCHED_WALT */
-
-static void sched_freq_tick(int cpu)
-{
- if (!sched_freq())
- return;
-
- _sched_freq_tick(cpu);
-}
-#else
-static inline void sched_freq_tick(int cpu) { }
-#endif /* CONFIG_CPU_FREQ_GOV_SCHED */
-
/*
* This function gets called by the timer code, with HZ frequency.
* We call it with interrupts disabled.
@@ -3326,7 +3262,6 @@
curr->sched_class->task_tick(rq, curr, 0);
cpu_load_update_active(rq);
calc_global_load_tick(rq);
- sched_freq_tick(cpu);
early_notif = early_detection_notify(rq, wallclock);
if (early_notif)
@@ -6447,6 +6382,19 @@
call_rcu_sched(&old_rd->rcu, free_rootdomain);
}
+void sched_get_rd(struct root_domain *rd)
+{
+ atomic_inc(&rd->refcount);
+}
+
+void sched_put_rd(struct root_domain *rd)
+{
+ if (!atomic_dec_and_test(&rd->refcount))
+ return;
+
+ call_rcu_sched(&rd->rcu, free_rootdomain);
+}
+
static int init_rootdomain(struct root_domain *rd)
{
memset(rd, 0, sizeof(*rd));
diff --git a/kernel/sched/cpufreq_sched.c b/kernel/sched/cpufreq_sched.c
deleted file mode 100644
index 843eaa7..0000000
--- a/kernel/sched/cpufreq_sched.c
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * Copyright (C) 2015 Michael Turquette <mturquette@linaro.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/cpufreq.h>
-#include <linux/module.h>
-#include <linux/kthread.h>
-#include <linux/percpu.h>
-#include <linux/irq_work.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-
-#define CREATE_TRACE_POINTS
-#include <trace/events/cpufreq_sched.h>
-
-#include "sched.h"
-
-#define THROTTLE_DOWN_NSEC 50000000 /* 50ms default */
-#define THROTTLE_UP_NSEC 500000 /* 500us default */
-
-struct static_key __read_mostly __sched_freq = STATIC_KEY_INIT_FALSE;
-static bool __read_mostly cpufreq_driver_slow;
-
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_SCHED
-static struct cpufreq_governor cpufreq_gov_sched;
-#endif
-
-static DEFINE_PER_CPU(unsigned long, enabled);
-DEFINE_PER_CPU(struct sched_capacity_reqs, cpu_sched_capacity_reqs);
-
-struct gov_tunables {
- struct gov_attr_set attr_set;
- unsigned int up_throttle_nsec;
- unsigned int down_throttle_nsec;
-};
-
-/**
- * gov_data - per-policy data internal to the governor
- * @up_throttle: next throttling period expiry if increasing OPP
- * @down_throttle: next throttling period expiry if decreasing OPP
- * @up_throttle_nsec: throttle period length in nanoseconds if increasing OPP
- * @down_throttle_nsec: throttle period length in nanoseconds if decreasing OPP
- * @task: worker thread for dvfs transition that may block/sleep
- * @irq_work: callback used to wake up worker thread
- * @requested_freq: last frequency requested by the sched governor
- *
- * struct gov_data is the per-policy cpufreq_sched-specific data structure. A
- * per-policy instance of it is created when the cpufreq_sched governor receives
- * the CPUFREQ_GOV_START condition and a pointer to it exists in the gov_data
- * member of struct cpufreq_policy.
- *
- * Readers of this data must call down_read(policy->rwsem). Writers must
- * call down_write(policy->rwsem).
- */
-struct gov_data {
- ktime_t up_throttle;
- ktime_t down_throttle;
- struct gov_tunables *tunables;
- struct list_head tunables_hook;
- struct task_struct *task;
- struct irq_work irq_work;
- unsigned int requested_freq;
-};
-
-static void cpufreq_sched_try_driver_target(struct cpufreq_policy *policy,
- unsigned int freq)
-{
- struct gov_data *gd = policy->governor_data;
-
- /* avoid race with cpufreq_sched_stop */
- if (!down_write_trylock(&policy->rwsem))
- return;
-
- __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
-
- gd->up_throttle = ktime_add_ns(ktime_get(),
- gd->tunables->up_throttle_nsec);
- gd->down_throttle = ktime_add_ns(ktime_get(),
- gd->tunables->down_throttle_nsec);
- up_write(&policy->rwsem);
-}
-
-static bool finish_last_request(struct gov_data *gd, unsigned int cur_freq)
-{
- ktime_t now = ktime_get();
-
- ktime_t throttle = gd->requested_freq < cur_freq ?
- gd->down_throttle : gd->up_throttle;
-
- if (ktime_after(now, throttle))
- return false;
-
- while (1) {
- int usec_left = ktime_to_ns(ktime_sub(throttle, now));
-
- usec_left /= NSEC_PER_USEC;
- trace_cpufreq_sched_throttled(usec_left);
- usleep_range(usec_left, usec_left + 100);
- now = ktime_get();
- if (ktime_after(now, throttle))
- return true;
- }
-}
-
-/*
- * we pass in struct cpufreq_policy. This is safe because changing out the
- * policy requires a call to __cpufreq_governor(policy, CPUFREQ_GOV_STOP),
- * which tears down all of the data structures and __cpufreq_governor(policy,
- * CPUFREQ_GOV_START) will do a full rebuild, including this kthread with the
- * new policy pointer
- */
-static int cpufreq_sched_thread(void *data)
-{
- struct sched_param param;
- struct cpufreq_policy *policy;
- struct gov_data *gd;
- unsigned int new_request = 0;
- unsigned int last_request = 0;
- int ret;
-
- policy = (struct cpufreq_policy *) data;
- gd = policy->governor_data;
-
- param.sched_priority = 50;
- ret = sched_setscheduler_nocheck(gd->task, SCHED_FIFO, ¶m);
- if (ret) {
- pr_warn("%s: failed to set SCHED_FIFO\n", __func__);
- do_exit(-EINVAL);
- } else {
- pr_debug("%s: kthread (%d) set to SCHED_FIFO\n",
- __func__, gd->task->pid);
- }
-
- do {
- new_request = gd->requested_freq;
- if (new_request == last_request) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (kthread_should_stop())
- break;
- schedule();
- } else {
- /*
- * if the frequency thread sleeps while waiting to be
- * unthrottled, start over to check for a newer request
- */
- if (finish_last_request(gd, policy->cur))
- continue;
- last_request = new_request;
- cpufreq_sched_try_driver_target(policy, new_request);
- }
- } while (!kthread_should_stop());
-
- return 0;
-}
-
-static void cpufreq_sched_irq_work(struct irq_work *irq_work)
-{
- struct gov_data *gd;
-
- gd = container_of(irq_work, struct gov_data, irq_work);
- if (!gd)
- return;
-
- wake_up_process(gd->task);
-}
-
-static void update_fdomain_capacity_request(int cpu)
-{
- unsigned int freq_new, index_new, cpu_tmp;
- struct cpufreq_policy *policy;
- struct gov_data *gd;
- unsigned long capacity = 0;
-
- /*
- * Avoid grabbing the policy if possible. A test is still
- * required after locking the CPU's policy to avoid racing
- * with the governor changing.
- */
- if (!per_cpu(enabled, cpu))
- return;
-
- policy = cpufreq_cpu_get(cpu);
- if (IS_ERR_OR_NULL(policy))
- return;
-
- if (policy->governor != &cpufreq_gov_sched ||
- !policy->governor_data)
- goto out;
-
- gd = policy->governor_data;
-
- /* find max capacity requested by cpus in this policy */
- for_each_cpu(cpu_tmp, policy->cpus) {
- struct sched_capacity_reqs *scr;
-
- scr = &per_cpu(cpu_sched_capacity_reqs, cpu_tmp);
- capacity = max(capacity, scr->total);
- }
-
- /* Convert the new maximum capacity request into a cpu frequency */
- freq_new = capacity * policy->max >> SCHED_CAPACITY_SHIFT;
- index_new = cpufreq_frequency_table_target(policy, freq_new, CPUFREQ_RELATION_L);
- freq_new = policy->freq_table[index_new].frequency;
-
- if (freq_new > policy->max)
- freq_new = policy->max;
-
- if (freq_new < policy->min)
- freq_new = policy->min;
-
- trace_cpufreq_sched_request_opp(cpu, capacity, freq_new,
- gd->requested_freq);
- if (freq_new == gd->requested_freq)
- goto out;
-
- gd->requested_freq = freq_new;
-
- /*
- * Throttling is not yet supported on platforms with fast cpufreq
- * drivers.
- */
- if (cpufreq_driver_slow)
- irq_work_queue_on(&gd->irq_work, cpu);
- else
- cpufreq_sched_try_driver_target(policy, freq_new);
-
-out:
- cpufreq_cpu_put(policy);
-}
-
-void update_cpu_capacity_request(int cpu, bool request)
-{
- unsigned long new_capacity;
- struct sched_capacity_reqs *scr;
-
- /* The rq lock serializes access to the CPU's sched_capacity_reqs. */
- lockdep_assert_held(&cpu_rq(cpu)->lock);
-
- scr = &per_cpu(cpu_sched_capacity_reqs, cpu);
-
-#ifdef CONFIG_SCHED_WALT
- if (walt_disabled || !sysctl_sched_use_walt_cpu_util)
- new_capacity = scr->cfs + scr->rt;
-#endif
- new_capacity = scr->cfs;
- new_capacity = new_capacity * capacity_margin_freq
- / SCHED_CAPACITY_SCALE;
- new_capacity += scr->dl;
-
- if (new_capacity == scr->total)
- return;
-
- trace_cpufreq_sched_update_capacity(cpu, request, scr, new_capacity);
-
- scr->total = new_capacity;
- if (request)
- update_fdomain_capacity_request(cpu);
-}
-
-static inline void set_sched_freq(void)
-{
- static_key_slow_inc(&__sched_freq);
-}
-
-static inline void clear_sched_freq(void)
-{
- static_key_slow_dec(&__sched_freq);
-}
-
-/* Tunables */
-static struct gov_tunables *global_tunables;
-
-static inline struct gov_tunables *to_tunables(struct gov_attr_set *attr_set)
-{
- return container_of(attr_set, struct gov_tunables, attr_set);
-}
-
-static ssize_t up_throttle_nsec_show(struct gov_attr_set *attr_set, char *buf)
-{
- struct gov_tunables *tunables = to_tunables(attr_set);
-
- return sprintf(buf, "%u\n", tunables->up_throttle_nsec);
-}
-
-static ssize_t up_throttle_nsec_store(struct gov_attr_set *attr_set,
- const char *buf, size_t count)
-{
- struct gov_tunables *tunables = to_tunables(attr_set);
- int ret;
- long unsigned int val;
-
- ret = kstrtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
- tunables->up_throttle_nsec = val;
- return count;
-}
-
-static ssize_t down_throttle_nsec_show(struct gov_attr_set *attr_set, char *buf)
-{
- struct gov_tunables *tunables = to_tunables(attr_set);
-
- return sprintf(buf, "%u\n", tunables->down_throttle_nsec);
-}
-
-static ssize_t down_throttle_nsec_store(struct gov_attr_set *attr_set,
- const char *buf, size_t count)
-{
- struct gov_tunables *tunables = to_tunables(attr_set);
- int ret;
- long unsigned int val;
-
- ret = kstrtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
- tunables->down_throttle_nsec = val;
- return count;
-}
-
-static struct governor_attr up_throttle_nsec = __ATTR_RW(up_throttle_nsec);
-static struct governor_attr down_throttle_nsec = __ATTR_RW(down_throttle_nsec);
-
-static struct attribute *schedfreq_attributes[] = {
- &up_throttle_nsec.attr,
- &down_throttle_nsec.attr,
- NULL
-};
-
-static struct kobj_type tunables_ktype = {
- .default_attrs = schedfreq_attributes,
- .sysfs_ops = &governor_sysfs_ops,
-};
-
-static int cpufreq_sched_policy_init(struct cpufreq_policy *policy)
-{
- struct gov_data *gd;
- int cpu;
- int rc;
-
- for_each_cpu(cpu, policy->cpus)
- memset(&per_cpu(cpu_sched_capacity_reqs, cpu), 0,
- sizeof(struct sched_capacity_reqs));
-
- gd = kzalloc(sizeof(*gd), GFP_KERNEL);
- if (!gd)
- return -ENOMEM;
-
- policy->governor_data = gd;
-
- if (!global_tunables) {
- gd->tunables = kzalloc(sizeof(*gd->tunables), GFP_KERNEL);
- if (!gd->tunables)
- goto free_gd;
-
- gd->tunables->up_throttle_nsec =
- policy->cpuinfo.transition_latency ?
- policy->cpuinfo.transition_latency :
- THROTTLE_UP_NSEC;
- gd->tunables->down_throttle_nsec =
- THROTTLE_DOWN_NSEC;
-
- rc = kobject_init_and_add(&gd->tunables->attr_set.kobj,
- &tunables_ktype,
- get_governor_parent_kobj(policy),
- "%s", cpufreq_gov_sched.name);
- if (rc)
- goto free_tunables;
-
- gov_attr_set_init(&gd->tunables->attr_set,
- &gd->tunables_hook);
-
- pr_debug("%s: throttle_threshold = %u [ns]\n",
- __func__, gd->tunables->up_throttle_nsec);
-
- if (!have_governor_per_policy())
- global_tunables = gd->tunables;
- } else {
- gd->tunables = global_tunables;
- gov_attr_set_get(&global_tunables->attr_set,
- &gd->tunables_hook);
- }
-
- policy->governor_data = gd;
- if (cpufreq_driver_is_slow()) {
- cpufreq_driver_slow = true;
- gd->task = kthread_create(cpufreq_sched_thread, policy,
- "kschedfreq:%d",
- cpumask_first(policy->related_cpus));
- if (IS_ERR_OR_NULL(gd->task)) {
- pr_err("%s: failed to create kschedfreq thread\n",
- __func__);
- goto free_tunables;
- }
- get_task_struct(gd->task);
- kthread_bind_mask(gd->task, policy->related_cpus);
- wake_up_process(gd->task);
- init_irq_work(&gd->irq_work, cpufreq_sched_irq_work);
- }
-
- set_sched_freq();
-
- return 0;
-
-free_tunables:
- kfree(gd->tunables);
-free_gd:
- policy->governor_data = NULL;
- kfree(gd);
- return -ENOMEM;
-}
-
-static void cpufreq_sched_policy_exit(struct cpufreq_policy *policy)
-{
- unsigned int count;
- struct gov_data *gd = policy->governor_data;
-
- clear_sched_freq();
- if (cpufreq_driver_slow) {
- kthread_stop(gd->task);
- put_task_struct(gd->task);
- }
-
- count = gov_attr_set_put(&gd->tunables->attr_set, &gd->tunables_hook);
- if (!count) {
- if (!have_governor_per_policy())
- global_tunables = NULL;
- kfree(gd->tunables);
- }
-
- policy->governor_data = NULL;
-
- kfree(gd);
-}
-
-static int cpufreq_sched_start(struct cpufreq_policy *policy)
-{
- int cpu;
-
- for_each_cpu(cpu, policy->cpus)
- per_cpu(enabled, cpu) = 1;
-
- return 0;
-}
-
-static void cpufreq_sched_limits(struct cpufreq_policy *policy)
-{
- unsigned int clamp_freq;
- struct gov_data *gd = policy->governor_data;;
-
- pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz\n",
- policy->cpu, policy->min, policy->max,
- policy->cur);
-
- clamp_freq = clamp(gd->requested_freq, policy->min, policy->max);
-
- if (policy->cur != clamp_freq)
- __cpufreq_driver_target(policy, clamp_freq, CPUFREQ_RELATION_L);
-}
-
-static void cpufreq_sched_stop(struct cpufreq_policy *policy)
-{
- int cpu;
-
- for_each_cpu(cpu, policy->cpus)
- per_cpu(enabled, cpu) = 0;
-}
-
-
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_SCHED
-static
-#endif
-struct cpufreq_governor cpufreq_gov_sched = {
- .name = "sched",
- .init = cpufreq_sched_policy_init,
- .exit = cpufreq_sched_policy_exit,
- .start = cpufreq_sched_start,
- .stop = cpufreq_sched_stop,
- .limits = cpufreq_sched_limits,
- .owner = THIS_MODULE,
-};
-
-static int __init cpufreq_sched_init(void)
-{
- int cpu;
-
- for_each_cpu(cpu, cpu_possible_mask)
- per_cpu(enabled, cpu) = 0;
- return cpufreq_register_governor(&cpufreq_gov_sched);
-}
-
-#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_SCHED
-struct cpufreq_governor *cpufreq_default_governor(void)
-{
- return &cpufreq_gov_sched;
-}
-#endif
-
-/* Try to make this the default governor */
-fs_initcall(cpufreq_sched_init);
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index 32b67eb..53974cc 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -19,10 +19,6 @@
#include "sched.h"
#include "tune.h"
-#ifdef CONFIG_SCHED_WALT
-unsigned long boosted_cpu_util(int cpu);
-#endif
-
#define SUGOV_KTHREAD_PRIORITY 50
struct sugov_tunables {
@@ -182,8 +178,7 @@
*util = min(rq->cfs.avg.util_avg, cfs_max);
*max = cfs_max;
- *util = cpu_util_freq(cpu, &loadcpu->walt_load);
- *util = boosted_cpu_util(cpu);
+ *util = boosted_cpu_util(cpu, &loadcpu->walt_load);
}
static void sugov_set_iowait_boost(struct sugov_cpu *sg_cpu, u64 time,
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index c091ca4..16065b2 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -784,7 +784,6 @@
P(sysctl_sched_child_runs_first);
P(sysctl_sched_features);
#ifdef CONFIG_SCHED_WALT
- P(sched_init_task_load_windows);
P(min_capacity);
P(max_capacity);
P(sched_ravg_window);
diff --git a/kernel/sched/energy.c b/kernel/sched/energy.c
index 420cb52..77d8361 100644
--- a/kernel/sched/energy.c
+++ b/kernel/sched/energy.c
@@ -150,6 +150,7 @@
int cpu;
unsigned long *max_frequencies = NULL;
int ret;
+ bool is_sge_valid = false;
if (!sched_is_energy_aware())
return 0;
@@ -248,6 +249,7 @@
sge_l0->cap_states[i].power);
}
+ is_sge_valid = true;
dev_info(&pdev->dev,
"cpu=%d eff=%d [freq=%ld cap=%ld power_d0=%ld] -> [freq=%ld cap=%ld power_d0=%ld]\n",
cpu, efficiency,
@@ -271,7 +273,8 @@
kfree(max_frequencies);
- walt_sched_energy_populated_callback();
+ if (is_sge_valid)
+ walt_sched_energy_populated_callback();
dev_info(&pdev->dev, "Sched-energy-costs capacity updated\n");
return 0;
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
old mode 100755
new mode 100644
index 55c3957..75ea4ff
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -87,7 +87,6 @@
unsigned int sysctl_sched_is_big_little = 1;
unsigned int sysctl_sched_sync_hint_enable = 1;
-unsigned int sysctl_sched_initial_task_util = 0;
unsigned int sysctl_sched_cstate_aware = 1;
DEFINE_PER_CPU_READ_MOSTLY(int, sched_load_boost);
@@ -165,6 +164,7 @@
*/
unsigned int sysctl_sched_capacity_margin = 1078; /* ~5% margin */
unsigned int sysctl_sched_capacity_margin_down = 1205; /* ~15% margin */
+#define capacity_margin sysctl_sched_capacity_margin
static inline void update_load_add(struct load_weight *lw, unsigned long inc)
{
@@ -288,10 +288,6 @@
return mul_u64_u32_shr(delta_exec, fact, shift);
}
-#ifdef CONFIG_SMP
-static int active_load_balance_cpu_stop(void *data);
-#endif
-
const struct sched_class fair_sched_class;
/**************************************************************
@@ -792,9 +788,7 @@
/*
* At this point, util_avg won't be used in select_task_rq_fair anyway
*/
- sa->util_avg = sched_freq() ?
- sysctl_sched_initial_task_util :
- 0;
+ sa->util_avg = 0;
sa->util_sum = 0;
/* when this task enqueue'ed, it will contribute to its cfs_rq's load_avg */
}
@@ -3379,6 +3373,7 @@
struct rq *rq = rq_of(cfs_rq);
int cpu = cpu_of(rq);
int decayed;
+ void *ptr = NULL;
/*
* Track task load average for carrying it to new CPU after migrated, and
@@ -3396,8 +3391,12 @@
if (decayed && (flags & UPDATE_TG))
update_tg_load_avg(cfs_rq, 0);
- if (entity_is_task(se))
- trace_sched_load_avg_task(task_of(se), &se->avg);
+ if (entity_is_task(se)) {
+#ifdef CONFIG_SCHED_WALT
+ ptr = (void *)&(task_of(se)->ravg);
+#endif
+ trace_sched_load_avg_task(task_of(se), &se->avg, ptr);
+ }
}
/**
@@ -4851,24 +4850,6 @@
#ifdef CONFIG_SMP
static unsigned long capacity_orig_of(int cpu);
static unsigned long cpu_util(int cpu);
-unsigned long boosted_cpu_util(int cpu);
-#else
-#define boosted_cpu_util(cpu) cpu_util_freq(cpu)
-#endif
-
-#ifdef CONFIG_SMP
-static void update_capacity_of(int cpu)
-{
- unsigned long req_cap;
-
- if (!sched_freq())
- return;
-
- /* Convert scale-invariant capacity to cpu. */
- req_cap = boosted_cpu_util(cpu);
- req_cap = req_cap * SCHED_CAPACITY_SCALE / capacity_orig_of(cpu);
- set_cfs_cpu_capacity(cpu, true, req_cap);
-}
#endif
/*
@@ -4883,7 +4864,6 @@
struct sched_entity *se = &p->se;
#ifdef CONFIG_SMP
int task_new = flags & ENQUEUE_WAKEUP_NEW;
- int task_wakeup = flags & ENQUEUE_WAKEUP;
#endif
#ifdef CONFIG_SCHED_WALT
@@ -4961,16 +4941,6 @@
rq->rd->overutilized = true;
trace_sched_overutilized(true);
}
-
- /*
- * We want to potentially trigger a freq switch
- * request only for tasks that are waking up; this is
- * because we get here also during load balancing, but
- * in these cases it seems wise to trigger as single
- * request after load balancing is done.
- */
- if (task_new || task_wakeup)
- update_capacity_of(cpu_of(rq));
}
#endif /* CONFIG_SMP */
@@ -5048,13 +5018,6 @@
*/
schedtune_dequeue_task(p, cpu_of(rq));
- if (!se) {
- if (rq->cfs.nr_running)
- update_capacity_of(cpu_of(rq));
- else if (sched_freq())
- set_cfs_cpu_capacity(cpu_of(rq), false, 0);
- }
-
#endif /* CONFIG_SMP */
hrtick_update(rq);
@@ -5527,6 +5490,15 @@
}
/*
+ * Externally visible function. Let's keep the one above
+ * so that the check is inlined/optimized in the sched paths.
+ */
+bool sched_is_energy_aware(void)
+{
+ return energy_aware();
+}
+
+/*
* Returns the current capacity of cpu after applying both
* cpu and freq scaling.
*/
@@ -5538,44 +5510,88 @@
}
/*
- * Externally visible function. Let's keep the one above
- * so that the check is inlined/optimized in the sched paths.
+ * Returns the current capacity of cpu after applying both
+ * cpu and min freq scaling.
*/
-bool sched_is_energy_aware(void)
+unsigned long capacity_min_of(int cpu)
{
- return energy_aware();
+ if (!sched_feat(MIN_CAPACITY_CAPPING))
+ return 0;
+ return arch_scale_cpu_capacity(NULL, cpu) *
+ arch_scale_min_freq_capacity(NULL, cpu)
+ >> SCHED_CAPACITY_SHIFT;
}
+/*
+ * CPU candidates.
+ *
+ * These are labels to reference CPU candidates for an energy_diff.
+ * Currently we support only two possible candidates: the task's previous CPU
+ * and another candiate CPU.
+ * More advanced/aggressive EAS selection policies can consider more
+ * candidates.
+ */
+#define EAS_CPU_PRV 0
+#define EAS_CPU_NXT 1
+#define EAS_CPU_BKP 2
+#define EAS_CPU_CNT 3
+
+/*
+ * energy_diff - supports the computation of the estimated energy impact in
+ * moving a "task"'s "util_delta" between different CPU candidates.
+ */
struct energy_env {
+ /* Utilization to move */
+ struct task_struct *p;
+ int util_delta;
+
+ /* Mask of CPUs candidates to evaluate */
+ cpumask_t cpus_mask;
+
+ /* CPU candidates to evaluate */
+ struct {
+
+ /* CPU ID, must be in cpus_mask */
+ int cpu_id;
+
+ /*
+ * Index (into sched_group_energy::cap_states) of the OPP the
+ * CPU needs to run at if the task is placed on it.
+ * This includes the both active and blocked load, due to
+ * other tasks on this CPU, as well as the task's own
+ * utilization.
+ */
+ int cap_idx;
+ int cap;
+
+ /* Estimated system energy */
+ unsigned int energy;
+
+ /* Estimated energy variation wrt EAS_CPU_PRV */
+ int nrg_delta;
+
+ } cpu[EAS_CPU_CNT];
+
+ /*
+ * Index (into energy_env::cpu) of the morst energy efficient CPU for
+ * the specified energy_env::task
+ */
+ int next_idx;
+
+ /* Support data */
struct sched_group *sg_top;
struct sched_group *sg_cap;
- int cap_idx;
- int util_delta;
- int src_cpu;
- int dst_cpu;
- int energy;
- int payoff;
- int sync_cpu;
- unsigned long curr_util;
- struct task_struct *task;
- struct {
- int before;
- int after;
- int delta;
- int diff;
- } nrg;
- struct {
- int before;
- int after;
- int delta;
- } cap;
+ struct sched_group *sg;
};
+static int cpu_util_wake(int cpu, struct task_struct *p);
+
/*
* __cpu_norm_util() returns the cpu util relative to a specific capacity,
- * i.e. it's busy ratio, in the range [0..SCHED_LOAD_SCALE] which is useful for
- * energy calculations. Using the scale-invariant util returned by
- * cpu_util() and approximating scale-invariant util by:
+ * i.e. it's busy ratio, in the range [0..SCHED_LOAD_SCALE], which is useful for
+ * energy calculations.
+ *
+ * Since util is a scale-invariant utilization defined as:
*
* util ~ (curr_freq/max_freq)*1024 * capacity_orig/1024 * running_time/time
*
@@ -5585,83 +5601,41 @@
*
* norm_util = running_time/time ~ util/capacity
*/
-static unsigned long __cpu_norm_util(int cpu, unsigned long capacity, int delta)
+static unsigned long __cpu_norm_util(unsigned long util, unsigned long capacity)
{
- int util = cpu_util_cum(cpu, delta);
-
if (util >= capacity)
return SCHED_CAPACITY_SCALE;
- return DIV_ROUND_UP(util << SCHED_CAPACITY_SHIFT, capacity);
+ return (util << SCHED_CAPACITY_SHIFT)/capacity;
}
-static inline bool
-bias_to_waker_cpu(struct task_struct *p, int cpu, struct cpumask *rtg_target)
+static unsigned long group_max_util(struct energy_env *eenv, int cpu_idx)
{
- 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);
-}
-
-static int calc_util_delta(struct energy_env *eenv, int cpu)
-{
-#ifdef CONFIG_SCHED_WALT
- if (cpu == eenv->src_cpu) {
- if (!walt_disabled && sysctl_sched_use_walt_task_util &&
- !task_in_cum_window_demand(cpu_rq(cpu), eenv->task)) {
- if (eenv->util_delta == 0)
- /*
- * energy before - calculate energy cost when
- * the new task is placed onto src_cpu. The
- * task is not on a runqueue so its util is not
- * in the WALT's cr_avg as it's discounted when
- * it slept last time. Hence return task's util
- * as delta to calculate energy cost of src_cpu
- * as if the new task on it.
- */
- return task_util(eenv->task);
- /*
- * energy after - WALT's cr_avg already doesn't have the
- * new task's util accounted in. Thus return 0 delta to
- * calculate energy cost of the src_cpu without the
- * task's util.
- */
- return 0;
- }
- /*
- * Task is already on a runqueue for example while load
- * balancing. WALT's cpu util already accounted the task's
- * util. return 0 delta for energy before so energy calculation
- * to be done with the task's util accounted, return -task_util
- * for energy after so the calculation to be doen with
- * discounted task's util.
- */
- return -eenv->util_delta;
- }
-#else
- if (cpu == eenv->src_cpu)
- return -eenv->util_delta;
-#endif
- if (cpu == eenv->dst_cpu)
- return eenv->util_delta;
- return 0;
-}
-
-static
-unsigned long group_max_util(struct energy_env *eenv)
-{
- int i, delta;
unsigned long max_util = 0;
+ unsigned long util;
+ int cpu;
- for_each_cpu(i, sched_group_cpus(eenv->sg_cap)) {
- delta = calc_util_delta(eenv, i);
- /* substract sync_cpu's rq->curr util to discount its cost */
- if (eenv->sync_cpu == i)
- delta -= eenv->curr_util;
- max_util = max(max_util, cpu_util_cum(i, delta));
+ for_each_cpu(cpu, sched_group_cpus(eenv->sg_cap)) {
+ util = cpu_util_wake(cpu, eenv->p);
+
+ /*
+ * If we are looking at the target CPU specified by the eenv,
+ * then we should add the (estimated) utilization of the task
+ * assuming we will wake it up on that CPU.
+ */
+ if (unlikely(cpu == eenv->cpu[cpu_idx].cpu_id))
+ util += eenv->util_delta;
+
+ max_util = max(max_util, util);
+
+ /*
+ * Take into account any minimum frequency imposed
+ * elsewhere which limits the energy states available
+ * If the MIN_CAPACITY_CAPPING feature is not enabled
+ * capacity_min_of will return 0 (not capped).
+ */
+ max_util = max(max_util, capacity_min_of(cpu));
+
}
return max_util;
@@ -5669,60 +5643,64 @@
/*
* group_norm_util() returns the approximated group util relative to it's
- * current capacity (busy ratio) in the range [0..SCHED_LOAD_SCALE] for use in
- * energy calculations. Since task executions may or may not overlap in time in
- * the group the true normalized util is between max(cpu_norm_util(i)) and
- * sum(cpu_norm_util(i)) when iterating over all cpus in the group, i. The
- * latter is used as the estimate as it leads to a more pessimistic energy
+ * current capacity (busy ratio), in the range [0..SCHED_LOAD_SCALE], for use
+ * in energy calculations.
+ *
+ * Since task executions may or may not overlap in time in the group the true
+ * normalized util is between MAX(cpu_norm_util(i)) and SUM(cpu_norm_util(i))
+ * when iterating over all CPUs in the group.
+ * The latter estimate is used as it leads to a more pessimistic energy
* estimate (more busy).
*/
static unsigned
-long group_norm_util(struct energy_env *eenv, struct sched_group *sg)
+long group_norm_util(struct energy_env *eenv, int cpu_idx)
{
- int i, delta;
- unsigned long util_sum = 0;
- unsigned long capacity = sg->sge->cap_states[eenv->cap_idx].cap;
+ unsigned long capacity = eenv->cpu[cpu_idx].cap;
+ unsigned long util, util_sum = 0;
+ int cpu;
- for_each_cpu(i, sched_group_cpus(sg)) {
- delta = calc_util_delta(eenv, i);
- /* substract sync_cpu's rq->curr util to discount its cost */
- if (eenv->sync_cpu == i)
- delta -= eenv->curr_util;
- util_sum += __cpu_norm_util(i, capacity, delta);
+ for_each_cpu(cpu, sched_group_cpus(eenv->sg)) {
+ util = cpu_util_wake(cpu, eenv->p);
+
+ /*
+ * If we are looking at the target CPU specified by the eenv,
+ * then we should add the (estimated) utilization of the task
+ * assuming we will wake it up on that CPU.
+ */
+ if (unlikely(cpu == eenv->cpu[cpu_idx].cpu_id))
+ util += eenv->util_delta;
+
+ util_sum += __cpu_norm_util(util, capacity);
}
- if (util_sum > SCHED_CAPACITY_SCALE)
- return SCHED_CAPACITY_SCALE;
- return util_sum;
+ return min_t(unsigned long, util_sum, SCHED_CAPACITY_SCALE);
}
-static int __find_new_capacity(unsigned long util,
- const struct sched_group_energy const *sge)
+static int find_new_capacity(struct energy_env *eenv, int cpu_idx)
{
- int idx;
+ const struct sched_group_energy *sge = eenv->sg->sge;
+ int idx, max_idx = sge->nr_cap_states - 1;
+ unsigned long util = group_max_util(eenv, cpu_idx);
+
+ /* default is max_cap if we don't find a match */
+ eenv->cpu[cpu_idx].cap_idx = max_idx;
+ eenv->cpu[cpu_idx].cap = sge->cap_states[max_idx].cap;
for (idx = 0; idx < sge->nr_cap_states; idx++) {
- if (sge->cap_states[idx].cap >= util)
- return idx;
+ if (sge->cap_states[idx].cap >= util) {
+ /* Keep track of SG's capacity */
+ eenv->cpu[cpu_idx].cap_idx = idx;
+ eenv->cpu[cpu_idx].cap = sge->cap_states[idx].cap;
+ break;
+ }
}
- return (sge->nr_cap_states - 1);
+ return eenv->cpu[cpu_idx].cap_idx;
}
-static int find_new_capacity(struct energy_env *eenv,
- const struct sched_group_energy const *sge)
+static int group_idle_state(struct energy_env *eenv, int cpu_idx)
{
- int idx;
- unsigned long util = group_max_util(eenv);
-
- idx = __find_new_capacity(util, sge);
- eenv->cap_idx = idx;
-
- return idx;
-}
-
-static int group_idle_state(struct energy_env *eenv, struct sched_group *sg)
-{
+ struct sched_group *sg = eenv->sg;
int i, state = INT_MAX;
int src_in_grp, dst_in_grp;
long grp_util = 0;
@@ -5731,31 +5709,29 @@
for_each_cpu(i, sched_group_cpus(sg))
state = min(state, idle_get_state_idx(cpu_rq(i)));
- if (unlikely(state == INT_MAX))
- return -EINVAL;
-
/* Take non-cpuidle idling into account (active idle/arch_cpu_idle()) */
state++;
- /*
- * Try to estimate if a deeper idle state is
- * achievable when we move the task.
- */
- for_each_cpu(i, sched_group_cpus(sg))
- grp_util += cpu_util(i);
-
- src_in_grp = cpumask_test_cpu(eenv->src_cpu, sched_group_cpus(sg));
- dst_in_grp = cpumask_test_cpu(eenv->dst_cpu, sched_group_cpus(sg));
+ src_in_grp = cpumask_test_cpu(eenv->cpu[EAS_CPU_PRV].cpu_id,
+ sched_group_cpus(sg));
+ dst_in_grp = cpumask_test_cpu(eenv->cpu[cpu_idx].cpu_id,
+ sched_group_cpus(sg));
if (src_in_grp == dst_in_grp) {
/* both CPUs under consideration are in the same group or not in
* either group, migration should leave idle state the same.
*/
goto end;
}
- /* add or remove util as appropriate to indicate what group util
- * will be (worst case - no concurrent execution) after moving the task
+
+ /*
+ * Try to estimate if a deeper idle state is
+ * achievable when we move the task.
*/
- grp_util += src_in_grp ? -eenv->util_delta : eenv->util_delta;
+ for_each_cpu(i, sched_group_cpus(sg)) {
+ grp_util += cpu_util_wake(i, eenv->p);
+ if (unlikely(i == eenv->cpu[cpu_idx].cpu_id))
+ grp_util += eenv->util_delta;
+ }
if (grp_util <=
((long)sg->sgc->max_capacity * (int)sg->group_weight)) {
@@ -5789,102 +5765,135 @@
}
/*
- * sched_group_energy(): Computes the absolute energy consumption of cpus
- * belonging to the sched_group including shared resources shared only by
- * members of the group. Iterates over all cpus in the hierarchy below the
- * sched_group starting from the bottom working it's way up before going to
- * the next cpu until all cpus are covered at all levels. The current
- * implementation is likely to gather the same util statistics multiple times.
- * This can probably be done in a faster but more complex way.
- * Note: sched_group_energy() may fail when racing with sched_domain updates.
+ * calc_sg_energy: compute energy for the eenv's SG (i.e. eenv->sg).
+ *
+ * This works in iterations to compute the SG's energy for each CPU
+ * candidate defined by the energy_env's cpu array.
+ *
+ * NOTE: in the following computations for busy_energy and idle_energy we do
+ * not shift by SCHED_CAPACITY_SHIFT in order to reduce rounding errors.
+ * The required scaling will be performed just one time, by the calling
+ * functions, once we accumulated the contributons for all the SGs.
*/
-static int sched_group_energy(struct energy_env *eenv)
+static void calc_sg_energy(struct energy_env *eenv)
{
- struct sched_domain *sd;
- int cpu;
- u64 total_energy = 0;
+ struct sched_group *sg = eenv->sg;
+ int busy_energy, idle_energy;
+ unsigned int busy_power;
+ unsigned int idle_power;
+ unsigned long sg_util;
+ int cap_idx, idle_idx;
+ int total_energy = 0;
+ int cpu_idx;
+
+ for (cpu_idx = EAS_CPU_PRV; cpu_idx < EAS_CPU_CNT; ++cpu_idx) {
+
+
+ if (eenv->cpu[cpu_idx].cpu_id == -1)
+ continue;
+ /* Compute ACTIVE energy */
+ cap_idx = find_new_capacity(eenv, cpu_idx);
+ busy_power = sg->sge->cap_states[cap_idx].power;
+ /*
+ * in order to calculate cpu_norm_util, we need to know which
+ * capacity level the group will be at, so calculate that first
+ */
+ sg_util = group_norm_util(eenv, cpu_idx);
+
+ busy_energy = sg_util * busy_power;
+
+ /* Compute IDLE energy */
+ idle_idx = group_idle_state(eenv, cpu_idx);
+ idle_power = sg->sge->idle_states[idle_idx].power;
+
+ idle_energy = SCHED_CAPACITY_SCALE - sg_util;
+ idle_energy *= idle_power;
+
+ total_energy = busy_energy + idle_energy;
+ eenv->cpu[cpu_idx].energy += total_energy;
+ }
+}
+
+/*
+ * compute_energy() computes the absolute variation in energy consumption by
+ * moving eenv.util_delta from EAS_CPU_PRV to EAS_CPU_NXT.
+ *
+ * NOTE: compute_energy() may fail when racing with sched_domain updates, in
+ * which case we abort by returning -EINVAL.
+ */
+static int compute_energy(struct energy_env *eenv)
+{
struct cpumask visit_cpus;
- struct sched_group *sg;
+ int cpu_count;
WARN_ON(!eenv->sg_top->sge);
cpumask_copy(&visit_cpus, sched_group_cpus(eenv->sg_top));
+ /* If a cpu is hotplugged in while we are in this function,
+ * it does not appear in the existing visit_cpus mask
+ * which came from the sched_group pointer of the
+ * sched_domain pointed at by sd_ea for either the prev
+ * or next cpu and was dereferenced in __energy_diff.
+ * Since we will dereference sd_scs later as we iterate
+ * through the CPUs we expect to visit, new CPUs can
+ * be present which are not in the visit_cpus mask.
+ * Guard this with cpu_count.
+ */
+ cpu_count = cpumask_weight(&visit_cpus);
while (!cpumask_empty(&visit_cpus)) {
struct sched_group *sg_shared_cap = NULL;
-
- cpu = cpumask_first(&visit_cpus);
+ int cpu = cpumask_first(&visit_cpus);
+ struct sched_domain *sd;
/*
* Is the group utilization affected by cpus outside this
* sched_group?
+ * This sd may have groups with cpus which were not present
+ * when we took visit_cpus.
*/
sd = rcu_dereference(per_cpu(sd_scs, cpu));
-
if (sd && sd->parent)
sg_shared_cap = sd->parent->groups;
for_each_domain(cpu, sd) {
- sg = sd->groups;
+ struct sched_group *sg = sd->groups;
/* Has this sched_domain already been visited? */
if (sd->child && group_first_cpu(sg) != cpu)
break;
do {
- unsigned long group_util;
- int sg_busy_energy, sg_idle_energy;
- int cap_idx, idle_idx;
-
+ eenv->sg_cap = sg;
if (sg_shared_cap && sg_shared_cap->group_weight >= sg->group_weight)
eenv->sg_cap = sg_shared_cap;
- else
- eenv->sg_cap = sg;
- cap_idx = find_new_capacity(eenv, sg->sge);
+ /*
+ * Compute the energy for all the candidate
+ * CPUs in the current visited SG.
+ */
+ eenv->sg = sg;
+ calc_sg_energy(eenv);
- if (sg->group_weight == 1) {
- /* Remove capacity of src CPU (before task move) */
- if (eenv->util_delta == 0 &&
- cpumask_test_cpu(eenv->src_cpu, sched_group_cpus(sg))) {
- eenv->cap.before = sg->sge->cap_states[cap_idx].cap;
- eenv->cap.delta -= eenv->cap.before;
- }
- /* Add capacity of dst CPU (after task move) */
- if (eenv->util_delta != 0 &&
- cpumask_test_cpu(eenv->dst_cpu, sched_group_cpus(sg))) {
- eenv->cap.after = sg->sge->cap_states[cap_idx].cap;
- eenv->cap.delta += eenv->cap.after;
- }
- }
-
- idle_idx = group_idle_state(eenv, sg);
- if (unlikely(idle_idx < 0))
- return idle_idx;
-
- if (idle_idx > sg->sge->nr_idle_states - 1)
- idle_idx = sg->sge->nr_idle_states - 1;
-
- group_util = group_norm_util(eenv, sg);
- sg_busy_energy = (group_util * sg->sge->cap_states[cap_idx].power);
-
- if (idle_idx == 0)
- sg_idle_energy = ((SCHED_CAPACITY_SCALE - group_util)
- * sg->sge->cap_states[cap_idx].power);
- else
- sg_idle_energy = ((SCHED_CAPACITY_SCALE - group_util)
- * sg->sge->idle_states[idle_idx].power);
-
- total_energy += sg_busy_energy + sg_idle_energy;
-
- trace_sched_group_energy(group_first_cpu(sg),
- group_util, total_energy,
- sg_busy_energy, sg_idle_energy,
- idle_idx,
- sg->sge->cap_states[eenv->cap_idx].cap);
-
- if (!sd->child)
+ /* remove CPUs we have just visited */
+ if (!sd->child) {
+ /*
+ * cpu_count here is the number of
+ * cpus we expect to visit in this
+ * calculation. If we race against
+ * hotplug, we can have extra cpus
+ * added to the groups we are
+ * iterating which do not appear in
+ * the visit_cpus mask. In that case
+ * we are not able to calculate energy
+ * without restarting so we will bail
+ * out and use prev_cpu this time.
+ */
+ if (!cpu_count)
+ return -EINVAL;
cpumask_xor(&visit_cpus, &visit_cpus, sched_group_cpus(sg));
+ cpu_count--;
+ }
if (cpumask_equal(sched_group_cpus(sg), sched_group_cpus(eenv->sg_top)))
goto next_cpu;
@@ -5896,6 +5905,9 @@
* If we raced with hotplug and got an sd NULL-pointer;
* returning a wrong energy estimation is better than
* entering an infinite loop.
+ * Specifically: If a cpu is unplugged after we took
+ * the visit_cpus mask, it no longer has an sd_scs
+ * pointer, so when we dereference it, we get NULL.
*/
if (cpumask_test_cpu(cpu, &visit_cpus))
return -EINVAL;
@@ -5904,7 +5916,6 @@
continue;
}
- eenv->energy = total_energy >> SCHED_CAPACITY_SHIFT;
return 0;
}
@@ -5914,166 +5925,106 @@
}
/*
- * energy_diff(): Estimate the energy impact of changing the utilization
- * distribution. eenv specifies the change: utilisation amount, source, and
- * destination cpu. Source or destination cpu may be -1 in which case the
- * utilization is removed from or added to the system (e.g. task wake-up). If
- * both are specified, the utilization is migrated.
+ * select_energy_cpu_idx(): estimate the energy impact of changing the
+ * utilization distribution.
+ *
+ * The eenv parameter specifies the changes: utilisation amount and a pair of
+ * possible CPU candidates (the previous CPU and a different target CPU).
+ *
+ * This function returns the index of a CPU candidate specified by the
+ * energy_env which corresponds to the first CPU saving energy.
+ * Thus, 0 (EAS_CPU_PRV) means that non of the CPU candidate is more energy
+ * efficient than running on prev_cpu. This is also the value returned in case
+ * of abort due to error conditions during the computations.
+ * A value greater than zero means that the first energy-efficient CPU is the
+ * one represented by eenv->cpu[eenv->next_idx].cpu_id.
*/
-static inline int __energy_diff(struct energy_env *eenv)
+static inline int select_energy_cpu_idx(struct energy_env *eenv)
{
struct sched_domain *sd;
struct sched_group *sg;
- int sd_cpu = -1, energy_before = 0, energy_after = 0;
- int diff, margin;
+ int sd_cpu = -1;
+ int cpu_idx;
+ int margin;
- struct energy_env eenv_before = {
- .util_delta = 0,
- .src_cpu = eenv->src_cpu,
- .dst_cpu = eenv->dst_cpu,
- .nrg = { 0, 0, 0, 0},
- .cap = { 0, 0, 0 },
- .task = eenv->task,
- .sync_cpu = eenv->sync_cpu,
- };
-
- if (eenv->src_cpu == eenv->dst_cpu)
- return 0;
-
- sd_cpu = (eenv->src_cpu != -1) ? eenv->src_cpu : eenv->dst_cpu;
+ sd_cpu = eenv->cpu[EAS_CPU_PRV].cpu_id;
sd = rcu_dereference(per_cpu(sd_ea, sd_cpu));
-
if (!sd)
- return 0; /* Error */
+ return EAS_CPU_PRV;
+
+ cpumask_clear(&eenv->cpus_mask);
+ for (cpu_idx = EAS_CPU_PRV; cpu_idx < EAS_CPU_CNT; ++cpu_idx) {
+ int cpu = eenv->cpu[cpu_idx].cpu_id;
+
+ if (cpu < 0)
+ continue;
+ cpumask_set_cpu(cpu, &eenv->cpus_mask);
+ }
sg = sd->groups;
-
do {
- if (cpu_in_sg(sg, eenv->src_cpu) || cpu_in_sg(sg, eenv->dst_cpu)) {
- eenv_before.sg_top = eenv->sg_top = sg;
+ /* Skip SGs which do not contains a candidate CPU */
+ if (!cpumask_intersects(&eenv->cpus_mask, sched_group_cpus(sg)))
+ continue;
- if (sched_group_energy(&eenv_before))
- return 0; /* Invalid result abort */
- energy_before += eenv_before.energy;
+ eenv->sg_top = sg;
+ /* energy is unscaled to reduce rounding errors */
+ if (compute_energy(eenv) == -EINVAL)
+ return EAS_CPU_PRV;
- /* Keep track of SRC cpu (before) capacity */
- eenv->cap.before = eenv_before.cap.before;
- eenv->cap.delta = eenv_before.cap.delta;
-
- if (sched_group_energy(eenv))
- return 0; /* Invalid result abort */
- energy_after += eenv->energy;
- }
} while (sg = sg->next, sg != sd->groups);
- eenv->nrg.before = energy_before;
- eenv->nrg.after = energy_after;
- eenv->nrg.diff = eenv->nrg.after - eenv->nrg.before;
- eenv->payoff = 0;
-#ifndef CONFIG_SCHED_TUNE
- trace_sched_energy_diff(eenv->task,
- eenv->src_cpu, eenv->dst_cpu, eenv->util_delta,
- eenv->nrg.before, eenv->nrg.after, eenv->nrg.diff,
- eenv->cap.before, eenv->cap.after, eenv->cap.delta,
- eenv->nrg.delta, eenv->payoff);
-#endif
+ /* Scale energy before comparisons */
+ for (cpu_idx = EAS_CPU_PRV; cpu_idx < EAS_CPU_CNT; ++cpu_idx)
+ eenv->cpu[cpu_idx].energy >>= SCHED_CAPACITY_SHIFT;
+
/*
- * Dead-zone margin preventing too many migrations.
+ * Compute the dead-zone margin used to prevent too many task
+ * migrations with negligible energy savings.
+ * An energy saving is considered meaningful if it reduces the energy
+ * consumption of EAS_CPU_PRV CPU candidate by at least ~1.56%
*/
+ margin = eenv->cpu[EAS_CPU_PRV].energy >> 6;
- margin = eenv->nrg.before >> 6; /* ~1.56% */
+ /*
+ * By default the EAS_CPU_PRV CPU is considered the most energy
+ * efficient, with a 0 energy variation.
+ */
+ eenv->next_idx = EAS_CPU_PRV;
- diff = eenv->nrg.after - eenv->nrg.before;
-
- eenv->nrg.diff = (abs(diff) < margin) ? 0 : eenv->nrg.diff;
-
- return eenv->nrg.diff;
-}
-
-#ifdef CONFIG_SCHED_TUNE
-
-struct target_nrg schedtune_target_nrg;
-extern bool schedtune_initialized;
-/*
- * System energy normalization
- * Returns the normalized value, in the range [0..SCHED_CAPACITY_SCALE],
- * corresponding to the specified energy variation.
- */
-static inline int
-normalize_energy(int energy_diff)
-{
- u32 normalized_nrg;
-
- /* during early setup, we don't know the extents */
- if (unlikely(!schedtune_initialized))
- return energy_diff < 0 ? -1 : 1 ;
-
-#ifdef CONFIG_SCHED_DEBUG
- {
- int max_delta;
-
- /* Check for boundaries */
- max_delta = schedtune_target_nrg.max_power;
- max_delta -= schedtune_target_nrg.min_power;
- WARN_ON(abs(energy_diff) >= max_delta);
+ trace_sched_energy_diff(eenv->p, eenv->cpu[EAS_CPU_PRV].cpu_id,
+ eenv->cpu[EAS_CPU_PRV].energy,
+ eenv->cpu[EAS_CPU_NXT].cpu_id,
+ eenv->cpu[EAS_CPU_NXT].energy,
+ eenv->cpu[EAS_CPU_BKP].cpu_id,
+ eenv->cpu[EAS_CPU_BKP].energy);
+ /*
+ * Compare the other CPU candidates to find a CPU which can be
+ * more energy efficient then EAS_CPU_PRV
+ */
+ for (cpu_idx = EAS_CPU_NXT; cpu_idx < EAS_CPU_CNT; ++cpu_idx) {
+ /* Skip not valid scheduled candidates */
+ if (eenv->cpu[cpu_idx].cpu_id < 0)
+ continue;
+ /* Compute energy delta wrt EAS_CPU_PRV */
+ eenv->cpu[cpu_idx].nrg_delta =
+ eenv->cpu[cpu_idx].energy -
+ eenv->cpu[EAS_CPU_PRV].energy;
+ /* filter energy variations within the dead-zone margin */
+ if (abs(eenv->cpu[cpu_idx].nrg_delta) < margin)
+ eenv->cpu[cpu_idx].nrg_delta = 0;
+ /* update the schedule candidate with min(nrg_delta) */
+ if (eenv->cpu[cpu_idx].nrg_delta <
+ eenv->cpu[eenv->next_idx].nrg_delta) {
+ eenv->next_idx = cpu_idx;
+ if (sched_feat(FBT_STRICT_ORDER))
+ break;
+ }
}
-#endif
- /* Do scaling using positive numbers to increase the range */
- normalized_nrg = (energy_diff < 0) ? -energy_diff : energy_diff;
-
- /* Scale by energy magnitude */
- normalized_nrg <<= SCHED_CAPACITY_SHIFT;
-
- /* Normalize on max energy for target platform */
- normalized_nrg = reciprocal_divide(
- normalized_nrg, schedtune_target_nrg.rdiv);
-
- return (energy_diff < 0) ? -normalized_nrg : normalized_nrg;
+ return eenv->next_idx;
}
-static inline int
-energy_diff(struct energy_env *eenv)
-{
- int boost = schedtune_task_boost(eenv->task);
- int nrg_delta;
-
- /* Conpute "absolute" energy diff */
- __energy_diff(eenv);
-
- /* Return energy diff when boost margin is 0 */
- if (boost == 0)
- return eenv->nrg.diff;
-
- /* Compute normalized energy diff */
- nrg_delta = normalize_energy(eenv->nrg.diff);
- eenv->nrg.delta = nrg_delta;
-
- eenv->payoff = schedtune_accept_deltas(
- eenv->nrg.delta,
- eenv->cap.delta,
- eenv->task);
-
- trace_sched_energy_diff(eenv->task,
- eenv->src_cpu, eenv->dst_cpu, eenv->util_delta,
- eenv->nrg.before, eenv->nrg.after, eenv->nrg.diff,
- eenv->cap.before, eenv->cap.after, eenv->cap.delta,
- eenv->nrg.delta, eenv->payoff);
-
- /*
- * When SchedTune is enabled, the energy_diff() function will return
- * the computed energy payoff value. Since the energy_diff() return
- * value is expected to be negative by its callers, this evaluation
- * function return a negative value each time the evaluation return a
- * positive payoff, which is the condition for the acceptance of
- * a scheduling decision
- */
- return -eenv->payoff;
-}
-#else /* CONFIG_SCHED_TUNE */
-#define energy_diff(eenv) __energy_diff(eenv)
-#endif
-
/*
* Detect M:N waker/wakee relationships via a switching-frequency heuristic.
*
@@ -6170,7 +6121,7 @@
return 1;
}
-static inline unsigned long boosted_task_util(struct task_struct *task);
+static inline unsigned long boosted_task_util(struct task_struct *p);
static inline bool __task_fits(struct task_struct *p, int cpu, int util)
{
@@ -6201,20 +6152,14 @@
return __task_fits(p, cpu, 0);
}
-static inline bool task_fits_spare(struct task_struct *p, int cpu)
+bool __cpu_overutilized(int cpu, int delta)
{
- return __task_fits(p, cpu, cpu_util(cpu));
-}
-
-bool __cpu_overutilized(int cpu, unsigned long util)
-{
- return (capacity_orig_of(cpu) * 1024 <
- util * sysctl_sched_capacity_margin);
+ return (capacity_of(cpu) * 1024) < ((cpu_util(cpu) + delta) * capacity_margin);
}
bool cpu_overutilized(int cpu)
{
- return __cpu_overutilized(cpu, cpu_util(cpu));
+ return __cpu_overutilized(cpu, 0);
}
#ifdef CONFIG_SCHED_TUNE
@@ -6259,16 +6204,16 @@
}
static inline long
-schedtune_task_margin(struct task_struct *task)
+schedtune_task_margin(struct task_struct *p)
{
- int boost = schedtune_task_boost(task);
+ int boost = schedtune_task_boost(p);
unsigned long util;
long margin;
if (boost == 0)
return 0;
- util = task_util(task);
+ util = task_util(p);
margin = schedtune_margin(util, boost);
return margin;
@@ -6283,7 +6228,7 @@
}
static inline int
-schedtune_task_margin(struct task_struct *task)
+schedtune_task_margin(struct task_struct *p)
{
return 0;
}
@@ -6291,9 +6236,9 @@
#endif /* CONFIG_SCHED_TUNE */
unsigned long
-boosted_cpu_util(int cpu)
+boosted_cpu_util(int cpu, struct sched_walt_cpu_load *walt_load)
{
- unsigned long util = cpu_util_freq(cpu, NULL);
+ unsigned long util = cpu_util_freq(cpu, walt_load);
long margin = schedtune_cpu_margin(util, cpu);
trace_sched_boost_cpu(cpu, util, margin);
@@ -6302,41 +6247,48 @@
}
static inline unsigned long
-boosted_task_util(struct task_struct *task)
+boosted_task_util(struct task_struct *p)
{
- unsigned long util = task_util(task);
- long margin = schedtune_task_margin(task);
+ unsigned long util = task_util(p);
+ long margin = schedtune_task_margin(p);
- trace_sched_boost_task(task, util, margin);
+ trace_sched_boost_task(p, util, margin);
return util + margin;
}
+static unsigned long capacity_spare_wake(int cpu, struct task_struct *p)
+{
+ return capacity_orig_of(cpu) - cpu_util_wake(cpu, p);
+}
+
/*
* find_idlest_group finds and returns the least busy CPU group within the
* domain.
+ *
+ * Assumes p is allowed on at least one CPU in sd.
*/
static struct sched_group *
find_idlest_group(struct sched_domain *sd, struct task_struct *p,
int this_cpu, int sd_flag)
{
struct sched_group *idlest = NULL, *group = sd->groups;
- struct sched_group *fit_group = NULL, *spare_group = NULL;
- unsigned long min_load = ULONG_MAX, this_load = 0;
- unsigned long fit_capacity = ULONG_MAX;
- unsigned long max_spare_capacity;
-
+ struct sched_group *most_spare_sg = NULL;
+ unsigned long min_runnable_load = ULONG_MAX;
+ unsigned long this_runnable_load = ULONG_MAX;
+ unsigned long min_avg_load = ULONG_MAX, this_avg_load = ULONG_MAX;
+ unsigned long most_spare = 0, this_spare = 0;
int load_idx = sd->forkexec_idx;
- int imbalance = 100 + (sd->imbalance_pct-100)/2;
-
- max_spare_capacity = sysctl_sched_capacity_margin -
- SCHED_CAPACITY_SCALE;
+ int imbalance_scale = 100 + (sd->imbalance_pct-100)/2;
+ unsigned long imbalance = scale_load_down(NICE_0_LOAD) *
+ (sd->imbalance_pct-100) / 100;
if (sd_flag & SD_BALANCE_WAKE)
load_idx = sd->wake_idx;
do {
- unsigned long load, avg_load, spare_capacity;
+ unsigned long load, avg_load, runnable_load;
+ unsigned long spare_cap, max_spare_cap;
int local_group;
int i;
@@ -6348,8 +6300,13 @@
local_group = cpumask_test_cpu(this_cpu,
sched_group_cpus(group));
- /* Tally up the load of all CPUs in the group */
+ /*
+ * Tally up the load of all CPUs in the group and find
+ * the group containing the CPU with most spare capacity.
+ */
avg_load = 0;
+ runnable_load = 0;
+ max_spare_cap = 0;
for_each_cpu(i, sched_group_cpus(group)) {
/* Bias balancing toward cpus of our domain */
@@ -6358,55 +6315,85 @@
else
load = target_load(i, load_idx);
- avg_load += load;
+ runnable_load += load;
- /*
- * Look for most energy-efficient group that can fit
- * that can fit the task.
- */
- if (capacity_of(i) < fit_capacity && task_fits_spare(p, i)) {
- fit_capacity = capacity_of(i);
- fit_group = group;
- }
+ avg_load += cfs_rq_load_avg(&cpu_rq(i)->cfs);
- /*
- * Look for group which has most spare capacity on a
- * single cpu.
- */
- spare_capacity = capacity_of(i) - cpu_util(i);
- if (spare_capacity > max_spare_capacity) {
- max_spare_capacity = spare_capacity;
- spare_group = group;
- }
+ spare_cap = capacity_spare_wake(i, p);
+
+ if (spare_cap > max_spare_cap)
+ max_spare_cap = spare_cap;
}
/* Adjust by relative CPU capacity of the group */
- avg_load = (avg_load * SCHED_CAPACITY_SCALE) / group->sgc->capacity;
+ avg_load = (avg_load * SCHED_CAPACITY_SCALE) /
+ group->sgc->capacity;
+ runnable_load = (runnable_load * SCHED_CAPACITY_SCALE) /
+ group->sgc->capacity;
if (local_group) {
- this_load = avg_load;
- } else if (avg_load < min_load) {
- min_load = avg_load;
- idlest = group;
+ this_runnable_load = runnable_load;
+ this_avg_load = avg_load;
+ this_spare = max_spare_cap;
+ } else {
+ if (min_runnable_load > (runnable_load + imbalance)) {
+ /*
+ * The runnable load is significantly smaller
+ * so we can pick this new cpu
+ */
+ min_runnable_load = runnable_load;
+ min_avg_load = avg_load;
+ idlest = group;
+ } else if ((runnable_load < (min_runnable_load + imbalance)) &&
+ (100*min_avg_load > imbalance_scale*avg_load)) {
+ /*
+ * The runnable loads are close so we take
+ * into account blocked load through avg_load
+ * which is blocked + runnable load
+ */
+ min_avg_load = avg_load;
+ idlest = group;
+ }
+
+ if (most_spare < max_spare_cap) {
+ most_spare = max_spare_cap;
+ most_spare_sg = group;
+ }
}
} while (group = group->next, group != sd->groups);
- if (fit_group)
- return fit_group;
+ /*
+ * The cross-over point between using spare capacity or least load
+ * is too conservative for high utilization tasks on partially
+ * utilized systems if we require spare_capacity > task_util(p),
+ * so we allow for some task stuffing by using
+ * spare_capacity > task_util(p)/2.
+ * spare capacity can't be used for fork because the utilization has
+ * not been set yet as it need to get a rq to init the utilization
+ */
+ if (sd_flag & SD_BALANCE_FORK)
+ goto skip_spare;
- if (spare_group)
- return spare_group;
+ if (this_spare > task_util(p) / 2 &&
+ imbalance_scale*this_spare > 100*most_spare)
+ return NULL;
+ else if (most_spare > task_util(p) / 2)
+ return most_spare_sg;
- if (!idlest || 100*this_load < imbalance*min_load)
+skip_spare:
+ if (!idlest ||
+ (min_runnable_load > (this_runnable_load + imbalance)) ||
+ ((this_runnable_load < (min_runnable_load + imbalance)) &&
+ (100*this_avg_load < imbalance_scale*min_avg_load)))
return NULL;
return idlest;
}
/*
- * find_idlest_cpu - find the idlest cpu among the cpus in group.
+ * find_idlest_group_cpu - find the idlest cpu among the cpus in group.
*/
static int
-find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
+find_idlest_group_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
{
unsigned long load, min_load = ULONG_MAX;
unsigned int min_exit_latency = UINT_MAX;
@@ -6421,7 +6408,7 @@
/* Traverse only the allowed CPUs */
for_each_cpu_and(i, sched_group_cpus(group), tsk_cpus_allowed(p)) {
- if (task_fits_spare(p, i)) {
+ if (idle_cpu(i)) {
struct rq *rq = cpu_rq(i);
struct cpuidle_state *idle = idle_get_state(rq);
if (idle && idle->exit_latency < min_exit_latency) {
@@ -6433,8 +6420,7 @@
min_exit_latency = idle->exit_latency;
latest_idle_timestamp = rq->idle_stamp;
shallowest_idle_cpu = i;
- } else if (idle_cpu(i) &&
- (!idle || idle->exit_latency == min_exit_latency) &&
+ } else if ((!idle || idle->exit_latency == min_exit_latency) &&
rq->idle_stamp > latest_idle_timestamp) {
/*
* If equal or no active idle state, then
@@ -6443,13 +6429,6 @@
*/
latest_idle_timestamp = rq->idle_stamp;
shallowest_idle_cpu = i;
- } else if (shallowest_idle_cpu == -1) {
- /*
- * If we haven't found an idle CPU yet
- * pick a non-idle one that can fit the task as
- * fallback.
- */
- shallowest_idle_cpu = i;
}
} else if (shallowest_idle_cpu == -1) {
load = weighted_cpuload(i);
@@ -6463,6 +6442,68 @@
return shallowest_idle_cpu != -1 ? shallowest_idle_cpu : least_loaded_cpu;
}
+static inline int find_idlest_cpu(struct sched_domain *sd, struct task_struct *p,
+ int cpu, int prev_cpu, int sd_flag)
+{
+ int wu = sd_flag & SD_BALANCE_WAKE;
+ int cas_cpu = -1;
+ int new_cpu = cpu;
+
+ if (wu) {
+ schedstat_inc(p->se.statistics.nr_wakeups_cas_attempts);
+ schedstat_inc(this_rq()->eas_stats.cas_attempts);
+ }
+
+ if (!cpumask_intersects(sched_domain_span(sd), &p->cpus_allowed))
+ return prev_cpu;
+
+ while (sd) {
+ struct sched_group *group;
+ struct sched_domain *tmp;
+ int weight;
+
+ if (wu)
+ schedstat_inc(sd->eas_stats.cas_attempts);
+
+ if (!(sd->flags & sd_flag)) {
+ sd = sd->child;
+ continue;
+ }
+
+ group = find_idlest_group(sd, p, cpu, sd_flag);
+ if (!group) {
+ sd = sd->child;
+ continue;
+ }
+
+ new_cpu = find_idlest_group_cpu(group, p, cpu);
+ if (new_cpu == cpu) {
+ /* Now try balancing at a lower domain level of cpu */
+ sd = sd->child;
+ continue;
+ }
+
+ /* Now try balancing at a lower domain level of new_cpu */
+ cpu = cas_cpu = new_cpu;
+ weight = sd->span_weight;
+ sd = NULL;
+ for_each_domain(cpu, tmp) {
+ if (weight <= tmp->span_weight)
+ break;
+ if (tmp->flags & sd_flag)
+ sd = tmp;
+ }
+ /* while loop will break here if sd == NULL */
+ }
+
+ if (wu && (cas_cpu >= 0)) {
+ schedstat_inc(p->se.statistics.nr_wakeups_cas_count);
+ schedstat_inc(this_rq()->eas_stats.cas_count);
+ }
+
+ return new_cpu;
+}
+
#ifdef CONFIG_SCHED_SMT
static inline void set_idle_cores(int cpu, int val)
@@ -6538,7 +6579,7 @@
idle = false;
}
- if (!cpu_isolated(cpu) && idle)
+ if (idle)
return core;
}
@@ -6560,8 +6601,6 @@
for_each_cpu(cpu, cpu_smt_mask(target)) {
if (!cpumask_test_cpu(cpu, tsk_cpus_allowed(p)))
continue;
- if (cpu_isolated(cpu))
- continue;
if (idle_cpu(cpu))
return cpu;
}
@@ -6614,8 +6653,6 @@
for_each_cpu_wrap(cpu, sched_domain_span(sd), target) {
if (!cpumask_test_cpu(cpu, tsk_cpus_allowed(p)))
continue;
- if (cpu_isolated(cpu))
- continue;
if (idle_cpu(cpu))
break;
}
@@ -6644,7 +6681,7 @@
schedstat_inc(this_rq()->eas_stats.sis_attempts);
if (!sysctl_sched_cstate_aware) {
- if (idle_cpu(target) && !cpu_isolated(target)) {
+ if (idle_cpu(target)) {
schedstat_inc(p->se.statistics.nr_wakeups_sis_idle);
schedstat_inc(this_rq()->eas_stats.sis_idle);
return target;
@@ -6653,8 +6690,7 @@
/*
* If the prevous cpu is cache affine and idle, don't be stupid.
*/
- if (i != target && cpus_share_cache(i, target) &&
- idle_cpu(i) && !cpu_isolated(i)) {
+ if (i != target && cpus_share_cache(i, target) && idle_cpu(i)) {
schedstat_inc(p->se.statistics.nr_wakeups_sis_cache_affine);
schedstat_inc(this_rq()->eas_stats.sis_cache_affine);
return i;
@@ -6695,9 +6731,6 @@
unsigned long new_usage = boosted_task_util(p);
unsigned long capacity_orig = capacity_orig_of(i);
- if (cpu_isolated(i))
- continue;
-
if (new_usage > capacity_orig || !idle_cpu(i))
goto next;
@@ -6717,9 +6750,6 @@
}
} else {
for_each_cpu(i, sched_group_cpus(sg)) {
- if (cpu_isolated(i))
- continue;
-
if (i == target || !idle_cpu(i))
goto next;
}
@@ -6747,463 +6777,654 @@
}
/*
- * Should task be woken to any available idle cpu?
- *
- * Waking tasks to idle cpu has mixed implications on both performance and
- * power. In many cases, scheduler can't estimate correctly impact of using idle
- * cpus on either performance or power. PF_WAKE_UP_IDLE allows external kernel
- * module to pass a strong hint to scheduler that the task in question should be
- * woken to idle cpu, generally to improve performance.
+ * cpu_util_wake: Compute cpu utilization with any contributions from
+ * the waking task p removed. check_for_migration() looks for a better CPU of
+ * rq->curr. For that case we should return cpu util with contributions from
+ * currently running task p removed.
*/
+static int cpu_util_wake(int cpu, struct task_struct *p)
+{
+ unsigned long util, capacity;
+
+#ifdef CONFIG_SCHED_WALT
+ /*
+ * WALT does not decay idle tasks in the same manner
+ * as PELT, so it makes little sense to subtract task
+ * utilization from cpu utilization. Instead just use
+ * cpu_util for this case.
+ */
+ if (!walt_disabled && sysctl_sched_use_walt_cpu_util &&
+ p->state == TASK_WAKING)
+ return cpu_util(cpu);
+#endif
+ /* Task has no contribution or is new */
+ if (cpu != task_cpu(p) || !p->se.avg.last_update_time)
+ return cpu_util(cpu);
+
+ capacity = capacity_orig_of(cpu);
+ util = max_t(long, cpu_util(cpu) - task_util(p), 0);
+
+ return (util >= capacity) ? capacity : util;
+}
+
+struct find_best_target_env {
+ struct cpumask *rtg_target;
+ bool need_idle;
+ bool placement_boost;
+ bool avoid_prev_cpu;
+};
+
+static bool is_packing_eligible(struct task_struct *p, int target_cpu,
+ struct find_best_target_env *fbt_env,
+ unsigned int target_cpus_count)
+{
+ unsigned long tutil, estimated_capacity;
+
+ if (fbt_env->placement_boost || fbt_env->need_idle)
+ return false;
+
+ if (target_cpus_count != 1)
+ return true;
+
+ if (task_in_cum_window_demand(cpu_rq(target_cpu), p))
+ tutil = 0;
+ else
+ tutil = task_util(p);
+
+ estimated_capacity = cpu_util_cum(target_cpu, tutil);
+ estimated_capacity = add_capacity_margin(estimated_capacity,
+ target_cpu);
+
+ /*
+ * If there is only one active CPU and it is already above its current
+ * capacity, avoid placing additional task on the CPU.
+ */
+ return (estimated_capacity <= capacity_curr_of(target_cpu));
+}
+
+static inline bool skip_sg(struct task_struct *p, struct sched_group *sg,
+ struct cpumask *rtg_target)
+{
+ int fcpu = group_first_cpu(sg);
+
+ /* Are all CPUs isolated in this group? */
+ if (!sg->group_weight)
+ return true;
+
+ if (!task_fits_max(p, fcpu))
+ return true;
+
+ if (rtg_target && !cpumask_test_cpu(fcpu, rtg_target))
+ return true;
+
+ return false;
+}
+
+static int start_cpu(bool boosted)
+{
+ struct root_domain *rd = cpu_rq(smp_processor_id())->rd;
+ int start_cpu;
+
+ start_cpu = boosted ? rd->max_cap_orig_cpu : rd->min_cap_orig_cpu;
+
+ return walt_start_cpu(start_cpu);
+}
+
+static inline int find_best_target(struct task_struct *p, int *backup_cpu,
+ bool boosted, bool prefer_idle,
+ struct find_best_target_env *fbt_env)
+{
+ unsigned long min_util = boosted_task_util(p);
+ unsigned long target_capacity = ULONG_MAX;
+ unsigned long min_wake_util = ULONG_MAX;
+ unsigned long target_max_spare_cap = 0;
+ unsigned long target_util = ULONG_MAX;
+ unsigned long best_active_util = ULONG_MAX;
+ unsigned long target_idle_max_spare_cap = 0;
+ int best_idle_cstate = INT_MAX;
+ struct sched_domain *sd;
+ struct sched_group *sg;
+ int best_active_cpu = -1;
+ int best_idle_cpu = -1;
+ int target_cpu = -1;
+ int cpu, i;
+ unsigned int active_cpus_count = 0;
+
+ *backup_cpu = -1;
+
+ schedstat_inc(p->se.statistics.nr_wakeups_fbt_attempts);
+ schedstat_inc(this_rq()->eas_stats.fbt_attempts);
+
+ /* Find start CPU based on boost value */
+ cpu = start_cpu(boosted);
+ if (cpu < 0) {
+ schedstat_inc(p->se.statistics.nr_wakeups_fbt_no_cpu);
+ schedstat_inc(this_rq()->eas_stats.fbt_no_cpu);
+ return -1;
+ }
+
+ /* Find SD for the start CPU */
+ sd = rcu_dereference(per_cpu(sd_ea, cpu));
+ if (!sd) {
+ schedstat_inc(p->se.statistics.nr_wakeups_fbt_no_sd);
+ schedstat_inc(this_rq()->eas_stats.fbt_no_sd);
+ return -1;
+ }
+
+ /* Scan CPUs in all SDs */
+ sg = sd->groups;
+ do {
+ cpumask_t search_cpus;
+ bool do_rotate = false, avoid_prev_cpu = false;
+
+ if (skip_sg(p, sg, fbt_env->rtg_target))
+ continue;
+
+ cpumask_copy(&search_cpus, tsk_cpus_allowed(p));
+ cpumask_and(&search_cpus, &search_cpus, sched_group_cpus(sg));
+ i = find_first_cpu_bit(p, &search_cpus, sg, &avoid_prev_cpu,
+ &do_rotate, &first_cpu_bit_env);
+ if (do_rotate)
+ fbt_env->avoid_prev_cpu = avoid_prev_cpu;
+
+retry:
+ while ((i = cpumask_next(i, &search_cpus)) < nr_cpu_ids) {
+ unsigned long capacity_curr = capacity_curr_of(i);
+ unsigned long capacity_orig = capacity_orig_of(i);
+ unsigned long wake_util, new_util, min_capped_util;
+
+ cpumask_clear_cpu(i, &search_cpus);
+ if (avoid_prev_cpu && i == task_cpu(p))
+ continue;
+
+ if (!cpu_online(i) || cpu_isolated(i) || is_reserved(i))
+ continue;
+
+ if (walt_cpu_high_irqload(i))
+ continue;
+
+ trace_sched_cpu_util(i);
+
+ /*
+ * p's blocked utilization is still accounted for on prev_cpu
+ * so prev_cpu will receive a negative bias due to the double
+ * accounting. However, the blocked utilization may be zero.
+ */
+ wake_util = cpu_util_wake(i, p);
+ new_util = wake_util + task_util(p);
+
+ /*
+ * Ensure minimum capacity to grant the required boost.
+ * The target CPU can be already at a capacity level higher
+ * than the one required to boost the task.
+ */
+ new_util = max(min_util, new_util);
+
+ /*
+ * Include minimum capacity constraint:
+ * new_util contains the required utilization including
+ * boost. min_capped_util also takes into account a
+ * minimum capacity cap imposed on the CPU by external
+ * actors.
+ */
+ min_capped_util = max(new_util, capacity_min_of(i));
+
+ if (new_util > capacity_orig)
+ continue;
+
+ /*
+ * Case A) Latency sensitive tasks
+ *
+ * Unconditionally favoring tasks that prefer idle CPU to
+ * improve latency.
+ *
+ * Looking for:
+ * - an idle CPU, whatever its idle_state is, since
+ * the first CPUs we explore are more likely to be
+ * reserved for latency sensitive tasks.
+ * - a non idle CPU where the task fits in its current
+ * capacity and has the maximum spare capacity.
+ * - a non idle CPU with lower contention from other
+ * tasks and running at the lowest possible OPP.
+ *
+ * The last two goals tries to favor a non idle CPU
+ * where the task can run as if it is "almost alone".
+ * A maximum spare capacity CPU is favoured since
+ * the task already fits into that CPU's capacity
+ * without waiting for an OPP chance.
+ *
+ * The following code path is the only one in the CPUs
+ * exploration loop which is always used by
+ * prefer_idle tasks. It exits the loop with wither a
+ * best_active_cpu or a target_cpu which should
+ * represent an optimal choice for latency sensitive
+ * tasks.
+ */
+ if (prefer_idle) {
+
+ /*
+ * Case A.1: IDLE CPU
+ * Return the first IDLE CPU we find.
+ */
+ if (idle_cpu(i)) {
+ schedstat_inc(p->se.statistics.nr_wakeups_fbt_pref_idle);
+ schedstat_inc(this_rq()->eas_stats.fbt_pref_idle);
+
+ trace_sched_find_best_target(p,
+ prefer_idle, min_util,
+ cpu, best_idle_cpu,
+ best_active_cpu, i);
+
+ return i;
+ }
+
+ /*
+ * Case A.2: Target ACTIVE CPU
+ * Favor CPUs with max spare capacity.
+ */
+ if ((capacity_curr > new_util) &&
+ (capacity_orig - new_util > target_max_spare_cap)) {
+ target_max_spare_cap = capacity_orig - new_util;
+ target_cpu = i;
+ continue;
+ }
+ if (target_cpu != -1)
+ continue;
+
+
+ /*
+ * Case A.3: Backup ACTIVE CPU
+ * Favor CPUs with:
+ * - lower utilization due to other tasks
+ * - lower utilization with the task in
+ */
+ if (wake_util > min_wake_util)
+ continue;
+ if (new_util > best_active_util)
+ continue;
+ min_wake_util = wake_util;
+ best_active_util = new_util;
+ best_active_cpu = i;
+ continue;
+ }
+
+ /*
+ * Favor CPUs with smaller capacity for Non latency
+ * sensitive tasks.
+ */
+ if (capacity_orig > target_capacity)
+ continue;
+
+ /*
+ * Case B) Non latency sensitive tasks on IDLE CPUs.
+ *
+ * Find an optimal backup IDLE CPU for non latency
+ * sensitive tasks.
+ *
+ * Looking for:
+ * - minimizing the capacity_orig,
+ * i.e. preferring LITTLE CPUs
+ * - favoring shallowest idle states
+ * i.e. avoid to wakeup deep-idle CPUs
+ *
+ * The following code path is used by non latency
+ * sensitive tasks if IDLE CPUs are available. If at
+ * least one of such CPUs are available it sets the
+ * best_idle_cpu to the most suitable idle CPU to be
+ * selected.
+ *
+ * If idle CPUs are available, favour these CPUs to
+ * improve performances by spreading tasks.
+ * Indeed, the energy_diff() computed by the caller
+ * will take care to ensure the minimization of energy
+ * consumptions without affecting performance.
+ */
+ if (idle_cpu(i)) {
+ int idle_idx = idle_get_state_idx(cpu_rq(i));
+
+ /* Favor CPUs that won't end up running at a
+ * high OPP.
+ */
+ if ((capacity_orig - min_capped_util) <
+ target_idle_max_spare_cap)
+ continue;
+
+ /*
+ * Skip CPUs in deeper idle state, but only
+ * if they are also less energy efficient.
+ * IOW, prefer a deep IDLE LITTLE CPU vs a
+ * shallow idle big CPU.
+ */
+ if (sysctl_sched_cstate_aware &&
+ best_idle_cstate <= idle_idx)
+ continue;
+
+ /* Keep track of best idle CPU */
+ target_capacity = capacity_orig;
+ target_idle_max_spare_cap = capacity_orig -
+ min_capped_util;
+ best_idle_cstate = idle_idx;
+ best_idle_cpu = i;
+ continue;
+ }
+
+ /*
+ * Case C) Non latency sensitive tasks on ACTIVE CPUs.
+ *
+ * Pack tasks in the most energy efficient capacities.
+ *
+ * This task packing strategy prefers more energy
+ * efficient CPUs (i.e. pack on smaller maximum
+ * capacity CPUs) while also trying to spread tasks to
+ * run them all at the lower OPP.
+ *
+ * This assumes for example that it's more energy
+ * efficient to run two tasks on two CPUs at a lower
+ * OPP than packing both on a single CPU but running
+ * that CPU at an higher OPP.
+ *
+ * Thus, this case keep track of the CPU with the
+ * smallest maximum capacity and highest spare maximum
+ * capacity.
+ */
+
+ active_cpus_count++;
+
+ /* Favor CPUs with maximum spare capacity */
+ if ((capacity_orig - min_capped_util) <
+ target_max_spare_cap)
+ continue;
+
+ target_max_spare_cap = capacity_orig - min_capped_util;
+ target_capacity = capacity_orig;
+ target_util = new_util;
+ target_cpu = i;
+ }
+
+ if (do_rotate) {
+ /*
+ * We started iteration somewhere in the middle of
+ * cpumask. Iterate once again from bit 0 to the
+ * previous starting point bit.
+ */
+ do_rotate = false;
+ i = -1;
+ goto retry;
+ }
+
+ if (!sysctl_sched_is_big_little && !prefer_idle) {
+
+ /*
+ * If we find an idle CPU in the primary cluster,
+ * stop the search. We select this idle CPU or
+ * the active CPU (if there is one), whichever
+ * saves the energy.
+ */
+ if (best_idle_cpu != -1)
+ break;
+
+ if (fbt_env->placement_boost) {
+ target_capacity = ULONG_MAX;
+ continue;
+ }
+
+ /*
+ * If we found an active CPU and its utilization
+ * is below the minimum packing threshold (overlap),
+ * no need to search further. Otherwise reset
+ * the target_capacity and continue the search.
+ */
+ if (target_cpu != -1 && target_util <
+ sched_smp_overlap_capacity)
+ break;
+
+ target_capacity = ULONG_MAX;
+ }
+ } while (sg = sg->next, sg != sd->groups);
+
+ if (best_idle_cpu != -1 && !is_packing_eligible(p, target_cpu, fbt_env,
+ active_cpus_count)) {
+ if (target_cpu == task_cpu(p))
+ fbt_env->avoid_prev_cpu = true;
+
+ target_cpu = best_idle_cpu;
+ best_idle_cpu = -1;
+ }
+
+ /*
+ * For non latency sensitive tasks, cases B and C in the previous loop,
+ * we pick the best IDLE CPU only if we was not able to find a target
+ * ACTIVE CPU.
+ *
+ * Policies priorities:
+ *
+ * - prefer_idle tasks:
+ *
+ * a) IDLE CPU available, we return immediately
+ * b) ACTIVE CPU where task fits and has the bigger maximum spare
+ * capacity (i.e. target_cpu)
+ * c) ACTIVE CPU with less contention due to other tasks
+ * (i.e. best_active_cpu)
+ *
+ * - NON prefer_idle tasks:
+ *
+ * a) ACTIVE CPU: target_cpu
+ * b) IDLE CPU: best_idle_cpu
+ */
+ if (target_cpu == -1)
+ target_cpu = prefer_idle
+ ? best_active_cpu
+ : best_idle_cpu;
+ else
+ *backup_cpu = prefer_idle
+ ? best_active_cpu
+ : best_idle_cpu;
+
+ trace_sched_find_best_target(p, prefer_idle, min_util, cpu,
+ best_idle_cpu, best_active_cpu,
+ target_cpu);
+
+ schedstat_inc(p->se.statistics.nr_wakeups_fbt_count);
+ schedstat_inc(this_rq()->eas_stats.fbt_count);
+
+ return target_cpu;
+}
+
+/*
+ * Disable WAKE_AFFINE in the case where task @p doesn't fit in the
+ * capacity of either the waking CPU @cpu or the previous CPU @prev_cpu.
+ *
+ * In that case WAKE_AFFINE doesn't make sense and we'll let
+ * BALANCE_WAKE sort things out.
+ */
+static int wake_cap(struct task_struct *p, int cpu, int prev_cpu)
+{
+ long min_cap, max_cap;
+ min_cap = min(capacity_orig_of(prev_cpu), capacity_orig_of(cpu));
+ max_cap = cpu_rq(cpu)->rd->max_cpu_capacity.val;
+ /* Minimum capacity is close to max, no need to abort wake_affine */
+ if (max_cap - min_cap < max_cap >> 3)
+ return 0;
+
+ /* Bring task utilization in sync with prev_cpu */
+ sync_entity_load_avg(&p->se);
+
+ return min_cap * 1024 < task_util(p) * capacity_margin;
+}
+
static inline int wake_to_idle(struct task_struct *p)
{
return (current->flags & PF_WAKE_UP_IDLE) ||
(p->flags & PF_WAKE_UP_IDLE);
}
-static bool
-is_packing_eligible(struct task_struct *p, unsigned long task_util,
- struct sched_group *sg_target,
- unsigned long target_cpu_new_util_cum,
- int targeted_cpus)
+static inline bool
+bias_to_waker_cpu(struct task_struct *p, int cpu, struct cpumask *rtg_target)
{
- int cpu_cap_idx_pack, cpu_cap_idx_spread, cap_idx0, cap_idx1;
+ int rtg_target_cpu = rtg_target ? cpumask_first(rtg_target) : cpu;
- if (targeted_cpus > 1)
- /*
- * More than one CPUs were evaulated and target_cpu is the
- * least loaded CPU among the CPUs. Thus target_cpu won't
- * raise OPP.
- */
- return true;
-
- /*
- * There is only one CPU out of C-state.
- *
- * cpu_cap_idx_pack contains estimated OPP index of target_cpu when we
- * pack the new task onto the target_cpu.
- * cap_idx0 and cap_idx1 contain OPP indices of two CPUs, one for
- * target_cpu without new task's load, one other for new idle CPU with
- * task's load.
- *
- * Pack : Spread :
- * cap_idx_pack is new OPP. max(cap_idx0, cap_idx1) is new OPP.
- * ________________ ________________
- * | | | | ______________
- * | cap_idx_pack | | cap_idx0 | | cap_idx1 |
- * | (target_cpu) | | (target_cpu) | | (idle cpu) |
- * ---------------- ---------------- --------------
- *
- * The target_cpu's current capacity can be much more than target_cpu's
- * current utilization due to for example hysteresis while task
- * migration. In that the case, packing onto the target_cpu based on
- * current capacity would deprive chance to lower the OPP and will end
- * up making target_cpu to keep the higher OOP longer than spreading.
- *
- * Try task packing only when packing won't make to keep the current
- * OPP longer than wihout packing.
- */
-
- cpu_cap_idx_pack = __find_new_capacity(target_cpu_new_util_cum,
- sg_target->sge);
-
- cap_idx0 = __find_new_capacity(target_cpu_new_util_cum - task_util,
- sg_target->sge);
- cap_idx1 = __find_new_capacity(task_util, sg_target->sge);
-
- cpu_cap_idx_spread = max(cap_idx0, cap_idx1);
-
- trace_sched_energy_diff_packing(p, task_util, targeted_cpus,
- cpu_cap_idx_pack, cpu_cap_idx_spread);
-
- return cpu_cap_idx_pack == cpu_cap_idx_spread;
+ 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);
}
-unsigned int sched_smp_overlap_capacity = SCHED_CAPACITY_SCALE;
-
-static int energy_aware_wake_cpu(struct task_struct *p, int target, int sync)
+static inline struct cpumask *find_rtg_target(struct task_struct *p)
{
- struct sched_domain *sd;
- struct sched_group *sg, *sg_target, *start_sg;
- int target_max_cap = INT_MAX;
- int target_cpu = -1, targeted_cpus = 0;
- unsigned long task_util_boosted = 0, curr_util = 0;
- long new_util, new_util_cum;
- int i;
- int ediff = -1;
- int cpu = smp_processor_id();
- int min_util_cpu = -1;
- int min_util_cpu_idle_idx = INT_MAX;
- long min_util_cpu_util_cum = LONG_MAX;
- unsigned int min_util = UINT_MAX;
- int cpu_idle_idx;
- int min_idle_idx_cpu;
- int min_idle_idx = INT_MAX;
- bool safe_to_pack = false;
- unsigned int target_cpu_util = UINT_MAX;
- long target_cpu_new_util_cum = LONG_MAX;
- struct cpumask *rtg_target = NULL;
- int isolated_candidate = -1;
- bool need_idle;
- enum sched_boost_policy placement_boost = task_sched_boost(p) ?
- sched_boost_policy() : SCHED_BOOST_NONE;
struct related_thread_group *grp;
- cpumask_t search_cpus;
- int prev_cpu = task_cpu(p);
- int start_cpu = walt_start_cpu(prev_cpu);
- bool do_rotate = false;
- bool avoid_prev_cpu = false;
+ struct cpumask *rtg_target;
- sd = rcu_dereference(per_cpu(sd_ea, start_cpu));
+ rcu_read_lock();
- if (!sd)
- return target;
-
- sg = sd->groups;
- sg_target = sg;
-
- sync = sync && sysctl_sched_sync_hint_enable;
-
- curr_util = boosted_task_util(cpu_rq(cpu)->curr);
-
- need_idle = wake_to_idle(p) || schedtune_prefer_idle(p);
- if (need_idle)
- sync = 0;
grp = task_related_thread_group(p);
- if (grp && grp->preferred_cluster)
+ 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, prev_cpu,
- task_util(p), cpu, cpu, 0, need_idle);
- return cpu;
+ if (!task_fits_max(p, cpumask_first(rtg_target)))
+ rtg_target = NULL;
+ } else {
+ rtg_target = NULL;
}
- task_util_boosted = boosted_task_util(p);
- if (sysctl_sched_is_big_little) {
- /*
- * Find group with sufficient capacity. We only get here if no cpu is
- * overutilized. We may end up overutilizing a cpu by adding the task,
- * but that should not be any worse than select_idle_sibling().
- * load_balance() should sort it out later as we get above the tipping
- * point.
- */
- do {
- int max_cap_cpu;
- cpumask_t avail_cpus;
+ rcu_read_unlock();
- /* Are all CPUs isolated in this group? */
- if (unlikely(!sg->group_weight))
- continue;
+ return rtg_target;
+}
- /* Can this task run on any CPUs of this group? */
- cpumask_and(&avail_cpus, sched_group_cpus(sg),
- tsk_cpus_allowed(p));
- cpumask_andnot(&avail_cpus, &avail_cpus,
- cpu_isolated_mask);
- if (cpumask_empty(&avail_cpus))
- continue;
+static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync)
+{
+ bool boosted, prefer_idle;
+ struct sched_domain *sd;
+ int target_cpu;
+ int backup_cpu = -1;
+ int next_cpu = -1;
+ struct cpumask *rtg_target = find_rtg_target(p);
+ struct find_best_target_env fbt_env;
- /* Assuming all cpus are the same in group */
- max_cap_cpu = group_first_cpu(sg);
+ schedstat_inc(p->se.statistics.nr_wakeups_secb_attempts);
+ schedstat_inc(this_rq()->eas_stats.secb_attempts);
- /*
- * Assume smaller max capacity means more energy-efficient.
- * Ideally we should query the energy model for the right
- * answer but it easily ends up in an exhaustive search.
- */
- if (capacity_orig_of(max_cap_cpu) < target_max_cap &&
- task_fits_max(p, max_cap_cpu)) {
- sg_target = sg;
+#ifdef CONFIG_CGROUP_SCHEDTUNE
+ boosted = schedtune_task_boost(p) > 0;
+ prefer_idle = schedtune_prefer_idle(p) > 0;
+#else
+ boosted = get_sysctl_sched_cfs_boost() > 0;
+ prefer_idle = 0;
+#endif
- if (rtg_target) {
- /*
- * For tasks that belong to a related
- * thread group, select the preferred
- * cluster if the task can fit there,
- * otherwise select the cluster which
- * can fit the task.
- */
- if (cpumask_test_cpu(max_cap_cpu,
- rtg_target))
- break;
- continue;
- }
-
- target_max_cap = capacity_of(max_cap_cpu);
- }
- } while (sg = sg->next, sg != sd->groups);
+ fbt_env.rtg_target = rtg_target;
+ if (sched_feat(EAS_USE_NEED_IDLE) && prefer_idle) {
+ fbt_env.need_idle = true;
+ prefer_idle = false;
+ } else {
+ fbt_env.need_idle = wake_to_idle(p);
}
+ fbt_env.placement_boost = task_sched_boost(p) ?
+ sched_boost_policy() != SCHED_BOOST_NONE :
+ false;
+ fbt_env.avoid_prev_cpu = false;
- start_sg = sg_target;
-next_sg:
- cpumask_copy(&search_cpus, tsk_cpus_allowed(p));
- cpumask_and(&search_cpus, &search_cpus,
- sched_group_cpus(sg_target));
+ if (prefer_idle || fbt_env.need_idle)
+ sync = 0;
- i = find_first_cpu_bit(p, &search_cpus, sg_target,
- &avoid_prev_cpu, &do_rotate,
- &first_cpu_bit_env);
+ if (sysctl_sched_sync_hint_enable && sync) {
+ int cpu = smp_processor_id();
-retry:
- /* Find cpu with sufficient capacity */
- while ((i = cpumask_next(i, &search_cpus)) < nr_cpu_ids) {
- cpumask_clear_cpu(i, &search_cpus);
-
- if (cpu_isolated(i))
- continue;
-
- if (isolated_candidate == -1)
- isolated_candidate = i;
-
- if (avoid_prev_cpu && i == prev_cpu)
- continue;
-
- if (is_reserved(i))
- continue;
-
- if (sched_cpu_high_irqload(i))
- continue;
-
- /*
- * Since this code is inside sched_is_big_little,
- * we are going to assume that boost policy is
- * SCHED_BOOST_ON_BIG.
- */
- if (placement_boost != SCHED_BOOST_NONE) {
- new_util = cpu_util(i);
- if (new_util < min_util) {
- min_util_cpu = i;
- min_util = new_util;
- }
- continue;
- }
-
- /*
- * p's blocked utilization is still accounted for on prev_cpu
- * so prev_cpu will receive a negative bias due to the double
- * accounting. However, the blocked utilization may be zero.
- */
- new_util = cpu_util(i) + task_util_boosted;
-
- if (task_in_cum_window_demand(cpu_rq(i), p))
- new_util_cum = cpu_util_cum(i, 0) +
- task_util_boosted - task_util(p);
- else
- new_util_cum = cpu_util_cum(i, 0) +
- task_util_boosted;
-
- if (sync && i == cpu)
- new_util -= curr_util;
-
- trace_sched_cpu_util(p, i, task_util_boosted, curr_util,
- new_util_cum, sync);
-
- /*
- * Ensure minimum capacity to grant the required boost.
- * The target CPU can be already at a capacity level higher
- * than the one required to boost the task.
- */
- if (new_util > capacity_orig_of(i))
- continue;
-
- cpu_idle_idx = idle_get_state_idx(cpu_rq(i));
-
- if (!need_idle &&
- add_capacity_margin(new_util_cum, i) <
- capacity_curr_of(i)) {
- if (sysctl_sched_cstate_aware) {
- if (cpu_idle_idx < min_idle_idx) {
- min_idle_idx = cpu_idle_idx;
- min_idle_idx_cpu = i;
- target_cpu = i;
- target_cpu_util = new_util;
- target_cpu_new_util_cum =
- new_util_cum;
- targeted_cpus = 1;
- } else if (cpu_idle_idx ==
- min_idle_idx &&
- (target_cpu_util >
- new_util ||
- (target_cpu_util ==
- new_util &&
- (i == prev_cpu ||
- (target_cpu !=
- prev_cpu &&
- target_cpu_new_util_cum >
- new_util_cum))))) {
- min_idle_idx_cpu = i;
- target_cpu = i;
- target_cpu_util = new_util;
- target_cpu_new_util_cum =
- new_util_cum;
- targeted_cpus++;
- }
- } else if (cpu_rq(i)->nr_running) {
- target_cpu = i;
- do_rotate = false;
- break;
- }
- } else if (!need_idle) {
- /*
- * At least one CPU other than target_cpu is
- * going to raise CPU's OPP higher than current
- * because current CPU util is more than current
- * capacity + margin. We can safely do task
- * packing without worrying about doing such
- * itself raises OPP.
- */
- safe_to_pack = true;
- }
-
- /*
- * cpu has capacity at higher OPP, keep it as
- * fallback.
- */
- if (new_util < min_util) {
- min_util_cpu = i;
- min_util = new_util;
- min_util_cpu_idle_idx = cpu_idle_idx;
- min_util_cpu_util_cum = new_util_cum;
- } else if (sysctl_sched_cstate_aware &&
- min_util == new_util) {
- if (min_util_cpu == task_cpu(p))
- continue;
-
- if (i == task_cpu(p) ||
- (cpu_idle_idx < min_util_cpu_idle_idx ||
- (cpu_idle_idx == min_util_cpu_idle_idx &&
- min_util_cpu_util_cum > new_util_cum))) {
- min_util_cpu = i;
- min_util_cpu_idle_idx = cpu_idle_idx;
- min_util_cpu_util_cum = new_util_cum;
- }
+ if (bias_to_waker_cpu(p, cpu, rtg_target)) {
+ schedstat_inc(p->se.statistics.nr_wakeups_secb_sync);
+ schedstat_inc(this_rq()->eas_stats.secb_sync);
+ return cpu;
}
}
- if (do_rotate) {
- /*
- * We started iteration somewhere in the middle of
- * cpumask. Iterate once again from bit 0 to the
- * previous starting point bit.
- */
- do_rotate = false;
- i = -1;
- goto retry;
+ rcu_read_lock();
+
+ sd = rcu_dereference(per_cpu(sd_ea, prev_cpu));
+ if (!sd) {
+ target_cpu = prev_cpu;
+ goto unlock;
}
- /*
- * If we don't find a CPU that fits this task without
- * increasing OPP above sched_smp_overlap_capacity or
- * when placement boost is active, expand the search to
- * the other groups on a SMP system.
- */
- if (!sysctl_sched_is_big_little &&
- (placement_boost == SCHED_BOOST_ON_ALL ||
- (target_cpu == -1 && min_util_cpu_util_cum >
- sched_smp_overlap_capacity))) {
- if (sg_target->next != start_sg) {
- sg_target = sg_target->next;
- goto next_sg;
- }
+ sync_entity_load_avg(&p->se);
+
+ /* Find a cpu with sufficient capacity */
+ next_cpu = find_best_target(p, &backup_cpu, boosted, prefer_idle,
+ &fbt_env);
+ if (next_cpu == -1) {
+ target_cpu = prev_cpu;
+ goto unlock;
}
- if (target_cpu == -1 ||
- (target_cpu != min_util_cpu && !safe_to_pack &&
- !is_packing_eligible(p, task_util_boosted, sg_target,
- target_cpu_new_util_cum,
- targeted_cpus))) {
- if (likely(min_util_cpu != -1))
- target_cpu = min_util_cpu;
- else if (cpu_isolated(task_cpu(p)) &&
- isolated_candidate != -1)
- target_cpu = isolated_candidate;
- else
- target_cpu = task_cpu(p);
+ if (fbt_env.placement_boost || fbt_env.need_idle ||
+ fbt_env.avoid_prev_cpu || (rtg_target &&
+ !cpumask_test_cpu(prev_cpu, rtg_target))) {
+ target_cpu = next_cpu;
+ goto unlock;
}
- if (target_cpu != task_cpu(p) && !avoid_prev_cpu &&
- !cpu_isolated(task_cpu(p))) {
+ /* Unconditionally prefer IDLE CPUs for boosted/prefer_idle tasks */
+ if ((boosted || prefer_idle) && idle_cpu(next_cpu)) {
+ schedstat_inc(p->se.statistics.nr_wakeups_secb_idle_bt);
+ schedstat_inc(this_rq()->eas_stats.secb_idle_bt);
+ target_cpu = next_cpu;
+ goto unlock;
+ }
+
+ target_cpu = prev_cpu;
+ if (next_cpu != prev_cpu) {
+ int delta = 0;
struct energy_env eenv = {
- .util_delta = task_util(p),
- .src_cpu = task_cpu(p),
- .dst_cpu = target_cpu,
- .task = p,
- .sync_cpu = sync ? smp_processor_id() : -1,
- .curr_util = curr_util,
+ .p = p,
+ .util_delta = task_util(p),
+ /* Task's previous CPU candidate */
+ .cpu[EAS_CPU_PRV] = {
+ .cpu_id = prev_cpu,
+ },
+ /* Main alternative CPU candidate */
+ .cpu[EAS_CPU_NXT] = {
+ .cpu_id = next_cpu,
+ },
+ /* Backup alternative CPU candidate */
+ .cpu[EAS_CPU_BKP] = {
+ .cpu_id = backup_cpu,
+ },
};
- /*
- * We always want to migrate the task to the preferred cluster.
- */
- if (rtg_target) {
- trace_sched_task_util_colocated(p, task_cpu(p),
- task_util(p),
- cpumask_first(rtg_target),
- target_cpu, 0, need_idle);
- return target_cpu;
- }
-
- if (need_idle) {
- trace_sched_task_util_need_idle(p, task_cpu(p),
- task_util(p),
- target_cpu, target_cpu,
- 0, need_idle);
- return target_cpu;
- }
-
- /*
- * We always want to migrate the task to the best CPU when
- * placement boost is active.
- */
- if (placement_boost) {
- trace_sched_task_util_boosted(p, task_cpu(p),
- task_util(p),
- target_cpu,
- target_cpu, 0, need_idle);
- return target_cpu;
- }
#ifdef CONFIG_SCHED_WALT
- if (walt_disabled || !sysctl_sched_use_walt_cpu_util)
- task_util_boosted = 0;
-#else
- task_util_boosted = 0;
+ if (!walt_disabled && sysctl_sched_use_walt_cpu_util &&
+ p->state == TASK_WAKING)
+ delta = task_util(p);
#endif
/* Not enough spare capacity on previous cpu */
- if (__cpu_overutilized(task_cpu(p),
- cpu_util(task_cpu(p)) +
- task_util_boosted)) {
- trace_sched_task_util_overutilzed(p, task_cpu(p),
- task_util(p), target_cpu,
- target_cpu, 0, need_idle);
- return target_cpu;
+ if (__cpu_overutilized(prev_cpu, delta)) {
+ schedstat_inc(p->se.statistics.nr_wakeups_secb_insuff_cap);
+ schedstat_inc(this_rq()->eas_stats.secb_insuff_cap);
+ target_cpu = next_cpu;
+ goto unlock;
}
- ediff = energy_diff(&eenv);
-
- if (!sysctl_sched_cstate_aware) {
- if (ediff >= 0) {
- trace_sched_task_util_energy_diff(p,
- task_cpu(p), task_util(p),
- target_cpu, task_cpu(p), ediff,
- need_idle);
- return task_cpu(p);
- }
- } else {
- if (ediff > 0) {
- trace_sched_task_util_energy_diff(p,
- task_cpu(p), task_util(p),
- target_cpu, task_cpu(p), ediff,
- need_idle);
- return task_cpu(p);
- }
+ /* Check if EAS_CPU_NXT is a more energy efficient CPU */
+ if (select_energy_cpu_idx(&eenv) != EAS_CPU_PRV) {
+ schedstat_inc(p->se.statistics.nr_wakeups_secb_nrg_sav);
+ schedstat_inc(this_rq()->eas_stats.secb_nrg_sav);
+ target_cpu = eenv.cpu[eenv.next_idx].cpu_id;
+ goto unlock;
}
+
+ schedstat_inc(p->se.statistics.nr_wakeups_secb_no_nrg_sav);
+ schedstat_inc(this_rq()->eas_stats.secb_no_nrg_sav);
+ target_cpu = prev_cpu;
+ goto unlock;
}
- trace_sched_task_util_energy_aware(p, task_cpu(p), task_util(p),
- target_cpu, target_cpu, ediff,
- need_idle);
+ schedstat_inc(p->se.statistics.nr_wakeups_secb_count);
+ schedstat_inc(this_rq()->eas_stats.secb_count);
+
+unlock:
+ trace_sched_task_util(p, next_cpu, backup_cpu, target_cpu, sync,
+ fbt_env.need_idle, fbt_env.placement_boost,
+ rtg_target ? cpumask_first(rtg_target) : -1);
+ rcu_read_unlock();
return target_cpu;
}
@@ -7228,20 +7449,15 @@
int want_affine = 0;
int sync = wake_flags & WF_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);
- want_affine = (!wake_wide(p) && task_fits_max(p, cpu) &&
- cpumask_test_cpu(cpu, tsk_cpus_allowed(p))) ||
- energy_aware();
+ want_affine = (!wake_wide(p) && !wake_cap(p, cpu, prev_cpu) &&
+ cpumask_test_cpu(cpu, tsk_cpus_allowed(p)));
}
+ if (energy_aware())
+ return select_energy_cpu_brute(p, prev_cpu, sync);
+
rcu_read_lock();
for_each_domain(cpu, tmp) {
if (!(tmp->flags & SD_LOAD_BALANCE))
@@ -7269,45 +7485,21 @@
new_cpu = cpu;
}
+ if (sd && !(sd_flag & SD_BALANCE_FORK)) {
+ /*
+ * We're going to need the task's util for capacity_spare_wake
+ * in find_idlest_group. Sync it up to prev_cpu's
+ * last_update_time.
+ */
+ sync_entity_load_avg(&p->se);
+ }
+
if (!sd) {
- if (energy_aware() && !cpu_rq(cpu)->rd->overutilized)
- new_cpu = energy_aware_wake_cpu(p, prev_cpu, sync);
- else if (sd_flag & SD_BALANCE_WAKE) /* XXX always ? */
+ if (sd_flag & SD_BALANCE_WAKE) /* XXX always ? */
new_cpu = select_idle_sibling(p, prev_cpu, new_cpu);
- } else while (sd) {
- struct sched_group *group;
- int weight;
-
- if (!(sd->flags & sd_flag)) {
- sd = sd->child;
- continue;
- }
-
- group = find_idlest_group(sd, p, cpu, sd_flag);
- if (!group) {
- sd = sd->child;
- continue;
- }
-
- new_cpu = find_idlest_cpu(group, p, cpu);
- if (new_cpu == -1 || new_cpu == cpu) {
- /* Now try balancing at a lower domain level of cpu */
- sd = sd->child;
- continue;
- }
-
- /* Now try balancing at a lower domain level of new_cpu */
- cpu = new_cpu;
- weight = sd->span_weight;
- sd = NULL;
- for_each_domain(cpu, tmp) {
- if (weight <= tmp->span_weight)
- break;
- if (tmp->flags & sd_flag)
- sd = tmp;
- }
- /* while loop will break here if sd == NULL */
+ } else {
+ new_cpu = find_idlest_cpu(sd, p, cpu, prev_cpu, sd_flag);
}
rcu_read_unlock();
@@ -8271,10 +8463,6 @@
{
raw_spin_lock(&rq->lock);
attach_task(rq, p);
- /*
- * We want to potentially raise target_cpu's OPP.
- */
- update_capacity_of(cpu_of(rq));
raw_spin_unlock(&rq->lock);
}
@@ -8296,11 +8484,6 @@
attach_task(env->dst_rq, p);
}
- /*
- * We want to potentially raise env.dst_cpu's OPP.
- */
- update_capacity_of(env->dst_cpu);
-
raw_spin_unlock(&env->dst_rq->lock);
}
@@ -8536,6 +8719,9 @@
cpu_rq(cpu)->cpu_capacity_orig = capacity;
+ capacity *= arch_scale_max_freq_capacity(sd, cpu);
+ capacity >>= SCHED_CAPACITY_SHIFT;
+
mcc = &cpu_rq(cpu)->rd->max_cpu_capacity;
raw_spin_lock_irqsave(&mcc->lock, flags);
@@ -8767,6 +8953,38 @@
return group_other;
}
+#ifdef CONFIG_NO_HZ_COMMON
+/*
+ * idle load balancing data
+ * - used by the nohz balance, but we want it available here
+ * so that we can see which CPUs have no tick.
+ */
+static struct {
+ cpumask_var_t idle_cpus_mask;
+ atomic_t nr_cpus;
+ unsigned long next_balance; /* in jiffy units */
+} nohz ____cacheline_aligned;
+
+static inline void update_cpu_stats_if_tickless(struct rq *rq)
+{
+ /* only called from update_sg_lb_stats when irqs are disabled */
+ if (cpumask_test_cpu(rq->cpu, nohz.idle_cpus_mask)) {
+ /* rate limit updates to once-per-jiffie at most */
+ if (READ_ONCE(jiffies) <= rq->last_load_update_tick)
+ return;
+
+ raw_spin_lock(&rq->lock);
+ update_rq_clock(rq);
+ cpu_load_update_idle(rq);
+ update_cfs_rq_load_avg(rq->clock_task, &rq->cfs, false);
+ raw_spin_unlock(&rq->lock);
+ }
+}
+
+#else
+static inline void update_cpu_stats_if_tickless(struct rq *rq) { }
+#endif
+
/**
* update_sg_lb_stats - Update sched_group's statistics for load balancing.
* @env: The load balancing environment.
@@ -8797,6 +9015,12 @@
if (cpu_isolated(i))
continue;
+ /* if we are entering idle and there are CPUs with
+ * their tick stopped, do an update for them
+ */
+ if (env->idle == CPU_NEWLY_IDLE)
+ update_cpu_stats_if_tickless(rq);
+
/* Bias balancing toward cpus of our domain */
if (local_group)
load = target_load(i, load_idx);
@@ -9696,11 +9920,6 @@
* ld_moved - cumulative load moved across iterations
*/
cur_ld_moved = detach_tasks(&env);
- /*
- * We want to potentially lower env.src_cpu's OPP.
- */
- if (cur_ld_moved)
- update_capacity_of(env.src_cpu);
/*
* We've detached some tasks from busiest_rq. Every
@@ -9802,6 +10021,19 @@
if (need_active_balance(&env)) {
raw_spin_lock_irqsave(&busiest->lock, flags);
+ /*
+ * The CPUs are marked as reserved if tasks
+ * are pushed/pulled from other CPUs. In that case,
+ * bail out from the load balancer.
+ */
+ if (is_reserved(this_cpu) ||
+ is_reserved(cpu_of(busiest))) {
+ raw_spin_unlock_irqrestore(&busiest->lock,
+ flags);
+ *continue_balancing = 0;
+ goto out;
+ }
+
/* don't kick the active_load_balance_cpu_stop,
* if the curr task on busiest cpu can't be
* moved to this_cpu
@@ -9935,7 +10167,6 @@
struct sched_domain *sd;
int pulled_task = 0;
u64 curr_cost = 0;
- long removed_util=0;
if (cpu_isolated(this_cpu))
return 0;
@@ -9960,17 +10191,6 @@
raw_spin_unlock(&this_rq->lock);
- /*
- * If removed_util_avg is !0 we most probably migrated some task away
- * from this_cpu. In this case we might be willing to trigger an OPP
- * update, but we want to do so if we don't find anybody else to pull
- * here (we will trigger an OPP update with the pulled task's enqueue
- * anyway).
- *
- * Record removed_util before calling update_blocked_averages, and use
- * it below (before returning) to see if an OPP update is required.
- */
- removed_util = atomic_long_read(&(this_rq->cfs).removed_util_avg);
update_blocked_averages(this_cpu);
rcu_read_lock();
for_each_domain(this_cpu, sd) {
@@ -10037,13 +10257,6 @@
if (pulled_task)
this_rq->idle_stamp = 0;
- else if (removed_util) {
- /*
- * No task pulled and someone has been migrated away.
- * Good case to trigger an OPP update.
- */
- update_capacity_of(this_cpu);
- }
return pulled_task;
}
@@ -10125,10 +10338,6 @@
p = detach_one_task(&env);
if (p) {
schedstat_inc(sd->alb_pushed);
- /*
- * We want to potentially lower env.src_cpu's OPP.
- */
- update_capacity_of(env.src_cpu);
/* Active balancing done, reset the failure counter. */
sd->nr_balance_failed = 0;
moved = true;
@@ -10174,12 +10383,6 @@
* needed, they will kick the idle load balancer, which then does idle
* load balancing for all the idle CPUs.
*/
-static struct {
- cpumask_var_t idle_cpus_mask;
- atomic_t nr_cpus;
- unsigned long next_balance; /* in jiffy units */
-} nohz ____cacheline_aligned;
-
static inline int find_new_ilb(int type)
{
int ilb = nr_cpu_ids;
@@ -11582,7 +11785,7 @@
raw_spin_lock(&migration_lock);
rcu_read_lock();
- new_cpu = energy_aware_wake_cpu(p, cpu, 0);
+ new_cpu = select_energy_cpu_brute(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);
diff --git a/kernel/sched/features.h b/kernel/sched/features.h
index a1afd13..ef52be4 100644
--- a/kernel/sched/features.h
+++ b/kernel/sched/features.h
@@ -83,3 +83,24 @@
#else
SCHED_FEAT(ENERGY_AWARE, false)
#endif
+
+/*
+ * Minimum capacity capping. Keep track of minimum capacity factor when
+ * minimum frequency available to a policy is modified.
+ * If enabled, this can be used to inform the scheduler about capacity
+ * restrictions.
+ */
+SCHED_FEAT(MIN_CAPACITY_CAPPING, false)
+
+/*
+ * Enforce the priority of candidates selected by find_best_target()
+ * ON: If the target CPU saves any energy, use that.
+ * OFF: Use whichever of target or backup saves most.
+ */
+SCHED_FEAT(FBT_STRICT_ORDER, false)
+/*
+ * Enforce schedtune.prefer_idle to take need_idle path.
+ * ON: schedtune.prefer_idle is replaced with need_idle
+ * OFF: schedtune.prefer_idle is honored as is.
+ */
+SCHED_FEAT(EAS_USE_NEED_IDLE, true)
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 73f11c4..e6abbb4 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -2261,8 +2261,11 @@
rto_start_unlock(&rq->rd->rto_loop_start);
- if (cpu >= 0)
+ if (cpu >= 0) {
+ /* Make sure the rd does not get freed while pushing */
+ sched_get_rd(rq->rd);
irq_work_queue_on(&rq->rd->rto_push_work, cpu);
+ }
}
/* Called from hardirq context */
@@ -2292,8 +2295,10 @@
raw_spin_unlock(&rd->rto_lock);
- if (cpu < 0)
+ if (cpu < 0) {
+ sched_put_rd(rd);
return;
+ }
/* Try the next RT overloaded CPU */
irq_work_queue_on(&rd->rto_push_work, cpu);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index e0aa30d..8329e9c 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -679,6 +679,8 @@
};
extern struct root_domain def_root_domain;
+extern void sched_get_rd(struct root_domain *rd);
+extern void sched_put_rd(struct root_domain *rd);
#ifdef HAVE_RT_PUSH_IPI
extern void rto_push_irq_work_func(struct irq_work *work);
@@ -1469,7 +1471,7 @@
extern void set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask);
-bool __cpu_overutilized(int cpu, unsigned long util);
+bool __cpu_overutilized(int cpu, int delta);
bool cpu_overutilized(int cpu);
#endif
@@ -1697,6 +1699,26 @@
}
#endif
+#ifndef arch_scale_max_freq_capacity
+static __always_inline
+unsigned long arch_scale_max_freq_capacity(struct sched_domain *sd, int cpu)
+{
+ return SCHED_CAPACITY_SCALE;
+}
+#endif
+
+#ifndef arch_scale_min_freq_capacity
+static __always_inline
+unsigned long arch_scale_min_freq_capacity(struct sched_domain *sd, int cpu)
+{
+ /*
+ * Multiplied with any capacity value, this scale factor will return
+ * 0, which represents an un-capped state
+ */
+ return 0;
+}
+#endif
+
#ifndef arch_scale_cpu_capacity
static __always_inline
unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu)
@@ -1868,7 +1890,7 @@
walt_load->prev_window_util = util;
walt_load->nl = nl;
walt_load->pl = pl;
- walt_load->ws = rq->window_start;
+ walt_load->ws = rq->load_reported_window;
}
return (util >= capacity) ? capacity : util;
@@ -1890,6 +1912,8 @@
#endif /* CONFIG_SCHED_WALT */
+extern unsigned long
+boosted_cpu_util(int cpu, struct sched_walt_cpu_load *walt_load);
#endif
extern unsigned int capacity_margin_freq;
@@ -1904,76 +1928,6 @@
return cpu_capacity;
}
-#ifdef CONFIG_CPU_FREQ_GOV_SCHED
-#define capacity_max SCHED_CAPACITY_SCALE
-extern struct static_key __sched_freq;
-
-static inline bool sched_freq(void)
-{
- return static_key_false(&__sched_freq);
-}
-
-DECLARE_PER_CPU(struct sched_capacity_reqs, cpu_sched_capacity_reqs);
-void update_cpu_capacity_request(int cpu, bool request);
-
-static inline void set_cfs_cpu_capacity(int cpu, bool request,
- unsigned long capacity)
-{
- struct sched_capacity_reqs *scr = &per_cpu(cpu_sched_capacity_reqs, cpu);
-
-#ifdef CONFIG_SCHED_WALT
- if (!walt_disabled && sysctl_sched_use_walt_cpu_util) {
- int rtdl = scr->rt + scr->dl;
- /*
- * WALT tracks the utilization of a CPU considering the load
- * generated by all the scheduling classes.
- * Since the following call to:
- * update_cpu_capacity
- * is already adding the RT and DL utilizations let's remove
- * these contributions from the WALT signal.
- */
- if (capacity > rtdl)
- capacity -= rtdl;
- else
- capacity = 0;
- }
-#endif
- if (scr->cfs != capacity) {
- scr->cfs = capacity;
- update_cpu_capacity_request(cpu, request);
- }
-}
-
-static inline void set_rt_cpu_capacity(int cpu, bool request,
- unsigned long capacity)
-{
- if (per_cpu(cpu_sched_capacity_reqs, cpu).rt != capacity) {
- per_cpu(cpu_sched_capacity_reqs, cpu).rt = capacity;
- update_cpu_capacity_request(cpu, request);
- }
-}
-
-static inline void set_dl_cpu_capacity(int cpu, bool request,
- unsigned long capacity)
-{
- if (per_cpu(cpu_sched_capacity_reqs, cpu).dl != capacity) {
- per_cpu(cpu_sched_capacity_reqs, cpu).dl = capacity;
- update_cpu_capacity_request(cpu, request);
- }
-}
-#else
-static inline bool sched_freq(void) { return false; }
-static inline void set_cfs_cpu_capacity(int cpu, bool request,
- unsigned long capacity)
-{ }
-static inline void set_rt_cpu_capacity(int cpu, bool request,
- unsigned long capacity)
-{ }
-static inline void set_dl_cpu_capacity(int cpu, bool request,
- unsigned long capacity)
-{ }
-#endif
-
static inline void sched_rt_avg_update(struct rq *rq, u64 rt_delta)
{
rq->rt_avg += rt_delta * arch_scale_freq_capacity(NULL, cpu_of(rq));
@@ -2316,7 +2270,8 @@
(rq->load_reported_window == rq->window_start) &&
!(flags & exception_flags))
return;
- rq->load_reported_window = rq->window_start;
+ if (!(flags & exception_flags))
+ rq->load_reported_window = rq->window_start;
#endif
data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data,
@@ -2391,7 +2346,6 @@
extern unsigned int max_possible_capacity;
extern unsigned int min_max_possible_capacity;
extern unsigned int max_power_cost;
-extern unsigned int sched_init_task_load_windows;
extern unsigned int up_down_migrate_scale_factor;
extern unsigned int sysctl_sched_restrict_cluster_spill;
extern unsigned int sched_pred_alert_load;
diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c
index 93643ba..bdcd174 100644
--- a/kernel/sched/tune.c
+++ b/kernel/sched/tune.c
@@ -20,7 +20,7 @@
unsigned int sysctl_sched_cfs_boost __read_mostly;
extern struct reciprocal_value schedtune_spc_rdiv;
-extern struct target_nrg schedtune_target_nrg;
+struct target_nrg schedtune_target_nrg;
/* Performance Boost region (B) threshold params */
static int perf_boost_idx;
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index 23fd885..b4d815c 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -119,7 +119,6 @@
__read_mostly unsigned int walt_cpu_util_freq_divisor;
/* Initial task load. Newly created tasks are assigned this load. */
-unsigned int __read_mostly sched_init_task_load_windows;
unsigned int __read_mostly sysctl_sched_init_task_load_pct = 15;
/*
@@ -1910,12 +1909,16 @@
update_task_demand(p, rq, event, wallclock);
update_cpu_busy_time(p, rq, event, wallclock, irqtime);
update_task_pred_demand(rq, p, event);
-done:
+
+ if (exiting_task(p))
+ goto done;
+
trace_sched_update_task_ravg(p, rq, event, wallclock, irqtime,
rq->cc.cycles, rq->cc.time, &rq->grp_time);
trace_sched_update_task_ravg_mini(p, rq, event, wallclock, irqtime,
rq->cc.cycles, rq->cc.time, &rq->grp_time);
+done:
p->ravg.mark_start = wallclock;
run_walt_irq_work(old_window_start, rq);
@@ -1939,8 +1942,8 @@
void init_new_task_load(struct task_struct *p, bool idle_task)
{
int i;
- u32 init_load_windows = sched_init_task_load_windows;
- u32 init_load_pct = current->init_load_pct;
+ u32 init_load_windows;
+ u32 init_load_pct;
p->init_load_pct = 0;
rcu_assign_pointer(p->grp, NULL);
@@ -1957,9 +1960,13 @@
if (idle_task)
return;
- if (init_load_pct)
- init_load_windows = div64_u64((u64)init_load_pct *
- (u64)sched_ravg_window, 100);
+ if (current->init_load_pct)
+ init_load_pct = current->init_load_pct;
+ else
+ init_load_pct = sysctl_sched_init_task_load_pct;
+
+ init_load_windows = div64_u64((u64)init_load_pct *
+ (u64)sched_ravg_window, 100);
p->ravg.demand = init_load_windows;
p->ravg.coloc_demand = init_load_windows;
@@ -2186,6 +2193,7 @@
int __read_mostly min_power_cpu;
+unsigned int sched_smp_overlap_capacity;
void walt_sched_energy_populated_callback(void)
{
struct sched_cluster *cluster;
@@ -3242,8 +3250,4 @@
walt_cpu_util_freq_divisor =
(sched_ravg_window >> SCHED_CAPACITY_SHIFT) * 100;
-
- sched_init_task_load_windows =
- div64_u64((u64)sysctl_sched_init_task_load_pct *
- (u64)sched_ravg_window, 100);
}
diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h
index da53ea4..414c4ae 100644
--- a/kernel/sched/walt.h
+++ b/kernel/sched/walt.h
@@ -40,7 +40,6 @@
extern unsigned int min_possible_efficiency;
extern unsigned int max_possible_freq;
extern unsigned int sched_major_task_runtime;
-extern unsigned int __read_mostly sched_init_task_load_windows;
extern unsigned int __read_mostly sched_load_granule;
extern struct mutex cluster_lock;
@@ -182,6 +181,7 @@
{
return sched_irqload(cpu) >= sysctl_sched_cpu_high_irqload;
}
+#define walt_cpu_high_irqload(cpu) sched_cpu_high_irqload(cpu)
static inline int exiting_task(struct task_struct *p)
{
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 6833ffa..b593317 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -85,17 +85,6 @@
}
/*
- * If ksoftirqd is scheduled, we do not want to process pending softirqs
- * right now. Let ksoftirqd handle this at its own rate, to get fairness.
- */
-static bool ksoftirqd_running(void)
-{
- struct task_struct *tsk = __this_cpu_read(ksoftirqd);
-
- return tsk && (tsk->state == TASK_RUNNING);
-}
-
-/*
* preempt_count and SOFTIRQ_OFFSET usage:
* - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving
* softirq processing.
@@ -245,8 +234,16 @@
static inline void lockdep_softirq_end(bool in_hardirq) { }
#endif
-#define long_softirq_pending() (local_softirq_pending() & LONG_SOFTIRQ_MASK)
-#define defer_for_rt() (long_softirq_pending() && cpupri_check_rt())
+#define softirq_deferred_for_rt(pending) \
+({ \
+ __u32 deferred = 0; \
+ if (cpupri_check_rt()) { \
+ deferred = pending & LONG_SOFTIRQ_MASK; \
+ pending &= ~LONG_SOFTIRQ_MASK; \
+ } \
+ deferred; \
+})
+
asmlinkage __visible void __softirq_entry __do_softirq(void)
{
unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
@@ -254,6 +251,7 @@
int max_restart = MAX_SOFTIRQ_RESTART;
struct softirq_action *h;
bool in_hardirq;
+ __u32 deferred;
__u32 pending;
int softirq_bit;
@@ -265,14 +263,14 @@
current->flags &= ~PF_MEMALLOC;
pending = local_softirq_pending();
+ deferred = softirq_deferred_for_rt(pending);
account_irq_enter_time(current);
-
__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
in_hardirq = lockdep_softirq_start();
restart:
/* Reset the pending bitmask before enabling irqs */
- set_softirq_pending(0);
+ set_softirq_pending(deferred);
__this_cpu_write(active_softirqs, pending);
local_irq_enable();
@@ -308,15 +306,16 @@
local_irq_disable();
pending = local_softirq_pending();
+ deferred = softirq_deferred_for_rt(pending);
+
if (pending) {
if (time_before(jiffies, end) && !need_resched() &&
- !defer_for_rt() &&
--max_restart)
goto restart;
-
- wakeup_softirqd();
}
+ if (pending | deferred)
+ wakeup_softirqd();
lockdep_softirq_end(in_hardirq);
account_irq_exit_time(current);
__local_bh_enable(SOFTIRQ_OFFSET);
@@ -336,7 +335,7 @@
pending = local_softirq_pending();
- if (pending && !ksoftirqd_running())
+ if (pending)
do_softirq_own_stack();
local_irq_restore(flags);
@@ -363,10 +362,7 @@
static inline void invoke_softirq(void)
{
- if (ksoftirqd_running())
- return;
-
- if (!force_irqthreads && !defer_for_rt()) {
+ if (!force_irqthreads) {
#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
/*
* We can safely execute softirq on the current stack if
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index b057784..6340010 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -334,6 +334,13 @@
.extra1 = &zero,
.extra2 = &one,
},
+ {
+ .procname = "sched_initial_task_util",
+ .data = &sysctl_sched_init_task_load_pct,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
#endif
{
.procname = "sched_upmigrate",
@@ -392,13 +399,6 @@
},
#endif
{
- .procname = "sched_initial_task_util",
- .data = &sysctl_sched_initial_task_util,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
.procname = "sched_cstate_aware",
.data = &sysctl_sched_cstate_aware,
.maxlen = sizeof(unsigned int),
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index d542c09..8f79045 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -527,6 +527,7 @@
{ CTL_INT, NET_IPV6_PROXY_NDP, "proxy_ndp" },
{ CTL_INT, NET_IPV6_ACCEPT_SOURCE_ROUTE, "accept_source_route" },
{ CTL_INT, NET_IPV6_ACCEPT_RA_FROM_LOCAL, "accept_ra_from_local" },
+ { CTL_INT, NET_IPV6_ACCEPT_RA_PREFIX_ROUTE, "accept_ra_prefix_route" },
{}
};
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index f2826c3..fc7c37a 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -507,17 +507,22 @@
{
struct task_struct *rtn = current->group_leader;
- if ((event->sigev_notify & SIGEV_THREAD_ID ) &&
- (!(rtn = find_task_by_vpid(event->sigev_notify_thread_id)) ||
- !same_thread_group(rtn, current) ||
- (event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_SIGNAL))
+ switch (event->sigev_notify) {
+ case SIGEV_SIGNAL | SIGEV_THREAD_ID:
+ rtn = find_task_by_vpid(event->sigev_notify_thread_id);
+ if (!rtn || !same_thread_group(rtn, current))
+ return NULL;
+ /* FALLTHRU */
+ case SIGEV_SIGNAL:
+ case SIGEV_THREAD:
+ if (event->sigev_signo <= 0 || event->sigev_signo > SIGRTMAX)
+ return NULL;
+ /* FALLTHRU */
+ case SIGEV_NONE:
+ return task_pid(rtn);
+ default:
return NULL;
-
- if (((event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) &&
- ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX)))
- return NULL;
-
- return task_pid(rtn);
+ }
}
void posix_timers_register_clock(const clockid_t clock_id,
@@ -745,8 +750,7 @@
/* interval timer ? */
if (iv.tv64)
cur_setting->it_interval = ktime_to_timespec(iv);
- else if (!hrtimer_active(timer) &&
- (timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
+ else if (!hrtimer_active(timer) && timr->it_sigev_notify != SIGEV_NONE)
return;
now = timer->base->get_time();
@@ -757,7 +761,7 @@
* expiry is > now.
*/
if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING ||
- (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE))
+ timr->it_sigev_notify == SIGEV_NONE))
timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv);
remaining = __hrtimer_expires_remaining_adjusted(timer, now);
@@ -767,7 +771,7 @@
* A single shot SIGEV_NONE timer must return 0, when
* it is expired !
*/
- if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
+ if (timr->it_sigev_notify != SIGEV_NONE)
cur_setting->it_value.tv_nsec = 1;
} else
cur_setting->it_value = ktime_to_timespec(remaining);
@@ -865,7 +869,7 @@
timr->it.real.interval = timespec_to_ktime(new_setting->it_interval);
/* SIGEV_NONE timers are not queued ! See common_timer_get */
- if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) {
+ if (timr->it_sigev_notify == SIGEV_NONE) {
/* Setup correct expiry time for relative timers */
if (mode == HRTIMER_MODE_REL) {
hrtimer_add_expires(timer, timer->base->get_time());
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 234d3e4..427e33d 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -70,6 +70,10 @@
tk->tkr_mono.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_mono.shift;
tk->xtime_sec++;
}
+ while (tk->tkr_raw.xtime_nsec >= ((u64)NSEC_PER_SEC << tk->tkr_raw.shift)) {
+ tk->tkr_raw.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_raw.shift;
+ tk->raw_sec++;
+ }
}
static inline struct timespec64 tk_xtime(struct timekeeper *tk)
@@ -283,12 +287,14 @@
/* if changing clocks, convert xtime_nsec shift units */
if (old_clock) {
int shift_change = clock->shift - old_clock->shift;
- if (shift_change < 0)
+ if (shift_change < 0) {
tk->tkr_mono.xtime_nsec >>= -shift_change;
- else
+ tk->tkr_raw.xtime_nsec >>= -shift_change;
+ } else {
tk->tkr_mono.xtime_nsec <<= shift_change;
+ tk->tkr_raw.xtime_nsec <<= shift_change;
+ }
}
- tk->tkr_raw.xtime_nsec = 0;
tk->tkr_mono.shift = clock->shift;
tk->tkr_raw.shift = clock->shift;
@@ -619,9 +625,6 @@
nsec = (u32) tk->wall_to_monotonic.tv_nsec;
tk->tkr_mono.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);
- /* Update the monotonic raw base */
- tk->tkr_raw.base = timespec64_to_ktime(tk->raw_time);
-
/*
* The sum of the nanoseconds portions of xtime and
* wall_to_monotonic can be greater/equal one second. Take
@@ -631,6 +634,9 @@
if (nsec >= NSEC_PER_SEC)
seconds++;
tk->ktime_sec = seconds;
+
+ /* Update the monotonic raw base */
+ tk->tkr_raw.base = ns_to_ktime(tk->raw_sec * NSEC_PER_SEC);
}
/* must hold timekeeper_lock */
@@ -672,7 +678,6 @@
static void timekeeping_forward_now(struct timekeeper *tk)
{
cycle_t cycle_now, delta;
- s64 nsec;
cycle_now = tk_clock_read(&tk->tkr_mono);
delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, tk->tkr_mono.mask);
@@ -684,10 +689,13 @@
/* If arch requires, add in get_arch_timeoffset() */
tk->tkr_mono.xtime_nsec += (u64)arch_gettimeoffset() << tk->tkr_mono.shift;
- tk_normalize_xtime(tk);
- nsec = clocksource_cyc2ns(delta, tk->tkr_raw.mult, tk->tkr_raw.shift);
- timespec64_add_ns(&tk->raw_time, nsec);
+ tk->tkr_raw.xtime_nsec += delta * tk->tkr_raw.mult;
+
+ /* If arch requires, add in get_arch_timeoffset() */
+ tk->tkr_raw.xtime_nsec += (u64)arch_gettimeoffset() << tk->tkr_raw.shift;
+
+ tk_normalize_xtime(tk);
}
/**
@@ -1411,19 +1419,18 @@
void getrawmonotonic64(struct timespec64 *ts)
{
struct timekeeper *tk = &tk_core.timekeeper;
- struct timespec64 ts64;
unsigned long seq;
s64 nsecs;
do {
seq = read_seqcount_begin(&tk_core.seq);
+ ts->tv_sec = tk->raw_sec;
nsecs = timekeeping_get_ns(&tk->tkr_raw);
- ts64 = tk->raw_time;
} while (read_seqcount_retry(&tk_core.seq, seq));
- timespec64_add_ns(&ts64, nsecs);
- *ts = ts64;
+ ts->tv_nsec = 0;
+ timespec64_add_ns(ts, nsecs);
}
EXPORT_SYMBOL(getrawmonotonic64);
@@ -1547,8 +1554,7 @@
tk_setup_internals(tk, clock);
tk_set_xtime(tk, &now);
- tk->raw_time.tv_sec = 0;
- tk->raw_time.tv_nsec = 0;
+ tk->raw_sec = 0;
if (boot.tv_sec == 0 && boot.tv_nsec == 0)
boot = tk_xtime(tk);
@@ -2066,15 +2072,12 @@
*clock_set |= accumulate_nsecs_to_secs(tk);
/* Accumulate raw time */
- tk->tkr_raw.xtime_nsec += (u64)tk->raw_time.tv_nsec << tk->tkr_raw.shift;
tk->tkr_raw.xtime_nsec += tk->raw_interval << shift;
snsec_per_sec = (u64)NSEC_PER_SEC << tk->tkr_raw.shift;
while (tk->tkr_raw.xtime_nsec >= snsec_per_sec) {
tk->tkr_raw.xtime_nsec -= snsec_per_sec;
- tk->raw_time.tv_sec++;
+ tk->raw_sec++;
}
- tk->raw_time.tv_nsec = tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift;
- tk->tkr_raw.xtime_nsec -= (u64)tk->raw_time.tv_nsec << tk->tkr_raw.shift;
/* Accumulate error between NTP and clock interval */
tk->ntp_error += tk->ntp_tick << shift;
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index a6f8a44..41481dc 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -208,6 +208,7 @@
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;
@@ -1488,8 +1489,6 @@
#ifdef CONFIG_SMP
-static atomic_t deferrable_pending;
-
/*
* check_pending_deferrable_timers - Check for unbound deferrable timer expiry
* @cpu - Current CPU
@@ -1670,27 +1669,6 @@
spin_unlock_irq(&base->lock);
}
-#ifdef CONFIG_SMP
-static inline bool should_this_cpu_run_deferrable_timers(void)
-{
- int tick_cpu = READ_ONCE(tick_do_timer_cpu);
-
- if (atomic_cmpxchg(&deferrable_pending, 1, 0) &&
- tick_cpu == TICK_DO_TIMER_NONE)
- return true;
-
- if (tick_cpu == smp_processor_id())
- return true;
-
- return (tick_cpu >= 0 && ksoftirqd_running_on(tick_cpu));
-}
-#else
-static inline bool should_this_cpu_run_deferrable_timers(void)
-{
- return true;
-}
-#endif
-
/*
* This function runs timers and the timer-tq in bottom half context.
*/
@@ -1715,7 +1693,9 @@
if (IS_ENABLED(CONFIG_NO_HZ_COMMON))
__run_timers(this_cpu_ptr(&timer_bases[BASE_DEF]));
- if (should_this_cpu_run_deferrable_timers())
+ 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/Kconfig b/kernel/trace/Kconfig
index ed7ba6d..1f89ca0 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -189,6 +189,17 @@
address on the current task structure into a stack of calls.
+config PREEMPTIRQ_EVENTS
+ bool "Enable trace events for preempt and irq disable/enable"
+ select TRACE_IRQFLAGS
+ depends on DEBUG_PREEMPT || !PROVE_LOCKING
+ default n
+ help
+ Enable tracing of disable and enable events for preemption and irqs.
+ For tracing preempt disable/enable events, DEBUG_PREEMPT must be
+ enabled. For tracing irq disable/enable events, PROVE_LOCKING must
+ be disabled.
+
config IRQSOFF_TRACER
bool "Interrupts-off Latency Tracer"
default n
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 8ee9cc1..b4f8e16 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -34,6 +34,7 @@
obj-$(CONFIG_TRACING_MAP) += tracing_map.o
obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o
obj-$(CONFIG_FUNCTION_TRACER) += trace_functions.o
+obj-$(CONFIG_PREEMPTIRQ_EVENTS) += trace_irqsoff.o
obj-$(CONFIG_IRQSOFF_TRACER) += trace_irqsoff.o
obj-$(CONFIG_PREEMPT_TRACER) += trace_irqsoff.o
obj-$(CONFIG_SCHED_TRACER) += trace_sched_wakeup.o
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index dbafc5d..4e17d55 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -57,7 +57,8 @@
};
/* Global reference count of probes */
-static atomic_t blk_probes_ref = ATOMIC_INIT(0);
+static DEFINE_MUTEX(blk_probe_mutex);
+static int blk_probes_ref;
static void blk_register_tracepoints(void);
static void blk_unregister_tracepoints(void);
@@ -306,11 +307,26 @@
kfree(bt);
}
+static void get_probe_ref(void)
+{
+ mutex_lock(&blk_probe_mutex);
+ if (++blk_probes_ref == 1)
+ blk_register_tracepoints();
+ mutex_unlock(&blk_probe_mutex);
+}
+
+static void put_probe_ref(void)
+{
+ mutex_lock(&blk_probe_mutex);
+ if (!--blk_probes_ref)
+ blk_unregister_tracepoints();
+ mutex_unlock(&blk_probe_mutex);
+}
+
static void blk_trace_cleanup(struct blk_trace *bt)
{
blk_trace_free(bt);
- if (atomic_dec_and_test(&blk_probes_ref))
- blk_unregister_tracepoints();
+ put_probe_ref();
}
int blk_trace_remove(struct request_queue *q)
@@ -522,8 +538,7 @@
if (cmpxchg(&q->blk_trace, NULL, bt))
goto err;
- if (atomic_inc_return(&blk_probes_ref) == 1)
- blk_register_tracepoints();
+ get_probe_ref();
return 0;
err:
@@ -1469,9 +1484,7 @@
if (bt == NULL)
return -EINVAL;
- if (atomic_dec_and_test(&blk_probes_ref))
- blk_unregister_tracepoints();
-
+ put_probe_ref();
blk_trace_free(bt);
return 0;
}
@@ -1502,8 +1515,7 @@
if (cmpxchg(&q->blk_trace, NULL, bt))
goto free_bt;
- if (atomic_inc_return(&blk_probes_ref) == 1)
- blk_register_tracepoints();
+ get_probe_ref();
return 0;
free_bt:
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 5b8d718..2884fe0 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3911,7 +3911,6 @@
func_g.type = filter_parse_regex(glob, strlen(glob),
&func_g.search, ¬);
func_g.len = strlen(func_g.search);
- func_g.search = glob;
/* we do not support '!' for function probes */
if (WARN_ON(not))
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 03cdff8..c180fe5 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -16,6 +16,10 @@
#include "trace.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/preemptirq.h>
+
+#if defined(CONFIG_IRQSOFF_TRACER) || defined(CONFIG_PREEMPT_TRACER)
static struct trace_array *irqsoff_trace __read_mostly;
static int tracer_enabled __read_mostly;
@@ -451,63 +455,43 @@
#else /* !CONFIG_PROVE_LOCKING */
/*
- * Stubs:
- */
-
-void trace_softirqs_on(unsigned long ip)
-{
-}
-
-void trace_softirqs_off(unsigned long ip)
-{
-}
-
-inline void print_irqtrace_events(struct task_struct *curr)
-{
-}
-
-/*
* We are only interested in hardirq on/off events:
*/
-void trace_hardirqs_on(void)
+static inline void tracer_hardirqs_on(void)
{
if (!preempt_trace() && irq_trace())
stop_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
}
-EXPORT_SYMBOL(trace_hardirqs_on);
-void trace_hardirqs_off(void)
+static inline void tracer_hardirqs_off(void)
{
if (!preempt_trace() && irq_trace())
start_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
}
-EXPORT_SYMBOL(trace_hardirqs_off);
-__visible void trace_hardirqs_on_caller(unsigned long caller_addr)
+static inline void tracer_hardirqs_on_caller(unsigned long caller_addr)
{
if (!preempt_trace() && irq_trace())
stop_critical_timing(CALLER_ADDR0, caller_addr);
}
-EXPORT_SYMBOL(trace_hardirqs_on_caller);
-__visible void trace_hardirqs_off_caller(unsigned long caller_addr)
+static inline void tracer_hardirqs_off_caller(unsigned long caller_addr)
{
if (!preempt_trace() && irq_trace())
start_critical_timing(CALLER_ADDR0, caller_addr);
}
-EXPORT_SYMBOL(trace_hardirqs_off_caller);
#endif /* CONFIG_PROVE_LOCKING */
#endif /* CONFIG_IRQSOFF_TRACER */
#ifdef CONFIG_PREEMPT_TRACER
-void trace_preempt_on(unsigned long a0, unsigned long a1)
+static inline void tracer_preempt_on(unsigned long a0, unsigned long a1)
{
if (preempt_trace() && !irq_trace())
stop_critical_timing(a0, a1);
}
-void trace_preempt_off(unsigned long a0, unsigned long a1)
+static inline void tracer_preempt_off(unsigned long a0, unsigned long a1)
{
if (preempt_trace() && !irq_trace())
start_critical_timing(a0, a1);
@@ -769,3 +753,100 @@
return 0;
}
core_initcall(init_irqsoff_tracer);
+#endif /* IRQSOFF_TRACER || PREEMPTOFF_TRACER */
+
+#ifndef CONFIG_IRQSOFF_TRACER
+static inline void tracer_hardirqs_on(void) { }
+static inline void tracer_hardirqs_off(void) { }
+static inline void tracer_hardirqs_on_caller(unsigned long caller_addr) { }
+static inline void tracer_hardirqs_off_caller(unsigned long caller_addr) { }
+#endif
+
+#ifndef CONFIG_PREEMPT_TRACER
+static inline void tracer_preempt_on(unsigned long a0, unsigned long a1) { }
+static inline void tracer_preempt_off(unsigned long a0, unsigned long a1) { }
+#endif
+
+/* Per-cpu variable to prevent redundant calls when IRQs already off */
+static DEFINE_PER_CPU(int, tracing_irq_cpu);
+
+#if defined(CONFIG_TRACE_IRQFLAGS) && !defined(CONFIG_PROVE_LOCKING)
+void trace_hardirqs_on(void)
+{
+ if (!this_cpu_read(tracing_irq_cpu))
+ return;
+
+ trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
+ tracer_hardirqs_on();
+
+ this_cpu_write(tracing_irq_cpu, 0);
+}
+EXPORT_SYMBOL(trace_hardirqs_on);
+
+void trace_hardirqs_off(void)
+{
+ if (this_cpu_read(tracing_irq_cpu))
+ return;
+
+ this_cpu_write(tracing_irq_cpu, 1);
+
+ trace_irq_disable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
+ tracer_hardirqs_off();
+}
+EXPORT_SYMBOL(trace_hardirqs_off);
+
+__visible void trace_hardirqs_on_caller(unsigned long caller_addr)
+{
+ if (!this_cpu_read(tracing_irq_cpu))
+ return;
+
+ trace_irq_enable_rcuidle(CALLER_ADDR0, caller_addr);
+ tracer_hardirqs_on_caller(caller_addr);
+
+ this_cpu_write(tracing_irq_cpu, 0);
+}
+EXPORT_SYMBOL(trace_hardirqs_on_caller);
+
+__visible void trace_hardirqs_off_caller(unsigned long caller_addr)
+{
+ if (this_cpu_read(tracing_irq_cpu))
+ return;
+
+ this_cpu_write(tracing_irq_cpu, 1);
+
+ trace_irq_disable_rcuidle(CALLER_ADDR0, caller_addr);
+ tracer_hardirqs_off_caller(caller_addr);
+}
+EXPORT_SYMBOL(trace_hardirqs_off_caller);
+
+/*
+ * Stubs:
+ */
+
+void trace_softirqs_on(unsigned long ip)
+{
+}
+
+void trace_softirqs_off(unsigned long ip)
+{
+}
+
+inline void print_irqtrace_events(struct task_struct *curr)
+{
+}
+#endif
+
+#if defined(CONFIG_PREEMPT_TRACER) || \
+ (defined(CONFIG_DEBUG_PREEMPT) && defined(CONFIG_PREEMPTIRQ_EVENTS))
+void trace_preempt_on(unsigned long a0, unsigned long a1)
+{
+ trace_preempt_enable_rcuidle(a0, a1);
+ tracer_preempt_on(a0, a1);
+}
+
+void trace_preempt_off(unsigned long a0, unsigned long a1)
+{
+ trace_preempt_disable_rcuidle(a0, a1);
+ tracer_preempt_off(a0, a1);
+}
+#endif
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 2812580..558be53 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -197,7 +197,6 @@
config FRAME_WARN
int "Warn for stack frames larger than (needs gcc 4.4)"
range 0 8192
- default 0 if KASAN
default 2048 if GCC_PLUGIN_LATENT_ENTROPY
default 1024 if !64BIT
default 2048 if 64BIT
diff --git a/lib/digsig.c b/lib/digsig.c
index a876156..6ba6fcd 100644
--- a/lib/digsig.c
+++ b/lib/digsig.c
@@ -85,7 +85,7 @@
struct pubkey_hdr *pkh;
down_read(&key->sem);
- ukp = user_key_payload(key);
+ ukp = user_key_payload_locked(key);
if (!ukp) {
/* key was revoked before we acquired its semaphore */
diff --git a/lib/kobject.c b/lib/kobject.c
index 445dcae..763d70a 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -601,12 +601,15 @@
}
EXPORT_SYMBOL(kobject_get);
-static struct kobject * __must_check kobject_get_unless_zero(struct kobject *kobj)
+struct kobject * __must_check kobject_get_unless_zero(struct kobject *kobj)
{
+ if (!kobj)
+ return NULL;
if (!kref_get_unless_zero(&kobj->kref))
kobj = NULL;
return kobj;
}
+EXPORT_SYMBOL(kobject_get_unless_zero);
/*
* kobject_cleanup - free kobject resources.
diff --git a/lib/oid_registry.c b/lib/oid_registry.c
index 318f382..150e04d 100644
--- a/lib/oid_registry.c
+++ b/lib/oid_registry.c
@@ -116,7 +116,7 @@
int count;
if (v >= end)
- return -EBADMSG;
+ goto bad;
n = *v++;
ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40);
@@ -134,7 +134,7 @@
num = n & 0x7f;
do {
if (v >= end)
- return -EBADMSG;
+ goto bad;
n = *v++;
num <<= 7;
num |= n & 0x7f;
@@ -148,6 +148,10 @@
}
return ret;
+
+bad:
+ snprintf(buffer, bufsize, "(bad)");
+ return -EBADMSG;
}
EXPORT_SYMBOL_GPL(sprint_oid);
diff --git a/lib/test_kasan.c b/lib/test_kasan.c
index fbdf879..0e70ecc 100644
--- a/lib/test_kasan.c
+++ b/lib/test_kasan.c
@@ -19,6 +19,7 @@
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/module.h>
+#include <linux/kasan.h>
/*
* Note: test functions are marked noinline so that their names appear in
@@ -441,6 +442,12 @@
static int __init kmalloc_tests_init(void)
{
+ /*
+ * Temporarily enable multi-shot mode. Otherwise, we'd only get a
+ * report for the first case.
+ */
+ bool multishot = kasan_save_enable_multi_shot();
+
kmalloc_oob_right();
kmalloc_oob_left();
kmalloc_node_oob_right();
@@ -465,6 +472,9 @@
ksize_unpoisons_memory();
copy_user_test();
use_after_scope_test();
+
+ kasan_restore_multi_shot(multishot);
+
return -EAGAIN;
}
diff --git a/lib/ubsan.c b/lib/ubsan.c
index fb0409d..50d1d5c 100644
--- a/lib/ubsan.c
+++ b/lib/ubsan.c
@@ -265,14 +265,14 @@
}
EXPORT_SYMBOL(__ubsan_handle_divrem_overflow);
-static void handle_null_ptr_deref(struct type_mismatch_data *data)
+static void handle_null_ptr_deref(struct type_mismatch_data_common *data)
{
unsigned long flags;
- if (suppress_report(&data->location))
+ if (suppress_report(data->location))
return;
- ubsan_prologue(&data->location, &flags);
+ ubsan_prologue(data->location, &flags);
pr_err("%s null pointer of type %s\n",
type_check_kinds[data->type_check_kind],
@@ -281,15 +281,15 @@
ubsan_epilogue(&flags);
}
-static void handle_missaligned_access(struct type_mismatch_data *data,
+static void handle_misaligned_access(struct type_mismatch_data_common *data,
unsigned long ptr)
{
unsigned long flags;
- if (suppress_report(&data->location))
+ if (suppress_report(data->location))
return;
- ubsan_prologue(&data->location, &flags);
+ ubsan_prologue(data->location, &flags);
pr_err("%s misaligned address %p for type %s\n",
type_check_kinds[data->type_check_kind],
@@ -299,15 +299,15 @@
ubsan_epilogue(&flags);
}
-static void handle_object_size_mismatch(struct type_mismatch_data *data,
+static void handle_object_size_mismatch(struct type_mismatch_data_common *data,
unsigned long ptr)
{
unsigned long flags;
- if (suppress_report(&data->location))
+ if (suppress_report(data->location))
return;
- ubsan_prologue(&data->location, &flags);
+ ubsan_prologue(data->location, &flags);
pr_err("%s address %p with insufficient space\n",
type_check_kinds[data->type_check_kind],
(void *) ptr);
@@ -315,19 +315,47 @@
ubsan_epilogue(&flags);
}
-void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
+static void ubsan_type_mismatch_common(struct type_mismatch_data_common *data,
unsigned long ptr)
{
if (!ptr)
handle_null_ptr_deref(data);
else if (data->alignment && !IS_ALIGNED(ptr, data->alignment))
- handle_missaligned_access(data, ptr);
+ handle_misaligned_access(data, ptr);
else
handle_object_size_mismatch(data, ptr);
}
+
+void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
+ unsigned long ptr)
+{
+ struct type_mismatch_data_common common_data = {
+ .location = &data->location,
+ .type = data->type,
+ .alignment = data->alignment,
+ .type_check_kind = data->type_check_kind
+ };
+
+ ubsan_type_mismatch_common(&common_data, ptr);
+}
EXPORT_SYMBOL(__ubsan_handle_type_mismatch);
+void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data,
+ unsigned long ptr)
+{
+
+ struct type_mismatch_data_common common_data = {
+ .location = &data->location,
+ .type = data->type,
+ .alignment = 1UL << data->log_alignment,
+ .type_check_kind = data->type_check_kind
+ };
+
+ ubsan_type_mismatch_common(&common_data, ptr);
+}
+EXPORT_SYMBOL(__ubsan_handle_type_mismatch_v1);
+
void __ubsan_handle_nonnull_return(struct nonnull_return_data *data)
{
unsigned long flags;
diff --git a/lib/ubsan.h b/lib/ubsan.h
index b2d18d4..d8b8085 100644
--- a/lib/ubsan.h
+++ b/lib/ubsan.h
@@ -36,6 +36,20 @@
unsigned char type_check_kind;
};
+struct type_mismatch_data_v1 {
+ struct source_location location;
+ struct type_descriptor *type;
+ unsigned char log_alignment;
+ unsigned char type_check_kind;
+};
+
+struct type_mismatch_data_common {
+ struct source_location *location;
+ struct type_descriptor *type;
+ unsigned long alignment;
+ unsigned char type_check_kind;
+};
+
struct nonnull_arg_data {
struct source_location location;
struct source_location attr_location;
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 6ff2d77..62ca907 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -237,6 +237,7 @@
bdi_class->dev_groups = bdi_dev_groups;
bdi_debug_init();
+
return 0;
}
postcore_initcall(bdi_class_init);
@@ -293,6 +294,8 @@
memset(wb, 0, sizeof(*wb));
+ if (wb != &bdi->wb)
+ bdi_get(bdi);
wb->bdi = bdi;
wb->last_old_flush = jiffies;
INIT_LIST_HEAD(&wb->b_dirty);
@@ -312,8 +315,10 @@
INIT_DELAYED_WORK(&wb->dwork, wb_workfn);
wb->congested = wb_congested_get_create(bdi, blkcg_id, gfp);
- if (!wb->congested)
- return -ENOMEM;
+ if (!wb->congested) {
+ err = -ENOMEM;
+ goto out_put_bdi;
+ }
err = fprop_local_init_percpu(&wb->completions, gfp);
if (err)
@@ -333,9 +338,14 @@
fprop_local_destroy_percpu(&wb->completions);
out_put_cong:
wb_congested_put(wb->congested);
+out_put_bdi:
+ if (wb != &bdi->wb)
+ bdi_put(bdi);
return err;
}
+static void cgwb_remove_from_bdi_list(struct bdi_writeback *wb);
+
/*
* Remove bdi from the global list and shutdown any threads we have running
*/
@@ -345,10 +355,18 @@
spin_lock_bh(&wb->work_lock);
if (!test_and_clear_bit(WB_registered, &wb->state)) {
spin_unlock_bh(&wb->work_lock);
+ /*
+ * Wait for wb shutdown to finish if someone else is just
+ * running wb_shutdown(). Otherwise we could proceed to wb /
+ * bdi destruction before wb_shutdown() is finished.
+ */
+ wait_on_bit(&wb->state, WB_shutting_down, TASK_UNINTERRUPTIBLE);
return;
}
+ set_bit(WB_shutting_down, &wb->state);
spin_unlock_bh(&wb->work_lock);
+ cgwb_remove_from_bdi_list(wb);
/*
* Drain work list and shutdown the delayed_work. !WB_registered
* tells wb_workfn() that @wb is dying and its work_list needs to
@@ -357,6 +375,12 @@
mod_delayed_work(bdi_wq, &wb->dwork, 0);
flush_delayed_work(&wb->dwork);
WARN_ON(!list_empty(&wb->work_list));
+ /*
+ * Make sure bit gets cleared after shutdown is finished. Matches with
+ * the barrier provided by test_and_clear_bit() above.
+ */
+ smp_wmb();
+ clear_bit(WB_shutting_down, &wb->state);
}
static void wb_exit(struct bdi_writeback *wb)
@@ -370,6 +394,8 @@
fprop_local_destroy_percpu(&wb->completions);
wb_congested_put(wb->congested);
+ if (wb != &wb->bdi->wb)
+ bdi_put(wb->bdi);
}
#ifdef CONFIG_CGROUP_WRITEBACK
@@ -379,11 +405,9 @@
/*
* cgwb_lock protects bdi->cgwb_tree, bdi->cgwb_congested_tree,
* blkcg->cgwb_list, and memcg->cgwb_list. bdi->cgwb_tree is also RCU
- * protected. cgwb_release_wait is used to wait for the completion of cgwb
- * releases from bdi destruction path.
+ * protected.
*/
static DEFINE_SPINLOCK(cgwb_lock);
-static DECLARE_WAIT_QUEUE_HEAD(cgwb_release_wait);
/**
* wb_congested_get_create - get or create a wb_congested
@@ -436,7 +460,7 @@
return NULL;
atomic_set(&new_congested->refcnt, 0);
- new_congested->bdi = bdi;
+ new_congested->__bdi = bdi;
new_congested->blkcg_id = blkcg_id;
goto retry;
@@ -464,10 +488,10 @@
}
/* bdi might already have been destroyed leaving @congested unlinked */
- if (congested->bdi) {
+ if (congested->__bdi) {
rb_erase(&congested->rb_node,
- &congested->bdi->cgwb_congested_tree);
- congested->bdi = NULL;
+ &congested->__bdi->cgwb_congested_tree);
+ congested->__bdi = NULL;
}
spin_unlock_irqrestore(&cgwb_lock, flags);
@@ -478,11 +502,6 @@
{
struct bdi_writeback *wb = container_of(work, struct bdi_writeback,
release_work);
- struct backing_dev_info *bdi = wb->bdi;
-
- spin_lock_irq(&cgwb_lock);
- list_del_rcu(&wb->bdi_node);
- spin_unlock_irq(&cgwb_lock);
wb_shutdown(wb);
@@ -493,9 +512,6 @@
percpu_ref_exit(&wb->refcnt);
wb_exit(wb);
kfree_rcu(wb, rcu);
-
- if (atomic_dec_and_test(&bdi->usage_cnt))
- wake_up_all(&cgwb_release_wait);
}
static void cgwb_release(struct percpu_ref *refcnt)
@@ -515,6 +531,13 @@
percpu_ref_kill(&wb->refcnt);
}
+static void cgwb_remove_from_bdi_list(struct bdi_writeback *wb)
+{
+ spin_lock_irq(&cgwb_lock);
+ list_del_rcu(&wb->bdi_node);
+ spin_unlock_irq(&cgwb_lock);
+}
+
static int cgwb_create(struct backing_dev_info *bdi,
struct cgroup_subsys_state *memcg_css, gfp_t gfp)
{
@@ -578,7 +601,6 @@
/* we might have raced another instance of this function */
ret = radix_tree_insert(&bdi->cgwb_tree, memcg_css->id, wb);
if (!ret) {
- atomic_inc(&bdi->usage_cnt);
list_add_tail_rcu(&wb->bdi_node, &bdi->wb_list);
list_add(&wb->memcg_node, memcg_cgwb_list);
list_add(&wb->blkcg_node, blkcg_cgwb_list);
@@ -668,7 +690,6 @@
INIT_RADIX_TREE(&bdi->cgwb_tree, GFP_ATOMIC);
bdi->cgwb_congested_tree = RB_ROOT;
- atomic_set(&bdi->usage_cnt, 1);
ret = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL);
if (!ret) {
@@ -678,36 +699,26 @@
return ret;
}
-static void cgwb_bdi_destroy(struct backing_dev_info *bdi)
+static void cgwb_bdi_unregister(struct backing_dev_info *bdi)
{
struct radix_tree_iter iter;
- struct rb_node *rbn;
void **slot;
+ struct bdi_writeback *wb;
WARN_ON(test_bit(WB_registered, &bdi->wb.state));
spin_lock_irq(&cgwb_lock);
-
radix_tree_for_each_slot(slot, &bdi->cgwb_tree, &iter, 0)
cgwb_kill(*slot);
- while ((rbn = rb_first(&bdi->cgwb_congested_tree))) {
- struct bdi_writeback_congested *congested =
- rb_entry(rbn, struct bdi_writeback_congested, rb_node);
-
- rb_erase(rbn, &bdi->cgwb_congested_tree);
- congested->bdi = NULL; /* mark @congested unlinked */
+ while (!list_empty(&bdi->wb_list)) {
+ wb = list_first_entry(&bdi->wb_list, struct bdi_writeback,
+ bdi_node);
+ spin_unlock_irq(&cgwb_lock);
+ wb_shutdown(wb);
+ spin_lock_irq(&cgwb_lock);
}
-
spin_unlock_irq(&cgwb_lock);
-
- /*
- * All cgwb's and their congested states must be shutdown and
- * released before returning. Drain the usage counter to wait for
- * all cgwb's and cgwb_congested's ever created on @bdi.
- */
- atomic_dec(&bdi->usage_cnt);
- wait_event(cgwb_release_wait, !atomic_read(&bdi->usage_cnt));
}
/**
@@ -747,6 +758,28 @@
spin_unlock_irq(&cgwb_lock);
}
+static void cgwb_bdi_exit(struct backing_dev_info *bdi)
+{
+ struct rb_node *rbn;
+
+ spin_lock_irq(&cgwb_lock);
+ while ((rbn = rb_first(&bdi->cgwb_congested_tree))) {
+ struct bdi_writeback_congested *congested =
+ rb_entry(rbn, struct bdi_writeback_congested, rb_node);
+
+ rb_erase(rbn, &bdi->cgwb_congested_tree);
+ congested->__bdi = NULL; /* mark @congested unlinked */
+ }
+ spin_unlock_irq(&cgwb_lock);
+}
+
+static void cgwb_bdi_register(struct backing_dev_info *bdi)
+{
+ spin_lock_irq(&cgwb_lock);
+ list_add_tail_rcu(&bdi->wb.bdi_node, &bdi->wb_list);
+ spin_unlock_irq(&cgwb_lock);
+}
+
#else /* CONFIG_CGROUP_WRITEBACK */
static int cgwb_bdi_init(struct backing_dev_info *bdi)
@@ -767,11 +800,23 @@
return 0;
}
-static void cgwb_bdi_destroy(struct backing_dev_info *bdi)
+static void cgwb_bdi_unregister(struct backing_dev_info *bdi) { }
+
+static void cgwb_bdi_exit(struct backing_dev_info *bdi)
{
wb_congested_put(bdi->wb_congested);
}
+static void cgwb_bdi_register(struct backing_dev_info *bdi)
+{
+ list_add_tail_rcu(&bdi->wb.bdi_node, &bdi->wb_list);
+}
+
+static void cgwb_remove_from_bdi_list(struct bdi_writeback *wb)
+{
+ list_del_rcu(&wb->bdi_node);
+}
+
#endif /* CONFIG_CGROUP_WRITEBACK */
int bdi_init(struct backing_dev_info *bdi)
@@ -780,6 +825,7 @@
bdi->dev = NULL;
+ kref_init(&bdi->refcnt);
bdi->min_ratio = 0;
bdi->max_ratio = 100;
bdi->max_prop_frac = FPROP_FRAC_BASE;
@@ -789,12 +835,26 @@
ret = cgwb_bdi_init(bdi);
- list_add_tail_rcu(&bdi->wb.bdi_node, &bdi->wb_list);
-
return ret;
}
EXPORT_SYMBOL(bdi_init);
+struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id)
+{
+ struct backing_dev_info *bdi;
+
+ bdi = kmalloc_node(sizeof(struct backing_dev_info),
+ gfp_mask | __GFP_ZERO, node_id);
+ if (!bdi)
+ return NULL;
+
+ if (bdi_init(bdi)) {
+ kfree(bdi);
+ return NULL;
+ }
+ return bdi;
+}
+
int bdi_register(struct backing_dev_info *bdi, struct device *parent,
const char *fmt, ...)
{
@@ -810,6 +870,7 @@
if (IS_ERR(dev))
return PTR_ERR(dev);
+ cgwb_bdi_register(bdi);
bdi->dev = dev;
bdi_debug_register(bdi, dev_name(dev));
@@ -838,6 +899,8 @@
MINOR(owner->devt));
if (rc)
return rc;
+ /* Leaking owner reference... */
+ WARN_ON(bdi->owner);
bdi->owner = owner;
get_device(owner);
return 0;
@@ -861,7 +924,7 @@
/* make sure nobody finds us on the bdi_list anymore */
bdi_remove_from_list(bdi);
wb_shutdown(&bdi->wb);
- cgwb_bdi_destroy(bdi);
+ cgwb_bdi_unregister(bdi);
if (bdi->dev) {
bdi_debug_unregister(bdi);
@@ -875,10 +938,25 @@
}
}
-void bdi_exit(struct backing_dev_info *bdi)
+static void bdi_exit(struct backing_dev_info *bdi)
{
WARN_ON_ONCE(bdi->dev);
wb_exit(&bdi->wb);
+ cgwb_bdi_exit(bdi);
+}
+
+static void release_bdi(struct kref *ref)
+{
+ struct backing_dev_info *bdi =
+ container_of(ref, struct backing_dev_info, refcnt);
+
+ bdi_exit(bdi);
+ kfree(bdi);
+}
+
+void bdi_put(struct backing_dev_info *bdi)
+{
+ kref_put(&bdi->refcnt, release_bdi);
}
void bdi_destroy(struct backing_dev_info *bdi)
diff --git a/mm/early_ioremap.c b/mm/early_ioremap.c
index 6d5717b..57540de 100644
--- a/mm/early_ioremap.c
+++ b/mm/early_ioremap.c
@@ -103,7 +103,7 @@
enum fixed_addresses idx;
int i, slot;
- WARN_ON(system_state != SYSTEM_BOOTING);
+ WARN_ON(system_state >= SYSTEM_RUNNING);
slot = -1;
for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
index 1258b16..7a6d1a1 100644
--- a/mm/kasan/kasan.c
+++ b/mm/kasan/kasan.c
@@ -39,6 +39,16 @@
#include "kasan.h"
#include "../slab.h"
+void kasan_enable_current(void)
+{
+ current->kasan_depth++;
+}
+
+void kasan_disable_current(void)
+{
+ current->kasan_depth--;
+}
+
/*
* Poisons the shadow memory for 'size' bytes starting from 'addr'.
* Memory addresses should be aligned to KASAN_SHADOW_SCALE_SIZE.
@@ -428,7 +438,7 @@
quarantine_remove_cache(cache);
}
-void kasan_cache_destroy(struct kmem_cache *cache)
+void kasan_cache_shutdown(struct kmem_cache *cache)
{
quarantine_remove_cache(cache);
}
diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h
index 7572917..1229298 100644
--- a/mm/kasan/kasan.h
+++ b/mm/kasan/kasan.h
@@ -96,11 +96,6 @@
<< KASAN_SHADOW_SCALE_SHIFT);
}
-static inline bool kasan_report_enabled(void)
-{
- return !current->kasan_depth;
-}
-
void kasan_report(unsigned long addr, size_t size,
bool is_write, unsigned long ip);
void kasan_report_double_free(struct kmem_cache *cache, void *object,
diff --git a/mm/kasan/quarantine.c b/mm/kasan/quarantine.c
index baabaad..3a8ddf8 100644
--- a/mm/kasan/quarantine.c
+++ b/mm/kasan/quarantine.c
@@ -25,6 +25,7 @@
#include <linux/printk.h>
#include <linux/shrinker.h>
#include <linux/slab.h>
+#include <linux/srcu.h>
#include <linux/string.h>
#include <linux/types.h>
@@ -86,24 +87,9 @@
qlist_init(from);
}
-static void qlist_move(struct qlist_head *from, struct qlist_node *last,
- struct qlist_head *to, size_t size)
-{
- if (unlikely(last == from->tail)) {
- qlist_move_all(from, to);
- return;
- }
- if (qlist_empty(to))
- to->head = from->head;
- else
- to->tail->next = from->head;
- to->tail = last;
- from->head = last->next;
- last->next = NULL;
- from->bytes -= size;
- to->bytes += size;
-}
-
+#define QUARANTINE_PERCPU_SIZE (1 << 20)
+#define QUARANTINE_BATCHES \
+ (1024 > 4 * CONFIG_NR_CPUS ? 1024 : 4 * CONFIG_NR_CPUS)
/*
* The object quarantine consists of per-cpu queues and a global queue,
@@ -111,11 +97,23 @@
*/
static DEFINE_PER_CPU(struct qlist_head, cpu_quarantine);
-static struct qlist_head global_quarantine;
+/* Round-robin FIFO array of batches. */
+static struct qlist_head global_quarantine[QUARANTINE_BATCHES];
+static int quarantine_head;
+static int quarantine_tail;
+/* Total size of all objects in global_quarantine across all batches. */
+static unsigned long quarantine_size;
static DEFINE_SPINLOCK(quarantine_lock);
+DEFINE_STATIC_SRCU(remove_cache_srcu);
/* Maximum size of the global queue. */
-static unsigned long quarantine_size;
+static unsigned long quarantine_max_size;
+
+/*
+ * Target size of a batch in global_quarantine.
+ * Usually equal to QUARANTINE_PERCPU_SIZE unless we have too much RAM.
+ */
+static unsigned long quarantine_batch_size;
/*
* The fraction of physical memory the quarantine is allowed to occupy.
@@ -124,9 +122,6 @@
*/
#define QUARANTINE_FRACTION 32
-#define QUARANTINE_LOW_SIZE (READ_ONCE(quarantine_size) * 3 / 4)
-#define QUARANTINE_PERCPU_SIZE (1 << 20)
-
static struct kmem_cache *qlink_to_cache(struct qlist_node *qlink)
{
return virt_to_head_page(qlink)->slab_cache;
@@ -180,62 +175,89 @@
struct qlist_head *q;
struct qlist_head temp = QLIST_INIT;
+ /*
+ * Note: irq must be disabled until after we move the batch to the
+ * global quarantine. Otherwise quarantine_remove_cache() can miss
+ * some objects belonging to the cache if they are in our local temp
+ * list. quarantine_remove_cache() executes on_each_cpu() at the
+ * beginning which ensures that it either sees the objects in per-cpu
+ * lists or in the global quarantine.
+ */
local_irq_save(flags);
q = this_cpu_ptr(&cpu_quarantine);
qlist_put(q, &info->quarantine_link, cache->size);
- if (unlikely(q->bytes > QUARANTINE_PERCPU_SIZE))
+ if (unlikely(q->bytes > QUARANTINE_PERCPU_SIZE)) {
qlist_move_all(q, &temp);
- local_irq_restore(flags);
+ spin_lock(&quarantine_lock);
+ WRITE_ONCE(quarantine_size, quarantine_size + temp.bytes);
+ qlist_move_all(&temp, &global_quarantine[quarantine_tail]);
+ if (global_quarantine[quarantine_tail].bytes >=
+ READ_ONCE(quarantine_batch_size)) {
+ int new_tail;
- if (unlikely(!qlist_empty(&temp))) {
- spin_lock_irqsave(&quarantine_lock, flags);
- qlist_move_all(&temp, &global_quarantine);
- spin_unlock_irqrestore(&quarantine_lock, flags);
+ new_tail = quarantine_tail + 1;
+ if (new_tail == QUARANTINE_BATCHES)
+ new_tail = 0;
+ if (new_tail != quarantine_head)
+ quarantine_tail = new_tail;
+ }
+ spin_unlock(&quarantine_lock);
}
+
+ local_irq_restore(flags);
}
void quarantine_reduce(void)
{
- size_t new_quarantine_size, percpu_quarantines;
+ size_t total_size, new_quarantine_size, percpu_quarantines;
unsigned long flags;
+ int srcu_idx;
struct qlist_head to_free = QLIST_INIT;
- size_t size_to_free = 0;
- struct qlist_node *last;
- if (likely(READ_ONCE(global_quarantine.bytes) <=
- READ_ONCE(quarantine_size)))
+ if (likely(READ_ONCE(quarantine_size) <=
+ READ_ONCE(quarantine_max_size)))
return;
+ /*
+ * srcu critical section ensures that quarantine_remove_cache()
+ * will not miss objects belonging to the cache while they are in our
+ * local to_free list. srcu is chosen because (1) it gives us private
+ * grace period domain that does not interfere with anything else,
+ * and (2) it allows synchronize_srcu() to return without waiting
+ * if there are no pending read critical sections (which is the
+ * expected case).
+ */
+ srcu_idx = srcu_read_lock(&remove_cache_srcu);
spin_lock_irqsave(&quarantine_lock, flags);
/*
* Update quarantine size in case of hotplug. Allocate a fraction of
* the installed memory to quarantine minus per-cpu queue limits.
*/
- new_quarantine_size = (READ_ONCE(totalram_pages) << PAGE_SHIFT) /
+ total_size = (READ_ONCE(totalram_pages) << PAGE_SHIFT) /
QUARANTINE_FRACTION;
percpu_quarantines = QUARANTINE_PERCPU_SIZE * num_online_cpus();
- new_quarantine_size = (new_quarantine_size < percpu_quarantines) ?
- 0 : new_quarantine_size - percpu_quarantines;
- WRITE_ONCE(quarantine_size, new_quarantine_size);
+ new_quarantine_size = (total_size < percpu_quarantines) ?
+ 0 : total_size - percpu_quarantines;
+ WRITE_ONCE(quarantine_max_size, new_quarantine_size);
+ /* Aim at consuming at most 1/2 of slots in quarantine. */
+ WRITE_ONCE(quarantine_batch_size, max((size_t)QUARANTINE_PERCPU_SIZE,
+ 2 * total_size / QUARANTINE_BATCHES));
- last = global_quarantine.head;
- while (last) {
- struct kmem_cache *cache = qlink_to_cache(last);
-
- size_to_free += cache->size;
- if (!last->next || size_to_free >
- global_quarantine.bytes - QUARANTINE_LOW_SIZE)
- break;
- last = last->next;
+ if (likely(quarantine_size > quarantine_max_size)) {
+ qlist_move_all(&global_quarantine[quarantine_head], &to_free);
+ WRITE_ONCE(quarantine_size, quarantine_size - to_free.bytes);
+ quarantine_head++;
+ if (quarantine_head == QUARANTINE_BATCHES)
+ quarantine_head = 0;
}
- qlist_move(&global_quarantine, last, &to_free, size_to_free);
spin_unlock_irqrestore(&quarantine_lock, flags);
qlist_free_all(&to_free, NULL);
+ srcu_read_unlock(&remove_cache_srcu, srcu_idx);
}
static void qlist_move_cache(struct qlist_head *from,
@@ -273,16 +295,34 @@
qlist_free_all(&to_free, cache);
}
+/* Free all quarantined objects belonging to cache. */
void quarantine_remove_cache(struct kmem_cache *cache)
{
- unsigned long flags;
+ unsigned long flags, i;
struct qlist_head to_free = QLIST_INIT;
+ /*
+ * Must be careful to not miss any objects that are being moved from
+ * per-cpu list to the global quarantine in quarantine_put(),
+ * nor objects being freed in quarantine_reduce(). on_each_cpu()
+ * achieves the first goal, while synchronize_srcu() achieves the
+ * second.
+ */
on_each_cpu(per_cpu_remove_cache, cache, 1);
spin_lock_irqsave(&quarantine_lock, flags);
- qlist_move_cache(&global_quarantine, &to_free, cache);
+ for (i = 0; i < QUARANTINE_BATCHES; i++) {
+ if (qlist_empty(&global_quarantine[i]))
+ continue;
+ qlist_move_cache(&global_quarantine[i], &to_free, cache);
+ /* Scanning whole quarantine can take a while. */
+ spin_unlock_irqrestore(&quarantine_lock, flags);
+ cond_resched();
+ spin_lock_irqsave(&quarantine_lock, flags);
+ }
spin_unlock_irqrestore(&quarantine_lock, flags);
qlist_free_all(&to_free, cache);
+
+ synchronize_srcu(&remove_cache_srcu);
}
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index 5cbd2de..0b8cf43 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -13,7 +13,9 @@
*
*/
+#include <linux/bitops.h>
#include <linux/ftrace.h>
+#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/printk.h>
@@ -105,7 +107,7 @@
return bug_type;
}
-const char *get_wild_bug_type(struct kasan_access_info *info)
+static const char *get_wild_bug_type(struct kasan_access_info *info)
{
const char *bug_type = "unknown-crash";
@@ -170,6 +172,8 @@
pr_err("==================================================================\n");
add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
spin_unlock_irqrestore(&report_lock, *flags);
+ if (panic_on_warn)
+ panic("panic_on_warn set ...\n");
kasan_enable_current();
}
@@ -352,6 +356,40 @@
kasan_end_report(&flags);
}
+static unsigned long kasan_flags;
+
+#define KASAN_BIT_REPORTED 0
+#define KASAN_BIT_MULTI_SHOT 1
+
+bool kasan_save_enable_multi_shot(void)
+{
+ return test_and_set_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
+}
+EXPORT_SYMBOL_GPL(kasan_save_enable_multi_shot);
+
+void kasan_restore_multi_shot(bool enabled)
+{
+ if (!enabled)
+ clear_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
+}
+EXPORT_SYMBOL_GPL(kasan_restore_multi_shot);
+
+static int __init kasan_set_multi_shot(char *str)
+{
+ set_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
+ return 1;
+}
+__setup("kasan_multi_shot", kasan_set_multi_shot);
+
+static inline bool kasan_report_enabled(void)
+{
+ if (current->kasan_depth)
+ return false;
+ if (test_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags))
+ return true;
+ return !test_and_set_bit(KASAN_BIT_REPORTED, &kasan_flags);
+}
+
void kasan_report(unsigned long addr, size_t size,
bool is_write, unsigned long ip)
{
diff --git a/mm/memory.c b/mm/memory.c
index 82d2000..f882280 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -75,7 +75,7 @@
#include "internal.h"
-#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
+#if defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) && !defined(CONFIG_COMPILE_TEST)
#warning Unfortunate NUMA and NUMA Balancing config, growing page-frame for last_cpupid.
#endif
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index dd7817cd3..e6fbdf4 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -1987,11 +1987,11 @@
* We want to write everything out, not just down to the dirty
* threshold
*/
- if (!bdi_has_dirty_io(&q->backing_dev_info))
+ if (!bdi_has_dirty_io(q->backing_dev_info))
return;
rcu_read_lock();
- list_for_each_entry_rcu(wb, &q->backing_dev_info.wb_list, bdi_node)
+ list_for_each_entry_rcu(wb, &q->backing_dev_info->wb_list, bdi_node)
if (wb_has_dirty_io(wb))
wb_start_writeback(wb, nr_pages, true,
WB_REASON_LAPTOP_TIMER);
diff --git a/mm/page_io.c b/mm/page_io.c
index a2651f5..efe6fd6 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -56,7 +56,7 @@
* Also clear PG_reclaim to avoid rotate_reclaimable_page()
*/
set_page_dirty(page);
- pr_alert("Write-error on swap-device (%u:%u:%llu)\n",
+ pr_alert_ratelimited("Write-error on swap-device (%u:%u:%llu)\n",
imajor(bio->bi_bdev->bd_inode),
iminor(bio->bi_bdev->bd_inode),
(unsigned long long)bio->bi_iter.bi_sector);
diff --git a/mm/shmem.c b/mm/shmem.c
index 7a74b6d..0a6ac6a 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -370,6 +370,7 @@
int shmem_huge __read_mostly;
+#if defined(CONFIG_SYSFS) || defined(CONFIG_TMPFS)
static int shmem_parse_huge(const char *str)
{
if (!strcmp(str, "never"))
@@ -407,6 +408,7 @@
return "bad_val";
}
}
+#endif
static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo,
struct shrink_control *sc, unsigned long nr_to_split)
@@ -1550,7 +1552,7 @@
struct mm_struct *fault_mm, int *fault_type)
{
struct address_space *mapping = inode->i_mapping;
- struct shmem_inode_info *info;
+ struct shmem_inode_info *info = SHMEM_I(inode);
struct shmem_sb_info *sbinfo;
struct mm_struct *charge_mm;
struct mem_cgroup *memcg;
@@ -1600,7 +1602,6 @@
* Fast cache lookup did not find it:
* bring it back from swap or allocate.
*/
- info = SHMEM_I(inode);
sbinfo = SHMEM_SB(inode->i_sb);
charge_mm = fault_mm ? : current->mm;
@@ -1852,7 +1853,6 @@
put_page(page);
}
if (error == -ENOSPC && !once++) {
- info = SHMEM_I(inode);
spin_lock_irq(&info->lock);
shmem_recalc_inode(inode);
spin_unlock_irq(&info->lock);
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 622f6b6..0dc614d 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -458,6 +458,9 @@
static int shutdown_cache(struct kmem_cache *s,
struct list_head *release, bool *need_rcu_barrier)
{
+ /* free asan quarantined objects */
+ kasan_cache_shutdown(s);
+
if (__kmem_cache_shutdown(s) != 0)
return -EBUSY;
@@ -741,7 +744,6 @@
get_online_cpus();
get_online_mems();
- kasan_cache_destroy(s);
mutex_lock(&slab_mutex);
s->refcount--;
diff --git a/mm/util.c b/mm/util.c
index 1a41553..8c755d0 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -80,6 +80,8 @@
* @s: the string to duplicate
* @max: read at most @max chars from @s
* @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ *
+ * Note: Use kmemdup_nul() instead if the size is known exactly.
*/
char *kstrndup(const char *s, size_t max, gfp_t gfp)
{
@@ -118,6 +120,28 @@
EXPORT_SYMBOL(kmemdup);
/**
+ * kmemdup_nul - Create a NUL-terminated string from unterminated data
+ * @s: The data to stringify
+ * @len: The size of the data
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ */
+char *kmemdup_nul(const char *s, size_t len, gfp_t gfp)
+{
+ char *buf;
+
+ if (!s)
+ return NULL;
+
+ buf = kmalloc_track_caller(len + 1, gfp);
+ if (buf) {
+ memcpy(buf, s, len);
+ buf[len] = '\0';
+ }
+ return buf;
+}
+EXPORT_SYMBOL(kmemdup_nul);
+
+/**
* memdup_user - duplicate memory region from user space
*
* @src: source address in user space
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 2740973..658d62c 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -297,10 +297,13 @@
*/
void unregister_shrinker(struct shrinker *shrinker)
{
+ if (!shrinker->nr_deferred)
+ return;
down_write(&shrinker_rwsem);
list_del(&shrinker->list);
up_write(&shrinker_rwsem);
kfree(shrinker->nr_deferred);
+ shrinker->nr_deferred = NULL;
}
EXPORT_SYMBOL(unregister_shrinker);
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index f3a4efc..3aa5a93 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -160,7 +160,8 @@
spin_unlock_irqrestore(&chan->lock, flags);
/* Wakeup if anyone waiting for VirtIO ring space. */
wake_up(chan->vc_wq);
- p9_client_cb(chan->client, req, REQ_STATUS_RCVD);
+ if (len)
+ p9_client_cb(chan->client, req, REQ_STATUS_RCVD);
}
}
diff --git a/net/core/dev.c b/net/core/dev.c
index ca40d8e..c2f62d2 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2765,7 +2765,7 @@
segs = skb_mac_gso_segment(skb, features);
- if (unlikely(skb_needs_check(skb, tx_path)))
+ if (unlikely(skb_needs_check(skb, tx_path) && !IS_ERR(segs)))
skb_warn_bad_offload(skb);
return segs;
diff --git a/net/core/sock_reuseport.c b/net/core/sock_reuseport.c
index 77f396b..5dce429 100644
--- a/net/core/sock_reuseport.c
+++ b/net/core/sock_reuseport.c
@@ -93,6 +93,16 @@
return more_reuse;
}
+static void reuseport_free_rcu(struct rcu_head *head)
+{
+ struct sock_reuseport *reuse;
+
+ reuse = container_of(head, struct sock_reuseport, rcu);
+ if (reuse->prog)
+ bpf_prog_destroy(reuse->prog);
+ kfree(reuse);
+}
+
/**
* reuseport_add_sock - Add a socket to the reuseport group of another.
* @sk: New socket to add to the group.
@@ -101,7 +111,7 @@
*/
int reuseport_add_sock(struct sock *sk, struct sock *sk2)
{
- struct sock_reuseport *reuse;
+ struct sock_reuseport *old_reuse, *reuse;
if (!rcu_access_pointer(sk2->sk_reuseport_cb)) {
int err = reuseport_alloc(sk2);
@@ -112,10 +122,13 @@
spin_lock_bh(&reuseport_lock);
reuse = rcu_dereference_protected(sk2->sk_reuseport_cb,
- lockdep_is_held(&reuseport_lock)),
- WARN_ONCE(rcu_dereference_protected(sk->sk_reuseport_cb,
- lockdep_is_held(&reuseport_lock)),
- "socket already in reuseport group");
+ lockdep_is_held(&reuseport_lock));
+ old_reuse = rcu_dereference_protected(sk->sk_reuseport_cb,
+ lockdep_is_held(&reuseport_lock));
+ if (old_reuse && old_reuse->num_socks != 1) {
+ spin_unlock_bh(&reuseport_lock);
+ return -EBUSY;
+ }
if (reuse->num_socks == reuse->max_socks) {
reuse = reuseport_grow(reuse);
@@ -133,19 +146,11 @@
spin_unlock_bh(&reuseport_lock);
+ if (old_reuse)
+ call_rcu(&old_reuse->rcu, reuseport_free_rcu);
return 0;
}
-static void reuseport_free_rcu(struct rcu_head *head)
-{
- struct sock_reuseport *reuse;
-
- reuse = container_of(head, struct sock_reuseport, rcu);
- if (reuse->prog)
- bpf_prog_destroy(reuse->prog);
- kfree(reuse);
-}
-
void reuseport_detach_sock(struct sock *sk)
{
struct sock_reuseport *reuse;
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index b68168f..9d43c1f 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -259,6 +259,7 @@
{
struct inet_connection_sock *icsk = inet_csk(sk);
struct inet_sock *inet = inet_sk(sk);
+ struct dccp_sock *dp = dccp_sk(sk);
int err = 0;
const int old_state = sk->sk_state;
@@ -278,6 +279,10 @@
sk->sk_err = ECONNRESET;
dccp_clear_xmit_timers(sk);
+ ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+ ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+ dp->dccps_hc_rx_ccid = NULL;
+ dp->dccps_hc_tx_ccid = NULL;
__skb_queue_purge(&sk->sk_receive_queue);
__skb_queue_purge(&sk->sk_write_queue);
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 13d6b1a..9d8fcdef 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1337,6 +1337,12 @@
lock_sock(sk);
err = __dn_setsockopt(sock, level, optname, optval, optlen, 0);
release_sock(sk);
+#ifdef CONFIG_NETFILTER
+ /* we need to exclude all possible ENOPROTOOPTs except default case */
+ if (err == -ENOPROTOOPT && optname != DSO_LINKINFO &&
+ optname != DSO_STREAM && optname != DSO_SEQPACKET)
+ err = nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
+#endif
return err;
}
@@ -1444,15 +1450,6 @@
dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation);
break;
- default:
-#ifdef CONFIG_NETFILTER
- return nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
-#endif
- case DSO_LINKINFO:
- case DSO_STREAM:
- case DSO_SEQPACKET:
- return -ENOPROTOOPT;
-
case DSO_MAXWINDOW:
if (optlen != sizeof(unsigned long))
return -EINVAL;
@@ -1500,6 +1497,12 @@
return -EINVAL;
scp->info_loc = u.info;
break;
+
+ case DSO_LINKINFO:
+ case DSO_STREAM:
+ case DSO_SEQPACKET:
+ default:
+ return -ENOPROTOOPT;
}
return 0;
@@ -1513,6 +1516,20 @@
lock_sock(sk);
err = __dn_getsockopt(sock, level, optname, optval, optlen, 0);
release_sock(sk);
+#ifdef CONFIG_NETFILTER
+ if (err == -ENOPROTOOPT && optname != DSO_STREAM &&
+ optname != DSO_SEQPACKET && optname != DSO_CONACCEPT &&
+ optname != DSO_CONREJECT) {
+ int len;
+
+ if (get_user(len, optlen))
+ return -EFAULT;
+
+ err = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
+ if (err >= 0)
+ err = put_user(len, optlen);
+ }
+#endif
return err;
}
@@ -1578,26 +1595,6 @@
r_data = &link;
break;
- default:
-#ifdef CONFIG_NETFILTER
- {
- int ret, len;
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- ret = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
- if (ret >= 0)
- ret = put_user(len, optlen);
- return ret;
- }
-#endif
- case DSO_STREAM:
- case DSO_SEQPACKET:
- case DSO_CONACCEPT:
- case DSO_CONREJECT:
- return -ENOPROTOOPT;
-
case DSO_MAXWINDOW:
if (r_len > sizeof(unsigned long))
r_len = sizeof(unsigned long);
@@ -1629,6 +1626,13 @@
r_len = sizeof(unsigned char);
r_data = &scp->info_rem;
break;
+
+ case DSO_STREAM:
+ case DSO_SEQPACKET:
+ case DSO_CONACCEPT:
+ case DSO_CONREJECT:
+ default:
+ return -ENOPROTOOPT;
}
if (r_data) {
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c
index ecc28cf..d502c94 100644
--- a/net/dns_resolver/dns_query.c
+++ b/net/dns_resolver/dns_query.c
@@ -70,7 +70,7 @@
const char *options, char **_result, time64_t *_expiry)
{
struct key *rkey;
- const struct user_key_payload *upayload;
+ struct user_key_payload *upayload;
const struct cred *saved_cred;
size_t typelen, desclen;
char *desc, *cp;
@@ -141,7 +141,7 @@
if (ret)
goto put;
- upayload = user_key_payload(rkey);
+ upayload = user_key_payload_locked(rkey);
len = upayload->datalen;
ret = -ENOMEM;
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 2b887c5..f3bf1ba 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -587,13 +587,24 @@
int err;
long timeo;
- if (addr_len < sizeof(uaddr->sa_family))
- return -EINVAL;
+ /*
+ * uaddr can be NULL and addr_len can be 0 if:
+ * sk is a TCP fastopen active socket and
+ * TCP_FASTOPEN_CONNECT sockopt is set and
+ * we already have a valid cookie for this socket.
+ * In this case, user can call write() after connect().
+ * write() will invoke tcp_sendmsg_fastopen() which calls
+ * __inet_stream_connect().
+ */
+ if (uaddr) {
+ if (addr_len < sizeof(uaddr->sa_family))
+ return -EINVAL;
- if (uaddr->sa_family == AF_UNSPEC) {
- err = sk->sk_prot->disconnect(sk, flags);
- sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;
- goto out;
+ if (uaddr->sa_family == AF_UNSPEC) {
+ err = sk->sk_prot->disconnect(sk, flags);
+ sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;
+ goto out;
+ }
}
switch (sock->state) {
@@ -604,7 +615,10 @@
err = -EISCONN;
goto out;
case SS_CONNECTING:
- err = -EALREADY;
+ if (inet_sk(sk)->defer_connect)
+ err = -EINPROGRESS;
+ else
+ err = -EALREADY;
/* Fall out of switch with err, set for this state */
break;
case SS_UNCONNECTED:
@@ -618,6 +632,9 @@
sock->state = SS_CONNECTING;
+ if (!err && inet_sk(sk)->defer_connect)
+ goto out;
+
/* Just entered SS_CONNECTING state; the only
* difference is that return value in non-blocking
* case is EINPROGRESS, rather than EALREADY.
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 9c7a4ce..7f5fe07 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -386,7 +386,11 @@
pip->frag_off = htons(IP_DF);
pip->ttl = 1;
pip->daddr = fl4.daddr;
+
+ rcu_read_lock();
pip->saddr = igmpv3_get_srcaddr(dev, &fl4);
+ rcu_read_unlock();
+
pip->protocol = IPPROTO_IGMP;
pip->tot_len = 0; /* filled in later */
ip_select_ident(net, skb, NULL);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 551dd39..bf62fa4 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -1243,11 +1243,8 @@
if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
optname != IP_IPSEC_POLICY &&
optname != IP_XFRM_POLICY &&
- !ip_mroute_opt(optname)) {
- lock_sock(sk);
+ !ip_mroute_opt(optname))
err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);
- release_sock(sk);
- }
#endif
return err;
}
@@ -1272,12 +1269,9 @@
if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
optname != IP_IPSEC_POLICY &&
optname != IP_XFRM_POLICY &&
- !ip_mroute_opt(optname)) {
- lock_sock(sk);
- err = compat_nf_setsockopt(sk, PF_INET, optname,
- optval, optlen);
- release_sock(sk);
- }
+ !ip_mroute_opt(optname))
+ err = compat_nf_setsockopt(sk, PF_INET, optname, optval,
+ optlen);
#endif
return err;
}
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 4a9e6db..16599ba 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -365,7 +365,7 @@
struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
const struct ipt_entry *e = par->entryinfo;
struct clusterip_config *config;
- int ret;
+ int ret, i;
if (par->nft_compat) {
pr_err("cannot use CLUSTERIP target from nftables compat\n");
@@ -384,8 +384,18 @@
pr_info("Please specify destination IP\n");
return -EINVAL;
}
-
- /* FIXME: further sanity checks */
+ if (cipinfo->num_local_nodes > ARRAY_SIZE(cipinfo->local_nodes)) {
+ pr_info("bad num_local_nodes %u\n", cipinfo->num_local_nodes);
+ return -EINVAL;
+ }
+ for (i = 0; i < cipinfo->num_local_nodes; i++) {
+ if (cipinfo->local_nodes[i] - 1 >=
+ sizeof(config->local_nodes) * 8) {
+ pr_info("bad local_nodes[%d] %u\n",
+ i, cipinfo->local_nodes[i]);
+ return -EINVAL;
+ }
+ }
config = clusterip_config_find_get(par->net, e->ip.dst.s_addr, 1);
if (!config) {
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 0c9ded2..6dc8eab 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -218,15 +218,19 @@
struct nf_conntrack_tuple tuple;
memset(&tuple, 0, sizeof(tuple));
+
+ lock_sock(sk);
tuple.src.u3.ip = inet->inet_rcv_saddr;
tuple.src.u.tcp.port = inet->inet_sport;
tuple.dst.u3.ip = inet->inet_daddr;
tuple.dst.u.tcp.port = inet->inet_dport;
tuple.src.l3num = PF_INET;
tuple.dst.protonum = sk->sk_protocol;
+ release_sock(sk);
/* We only do TCP and SCTP at the moment: is there a better way? */
- if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP) {
+ if (tuple.dst.protonum != IPPROTO_TCP &&
+ tuple.dst.protonum != IPPROTO_SCTP) {
pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n");
return -ENOPROTOOPT;
}
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index cb3f08c..af0b324 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -544,6 +544,12 @@
if (tp->urg_data & TCP_URG_VALID)
mask |= POLLPRI;
+ } else if (state == TCP_SYN_SENT && inet_sk(sk)->defer_connect) {
+ /* Active TCP fastopen socket with defer_connect
+ * Return POLLOUT so application can call write()
+ * in order for kernel to generate SYN+data
+ */
+ mask |= POLLOUT | POLLWRNORM;
}
/* This barrier is coupled with smp_wmb() in tcp_reset() */
smp_rmb();
@@ -1085,6 +1091,7 @@
int *copied, size_t size)
{
struct tcp_sock *tp = tcp_sk(sk);
+ struct inet_sock *inet = inet_sk(sk);
struct sockaddr *uaddr = msg->msg_name;
int err, flags;
@@ -1102,11 +1109,26 @@
tp->fastopen_req->data = msg;
tp->fastopen_req->size = size;
+ if (inet->defer_connect) {
+ err = tcp_connect(sk);
+ /* Same failure procedure as in tcp_v4/6_connect */
+ if (err) {
+ tcp_set_state(sk, TCP_CLOSE);
+ inet->inet_dport = 0;
+ sk->sk_route_caps = 0;
+ }
+ }
flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0;
err = __inet_stream_connect(sk->sk_socket, uaddr,
msg->msg_namelen, flags);
- *copied = tp->fastopen_req->copied;
- tcp_free_fastopen_req(tp);
+ /* fastopen_req could already be freed in __inet_stream_connect
+ * if the connection times out or gets rst
+ */
+ if (tp->fastopen_req) {
+ *copied = tp->fastopen_req->copied;
+ tcp_free_fastopen_req(tp);
+ inet->defer_connect = 0;
+ }
return err;
}
@@ -1124,7 +1146,7 @@
lock_sock(sk);
flags = msg->msg_flags;
- if (flags & MSG_FASTOPEN) {
+ if (unlikely(flags & MSG_FASTOPEN || inet_sk(sk)->defer_connect)) {
err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
if (err == -EINPROGRESS && copied_syn > 0)
goto out;
@@ -2323,8 +2345,18 @@
sk->sk_rx_dst = NULL;
tcp_saved_syn_free(tp);
+ /* Clean up fastopen related fields */
+ tcp_free_fastopen_req(tp);
+ inet->defer_connect = 0;
+
WARN_ON(inet->inet_num && !icsk->icsk_bind_hash);
+ if (sk->sk_frag.page) {
+ put_page(sk->sk_frag.page);
+ sk->sk_frag.page = NULL;
+ sk->sk_frag.offset = 0;
+ }
+
sk->sk_error_report(sk);
return err;
}
@@ -2689,6 +2721,18 @@
err = -EINVAL;
}
break;
+ case TCP_FASTOPEN_CONNECT:
+ if (val > 1 || val < 0) {
+ err = -EINVAL;
+ } else if (sysctl_tcp_fastopen & TFO_CLIENT_ENABLE) {
+ if (sk->sk_state == TCP_CLOSE)
+ tp->fastopen_connect = val;
+ else
+ err = -EINVAL;
+ } else {
+ err = -EOPNOTSUPP;
+ }
+ break;
case TCP_TIMESTAMP:
if (!tp->repair)
err = -EPERM;
@@ -3002,6 +3046,10 @@
val = icsk->icsk_accept_queue.fastopenq.max_qlen;
break;
+ case TCP_FASTOPEN_CONNECT:
+ val = tp->fastopen_connect;
+ break;
+
case TCP_TIMESTAMP:
val = tcp_time_stamp + tp->tsoffset;
break;
diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c
index e86a34f..8ec6053 100644
--- a/net/ipv4/tcp_bbr.c
+++ b/net/ipv4/tcp_bbr.c
@@ -452,7 +452,8 @@
bbr->cycle_idx = (bbr->cycle_idx + 1) & (CYCLE_LEN - 1);
bbr->cycle_mstamp = tp->delivered_mstamp;
- bbr->pacing_gain = bbr_pacing_gain[bbr->cycle_idx];
+ bbr->pacing_gain = bbr->lt_use_bw ? BBR_UNIT :
+ bbr_pacing_gain[bbr->cycle_idx];
}
/* Gain cycling: cycle pacing gain to converge to fair share of available bw. */
@@ -461,8 +462,7 @@
{
struct bbr *bbr = inet_csk_ca(sk);
- if ((bbr->mode == BBR_PROBE_BW) && !bbr->lt_use_bw &&
- bbr_is_next_cycle_phase(sk, rs))
+ if (bbr->mode == BBR_PROBE_BW && bbr_is_next_cycle_phase(sk, rs))
bbr_advance_cycle_phase(sk);
}
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c
index dd2560c..8ea4e97 100644
--- a/net/ipv4/tcp_fastopen.c
+++ b/net/ipv4/tcp_fastopen.c
@@ -326,3 +326,57 @@
*foc = valid_foc;
return NULL;
}
+
+bool tcp_fastopen_cookie_check(struct sock *sk, u16 *mss,
+ struct tcp_fastopen_cookie *cookie)
+{
+ unsigned long last_syn_loss = 0;
+ int syn_loss = 0;
+
+ tcp_fastopen_cache_get(sk, mss, cookie, &syn_loss, &last_syn_loss);
+
+ /* Recurring FO SYN losses: no cookie or data in SYN */
+ if (syn_loss > 1 &&
+ time_before(jiffies, last_syn_loss + (60*HZ << syn_loss))) {
+ cookie->len = -1;
+ return false;
+ }
+ if (sysctl_tcp_fastopen & TFO_CLIENT_NO_COOKIE) {
+ cookie->len = -1;
+ return true;
+ }
+ return cookie->len > 0;
+}
+
+/* This function checks if we want to defer sending SYN until the first
+ * write(). We defer under the following conditions:
+ * 1. fastopen_connect sockopt is set
+ * 2. we have a valid cookie
+ * Return value: return true if we want to defer until application writes data
+ * return false if we want to send out SYN immediately
+ */
+bool tcp_fastopen_defer_connect(struct sock *sk, int *err)
+{
+ struct tcp_fastopen_cookie cookie = { .len = 0 };
+ struct tcp_sock *tp = tcp_sk(sk);
+ u16 mss;
+
+ if (tp->fastopen_connect && !tp->fastopen_req) {
+ if (tcp_fastopen_cookie_check(sk, &mss, &cookie)) {
+ inet_sk(sk)->defer_connect = 1;
+ return true;
+ }
+
+ /* Alloc fastopen_req in order for FO option to be included
+ * in SYN
+ */
+ tp->fastopen_req = kzalloc(sizeof(*tp->fastopen_req),
+ sk->sk_allocation);
+ if (tp->fastopen_req)
+ tp->fastopen_req->cookie = cookie;
+ else
+ *err = -ENOBUFS;
+ }
+ return false;
+}
+EXPORT_SYMBOL(tcp_fastopen_defer_connect);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 05ac17a..71335ac 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -232,6 +232,7 @@
/* OK, now commit destination to socket. */
sk->sk_gso_type = SKB_GSO_TCPV4;
sk_setup_caps(sk, &rt->dst);
+ rt = NULL;
if (!tp->write_seq && likely(!tp->repair))
tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
@@ -241,9 +242,13 @@
inet->inet_id = tp->write_seq ^ jiffies;
+ if (tcp_fastopen_defer_connect(sk, &err))
+ return err;
+ if (err)
+ goto failure;
+
err = tcp_connect(sk);
- rt = NULL;
if (err)
goto failure;
@@ -1673,7 +1678,9 @@
*/
sock_hold(sk);
refcounted = true;
- nsk = tcp_check_req(sk, skb, req, false);
+ nsk = NULL;
+ if (!tcp_filter(sk, skb))
+ nsk = tcp_check_req(sk, skb, req, false);
if (!nsk) {
reqsk_put(req);
goto discard_and_relse;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 3438faa..20634ea 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -3251,23 +3251,11 @@
{
struct tcp_sock *tp = tcp_sk(sk);
struct tcp_fastopen_request *fo = tp->fastopen_req;
- int syn_loss = 0, space, err = 0;
- unsigned long last_syn_loss = 0;
+ int space, err = 0;
struct sk_buff *syn_data;
tp->rx_opt.mss_clamp = tp->advmss; /* If MSS is not cached */
- tcp_fastopen_cache_get(sk, &tp->rx_opt.mss_clamp, &fo->cookie,
- &syn_loss, &last_syn_loss);
- /* Recurring FO SYN losses: revert to regular handshake temporarily */
- if (syn_loss > 1 &&
- time_before(jiffies, last_syn_loss + (60*HZ << syn_loss))) {
- fo->cookie.len = -1;
- goto fallback;
- }
-
- if (sysctl_tcp_fastopen & TFO_CLIENT_NO_COOKIE)
- fo->cookie.len = -1;
- else if (fo->cookie.len <= 0)
+ if (!tcp_fastopen_cookie_check(sk, &tp->rx_opt.mss_clamp, &fo->cookie))
goto fallback;
/* MSS for SYN-data is based on cached MSS and bounded by PMTU and
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 140d05f..a5c1ff3 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -240,6 +240,7 @@
.use_oif_addrs_only = 0,
.ignore_routes_with_linkdown = 0,
.keep_addr_on_down = 0,
+ .accept_ra_prefix_route = 1,
};
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -288,6 +289,7 @@
.use_oif_addrs_only = 0,
.ignore_routes_with_linkdown = 0,
.keep_addr_on_down = 0,
+ .accept_ra_prefix_route = 1,
};
/* Check if link is ready: is it up and is a valid qdisc available */
@@ -2607,8 +2609,11 @@
flags |= RTF_EXPIRES;
expires = jiffies_to_clock_t(rt_expires);
}
- addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,
- dev, expires, flags);
+ if (dev->ip6_ptr->cnf.accept_ra_prefix_route) {
+ addrconf_prefix_route(&pinfo->prefix,
+ pinfo->prefix_len,
+ dev, expires, flags);
+ }
}
ip6_rt_put(rt);
}
@@ -6125,6 +6130,13 @@
},
{
+ .procname = "accept_ra_prefix_route",
+ .data = &ipv6_devconf.accept_ra_prefix_route,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
/* sentinel */
}
};
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 55a8f68..1111684 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -290,6 +290,7 @@
struct net *net = sock_net(sk);
__be32 v4addr = 0;
unsigned short snum;
+ bool saved_ipv6only;
int addr_type = 0;
int err = 0;
@@ -394,19 +395,21 @@
if (!(addr_type & IPV6_ADDR_MULTICAST))
np->saddr = addr->sin6_addr;
+ saved_ipv6only = sk->sk_ipv6only;
+ if (addr_type != IPV6_ADDR_ANY && addr_type != IPV6_ADDR_MAPPED)
+ sk->sk_ipv6only = 1;
+
/* Make sure we are allowed to bind here. */
if ((snum || !inet->bind_address_no_port) &&
sk->sk_prot->get_port(sk, snum)) {
+ sk->sk_ipv6only = saved_ipv6only;
inet_reset_saddr(sk);
err = -EADDRINUSE;
goto out;
}
- if (addr_type != IPV6_ADDR_ANY) {
+ if (addr_type != IPV6_ADDR_ANY)
sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
- if (addr_type != IPV6_ADDR_MAPPED)
- sk->sk_ipv6only = 1;
- }
if (snum)
sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
inet->inet_sport = htons(inet->inet_num);
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 117405d..a30e7e9 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -495,6 +495,7 @@
return ERR_PTR(-ENOENT);
it->mrt = mrt;
+ it->cache = NULL;
return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
: SEQ_START_TOKEN;
}
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index bcea985..493a32f 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -907,12 +907,8 @@
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
- optname != IPV6_XFRM_POLICY) {
- lock_sock(sk);
- err = nf_setsockopt(sk, PF_INET6, optname, optval,
- optlen);
- release_sock(sk);
- }
+ optname != IPV6_XFRM_POLICY)
+ err = nf_setsockopt(sk, PF_INET6, optname, optval, optlen);
#endif
return err;
}
@@ -942,12 +938,9 @@
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
- optname != IPV6_XFRM_POLICY) {
- lock_sock(sk);
- err = compat_nf_setsockopt(sk, PF_INET6, optname,
- optval, optlen);
- release_sock(sk);
- }
+ optname != IPV6_XFRM_POLICY)
+ err = compat_nf_setsockopt(sk, PF_INET6, optname, optval,
+ optlen);
#endif
return err;
}
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 963ee38..af80e97 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -226,20 +226,27 @@
static int
ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
{
- const struct inet_sock *inet = inet_sk(sk);
+ struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
const struct ipv6_pinfo *inet6 = inet6_sk(sk);
+ const struct inet_sock *inet = inet_sk(sk);
const struct nf_conntrack_tuple_hash *h;
struct sockaddr_in6 sin6;
- struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
struct nf_conn *ct;
+ __be32 flow_label;
+ int bound_dev_if;
+ lock_sock(sk);
tuple.src.u3.in6 = sk->sk_v6_rcv_saddr;
tuple.src.u.tcp.port = inet->inet_sport;
tuple.dst.u3.in6 = sk->sk_v6_daddr;
tuple.dst.u.tcp.port = inet->inet_dport;
tuple.dst.protonum = sk->sk_protocol;
+ bound_dev_if = sk->sk_bound_dev_if;
+ flow_label = inet6->flow_label;
+ release_sock(sk);
- if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP)
+ if (tuple.dst.protonum != IPPROTO_TCP &&
+ tuple.dst.protonum != IPPROTO_SCTP)
return -ENOPROTOOPT;
if (*len < 0 || (unsigned int) *len < sizeof(sin6))
@@ -257,14 +264,13 @@
sin6.sin6_family = AF_INET6;
sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
- sin6.sin6_flowinfo = inet6->flow_label & IPV6_FLOWINFO_MASK;
+ sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK;
memcpy(&sin6.sin6_addr,
&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6,
sizeof(sin6.sin6_addr));
nf_ct_put(ct);
- sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr,
- sk->sk_bound_dev_if);
+ sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if);
return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index bb84165..8efeff6 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -290,6 +290,11 @@
inet->inet_sport,
inet->inet_dport);
+ if (tcp_fastopen_defer_connect(sk, &err))
+ return err;
+ if (err)
+ goto late_failure;
+
err = tcp_connect(sk);
if (err)
goto late_failure;
@@ -298,7 +303,6 @@
late_failure:
tcp_set_state(sk, TCP_CLOSE);
- __sk_dst_reset(sk);
failure:
inet->inet_dport = 0;
sk->sk_route_caps = 0;
@@ -1438,7 +1442,9 @@
}
sock_hold(sk);
refcounted = true;
- nsk = tcp_check_req(sk, skb, req, false);
+ nsk = NULL;
+ if (!tcp_filter(sk, skb))
+ nsk = tcp_check_req(sk, skb, req, false);
if (!nsk) {
reqsk_put(req);
goto discard_and_relse;
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c
index 22785dc..179cd9b 100644
--- a/net/kcm/kcmsock.c
+++ b/net/kcm/kcmsock.c
@@ -1381,8 +1381,13 @@
if (!csk)
return -EINVAL;
- /* We must prevent loops or risk deadlock ! */
- if (csk->sk_family == PF_KCM)
+ /* Only allow TCP sockets to be attached for now */
+ if ((csk->sk_family != AF_INET && csk->sk_family != AF_INET6) ||
+ csk->sk_protocol != IPPROTO_TCP)
+ return -EOPNOTSUPP;
+
+ /* Don't allow listeners or closed sockets */
+ if (csk->sk_state == TCP_LISTEN || csk->sk_state == TCP_CLOSE)
return -EOPNOTSUPP;
psock = kmem_cache_zalloc(kcm_psockp, GFP_KERNEL);
@@ -1404,9 +1409,18 @@
return err;
}
- sock_hold(csk);
-
write_lock_bh(&csk->sk_callback_lock);
+
+ /* Check if sk_user_data is aready by KCM or someone else.
+ * Must be done under lock to prevent race conditions.
+ */
+ if (csk->sk_user_data) {
+ write_unlock_bh(&csk->sk_callback_lock);
+ strp_done(&psock->strp);
+ kmem_cache_free(kcm_psockp, psock);
+ return -EALREADY;
+ }
+
psock->save_data_ready = csk->sk_data_ready;
psock->save_write_space = csk->sk_write_space;
psock->save_state_change = csk->sk_state_change;
@@ -1414,8 +1428,11 @@
csk->sk_data_ready = psock_data_ready;
csk->sk_write_space = psock_write_space;
csk->sk_state_change = psock_state_change;
+
write_unlock_bh(&csk->sk_callback_lock);
+ sock_hold(csk);
+
/* Finished initialization, now add the psock to the MUX. */
spin_lock_bh(&mux->lock);
head = &mux->psocks;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index f0fe6ee..fa4d1ec 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1060,7 +1060,7 @@
next_run = gc_work->next_gc_run;
gc_work->last_bucket = i;
- queue_delayed_work(system_long_wq, &gc_work->dwork, next_run);
+ queue_delayed_work(system_power_efficient_wq, &gc_work->dwork, next_run);
}
static void conntrack_gc_work_init(struct conntrack_gc_work *gc_work)
@@ -2001,7 +2001,7 @@
nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED);
conntrack_gc_work_init(&conntrack_gc_work);
- queue_delayed_work(system_long_wq, &conntrack_gc_work.dwork, HZ);
+ queue_delayed_work(system_power_efficient_wq, &conntrack_gc_work.dwork, HZ);
return 0;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index fc49774..e47ade3 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -39,8 +39,6 @@
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module");
-#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
-
struct compat_delta {
unsigned int offset; /* offset in kernel */
int delta; /* delta in 32bit user land */
@@ -209,6 +207,9 @@
{
struct xt_match *match;
+ if (strnlen(name, XT_EXTENSION_MAXNAMELEN) == XT_EXTENSION_MAXNAMELEN)
+ return ERR_PTR(-EINVAL);
+
match = xt_find_match(nfproto, name, revision);
if (IS_ERR(match)) {
request_module("%st_%s", xt_prefix[nfproto], name);
@@ -251,6 +252,9 @@
{
struct xt_target *target;
+ if (strnlen(name, XT_EXTENSION_MAXNAMELEN) == XT_EXTENSION_MAXNAMELEN)
+ return ERR_PTR(-EINVAL);
+
target = xt_find_target(af, name, revision);
if (IS_ERR(target)) {
request_module("%st_%s", xt_prefix[af], name);
@@ -952,7 +956,7 @@
return NULL;
/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
- if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages)
+ if ((size >> PAGE_SHIFT) + 2 > totalram_pages)
return NULL;
if (sz <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER))
diff --git a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c
index dbd6c4a..92cfae6 100644
--- a/net/netfilter/xt_RATEEST.c
+++ b/net/netfilter/xt_RATEEST.c
@@ -39,23 +39,31 @@
hlist_add_head(&est->list, &rateest_hash[h]);
}
-struct xt_rateest *xt_rateest_lookup(const char *name)
+static struct xt_rateest *__xt_rateest_lookup(const char *name)
{
struct xt_rateest *est;
unsigned int h;
h = xt_rateest_hash(name);
- mutex_lock(&xt_rateest_mutex);
hlist_for_each_entry(est, &rateest_hash[h], list) {
if (strcmp(est->name, name) == 0) {
est->refcnt++;
- mutex_unlock(&xt_rateest_mutex);
return est;
}
}
- mutex_unlock(&xt_rateest_mutex);
+
return NULL;
}
+
+struct xt_rateest *xt_rateest_lookup(const char *name)
+{
+ struct xt_rateest *est;
+
+ mutex_lock(&xt_rateest_mutex);
+ est = __xt_rateest_lookup(name);
+ mutex_unlock(&xt_rateest_mutex);
+ return est;
+}
EXPORT_SYMBOL_GPL(xt_rateest_lookup);
void xt_rateest_put(struct xt_rateest *est)
@@ -100,8 +108,10 @@
net_get_random_once(&jhash_rnd, sizeof(jhash_rnd));
- est = xt_rateest_lookup(info->name);
+ mutex_lock(&xt_rateest_mutex);
+ est = __xt_rateest_lookup(info->name);
if (est) {
+ mutex_unlock(&xt_rateest_mutex);
/*
* If estimator parameters are specified, they must match the
* existing estimator.
@@ -139,11 +149,13 @@
info->est = est;
xt_rateest_hash_insert(est);
+ mutex_unlock(&xt_rateest_mutex);
return 0;
err2:
kfree(est);
err1:
+ mutex_unlock(&xt_rateest_mutex);
return ret;
}
diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c
index a086a91..0eddbd5 100644
--- a/net/netfilter/xt_cgroup.c
+++ b/net/netfilter/xt_cgroup.c
@@ -52,6 +52,7 @@
return -EINVAL;
}
+ info->priv = NULL;
if (info->has_path) {
cgrp = cgroup_get_from_path(info->path);
if (IS_ERR(cgrp)) {
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 822be06..d2141a6 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -519,13 +519,11 @@
DR_DEBUG("qtaguid: get_tag_ref(0x%llx)\n",
full_tag);
- spin_lock_bh(&uid_tag_data_tree_lock);
tr_entry = lookup_tag_ref(full_tag, &utd_entry);
BUG_ON(IS_ERR_OR_NULL(utd_entry));
if (!tr_entry)
tr_entry = new_tag_ref(full_tag, utd_entry);
- spin_unlock_bh(&uid_tag_data_tree_lock);
if (utd_res)
*utd_res = utd_entry;
DR_DEBUG("qtaguid: get_tag_ref(0x%llx) utd=%p tr=%p\n",
@@ -2027,6 +2025,7 @@
/* Delete socket tags */
spin_lock_bh(&sock_tag_list_lock);
+ spin_lock_bh(&uid_tag_data_tree_lock);
node = rb_first(&sock_tag_tree);
while (node) {
st_entry = rb_entry(node, struct sock_tag, sock_node);
@@ -2056,6 +2055,7 @@
list_del(&st_entry->list);
}
}
+ spin_unlock_bh(&uid_tag_data_tree_lock);
spin_unlock_bh(&sock_tag_list_lock);
sock_tag_tree_erase(&st_to_free_tree);
@@ -2265,10 +2265,12 @@
full_tag = combine_atag_with_uid(acct_tag, uid_int);
spin_lock_bh(&sock_tag_list_lock);
+ spin_lock_bh(&uid_tag_data_tree_lock);
sock_tag_entry = get_sock_stat_nl(el_socket->sk);
tag_ref_entry = get_tag_ref(full_tag, &uid_tag_data_entry);
if (IS_ERR(tag_ref_entry)) {
res = PTR_ERR(tag_ref_entry);
+ spin_unlock_bh(&uid_tag_data_tree_lock);
spin_unlock_bh(&sock_tag_list_lock);
goto err_put;
}
@@ -2295,9 +2297,14 @@
pr_err("qtaguid: ctrl_tag(%s): "
"socket tag alloc failed\n",
input);
+ BUG_ON(tag_ref_entry->num_sock_tags <= 0);
+ tag_ref_entry->num_sock_tags--;
+ free_tag_ref_from_utd_entry(tag_ref_entry,
+ uid_tag_data_entry);
+ spin_unlock_bh(&uid_tag_data_tree_lock);
spin_unlock_bh(&sock_tag_list_lock);
res = -ENOMEM;
- goto err_tag_unref_put;
+ goto err_put;
}
/*
* Hold the sk refcount here to make sure the sk pointer cannot
@@ -2307,7 +2314,6 @@
sock_tag_entry->sk = el_socket->sk;
sock_tag_entry->pid = current->tgid;
sock_tag_entry->tag = combine_atag_with_uid(acct_tag, uid_int);
- spin_lock_bh(&uid_tag_data_tree_lock);
pqd_entry = proc_qtu_data_tree_search(
&proc_qtu_data_tree, current->tgid);
/*
@@ -2325,11 +2331,11 @@
else
list_add(&sock_tag_entry->list,
&pqd_entry->sock_tag_list);
- spin_unlock_bh(&uid_tag_data_tree_lock);
sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree);
atomic64_inc(&qtu_events.sockets_tagged);
}
+ spin_unlock_bh(&uid_tag_data_tree_lock);
spin_unlock_bh(&sock_tag_list_lock);
/* We keep the ref to the sk until it is untagged */
CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->sk_refcnt=%d\n",
@@ -2338,10 +2344,6 @@
sockfd_put(el_socket);
return 0;
-err_tag_unref_put:
- BUG_ON(tag_ref_entry->num_sock_tags <= 0);
- tag_ref_entry->num_sock_tags--;
- free_tag_ref_from_utd_entry(tag_ref_entry, uid_tag_data_entry);
err_put:
CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->sk_refcnt=%d\n",
input, atomic_read(&el_socket->sk->sk_refcnt) - 1);
diff --git a/net/rds/tcp.c b/net/rds/tcp.c
index 78f976d3..d36effb 100644
--- a/net/rds/tcp.c
+++ b/net/rds/tcp.c
@@ -303,7 +303,8 @@
rdsdebug("freeing tc %p\n", tc);
spin_lock_irqsave(&rds_tcp_conn_lock, flags);
- list_del(&tc->t_tcp_node);
+ if (!tc->t_tcp_node_detached)
+ list_del(&tc->t_tcp_node);
spin_unlock_irqrestore(&rds_tcp_conn_lock, flags);
kmem_cache_free(rds_tcp_conn_slab, tc);
@@ -528,8 +529,12 @@
if (net != c_net || !tc->t_sock)
continue;
- if (!list_has_conn(&tmp_list, tc->t_cpath->cp_conn))
+ if (!list_has_conn(&tmp_list, tc->t_cpath->cp_conn)) {
list_move_tail(&tc->t_tcp_node, &tmp_list);
+ } else {
+ list_del(&tc->t_tcp_node);
+ tc->t_tcp_node_detached = true;
+ }
}
spin_unlock_irq(&rds_tcp_conn_lock);
list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node) {
diff --git a/net/rds/tcp.h b/net/rds/tcp.h
index 56ea662..800e847 100644
--- a/net/rds/tcp.h
+++ b/net/rds/tcp.h
@@ -11,6 +11,7 @@
struct rds_tcp_connection {
struct list_head t_tcp_node;
+ bool t_tcp_node_detached;
struct rds_conn_path *t_cpath;
/* t_conn_path_lock synchronizes the connection establishment between
* rds_tcp_accept_one and rds_tcp_conn_path_connect
diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c
index 50dd516..98b2511 100644
--- a/net/rmnet_data/rmnet_data_handlers.c
+++ b/net/rmnet_data/rmnet_data_handlers.c
@@ -356,6 +356,7 @@
napi = get_current_napi_context();
skb_size = skb->len;
+ skb_get_hash(skb);
gro_res = napi_gro_receive(napi, skb);
trace_rmnet_gro_downlink(gro_res);
rmnet_optional_gro_flush(napi, ep, skb_size);
diff --git a/net/rmnet_data/rmnet_map_data.c b/net/rmnet_data/rmnet_map_data.c
index cc377bb..771a6b7 100644
--- a/net/rmnet_data/rmnet_map_data.c
+++ b/net/rmnet_data/rmnet_map_data.c
@@ -292,7 +292,7 @@
config->agg_count = 1;
getnstimeofday(&config->agg_time);
trace_rmnet_start_aggregation(skb);
- rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_AGG_CPY_EXPAND);
+ dev_kfree_skb_any(skb);
goto schedule;
}
diff = timespec_sub(config->agg_last, config->agg_time);
@@ -321,7 +321,7 @@
dest_buff = skb_put(config->agg_skb, skb->len);
memcpy(dest_buff, skb->data, skb->len);
config->agg_count++;
- rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_AGG_INTO_BUFF);
+ dev_kfree_skb_any(skb);
schedule:
if (config->agg_state != RMNET_MAP_TXFER_SCHEDULED) {
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index ae83c3ae..da574a1 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -496,6 +496,7 @@
static int u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n,
u32 flags)
{
+ struct tc_u_hnode *ht = rtnl_dereference(n->ht_down);
struct net_device *dev = tp->q->dev_queue->dev;
struct tc_cls_u32_offload u32_offload = {0};
struct tc_to_netdev offload;
@@ -520,7 +521,7 @@
offload.cls_u32->knode.sel = &n->sel;
offload.cls_u32->knode.exts = &n->exts;
if (n->ht_down)
- offload.cls_u32->knode.link_handle = n->ht_down->handle;
+ offload.cls_u32->knode.link_handle = ht->handle;
err = dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle,
tp->protocol, &offload);
@@ -788,8 +789,9 @@
static struct tc_u_knode *u32_init_knode(struct tcf_proto *tp,
struct tc_u_knode *n)
{
- struct tc_u_knode *new;
+ struct tc_u_hnode *ht = rtnl_dereference(n->ht_down);
struct tc_u32_sel *s = &n->sel;
+ struct tc_u_knode *new;
new = kzalloc(sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key),
GFP_KERNEL);
@@ -807,11 +809,11 @@
new->fshift = n->fshift;
new->res = n->res;
new->flags = n->flags;
- RCU_INIT_POINTER(new->ht_down, n->ht_down);
+ RCU_INIT_POINTER(new->ht_down, ht);
/* bump reference count as long as we hold pointer to structure */
- if (new->ht_down)
- new->ht_down->refcnt++;
+ if (ht)
+ ht->refcnt++;
#ifdef CONFIG_CLS_U32_PERF
/* Statistics may be incremented by readers during update
diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c
index 3b6d5bd..6125c17 100644
--- a/net/sched/sch_choke.c
+++ b/net/sched/sch_choke.c
@@ -424,6 +424,9 @@
ctl = nla_data(tb[TCA_CHOKE_PARMS]);
+ if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog))
+ return -EINVAL;
+
if (ctl->limit > CHOKE_MAX_QUEUE)
return -EINVAL;
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index c78a093..44941e2 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -356,6 +356,9 @@
struct gred_sched *table = qdisc_priv(sch);
struct gred_sched_data *q = table->tab[dp];
+ if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog))
+ return -EINVAL;
+
if (!q) {
table->tab[dp] = q = *prealloc;
*prealloc = NULL;
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 249b2a1..4610d44 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -184,6 +184,8 @@
max_P = tb[TCA_RED_MAX_P] ? nla_get_u32(tb[TCA_RED_MAX_P]) : 0;
ctl = nla_data(tb[TCA_RED_PARMS]);
+ if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog))
+ return -EINVAL;
if (ctl->limit > 0) {
child = fifo_create_dflt(sch, &bfifo_qdisc_ops, ctl->limit);
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index ea8a56f..d8c2b6b 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -633,6 +633,9 @@
if (ctl->divisor &&
(!is_power_of_2(ctl->divisor) || ctl->divisor > 65536))
return -EINVAL;
+ if (ctl_v1 && !red_check_params(ctl_v1->qth_min, ctl_v1->qth_max,
+ ctl_v1->Wlog))
+ return -EINVAL;
if (ctl_v1 && ctl_v1->qth_min) {
p = kmalloc(sizeof(*p), GFP_KERNEL);
if (!p)
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 0994ce4..0188d9e 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -364,7 +364,8 @@
asoc->sent_cnt_removable--;
asoc->abandoned_sent[SCTP_PR_INDEX(PRIO)]++;
- if (!chk->tsn_gap_acked) {
+ if (queue != &asoc->outqueue.retransmit &&
+ !chk->tsn_gap_acked) {
if (chk->transport)
chk->transport->flight_size -=
sctp_data_size(chk);
@@ -1409,7 +1410,8 @@
/* If this chunk has not been acked, stop
* considering it as 'outstanding'.
*/
- if (!tchunk->tsn_gap_acked) {
+ if (transmitted_queue != &q->retransmit &&
+ !tchunk->tsn_gap_acked) {
if (tchunk->transport)
tchunk->transport->flight_size -=
sctp_data_size(tchunk);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index c472b83..fd5b9d5 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -3125,9 +3125,9 @@
*/
static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen)
{
+ struct sctp_sock *sp = sctp_sk(sk);
struct sctp_assoc_value params;
struct sctp_association *asoc;
- struct sctp_sock *sp = sctp_sk(sk);
int val;
if (optlen == sizeof(int)) {
@@ -3143,26 +3143,35 @@
if (copy_from_user(¶ms, optval, optlen))
return -EFAULT;
val = params.assoc_value;
- } else
+ } else {
return -EINVAL;
+ }
- if ((val != 0) && ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)))
- return -EINVAL;
+ if (val) {
+ int min_len, max_len;
+
+ min_len = SCTP_DEFAULT_MINSEGMENT - sp->pf->af->net_header_len;
+ min_len -= sizeof(struct sctphdr) +
+ sizeof(struct sctp_data_chunk);
+
+ max_len = SCTP_MAX_CHUNK_LEN - sizeof(struct sctp_data_chunk);
+
+ if (val < min_len || val > max_len)
+ return -EINVAL;
+ }
asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id && sctp_style(sk, UDP))
- return -EINVAL;
-
if (asoc) {
if (val == 0) {
- val = asoc->pathmtu;
- val -= sp->pf->af->net_header_len;
+ val = asoc->pathmtu - sp->pf->af->net_header_len;
val -= sizeof(struct sctphdr) +
- sizeof(struct sctp_data_chunk);
+ sizeof(struct sctp_data_chunk);
}
asoc->user_frag = val;
asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu);
} else {
+ if (params.assoc_id && sctp_style(sk, UDP))
+ return -EINVAL;
sp->user_frag = val;
}
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 8201e6d..3181b07 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -421,6 +421,8 @@
if (rv)
goto use_default_name;
} else {
+ int rv;
+
use_default_name:
/* NOTE: This is *probably* safe w/out holding rtnl because of
* the restrictions on phy names. Probably this call could
@@ -428,7 +430,11 @@
* phyX. But, might should add some locking and check return
* value, and use a different name if this one exists?
*/
- dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+ rv = dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+ if (rv < 0) {
+ kfree(rdev);
+ return NULL;
+ }
}
INIT_LIST_HEAD(&rdev->wiphy.wdev_list);
@@ -1117,6 +1123,8 @@
wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
dev->priv_flags |= IFF_DONT_BRIDGE;
+ INIT_WORK(&wdev->disconnect_wk, cfg80211_autodisconnect_wk);
+
nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
break;
case NETDEV_GOING_DOWN:
@@ -1205,6 +1213,7 @@
#ifdef CONFIG_CFG80211_WEXT
kzfree(wdev->wext.keys);
#endif
+ flush_work(&wdev->disconnect_wk);
}
/*
* synchronise (so that we won't find this netdev
diff --git a/net/wireless/core.h b/net/wireless/core.h
index c40f3de..478e37a 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -382,6 +382,7 @@
struct cfg80211_roam_info *info);
int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);
+void cfg80211_autodisconnect_wk(struct work_struct *work);
/* SME implementation */
void cfg80211_conn_work(struct work_struct *work);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 5499e9f..5f85a4e 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -350,6 +350,11 @@
!ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
return 0;
+ if (ether_addr_equal(wdev->disconnect_bssid, bssid) ||
+ (wdev->current_bss &&
+ ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
+ wdev->conn_owner_nlportid = 0;
+
return rdev_deauth(rdev, dev, &req);
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 8f9bd38..febd5ab 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -16,6 +16,7 @@
#include <linux/nl80211.h>
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
+#include <linux/nospec.h>
#include <linux/etherdevice.h>
#include <net/net_namespace.h>
#include <net/genetlink.h>
@@ -433,6 +434,7 @@
.len = FILS_ERP_MAX_RRK_LEN },
[NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
[NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
+ [NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG },
};
/* policy for the key attributes */
@@ -2039,20 +2041,22 @@
static int parse_txq_params(struct nlattr *tb[],
struct ieee80211_txq_params *txq_params)
{
+ u8 ac;
+
if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
!tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
!tb[NL80211_TXQ_ATTR_AIFS])
return -EINVAL;
- txq_params->ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
+ ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
- if (txq_params->ac >= NL80211_NUM_ACS)
+ if (ac >= NL80211_NUM_ACS)
return -EINVAL;
-
+ txq_params->ac = array_index_nospec(ac, NL80211_NUM_ACS);
return 0;
}
@@ -3784,9 +3788,10 @@
return false;
return true;
case NL80211_CMD_CONNECT:
- /* SAE not supported yet */
- if (auth_type == NL80211_AUTHTYPE_SAE)
+ if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
+ auth_type == NL80211_AUTHTYPE_SAE)
return false;
+
/* FILS with SK PFS or PK not supported yet */
if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
auth_type == NL80211_AUTHTYPE_FILS_PK)
@@ -8126,8 +8131,17 @@
err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
if (!err) {
wdev_lock(dev->ieee80211_ptr);
+
err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
ssid, ssid_len, &req);
+
+ if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
+ dev->ieee80211_ptr->conn_owner_nlportid =
+ info->snd_portid;
+ memcpy(dev->ieee80211_ptr->disconnect_bssid,
+ bssid, ETH_ALEN);
+ }
+
wdev_unlock(dev->ieee80211_ptr);
}
@@ -8875,12 +8889,32 @@
return -EINVAL;
}
+ if (nla_get_flag(info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])) {
+ if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
+ return -EINVAL;
+ }
+ connect.flags |= CONNECT_REQ_EXTERNAL_AUTH_SUPPORT;
+ }
+
wdev_lock(dev->ieee80211_ptr);
+
err = cfg80211_connect(rdev, dev, &connect, connkeys,
connect.prev_bssid);
- wdev_unlock(dev->ieee80211_ptr);
if (err)
kzfree(connkeys);
+
+ if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
+ dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
+ if (connect.bssid)
+ memcpy(dev->ieee80211_ptr->disconnect_bssid,
+ connect.bssid, ETH_ALEN);
+ else
+ memset(dev->ieee80211_ptr->disconnect_bssid,
+ 0, ETH_ALEN);
+ }
+
+ wdev_unlock(dev->ieee80211_ptr);
+
return err;
}
@@ -12018,6 +12052,41 @@
return rdev_set_multicast_to_unicast(rdev, dev, enabled);
}
+static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct cfg80211_external_auth_params params;
+
+ if (!rdev->ops->external_auth)
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_SSID])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_BSSID])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_STATUS_CODE])
+ return -EINVAL;
+
+ memset(¶ms, 0, sizeof(params));
+
+ params.ssid.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+ if (params.ssid.ssid_len == 0 ||
+ params.ssid.ssid_len > IEEE80211_MAX_SSID_LEN)
+ return -EINVAL;
+ memcpy(params.ssid.ssid, nla_data(info->attrs[NL80211_ATTR_SSID]),
+ params.ssid.ssid_len);
+
+ memcpy(params.bssid, nla_data(info->attrs[NL80211_ATTR_BSSID]),
+ ETH_ALEN);
+
+ params.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
+
+ return rdev_external_auth(rdev, dev, ¶ms);
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -12907,6 +12976,14 @@
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_EXTERNAL_AUTH,
+ .doit = nl80211_external_auth,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
/* notification functions */
@@ -14734,6 +14811,8 @@
if (wdev->owner_nlportid == notify->portid)
schedule_destroy_work = true;
+ else if (wdev->conn_owner_nlportid == notify->portid)
+ schedule_work(&wdev->disconnect_wk);
}
spin_lock_bh(&rdev->beacon_registrations_lock);
@@ -14898,6 +14977,47 @@
nlmsg_free(msg);
}
+int cfg80211_external_auth_request(struct net_device *dev,
+ struct cfg80211_external_auth_params *params,
+ gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+ struct sk_buff *msg;
+ void *hdr;
+
+ if (!wdev->conn_owner_nlportid)
+ return -EINVAL;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_EXTERNAL_AUTH);
+ if (!hdr)
+ goto nla_put_failure;
+
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+ nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, params->key_mgmt_suite) ||
+ nla_put_u32(msg, NL80211_ATTR_EXTERNAL_AUTH_ACTION,
+ params->action) ||
+ nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid) ||
+ nla_put(msg, NL80211_ATTR_SSID, params->ssid.ssid_len,
+ params->ssid.ssid))
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+ genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
+ wdev->conn_owner_nlportid);
+ return 0;
+
+ nla_put_failure:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+EXPORT_SYMBOL(cfg80211_external_auth_request);
+
/* initialisation/exit functions */
int nl80211_init(void)
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 2f42507..091806d 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1153,4 +1153,19 @@
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
+
+static inline int
+rdev_external_auth(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_external_auth_params *params)
+{
+ int ret = -EOPNOTSUPP;
+
+ trace_rdev_external_auth(&rdev->wiphy, dev, params);
+ if (rdev->ops->external_auth)
+ ret = rdev->ops->external_auth(&rdev->wiphy, dev, params);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
#endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index d414049..2d64e0f 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -763,6 +763,7 @@
kzfree(wdev->connect_keys);
wdev->connect_keys = NULL;
wdev->ssid_len = 0;
+ wdev->conn_owner_nlportid = 0;
if (cr->bss) {
cfg80211_unhold_bss(bss_from_pub(cr->bss));
cfg80211_put_bss(wdev->wiphy, cr->bss);
@@ -1010,6 +1011,7 @@
wdev->current_bss = NULL;
wdev->ssid_len = 0;
+ wdev->conn_owner_nlportid = 0;
nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
@@ -1182,6 +1184,8 @@
kzfree(wdev->connect_keys);
wdev->connect_keys = NULL;
+ wdev->conn_owner_nlportid = 0;
+
if (wdev->conn)
err = cfg80211_sme_disconnect(wdev, reason);
else if (!rdev->ops->disconnect)
@@ -1199,3 +1203,32 @@
return err;
}
+
+/*
+ * Used to clean up after the connection / connection attempt owner socket
+ * disconnects
+ */
+void cfg80211_autodisconnect_wk(struct work_struct *work)
+{
+ struct wireless_dev *wdev =
+ container_of(work, struct wireless_dev, disconnect_wk);
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+
+ wdev_lock(wdev);
+
+ if (wdev->conn_owner_nlportid) {
+ /*
+ * Use disconnect_bssid if still connecting and ops->disconnect
+ * not implemented. Otherwise we can use cfg80211_disconnect.
+ */
+ if (rdev->ops->disconnect || wdev->current_bss)
+ cfg80211_disconnect(rdev, wdev->netdev,
+ WLAN_REASON_DEAUTH_LEAVING, true);
+ else
+ cfg80211_mlme_deauth(rdev, wdev->netdev,
+ wdev->disconnect_bssid, NULL, 0,
+ WLAN_REASON_DEAUTH_LEAVING, false);
+ }
+
+ wdev_unlock(wdev);
+}
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index ea1b47e..80ea75a 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2230,6 +2230,29 @@
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(addr))
);
+TRACE_EVENT(rdev_external_auth,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_external_auth_params *params),
+ TP_ARGS(wiphy, netdev, params),
+ TP_STRUCT__entry(WIPHY_ENTRY
+ NETDEV_ENTRY
+ MAC_ENTRY(bssid)
+ __array(u8, ssid, IEEE80211_MAX_SSID_LEN + 1)
+ __field(u16, status)
+ ),
+ TP_fast_assign(WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ MAC_ASSIGN(bssid, params->bssid);
+ memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
+ memcpy(__entry->ssid, params->ssid.ssid,
+ params->ssid.ssid_len);
+ __entry->status = params->status;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT
+ ", ssid: %s, status: %u", WIPHY_PR_ARG, NETDEV_PR_ARG,
+ __entry->bssid, __entry->ssid, __entry->status)
+);
+
/*************************************************************
* cfg80211 exported functions traces *
*************************************************************/
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 178acf9..791ad6e 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -643,7 +643,8 @@
/* re-insert all policies by order of creation */
list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) {
- if (xfrm_policy_id2dir(policy->index) >= XFRM_POLICY_MAX) {
+ if (policy->walk.dead ||
+ xfrm_policy_id2dir(policy->index) >= XFRM_POLICY_MAX) {
/* skip socket policies */
continue;
}
@@ -1256,9 +1257,15 @@
again:
pol = rcu_dereference(sk->sk_policy[dir]);
if (pol != NULL) {
- bool match = xfrm_selector_match(&pol->selector, fl, family);
+ bool match;
int err = 0;
+ if (pol->family != family) {
+ pol = NULL;
+ goto out;
+ }
+
+ match = xfrm_selector_match(&pol->selector, fl, family);
if (match) {
if ((sk->sk_mark & pol->mark.m) != pol->mark.v) {
pol = NULL;
@@ -1339,7 +1346,7 @@
int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
{
- struct net *net = xp_net(pol);
+ struct net *net = sock_net(sk);
struct xfrm_policy *old_pol;
#ifdef CONFIG_XFRM_SUB_POLICY
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 419bf5d..74f2e8f 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1883,6 +1883,13 @@
struct xfrm_mgr *km;
struct xfrm_policy *pol = NULL;
+ if (!optval && !optlen) {
+ xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
+ xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
+ __sk_dst_reset(sk);
+ return 0;
+ }
+
if (optlen <= 0 || optlen > PAGE_SIZE)
return -EMSGSIZE;
@@ -1907,6 +1914,7 @@
if (err >= 0) {
xfrm_sk_policy_insert(sk, err, pol);
xfrm_pol_put(pol);
+ __sk_dst_reset(sk);
err = 0;
}
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 2cade02..3b3455a 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1388,11 +1388,14 @@
static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family)
{
+ u16 prev_family;
int i;
if (nr > XFRM_MAX_DEPTH)
return -EINVAL;
+ prev_family = family;
+
for (i = 0; i < nr; i++) {
/* We never validated the ut->family value, so many
* applications simply leave it at zero. The check was
@@ -1404,6 +1407,12 @@
if (!ut[i].family)
ut[i].family = family;
+ if ((ut[i].mode == XFRM_MODE_TRANSPORT) &&
+ (ut[i].family != prev_family))
+ return -EINVAL;
+
+ prev_family = ut[i].family;
+
switch (ut[i].family) {
case AF_INET:
break;
@@ -1414,6 +1423,21 @@
default:
return -EINVAL;
}
+
+ switch (ut[i].id.proto) {
+ case IPPROTO_AH:
+ case IPPROTO_ESP:
+ case IPPROTO_COMP:
+#if IS_ENABLED(CONFIG_IPV6)
+ case IPPROTO_ROUTING:
+ case IPPROTO_DSTOPTS:
+#endif
+ case IPSEC_PROTO_ANY:
+ break;
+ default:
+ return -EINVAL;
+ }
+
}
return 0;
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 1792198..140a0fa2 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -108,6 +108,11 @@
as-instr = $(call try-run,\
printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3))
+# __cc-option
+# Usage: MY_CFLAGS += $(call __cc-option,$(CC),$(MY_CFLAGS),-march=winchip-c6,-march=i586)
+__cc-option = $(call try-run,\
+ $(1) -Werror $(2) $(3) -c -x c /dev/null -o "$$TMP",$(3),$(4))
+
# Do not attempt to build with gcc plugins during cc-option tests.
# (And this uses delayed resolution so the flags will be up to date.)
CC_OPTION_CFLAGS = $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS))
@@ -115,13 +120,18 @@
# cc-option
# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
-cc-option = $(call try-run,\
- $(CC) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
+cc-option = $(call __cc-option, $(CC),\
+ $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS),$(1),$(2))
+
+# hostcc-option
+# Usage: cflags-y += $(call hostcc-option,-march=winchip-c6,-march=i586)
+hostcc-option = $(call __cc-option, $(HOSTCC),\
+ $(HOSTCFLAGS) $(HOST_EXTRACFLAGS),$(1),$(2))
# cc-option-yn
# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
cc-option-yn = $(call try-run,\
- $(CC) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n)
+ $(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n)
# cc-option-align
# Prefix align with either -falign or -malign
@@ -131,7 +141,7 @@
# cc-disable-warning
# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
cc-disable-warning = $(call try-run,\
- $(CC) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
+ $(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
# cc-name
# Expands to either gcc or clang
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 68637c9..3ecec72 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -181,6 +181,14 @@
$(obj)/%.symtypes : $(src)/%.c FORCE
$(call cmd,cc_symtypes_c)
+# LLVM assembly
+# Generate .ll files from .c
+quiet_cmd_cc_ll_c = CC $(quiet_modtag) $@
+ cmd_cc_ll_c = $(CC) $(c_flags) -emit-llvm -S -o $@ $<
+
+$(obj)/%.ll: $(src)/%.c FORCE
+ $(call if_changed_dep,cc_ll_c)
+
# C (.c) files
# The C file is compiled and updated dependency information is generated.
# (See cmd_cc_o_c + relevant part of rule_cc_o_c)
diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn
index 7c321a6..fb3522f 100644
--- a/scripts/Makefile.extrawarn
+++ b/scripts/Makefile.extrawarn
@@ -64,7 +64,6 @@
KBUILD_CFLAGS += $(call cc-disable-warning, initializer-overrides)
KBUILD_CFLAGS += $(call cc-disable-warning, unused-value)
KBUILD_CFLAGS += $(call cc-disable-warning, format)
-KBUILD_CFLAGS += $(call cc-disable-warning, unknown-warning-option)
KBUILD_CFLAGS += $(call cc-disable-warning, sign-compare)
KBUILD_CFLAGS += $(call cc-disable-warning, format-zero-length)
KBUILD_CFLAGS += $(call cc-disable-warning, uninitialized)
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
index 45b5b1a..9cfd5c8 100644
--- a/scripts/Makefile.host
+++ b/scripts/Makefile.host
@@ -20,12 +20,6 @@
# Will compile qconf as a C++ program, and menu as a C program.
# They are linked as C++ code to the executable qconf
-# hostcc-option
-# Usage: cflags-y += $(call hostcc-option,-march=winchip-c6,-march=i586)
-
-hostcc-option = $(call try-run,\
- $(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
-
__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
host-cshlib := $(sort $(hostlibs-y) $(hostlibs-m))
host-cxxshlib := $(sort $(hostcxxlibs-y) $(hostcxxlibs-m))
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index f156681..6bc33ee 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -420,3 +420,34 @@
cmd_xzmisc = (cat $(filter-out FORCE,$^) | \
xz --check=crc32 --lzma2=dict=1MiB) > $@ || \
(rm -f $@ ; false)
+
+# ASM offsets
+# ---------------------------------------------------------------------------
+
+# Default sed regexp - multiline due to syntax constraints
+#
+# Use [:space:] because LLVM's integrated assembler inserts <tab> around
+# the .ascii directive whereas GCC keeps the <space> as-is.
+define sed-offsets
+ 's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:; \
+ /^->/{s:->#\(.*\):/* \1 */:; \
+ s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
+ s:->::; p;}'
+endef
+
+# Use filechk to avoid rebuilds when a header changes, but the resulting file
+# does not
+define filechk_offsets
+ (set -e; \
+ echo "#ifndef $2"; \
+ echo "#define $2"; \
+ echo "/*"; \
+ echo " * DO NOT MODIFY."; \
+ echo " *"; \
+ echo " * This file was generated by Kbuild"; \
+ echo " */"; \
+ echo ""; \
+ sed -ne $(sed-offsets); \
+ echo ""; \
+ echo "#endif" )
+endef
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 93721f3..7b163f9 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -3139,4 +3139,4 @@
print STDERR "$warnings warnings\n";
}
-exit($errors);
+exit($output_mode eq "none" ? 0 : $errors);
diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile
index 19d9bca..b497d97 100644
--- a/scripts/mod/Makefile
+++ b/scripts/mod/Makefile
@@ -7,32 +7,8 @@
devicetable-offsets-file := devicetable-offsets.h
-define sed-y
- "/^->/{s:->#\(.*\):/* \1 */:; \
- s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \
- s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
- s:->::; p;}"
-endef
-
-quiet_cmd_offsets = GEN $@
-define cmd_offsets
- (set -e; \
- echo "#ifndef __DEVICETABLE_OFFSETS_H__"; \
- echo "#define __DEVICETABLE_OFFSETS_H__"; \
- echo "/*"; \
- echo " * DO NOT MODIFY."; \
- echo " *"; \
- echo " * This file was generated by Kbuild"; \
- echo " *"; \
- echo " */"; \
- echo ""; \
- sed -ne $(sed-y) $<; \
- echo ""; \
- echo "#endif" ) > $@
-endef
-
-$(obj)/$(devicetable-offsets-file): $(obj)/devicetable-offsets.s
- $(call if_changed,offsets)
+$(obj)/$(devicetable-offsets-file): $(obj)/devicetable-offsets.s FORCE
+ $(call filechk,offsets,__DEVICETABLE_OFFSETS_H__)
targets += $(devicetable-offsets-file) devicetable-offsets.s
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 845eb9b..238db4f 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -2130,6 +2130,14 @@
buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
}
+/* Cannot check for assembler */
+static void add_retpoline(struct buffer *b)
+{
+ buf_printf(b, "\n#ifdef RETPOLINE\n");
+ buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
+ buf_printf(b, "#endif\n");
+}
+
static void add_staging_flag(struct buffer *b, const char *name)
{
static const char *staging_dir = "drivers/staging";
@@ -2474,6 +2482,7 @@
add_header(&buf, mod);
add_intree_flag(&buf, !external_module);
+ add_retpoline(&buf);
add_staging_flag(&buf, mod->name);
err |= add_versions(&buf, mod);
add_depends(&buf, mod, modules);
diff --git a/security/Kconfig b/security/Kconfig
index 638afc8..2e68fa4 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -6,11 +6,6 @@
source security/keys/Kconfig
-if ARCH_QCOM
-source security/pfe/Kconfig
-endif
-
-
config SECURITY_DMESG_RESTRICT
bool "Restrict unprivileged access to the kernel syslog"
default n
diff --git a/security/Makefile b/security/Makefile
index 79166ba..f2d71cd 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -9,7 +9,6 @@
subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor
subdir-$(CONFIG_SECURITY_YAMA) += yama
subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin
-subdir-$(CONFIG_ARCH_QCOM) += pfe
# always enable default capabilities
obj-y += commoncap.o
@@ -25,7 +24,6 @@
obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/
obj-$(CONFIG_SECURITY_YAMA) += yama/
obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/
-obj-$(CONFIG_ARCH_QCOM) += pfe/
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
# Object integrity file lists
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index 0832f63..f298008 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -45,6 +45,7 @@
bool "Large payload keys"
depends on KEYS
depends on TMPFS
+ select CRYPTO
select CRYPTO_AES
select CRYPTO_GCM
help
diff --git a/security/keys/dh.c b/security/keys/dh.c
index 531ed2e..893af4c 100644
--- a/security/keys/dh.c
+++ b/security/keys/dh.c
@@ -55,7 +55,7 @@
if (status == 0) {
const struct user_key_payload *payload;
- payload = user_key_payload(key);
+ payload = user_key_payload_locked(key);
if (maxlen == 0) {
*mpi = NULL;
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index a871159..1f3d600 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -141,23 +141,22 @@
*/
static int valid_master_desc(const char *new_desc, const char *orig_desc)
{
- if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) {
- if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN)
- goto out;
- if (orig_desc)
- if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN))
- goto out;
- } else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) {
- if (strlen(new_desc) == KEY_USER_PREFIX_LEN)
- goto out;
- if (orig_desc)
- if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN))
- goto out;
- } else
- goto out;
+ int prefix_len;
+
+ if (!strncmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN))
+ prefix_len = KEY_TRUSTED_PREFIX_LEN;
+ else if (!strncmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN))
+ prefix_len = KEY_USER_PREFIX_LEN;
+ else
+ return -EINVAL;
+
+ if (!new_desc[prefix_len])
+ return -EINVAL;
+
+ if (orig_desc && strncmp(new_desc, orig_desc, prefix_len))
+ return -EINVAL;
+
return 0;
-out:
- return -EINVAL;
}
/*
@@ -314,7 +313,7 @@
goto error;
down_read(&ukey->sem);
- upayload = user_key_payload(ukey);
+ upayload = user_key_payload_locked(ukey);
if (!upayload) {
/* key was revoked before we acquired its semaphore */
up_read(&ukey->sem);
@@ -934,7 +933,7 @@
size_t asciiblob_len;
int ret;
- epayload = rcu_dereference_key(key);
+ epayload = dereference_key_locked(key);
/* returns the hex encoded iv, encrypted-data, and hmac as ascii */
asciiblob_len = epayload->datablob_len + ivsize + 1
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 4ba2f6b..e0fcb17 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -1139,12 +1139,12 @@
static long trusted_read(const struct key *key, char __user *buffer,
size_t buflen)
{
- struct trusted_key_payload *p;
+ const struct trusted_key_payload *p;
char *ascii_buf;
char *bufp;
int i;
- p = rcu_dereference_key(key);
+ p = dereference_key_locked(key);
if (!p)
return -EINVAL;
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 3dc2607..b4c170a 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -107,7 +107,7 @@
/* attach the new data, displacing the old */
key->expiry = prep->expiry;
if (key_is_positive(key))
- zap = rcu_dereference_key(key);
+ zap = dereference_key_locked(key);
rcu_assign_keypointer(key, prep->payload.data[0]);
prep->payload.data[0] = NULL;
@@ -123,7 +123,7 @@
*/
void user_revoke(struct key *key)
{
- struct user_key_payload *upayload = key->payload.data[0];
+ struct user_key_payload *upayload = user_key_payload_locked(key);
/* clear the quota */
key_payload_reserve(key, 0);
@@ -169,7 +169,7 @@
const struct user_key_payload *upayload;
long ret;
- upayload = user_key_payload(key);
+ upayload = user_key_payload_locked(key);
ret = upayload->datalen;
/* we can return the data as is */
diff --git a/security/pfe/Kconfig b/security/pfe/Kconfig
deleted file mode 100644
index 0cd9e81..0000000
--- a/security/pfe/Kconfig
+++ /dev/null
@@ -1,28 +0,0 @@
-menu "Qualcomm Technologies, Inc Per File Encryption security device drivers"
- depends on ARCH_QCOM
-
-config PFT
- bool "Per-File-Tagger driver"
- depends on SECURITY
- default n
- help
- This driver is used for tagging enterprise files.
- It is part of the Per-File-Encryption (PFE) feature.
- The driver is tagging files when created by
- registered application.
- Tagged files are encrypted using the dm-req-crypt driver.
-
-config PFK
- bool "Per-File-Key driver"
- depends on SECURITY
- depends on SECURITY_SELINUX
- default n
- help
- This driver is used for storing eCryptfs information
- in file node.
- This is part of eCryptfs hardware enhanced solution
- provided by Qualcomm Technologies, Inc.
- Information is used when file is encrypted later using
- ICE or dm crypto engine
-
-endmenu
diff --git a/security/pfe/Makefile b/security/pfe/Makefile
deleted file mode 100644
index 242a216..0000000
--- a/security/pfe/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Makefile for the MSM specific security device drivers.
-#
-
-ccflags-y += -Isecurity/selinux -Isecurity/selinux/include
-ccflags-y += -Ifs/ext4
-ccflags-y += -Ifs/crypto
-
-obj-$(CONFIG_PFT) += pft.o
-obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o
diff --git a/security/pfe/pfk.c b/security/pfe/pfk.c
deleted file mode 100644
index 615353e..0000000
--- a/security/pfe/pfk.c
+++ /dev/null
@@ -1,483 +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.
- */
-
-/*
- * Per-File-Key (PFK).
- *
- * This driver is responsible for overall management of various
- * Per File Encryption variants that work on top of or as part of different
- * file systems.
- *
- * The driver has the following purpose :
- * 1) Define priorities between PFE's if more than one is enabled
- * 2) Extract key information from inode
- * 3) Load and manage various keys in ICE HW engine
- * 4) It should be invoked from various layers in FS/BLOCK/STORAGE DRIVER
- * that need to take decision on HW encryption management of the data
- * Some examples:
- * BLOCK LAYER: when it takes decision on whether 2 chunks can be united
- * to one encryption / decryption request sent to the HW
- *
- * UFS DRIVER: when it need to configure ICE HW with a particular key slot
- * to be used for encryption / decryption
- *
- * PFE variants can differ on particular way of storing the cryptographic info
- * inside inode, actions to be taken upon file operations, etc., but the common
- * properties are described above
- *
- */
-
-
-/* Uncomment the line below to enable debug messages */
-/* #define DEBUG 1 */
-#define pr_fmt(fmt) "pfk [%s]: " fmt, __func__
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/printk.h>
-#include <linux/bio.h>
-#include <linux/security.h>
-#include <crypto/ice.h>
-
-#include <linux/pfk.h>
-
-#include "pfk_kc.h"
-#include "objsec.h"
-#include "pfk_ice.h"
-#include "pfk_ext4.h"
-#include "pfk_internal.h"
-#include "ext4.h"
-
-static bool pfk_ready;
-
-
-/* might be replaced by a table when more than one cipher is supported */
-#define PFK_SUPPORTED_KEY_SIZE 32
-#define PFK_SUPPORTED_SALT_SIZE 32
-
-/* Various PFE types and function tables to support each one of them */
-enum pfe_type {EXT4_CRYPT_PFE, INVALID_PFE};
-
-typedef int (*pfk_parse_inode_type)(const struct bio *bio,
- const struct inode *inode,
- struct pfk_key_info *key_info,
- enum ice_cryto_algo_mode *algo,
- bool *is_pfe);
-
-typedef bool (*pfk_allow_merge_bio_type)(const struct bio *bio1,
- const struct bio *bio2, const struct inode *inode1,
- const struct inode *inode2);
-
-static const pfk_parse_inode_type pfk_parse_inode_ftable[] = {
- /* EXT4_CRYPT_PFE */ &pfk_ext4_parse_inode,
-};
-
-static const pfk_allow_merge_bio_type pfk_allow_merge_bio_ftable[] = {
- /* EXT4_CRYPT_PFE */ &pfk_ext4_allow_merge_bio,
-};
-
-static void __exit pfk_exit(void)
-{
- pfk_ready = false;
- pfk_ext4_deinit();
- pfk_kc_deinit();
-}
-
-static int __init pfk_init(void)
-{
-
- int ret = 0;
-
- ret = pfk_ext4_init();
- if (ret != 0)
- goto fail;
-
- ret = pfk_kc_init();
- if (ret != 0) {
- pr_err("could init pfk key cache, error %d\n", ret);
- pfk_ext4_deinit();
- goto fail;
- }
-
- pfk_ready = true;
- pr_info("Driver initialized successfully\n");
-
- return 0;
-
-fail:
- pr_err("Failed to init driver\n");
- return -ENODEV;
-}
-
-/*
- * If more than one type is supported simultaneously, this function will also
- * set the priority between them
- */
-static enum pfe_type pfk_get_pfe_type(const struct inode *inode)
-{
- if (!inode)
- return INVALID_PFE;
-
- if (pfk_is_ext4_type(inode))
- return EXT4_CRYPT_PFE;
-
- return INVALID_PFE;
-}
-
-/**
- * inode_to_filename() - get the filename from inode pointer.
- * @inode: inode pointer
- *
- * it is used for debug prints.
- *
- * Return: filename string or "unknown".
- */
-char *inode_to_filename(const struct inode *inode)
-{
- struct dentry *dentry = NULL;
- char *filename = NULL;
-
- if (hlist_empty(&inode->i_dentry))
- return "unknown";
-
- dentry = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
- filename = dentry->d_iname;
-
- return filename;
-}
-
-/**
- * pfk_is_ready() - driver is initialized and ready.
- *
- * Return: true if the driver is ready.
- */
-static inline bool pfk_is_ready(void)
-{
- return pfk_ready;
-}
-
-/**
- * pfk_bio_get_inode() - get the inode from a bio.
- * @bio: Pointer to BIO structure.
- *
- * Walk the bio struct links to get the inode.
- * Please note, that in general bio may consist of several pages from
- * several files, but in our case we always assume that all pages come
- * from the same file, since our logic ensures it. That is why we only
- * walk through the first page to look for inode.
- *
- * Return: pointer to the inode struct if successful, or NULL otherwise.
- *
- */
-static struct inode *pfk_bio_get_inode(const struct bio *bio)
-{
- struct address_space *mapping;
-
- if (!bio)
- return NULL;
- if (!bio->bi_io_vec)
- return NULL;
- if (!bio->bi_io_vec->bv_page)
- return NULL;
- if (!bio_has_data((struct bio *)bio))
- return NULL;
-
- if (PageAnon(bio->bi_io_vec->bv_page)) {
- struct inode *inode;
-
- //Using direct-io (O_DIRECT) without page cache
- inode = dio_bio_get_inode((struct bio *)bio);
- pr_debug("inode on direct-io, inode = 0x%pK.\n", inode);
-
- return inode;
- }
-
- mapping = page_mapping(bio->bi_io_vec->bv_page);
- if (!mapping)
- return NULL;
-
- if (!mapping->host)
- return NULL;
-
- return bio->bi_io_vec->bv_page->mapping->host;
-}
-
-/**
- * pfk_key_size_to_key_type() - translate key size to key size enum
- * @key_size: key size in bytes
- * @key_size_type: pointer to store the output enum (can be null)
- *
- * return 0 in case of success, error otherwise (i.e not supported key size)
- */
-int pfk_key_size_to_key_type(size_t key_size,
- enum ice_crpto_key_size *key_size_type)
-{
- /*
- * currently only 32 bit key size is supported
- * in the future, table with supported key sizes might
- * be introduced
- */
-
- if (key_size != PFK_SUPPORTED_KEY_SIZE) {
- pr_err("not supported key size %zu\n", key_size);
- return -EINVAL;
- }
-
- if (key_size_type)
- *key_size_type = ICE_CRYPTO_KEY_SIZE_256;
-
- return 0;
-}
-
-/*
- * Retrieves filesystem type from inode's superblock
- */
-bool pfe_is_inode_filesystem_type(const struct inode *inode,
- const char *fs_type)
-{
- if (!inode || !fs_type)
- return false;
-
- if (!inode->i_sb)
- return false;
-
- if (!inode->i_sb->s_type)
- return false;
-
- return (strcmp(inode->i_sb->s_type->name, fs_type) == 0);
-}
-
-
-/**
- * pfk_load_key_start() - loads PFE encryption key to the ICE
- * Can also be invoked from non
- * PFE context, in this case it
- * is not relevant and is_pfe
- * flag is set to false
- *
- * @bio: Pointer to the BIO structure
- * @ice_setting: Pointer to ice setting structure that will be filled with
- * ice configuration values, including the index to which the key was loaded
- * @is_pfe: will be false if inode is not relevant to PFE, in such a case
- * it should be treated as non PFE by the block layer
- *
- * Returns the index where the key is stored in encryption hw and additional
- * information that will be used later for configuration of the encryption hw.
- *
- * Must be followed by pfk_load_key_end when key is no longer used by ice
- *
- */
-int pfk_load_key_start(const struct bio *bio,
- struct ice_crypto_setting *ice_setting, bool *is_pfe,
- bool async)
-{
- int ret = 0;
- struct pfk_key_info key_info = {NULL, NULL, 0, 0};
- enum ice_cryto_algo_mode algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS;
- enum ice_crpto_key_size key_size_type = 0;
- u32 key_index = 0;
- struct inode *inode = NULL;
- enum pfe_type which_pfe = INVALID_PFE;
-
- if (!is_pfe) {
- pr_err("is_pfe is NULL\n");
- return -EINVAL;
- }
-
- /*
- * only a few errors below can indicate that
- * this function was not invoked within PFE context,
- * otherwise we will consider it PFE
- */
- *is_pfe = true;
-
- if (!pfk_is_ready())
- return -ENODEV;
-
- if (!ice_setting) {
- pr_err("ice setting is NULL\n");
- return -EINVAL;
- }
-//pr_err("%s %d\n", __func__, __LINE__);
- inode = pfk_bio_get_inode(bio);
- if (!inode) {
- *is_pfe = false;
- return -EINVAL;
- }
- //pr_err("%s %d\n", __func__, __LINE__);
- which_pfe = pfk_get_pfe_type(inode);
- if (which_pfe == INVALID_PFE) {
- *is_pfe = false;
- return -EPERM;
- }
-
- pr_debug("parsing file %s with PFE %d\n",
- inode_to_filename(inode), which_pfe);
-//pr_err("%s %d\n", __func__, __LINE__);
- ret = (*(pfk_parse_inode_ftable[which_pfe]))
- (bio, inode, &key_info, &algo_mode, is_pfe);
- if (ret != 0)
- return ret;
-//pr_err("%s %d\n", __func__, __LINE__);
- ret = pfk_key_size_to_key_type(key_info.key_size, &key_size_type);
- if (ret != 0)
- return ret;
-//pr_err("%s %d\n", __func__, __LINE__);
- ret = pfk_kc_load_key_start(key_info.key, key_info.key_size,
- key_info.salt, key_info.salt_size, &key_index, async);
- if (ret) {
- if (ret != -EBUSY && ret != -EAGAIN)
- pr_err("start: could not load key into pfk key cache, error %d\n",
- ret);
-
- return ret;
- }
-
- ice_setting->key_size = key_size_type;
- ice_setting->algo_mode = algo_mode;
- /* hardcoded for now */
- ice_setting->key_mode = ICE_CRYPTO_USE_LUT_SW_KEY;
- ice_setting->key_index = key_index;
-
- pr_debug("loaded key for file %s key_index %d\n",
- inode_to_filename(inode), key_index);
-
- return 0;
-}
-
-/**
- * pfk_load_key_end() - marks the PFE key as no longer used by ICE
- * Can also be invoked from non
- * PFE context, in this case it is not
- * relevant and is_pfe flag is
- * set to false
- *
- * @bio: Pointer to the BIO structure
- * @is_pfe: Pointer to is_pfe flag, which will be true if function was invoked
- * from PFE context
- */
-int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
-{
- int ret = 0;
- struct pfk_key_info key_info = {0};
- enum pfe_type which_pfe = INVALID_PFE;
- struct inode *inode = NULL;
-
- if (!is_pfe) {
- pr_err("is_pfe is NULL\n");
- return -EINVAL;
- }
-
- /* only a few errors below can indicate that
- * this function was not invoked within PFE context,
- * otherwise we will consider it PFE
- */
- *is_pfe = true;
-
- if (!pfk_is_ready())
- return -ENODEV;
-
- inode = pfk_bio_get_inode(bio);
- if (!inode) {
- *is_pfe = false;
- return -EINVAL;
- }
-
- which_pfe = pfk_get_pfe_type(inode);
- if (which_pfe == INVALID_PFE) {
- *is_pfe = false;
- return -EPERM;
- }
-
- ret = (*(pfk_parse_inode_ftable[which_pfe]))
- (bio, inode, &key_info, NULL, is_pfe);
- if (ret != 0)
- return ret;
-
- pfk_kc_load_key_end(key_info.key, key_info.key_size,
- key_info.salt, key_info.salt_size);
-
- pr_debug("finished using key for file %s\n",
- inode_to_filename(inode));
-
- return 0;
-}
-
-/**
- * pfk_allow_merge_bio() - Check if 2 BIOs can be merged.
- * @bio1: Pointer to first BIO structure.
- * @bio2: Pointer to second BIO structure.
- *
- * Prevent merging of BIOs from encrypted and non-encrypted
- * files, or files encrypted with different key.
- * Also prevent non encrypted and encrypted data from the same file
- * to be merged (ecryptfs header if stored inside file should be non
- * encrypted)
- * This API is called by the file system block layer.
- *
- * Return: true if the BIOs allowed to be merged, false
- * otherwise.
- */
-bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2)
-{
- struct inode *inode1 = NULL;
- struct inode *inode2 = NULL;
- enum pfe_type which_pfe1 = INVALID_PFE;
- enum pfe_type which_pfe2 = INVALID_PFE;
-
- if (!pfk_is_ready())
- return false;
-
- if (!bio1 || !bio2)
- return false;
-
- if (bio1 == bio2)
- return true;
-
- inode1 = pfk_bio_get_inode(bio1);
- inode2 = pfk_bio_get_inode(bio2);
-
-
- which_pfe1 = pfk_get_pfe_type(inode1);
- which_pfe2 = pfk_get_pfe_type(inode2);
-
- /* nodes with different encryption, do not merge */
- if (which_pfe1 != which_pfe2)
- return false;
-
- /* both nodes do not have encryption, allow merge */
- if (which_pfe1 == INVALID_PFE)
- return true;
-
- return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2,
- inode1, inode2);
-}
-/**
- * Flush key table on storage core reset. During core reset key configuration
- * is lost in ICE. We need to flash the cache, so that the keys will be
- * reconfigured again for every subsequent transaction
- */
-void pfk_clear_on_reset(void)
-{
- if (!pfk_is_ready())
- return;
-
- pfk_kc_clear_on_reset();
-}
-
-module_init(pfk_init);
-module_exit(pfk_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Per-File-Key driver");
diff --git a/security/pfe/pfk_ext4.c b/security/pfe/pfk_ext4.c
deleted file mode 100644
index 7ce70bc..0000000
--- a/security/pfe/pfk_ext4.c
+++ /dev/null
@@ -1,212 +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.
- */
-
-/*
- * Per-File-Key (PFK) - EXT4
- *
- * This driver is used for working with EXT4 crypt extension
- *
- * The key information is stored in node by EXT4 when file is first opened
- * and will be later accessed by Block Device Driver to actually load the key
- * to encryption hw.
- *
- * PFK exposes API's for loading and removing keys from encryption hw
- * and also API to determine whether 2 adjacent blocks can be agregated by
- * Block Layer in one request to encryption hw.
- *
- */
-
-
-/* Uncomment the line below to enable debug messages */
-/* #define DEBUG 1 */
-#define pr_fmt(fmt) "pfk_ext4 [%s]: " fmt, __func__
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/printk.h>
-
-#include "ext4_ice.h"
-#include "pfk_ext4.h"
-
-static bool pfk_ext4_ready;
-
-/*
- * pfk_ext4_deinit() - Deinit function, should be invoked by upper PFK layer
- */
-void pfk_ext4_deinit(void)
-{
- pfk_ext4_ready = false;
-}
-
-/*
- * pfk_ecryptfs_init() - Init function, should be invoked by upper PFK layer
- */
-int __init pfk_ext4_init(void)
-{
- pfk_ext4_ready = true;
- pr_info("PFK EXT4 inited successfully\n");
-
- return 0;
-}
-
-/**
- * pfk_ecryptfs_is_ready() - driver is initialized and ready.
- *
- * Return: true if the driver is ready.
- */
-static inline bool pfk_ext4_is_ready(void)
-{
- return pfk_ext4_ready;
-}
-
-/**
- * pfk_ext4_dump_inode() - dumps all interesting info about inode to the screen
- *
- *
- */
-/*
- * static void pfk_ext4_dump_inode(const struct inode* inode)
- * {
- * struct ext4_crypt_info *ci = ext4_encryption_info((struct inode*)inode);
- *
- * pr_debug("dumping inode with address 0x%p\n", inode);
- * pr_debug("S_ISREG is %d\n", S_ISREG(inode->i_mode));
- * pr_debug("EXT4_INODE_ENCRYPT flag is %d\n",
- * ext4_test_inode_flag((struct inode*)inode, EXT4_INODE_ENCRYPT));
- * if (ci) {
- * pr_debug("crypt_info address 0x%p\n", ci);
- * pr_debug("ci->ci_data_mode %d\n", ci->ci_data_mode);
- * } else {
- * pr_debug("crypt_info is NULL\n");
- * }
- * }
- */
-
-/**
- * pfk_is_ext4_type() - return true if inode belongs to ICE EXT4 PFE
- * @inode: inode pointer
- */
-bool pfk_is_ext4_type(const struct inode *inode)
-{
- if (!pfe_is_inode_filesystem_type(inode, "ext4"))
- return false;
-
- return ext4_should_be_processed_by_ice(inode);
-}
-
-/**
- * pfk_ext4_parse_cipher() - parse cipher from inode to enum
- * @inode: inode
- * @algo: pointer to store the output enum (can be null)
- *
- * return 0 in case of success, error otherwise (i.e not supported cipher)
- */
-static int pfk_ext4_parse_cipher(const struct inode *inode,
- enum ice_cryto_algo_mode *algo)
-{
- /*
- * currently only AES XTS algo is supported
- * in the future, table with supported ciphers might
- * be introduced
- */
-
- if (!inode)
- return -EINVAL;
-
- if (!ext4_is_aes_xts_cipher(inode)) {
- pr_err("ext4 alghoritm is not supported by pfk\n");
- return -EINVAL;
- }
-
- if (algo)
- *algo = ICE_CRYPTO_ALGO_MODE_AES_XTS;
-
- return 0;
-}
-
-
-int pfk_ext4_parse_inode(const struct bio *bio,
- const struct inode *inode,
- struct pfk_key_info *key_info,
- enum ice_cryto_algo_mode *algo,
- bool *is_pfe)
-{
- int ret = 0;
-
- if (!is_pfe)
- return -EINVAL;
-
- /*
- * only a few errors below can indicate that
- * this function was not invoked within PFE context,
- * otherwise we will consider it PFE
- */
- *is_pfe = true;
-
- if (!pfk_ext4_is_ready())
- return -ENODEV;
-
- if (!inode)
- return -EINVAL;
-
- if (!key_info)
- return -EINVAL;
-
- key_info->key = ext4_get_ice_encryption_key(inode);
- if (!key_info->key) {
- pr_err("could not parse key from ext4\n");
- return -EINVAL;
- }
-
- key_info->key_size = ext4_get_ice_encryption_key_size(inode);
- if (!key_info->key_size) {
- pr_err("could not parse key size from ext4\n");
- return -EINVAL;
- }
-
- key_info->salt = ext4_get_ice_encryption_salt(inode);
- if (!key_info->salt) {
- pr_err("could not parse salt from ext4\n");
- return -EINVAL;
- }
-
- key_info->salt_size = ext4_get_ice_encryption_salt_size(inode);
- if (!key_info->salt_size) {
- pr_err("could not parse salt size from ext4\n");
- return -EINVAL;
- }
-
- ret = pfk_ext4_parse_cipher(inode, algo);
- if (ret != 0) {
- pr_err("not supported cipher\n");
- return ret;
- }
-
- return 0;
-}
-
-bool pfk_ext4_allow_merge_bio(const struct bio *bio1,
- const struct bio *bio2, const struct inode *inode1,
- const struct inode *inode2)
-{
- /* if there is no ext4 pfk, don't disallow merging blocks */
- if (!pfk_ext4_is_ready())
- return true;
-
- if (!inode1 || !inode2)
- return false;
-
- return ext4_is_ice_encryption_info_equal(inode1, inode2);
-}
-
diff --git a/security/pfe/pfk_ext4.h b/security/pfe/pfk_ext4.h
deleted file mode 100644
index 1f33632..0000000
--- a/security/pfe/pfk_ext4.h
+++ /dev/null
@@ -1,37 +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 _PFK_EXT4_H_
-#define _PFK_EXT4_H_
-
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <crypto/ice.h>
-#include "pfk_internal.h"
-
-bool pfk_is_ext4_type(const struct inode *inode);
-
-int pfk_ext4_parse_inode(const struct bio *bio,
- const struct inode *inode,
- struct pfk_key_info *key_info,
- enum ice_cryto_algo_mode *algo,
- bool *is_pfe);
-
-bool pfk_ext4_allow_merge_bio(const struct bio *bio1,
- const struct bio *bio2, const struct inode *inode1,
- const struct inode *inode2);
-
-int __init pfk_ext4_init(void);
-
-void pfk_ext4_deinit(void);
-
-#endif /* _PFK_EXT4_H_ */
diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c
deleted file mode 100644
index 16ed516..0000000
--- a/security/pfe/pfk_ice.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/* Copyright (c) 2015-2018, 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/errno.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/async.h>
-#include <linux/mm.h>
-#include <linux/of.h>
-#include <soc/qcom/scm.h>
-#include <linux/device-mapper.h>
-#include <soc/qcom/qseecomi.h>
-#include <crypto/ice.h>
-#include "pfk_ice.h"
-
-
-/**********************************/
-/** global definitions **/
-/**********************************/
-
-#define TZ_ES_SET_ICE_KEY 0x2
-#define TZ_ES_INVALIDATE_ICE_KEY 0x3
-
-/* index 0 and 1 is reserved for FDE */
-#define MIN_ICE_KEY_INDEX 2
-
-#define MAX_ICE_KEY_INDEX 31
-
-
-#define TZ_ES_SET_ICE_KEY_ID \
- TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, TZ_SVC_ES, TZ_ES_SET_ICE_KEY)
-
-
-#define TZ_ES_INVALIDATE_ICE_KEY_ID \
- TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, \
- TZ_SVC_ES, TZ_ES_INVALIDATE_ICE_KEY)
-
-
-#define TZ_ES_SET_ICE_KEY_PARAM_ID \
- TZ_SYSCALL_CREATE_PARAM_ID_5( \
- TZ_SYSCALL_PARAM_TYPE_VAL, \
- TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL, \
- TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
-
-#define TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID \
- TZ_SYSCALL_CREATE_PARAM_ID_1( \
- TZ_SYSCALL_PARAM_TYPE_VAL)
-
-#define ICE_KEY_SIZE 32
-#define ICE_SALT_SIZE 32
-
-static uint8_t ice_key[ICE_KEY_SIZE];
-static uint8_t ice_salt[ICE_KEY_SIZE];
-
-int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt,
- char *storage_type)
-{
- struct scm_desc desc = {0};
- int ret, ret1;
- char *tzbuf_key = (char *)ice_key;
- char *tzbuf_salt = (char *)ice_salt;
- char *s_type = storage_type;
-
- uint32_t smc_id = 0;
- u32 tzbuflen_key = sizeof(ice_key);
- u32 tzbuflen_salt = sizeof(ice_salt);
-
- if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) {
- pr_err("%s Invalid index %d\n", __func__, index);
- return -EINVAL;
- }
- if (!key || !salt) {
- pr_err("%s Invalid key/salt\n", __func__);
- return -EINVAL;
- }
-
- if (!tzbuf_key || !tzbuf_salt) {
- pr_err("%s No Memory\n", __func__);
- return -ENOMEM;
- }
-
- if (s_type == NULL) {
- pr_err("%s Invalid Storage type\n", __func__);
- return -EINVAL;
- }
-
- memset(tzbuf_key, 0, tzbuflen_key);
- memset(tzbuf_salt, 0, tzbuflen_salt);
-
- memcpy(ice_key, key, tzbuflen_key);
- memcpy(ice_salt, salt, tzbuflen_salt);
-
- dmac_flush_range(tzbuf_key, tzbuf_key + tzbuflen_key);
- dmac_flush_range(tzbuf_salt, tzbuf_salt + tzbuflen_salt);
-
- smc_id = TZ_ES_SET_ICE_KEY_ID;
-
- desc.arginfo = TZ_ES_SET_ICE_KEY_PARAM_ID;
- desc.args[0] = index;
- desc.args[1] = virt_to_phys(tzbuf_key);
- desc.args[2] = tzbuflen_key;
- desc.args[3] = virt_to_phys(tzbuf_salt);
- desc.args[4] = tzbuflen_salt;
-
- ret = qcom_ice_setup_ice_hw((const char *)s_type, true);
-
- if (ret) {
- pr_err("%s: could not enable clocks: %d\n", __func__, ret);
- goto out;
- }
-
- ret = scm_call2(smc_id, &desc);
-
- if (ret) {
- pr_err("%s: Set Key Error: %d\n", __func__, ret);
- if (ret == -EBUSY) {
- if (qcom_ice_setup_ice_hw((const char *)s_type, false))
- pr_err("%s: clock disable failed\n", __func__);
- goto out;
- }
- /*Try to invalidate the key to keep ICE in proper state*/
- smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID;
- desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID;
- desc.args[0] = index;
- ret1 = scm_call2(smc_id, &desc);
- if (ret1)
- pr_err("%s: Invalidate Key Error: %d\n", __func__,
- ret1);
- goto out;
- }
- ret = qcom_ice_setup_ice_hw((const char *)s_type, false);
-
-out:
- return ret;
-}
-
-int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type)
-{
- struct scm_desc desc = {0};
- int ret;
-
- uint32_t smc_id = 0;
-
- if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) {
- pr_err("%s Invalid index %d\n", __func__, index);
- return -EINVAL;
- }
-
- if (storage_type == NULL) {
- pr_err("%s Invalid Storage type\n", __func__);
- return -EINVAL;
- }
-
- smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID;
-
- desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID;
- desc.args[0] = index;
-
- ret = qcom_ice_setup_ice_hw((const char *)storage_type, true);
-
- if (ret) {
- pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret);
- return ret;
- }
-
- ret = scm_call2(smc_id, &desc);
-
- if (ret) {
- pr_err("%s: Error: 0x%x\n", __func__, ret);
- if (qcom_ice_setup_ice_hw((const char *)storage_type, false))
- pr_err("%s: could not disable clocks\n", __func__);
- } else {
- ret = qcom_ice_setup_ice_hw((const char *)storage_type, false);
- }
-
- return ret;
-}
diff --git a/security/pfe/pfk_ice.h b/security/pfe/pfk_ice.h
deleted file mode 100644
index fb7c0d1..0000000
--- a/security/pfe/pfk_ice.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef PFK_ICE_H_
-#define PFK_ICE_H_
-
-/*
- * PFK ICE
- *
- * ICE keys configuration through scm calls.
- *
- */
-
-#include <linux/types.h>
-
-int pfk_ice_init(void);
-int pfk_ice_deinit(void);
-
-int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt,
- char *storage_type);
-int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type);
-
-
-#endif /* PFK_ICE_H_ */
diff --git a/security/pfe/pfk_internal.h b/security/pfe/pfk_internal.h
deleted file mode 100644
index 86526fa..0000000
--- a/security/pfe/pfk_internal.h
+++ /dev/null
@@ -1,34 +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 _PFK_INTERNAL_H_
-#define _PFK_INTERNAL_H_
-
-#include <linux/types.h>
-#include <crypto/ice.h>
-
-struct pfk_key_info {
- const unsigned char *key;
- const unsigned char *salt;
- size_t key_size;
- size_t salt_size;
-};
-
-int pfk_key_size_to_key_type(size_t key_size,
- enum ice_crpto_key_size *key_size_type);
-
-bool pfe_is_inode_filesystem_type(const struct inode *inode,
- const char *fs_type);
-
-char *inode_to_filename(const struct inode *inode);
-
-#endif /* _PFK_INTERNAL_H_ */
diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c
deleted file mode 100644
index da71f80..0000000
--- a/security/pfe/pfk_kc.c
+++ /dev/null
@@ -1,905 +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.
- */
-
-/*
- * PFK Key Cache
- *
- * Key Cache used internally in PFK.
- * The purpose of the cache is to save access time to QSEE when loading keys.
- * Currently the cache is the same size as the total number of keys that can
- * be loaded to ICE. Since this number is relatively small, the algorithms for
- * cache eviction are simple, linear and based on last usage timestamp, i.e
- * the node that will be evicted is the one with the oldest timestamp.
- * Empty entries always have the oldest timestamp.
- */
-
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/spinlock.h>
-#include <crypto/ice.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/jiffies.h>
-#include <linux/slab.h>
-#include <linux/printk.h>
-#include <linux/sched.h>
-
-#include "pfk_kc.h"
-#include "pfk_ice.h"
-
-
-/** the first available index in ice engine */
-#define PFK_KC_STARTING_INDEX 2
-
-/** currently the only supported key and salt sizes */
-#define PFK_KC_KEY_SIZE 32
-#define PFK_KC_SALT_SIZE 32
-
-/** Table size */
-/* TODO replace by some constant from ice.h */
-#define PFK_KC_TABLE_SIZE ((32) - (PFK_KC_STARTING_INDEX))
-
-/** The maximum key and salt size */
-#define PFK_MAX_KEY_SIZE PFK_KC_KEY_SIZE
-#define PFK_MAX_SALT_SIZE PFK_KC_SALT_SIZE
-#define PFK_UFS "ufs"
-
-static DEFINE_SPINLOCK(kc_lock);
-static unsigned long flags;
-static bool kc_ready;
-static char *s_type = "sdcc";
-
-/**
- * enum pfk_kc_entry_state - state of the entry inside kc table
- *
- * @FREE: entry is free
- * @ACTIVE_ICE_PRELOAD: entry is actively used by ICE engine
- and cannot be used by others. SCM call
- to load key to ICE is pending to be performed
- * @ACTIVE_ICE_LOADED: entry is actively used by ICE engine and
- cannot be used by others. SCM call to load the
- key to ICE was successfully executed and key is
- now loaded
- * @INACTIVE_INVALIDATING: entry is being invalidated during file close
- and cannot be used by others until invalidation
- is complete
- * @INACTIVE: entry's key is already loaded, but is not
- currently being used. It can be re-used for
- optimization and to avoid SCM call cost or
- it can be taken by another key if there are
- no FREE entries
- * @SCM_ERROR: error occurred while scm call was performed to
- load the key to ICE
- */
-enum pfk_kc_entry_state {
- FREE,
- ACTIVE_ICE_PRELOAD,
- ACTIVE_ICE_LOADED,
- INACTIVE_INVALIDATING,
- INACTIVE,
- SCM_ERROR
-};
-
-struct kc_entry {
- unsigned char key[PFK_MAX_KEY_SIZE];
- size_t key_size;
-
- unsigned char salt[PFK_MAX_SALT_SIZE];
- size_t salt_size;
-
- u64 time_stamp;
- u32 key_index;
-
- struct task_struct *thread_pending;
-
- enum pfk_kc_entry_state state;
-
- /* ref count for the number of requests in the HW queue for this key */
- int loaded_ref_cnt;
- int scm_error;
-};
-
-static struct kc_entry kc_table[PFK_KC_TABLE_SIZE];
-
-/**
- * kc_is_ready() - driver is initialized and ready.
- *
- * Return: true if the key cache is ready.
- */
-static inline bool kc_is_ready(void)
-{
- return kc_ready;
-}
-
-static inline void kc_spin_lock(void)
-{
- spin_lock_irqsave(&kc_lock, flags);
-}
-
-static inline void kc_spin_unlock(void)
-{
- spin_unlock_irqrestore(&kc_lock, flags);
-}
-
-/**
- * kc_entry_is_available() - checks whether the entry is available
- *
- * Return true if it is , false otherwise or if invalid
- * Should be invoked under spinlock
- */
-static bool kc_entry_is_available(const struct kc_entry *entry)
-{
- if (!entry)
- return false;
-
- return (entry->state == FREE || entry->state == INACTIVE);
-}
-
-/**
- * kc_entry_wait_till_available() - waits till entry is available
- *
- * Returns 0 in case of success or -ERESTARTSYS if the wait was interrupted
- * by signal
- *
- * Should be invoked under spinlock
- */
-static int kc_entry_wait_till_available(struct kc_entry *entry)
-{
- int res = 0;
-
- while (!kc_entry_is_available(entry)) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (signal_pending(current)) {
- res = -ERESTARTSYS;
- break;
- }
- /* assuming only one thread can try to invalidate
- * the same entry
- */
- entry->thread_pending = current;
- kc_spin_unlock();
- schedule();
- kc_spin_lock();
- }
- set_current_state(TASK_RUNNING);
-
- return res;
-}
-
-/**
- * kc_entry_start_invalidating() - moves entry to state
- * INACTIVE_INVALIDATING
- * If entry is in use, waits till
- * it gets available
- * @entry: pointer to entry
- *
- * Return 0 in case of success, otherwise error
- * Should be invoked under spinlock
- */
-static int kc_entry_start_invalidating(struct kc_entry *entry)
-{
- int res;
-
- res = kc_entry_wait_till_available(entry);
- if (res)
- return res;
-
- entry->state = INACTIVE_INVALIDATING;
-
- return 0;
-}
-
-/**
- * kc_entry_finish_invalidating() - moves entry to state FREE
- * wakes up all the tasks waiting
- * on it
- *
- * @entry: pointer to entry
- *
- * Return 0 in case of success, otherwise error
- * Should be invoked under spinlock
- */
-static void kc_entry_finish_invalidating(struct kc_entry *entry)
-{
- if (!entry)
- return;
-
- if (entry->state != INACTIVE_INVALIDATING)
- return;
-
- entry->state = FREE;
-}
-
-/**
- * kc_min_entry() - compare two entries to find one with minimal time
- * @a: ptr to the first entry. If NULL the other entry will be returned
- * @b: pointer to the second entry
- *
- * Return the entry which timestamp is the minimal, or b if a is NULL
- */
-static inline struct kc_entry *kc_min_entry(struct kc_entry *a,
- struct kc_entry *b)
-{
- if (!a)
- return b;
-
- if (time_before64(b->time_stamp, a->time_stamp))
- return b;
-
- return a;
-}
-
-/**
- * kc_entry_at_index() - return entry at specific index
- * @index: index of entry to be accessed
- *
- * Return entry
- * Should be invoked under spinlock
- */
-static struct kc_entry *kc_entry_at_index(int index)
-{
- return &(kc_table[index]);
-}
-
-/**
- * kc_find_key_at_index() - find kc entry starting at specific index
- * @key: key to look for
- * @key_size: the key size
- * @salt: salt to look for
- * @salt_size: the salt size
- * @sarting_index: index to start search with, if entry found, updated with
- * index of that entry
- *
- * Return entry or NULL in case of error
- * Should be invoked under spinlock
- */
-static struct kc_entry *kc_find_key_at_index(const unsigned char *key,
- size_t key_size, const unsigned char *salt, size_t salt_size,
- int *starting_index)
-{
- struct kc_entry *entry = NULL;
- int i = 0;
-
- for (i = *starting_index; i < PFK_KC_TABLE_SIZE; i++) {
- entry = kc_entry_at_index(i);
-
- if (salt != NULL) {
- if (entry->salt_size != salt_size)
- continue;
-
- if (memcmp(entry->salt, salt, salt_size) != 0)
- continue;
- }
-
- if (entry->key_size != key_size)
- continue;
-
- if (memcmp(entry->key, key, key_size) == 0) {
- *starting_index = i;
- return entry;
- }
- }
-
- return NULL;
-}
-
-/**
- * kc_find_key() - find kc entry
- * @key: key to look for
- * @key_size: the key size
- * @salt: salt to look for
- * @salt_size: the salt size
- *
- * Return entry or NULL in case of error
- * Should be invoked under spinlock
- */
-static struct kc_entry *kc_find_key(const unsigned char *key, size_t key_size,
- const unsigned char *salt, size_t salt_size)
-{
- int index = 0;
-
- return kc_find_key_at_index(key, key_size, salt, salt_size, &index);
-}
-
-/**
- * kc_find_oldest_entry_non_locked() - finds the entry with minimal timestamp
- * that is not locked
- *
- * Returns entry with minimal timestamp. Empty entries have timestamp
- * of 0, therefore they are returned first.
- * If all the entries are locked, will return NULL
- * Should be invoked under spin lock
- */
-static struct kc_entry *kc_find_oldest_entry_non_locked(void)
-{
- struct kc_entry *curr_min_entry = NULL;
- struct kc_entry *entry = NULL;
- int i = 0;
-
- for (i = 0; i < PFK_KC_TABLE_SIZE; i++) {
- entry = kc_entry_at_index(i);
-
- if (entry->state == FREE)
- return entry;
-
- if (entry->state == INACTIVE)
- curr_min_entry = kc_min_entry(curr_min_entry, entry);
- }
-
- return curr_min_entry;
-}
-
-/**
- * kc_update_timestamp() - updates timestamp of entry to current
- *
- * @entry: entry to update
- *
- */
-static void kc_update_timestamp(struct kc_entry *entry)
-{
- if (!entry)
- return;
-
- entry->time_stamp = get_jiffies_64();
-}
-
-/**
- * kc_clear_entry() - clear the key from entry and mark entry not in use
- *
- * @entry: pointer to entry
- *
- * Should be invoked under spinlock
- */
-static void kc_clear_entry(struct kc_entry *entry)
-{
- if (!entry)
- return;
-
- memset(entry->key, 0, entry->key_size);
- memset(entry->salt, 0, entry->salt_size);
-
- entry->key_size = 0;
- entry->salt_size = 0;
-
- entry->time_stamp = 0;
- entry->scm_error = 0;
-
- entry->state = FREE;
-
- entry->loaded_ref_cnt = 0;
- entry->thread_pending = NULL;
-}
-
-/**
- * kc_update_entry() - replaces the key in given entry and
- * loads the new key to ICE
- *
- * @entry: entry to replace key in
- * @key: key
- * @key_size: key_size
- * @salt: salt
- * @salt_size: salt_size
- *
- * The previous key is securely released and wiped, the new one is loaded
- * to ICE.
- * Should be invoked under spinlock
- */
-static int kc_update_entry(struct kc_entry *entry, const unsigned char *key,
- size_t key_size, const unsigned char *salt, size_t salt_size)
-{
- int ret;
-
- kc_clear_entry(entry);
-
- memcpy(entry->key, key, key_size);
- entry->key_size = key_size;
-
- memcpy(entry->salt, salt, salt_size);
- entry->salt_size = salt_size;
-
- /* Mark entry as no longer free before releasing the lock */
- entry->state = ACTIVE_ICE_PRELOAD;
- kc_spin_unlock();
-
- ret = qti_pfk_ice_set_key(entry->key_index, entry->key,
- entry->salt, s_type);
-
- kc_spin_lock();
- return ret;
-}
-
-/**
- * pfk_kc_init() - init function
- *
- * Return 0 in case of success, error otherwise
- */
-int pfk_kc_init(void)
-{
- int i = 0;
- struct kc_entry *entry = NULL;
-
- kc_spin_lock();
- for (i = 0; i < PFK_KC_TABLE_SIZE; i++) {
- entry = kc_entry_at_index(i);
- entry->key_index = PFK_KC_STARTING_INDEX + i;
- }
- kc_ready = true;
- kc_spin_unlock();
- return 0;
-}
-
-/**
- * pfk_kc_denit() - deinit function
- *
- * Return 0 in case of success, error otherwise
- */
-int pfk_kc_deinit(void)
-{
- int res = pfk_kc_clear();
-
- kc_ready = false;
- return res;
-}
-
-/**
- * pfk_kc_load_key_start() - retrieve the key from cache or add it if
- * it's not there and return the ICE hw key index in @key_index.
- * @key: pointer to the key
- * @key_size: the size of the key
- * @salt: pointer to the salt
- * @salt_size: the size of the salt
- * @key_index: the pointer to key_index where the output will be stored
- * @async: whether scm calls are allowed in the caller context
- *
- * If key is present in cache, than the key_index will be retrieved from cache.
- * If it is not present, the oldest entry from kc table will be evicted,
- * the key will be loaded to ICE via QSEE to the index that is the evicted
- * entry number and stored in cache.
- * Entry that is going to be used is marked as being used, it will mark
- * as not being used when ICE finishes using it and pfk_kc_load_key_end
- * will be invoked.
- * As QSEE calls can only be done from a non-atomic context, when @async flag
- * is set to 'false', it specifies that it is ok to make the calls in the
- * current context. Otherwise, when @async is set, the caller should retry the
- * call again from a different context, and -EAGAIN error will be returned.
- *
- * Return 0 in case of success, error otherwise
- */
-int pfk_kc_load_key_start(const unsigned char *key, size_t key_size,
- const unsigned char *salt, size_t salt_size, u32 *key_index,
- bool async)
-{
- int ret = 0;
- struct kc_entry *entry = NULL;
- bool entry_exists = false;
-
- if (!kc_is_ready())
- return -ENODEV;
-
- if (!key || !salt || !key_index) {
- pr_err("%s key/salt/key_index NULL\n", __func__);
- return -EINVAL;
- }
-
- if (key_size != PFK_KC_KEY_SIZE) {
- pr_err("unsupported key size %zu\n", key_size);
- return -EINVAL;
- }
-
- if (salt_size != PFK_KC_SALT_SIZE) {
- pr_err("unsupported salt size %zu\n", salt_size);
- return -EINVAL;
- }
-
- kc_spin_lock();
-
- entry = kc_find_key(key, key_size, salt, salt_size);
- if (!entry) {
- if (async) {
- pr_debug("%s task will populate entry\n", __func__);
- kc_spin_unlock();
- return -EAGAIN;
- }
-
- entry = kc_find_oldest_entry_non_locked();
- if (!entry) {
- /* could not find a single non locked entry,
- * return EBUSY to upper layers so that the
- * request will be rescheduled
- */
- kc_spin_unlock();
- return -EBUSY;
- }
- } else {
- entry_exists = true;
- }
-
- pr_debug("entry with index %d is in state %d\n",
- entry->key_index, entry->state);
-
- switch (entry->state) {
- case (INACTIVE):
- if (entry_exists) {
- kc_update_timestamp(entry);
- entry->state = ACTIVE_ICE_LOADED;
-
- if (!strcmp(s_type, (char *)PFK_UFS)) {
- if (async)
- entry->loaded_ref_cnt++;
- } else {
- entry->loaded_ref_cnt++;
- }
- break;
- }
- case (FREE):
- ret = kc_update_entry(entry, key, key_size, salt, salt_size);
- if (ret) {
- entry->state = SCM_ERROR;
- entry->scm_error = ret;
- pr_err("%s: key load error (%d)\n", __func__, ret);
- } else {
- kc_update_timestamp(entry);
- entry->state = ACTIVE_ICE_LOADED;
-
- /*
- * In case of UFS only increase ref cnt for async calls,
- * sync calls from within work thread do not pass
- * requests further to HW
- */
- if (!strcmp(s_type, (char *)PFK_UFS)) {
- if (async)
- entry->loaded_ref_cnt++;
- } else {
- entry->loaded_ref_cnt++;
- }
- }
- break;
- case (ACTIVE_ICE_PRELOAD):
- case (INACTIVE_INVALIDATING):
- ret = -EAGAIN;
- break;
- case (ACTIVE_ICE_LOADED):
- kc_update_timestamp(entry);
-
- if (!strcmp(s_type, (char *)PFK_UFS)) {
- if (async)
- entry->loaded_ref_cnt++;
- } else {
- entry->loaded_ref_cnt++;
- }
- break;
- case(SCM_ERROR):
- ret = entry->scm_error;
- kc_clear_entry(entry);
- entry->state = FREE;
- break;
- default:
- pr_err("invalid state %d for entry with key index %d\n",
- entry->state, entry->key_index);
- ret = -EINVAL;
- }
-
- *key_index = entry->key_index;
- kc_spin_unlock();
-
- return ret;
-}
-
-/**
- * pfk_kc_load_key_end() - finish the process of key loading that was started
- * by pfk_kc_load_key_start
- * by marking the entry as not
- * being in use
- * @key: pointer to the key
- * @key_size: the size of the key
- * @salt: pointer to the salt
- * @salt_size: the size of the salt
- *
- */
-void pfk_kc_load_key_end(const unsigned char *key, size_t key_size,
- const unsigned char *salt, size_t salt_size)
-{
- struct kc_entry *entry = NULL;
- struct task_struct *tmp_pending = NULL;
- int ref_cnt = 0;
-
- if (!kc_is_ready())
- return;
-
- if (!key || !salt)
- return;
-
- if (key_size != PFK_KC_KEY_SIZE)
- return;
-
- if (salt_size != PFK_KC_SALT_SIZE)
- return;
-
- kc_spin_lock();
-
- entry = kc_find_key(key, key_size, salt, salt_size);
- if (!entry) {
- kc_spin_unlock();
- pr_err("internal error, there should an entry to unlock\n");
-
- return;
- }
- ref_cnt = --entry->loaded_ref_cnt;
-
- if (ref_cnt < 0)
- pr_err("internal error, ref count should never be negative\n");
-
- if (!ref_cnt) {
- entry->state = INACTIVE;
- /*
- * wake-up invalidation if it's waiting
- * for the entry to be released
- */
- if (entry->thread_pending) {
- tmp_pending = entry->thread_pending;
- entry->thread_pending = NULL;
-
- kc_spin_unlock();
- wake_up_process(tmp_pending);
- return;
- }
- }
-
- kc_spin_unlock();
-}
-
-/**
- * pfk_kc_remove_key() - remove the key from cache and from ICE engine
- * @key: pointer to the key
- * @key_size: the size of the key
- * @salt: pointer to the key
- * @salt_size: the size of the key
- *
- * Return 0 in case of success, error otherwise (also in case of non
- * (existing key)
- */
-int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size,
- const unsigned char *salt, size_t salt_size)
-{
- struct kc_entry *entry = NULL;
- int res = 0;
-
- if (!kc_is_ready())
- return -ENODEV;
-
- if (!key)
- return -EINVAL;
-
- if (!salt)
- return -EINVAL;
-
- if (key_size != PFK_KC_KEY_SIZE)
- return -EINVAL;
-
- if (salt_size != PFK_KC_SALT_SIZE)
- return -EINVAL;
-
- kc_spin_lock();
-
- entry = kc_find_key(key, key_size, salt, salt_size);
- if (!entry) {
- pr_debug("%s: key does not exist\n", __func__);
- kc_spin_unlock();
- return -EINVAL;
- }
-
- res = kc_entry_start_invalidating(entry);
- if (res != 0) {
- kc_spin_unlock();
- return res;
- }
- kc_clear_entry(entry);
-
- kc_spin_unlock();
-
- qti_pfk_ice_invalidate_key(entry->key_index, s_type);
-
- kc_spin_lock();
- kc_entry_finish_invalidating(entry);
- kc_spin_unlock();
-
- return 0;
-}
-
-/**
- * pfk_kc_remove_key() - remove the key from cache and from ICE engine
- * when no salt is available. Will only search key part, if there are several,
- * all will be removed
- *
- * @key: pointer to the key
- * @key_size: the size of the key
- *
- * Return 0 in case of success, error otherwise (also for non-existing key)
- */
-int pfk_kc_remove_key(const unsigned char *key, size_t key_size)
-{
- struct kc_entry *entry = NULL;
- int index = 0;
- int temp_indexes[PFK_KC_TABLE_SIZE] = {0};
- int temp_indexes_size = 0;
- int i = 0;
- int res = 0;
-
- if (!kc_is_ready())
- return -ENODEV;
-
- if (!key)
- return -EINVAL;
-
- if (key_size != PFK_KC_KEY_SIZE)
- return -EINVAL;
-
- memset(temp_indexes, -1, sizeof(temp_indexes));
-
- kc_spin_lock();
-
- entry = kc_find_key_at_index(key, key_size, NULL, 0, &index);
- if (!entry) {
- pr_err("%s: key does not exist\n", __func__);
- kc_spin_unlock();
- return -EINVAL;
- }
-
- res = kc_entry_start_invalidating(entry);
- if (res != 0) {
- kc_spin_unlock();
- return res;
- }
-
- temp_indexes[temp_indexes_size++] = index;
- kc_clear_entry(entry);
-
- /* let's clean additional entries with the same key if there are any */
- do {
- index++;
- entry = kc_find_key_at_index(key, key_size, NULL, 0, &index);
- if (!entry)
- break;
-
- res = kc_entry_start_invalidating(entry);
- if (res != 0) {
- kc_spin_unlock();
- goto out;
- }
-
- temp_indexes[temp_indexes_size++] = index;
-
- kc_clear_entry(entry);
-
-
- } while (true);
-
- kc_spin_unlock();
-
- temp_indexes_size--;
- for (i = temp_indexes_size; i >= 0 ; i--)
- qti_pfk_ice_invalidate_key(
- kc_entry_at_index(temp_indexes[i])->key_index,
- s_type);
-
- /* fall through */
- res = 0;
-
-out:
- kc_spin_lock();
- for (i = temp_indexes_size; i >= 0 ; i--)
- kc_entry_finish_invalidating(
- kc_entry_at_index(temp_indexes[i]));
- kc_spin_unlock();
-
- return res;
-}
-
-/**
- * pfk_kc_clear() - clear the table and remove all keys from ICE
- *
- * Return 0 on success, error otherwise
- *
- */
-int pfk_kc_clear(void)
-{
- struct kc_entry *entry = NULL;
- int i = 0;
- int res = 0;
-
- if (!kc_is_ready())
- return -ENODEV;
-
- kc_spin_lock();
- for (i = 0; i < PFK_KC_TABLE_SIZE; i++) {
- entry = kc_entry_at_index(i);
- res = kc_entry_start_invalidating(entry);
- if (res != 0) {
- kc_spin_unlock();
- goto out;
- }
- kc_clear_entry(entry);
- }
- kc_spin_unlock();
-
- for (i = 0; i < PFK_KC_TABLE_SIZE; i++)
- qti_pfk_ice_invalidate_key(kc_entry_at_index(i)->key_index,
- s_type);
-
- /* fall through */
- res = 0;
-out:
- kc_spin_lock();
- for (i = 0; i < PFK_KC_TABLE_SIZE; i++)
- kc_entry_finish_invalidating(kc_entry_at_index(i));
- kc_spin_unlock();
-
- return res;
-}
-
-/**
- * pfk_kc_clear_on_reset() - clear the table and remove all keys from ICE
- * The assumption is that at this point we don't have any pending transactions
- * Also, there is no need to clear keys from ICE
- *
- * Return 0 on success, error otherwise
- *
- */
-void pfk_kc_clear_on_reset(void)
-{
- struct kc_entry *entry = NULL;
- int i = 0;
-
- if (!kc_is_ready())
- return;
-
- kc_spin_lock();
- for (i = 0; i < PFK_KC_TABLE_SIZE; i++) {
- entry = kc_entry_at_index(i);
- kc_clear_entry(entry);
- }
- kc_spin_unlock();
-}
-
-static int pfk_kc_find_storage_type(char **device)
-{
- char boot[20] = {'\0'};
- char *match = (char *)strnstr(saved_command_line,
- "androidboot.bootdevice=",
- strlen(saved_command_line));
- if (match) {
- memcpy(boot, (match + strlen("androidboot.bootdevice=")),
- sizeof(boot) - 1);
- if (strnstr(boot, PFK_UFS, strlen(boot)))
- *device = PFK_UFS;
-
- return 0;
- }
- return -EINVAL;
-}
-
-static int __init pfk_kc_pre_init(void)
-{
- return pfk_kc_find_storage_type(&s_type);
-}
-
-static void __exit pfk_kc_exit(void)
-{
- s_type = NULL;
-}
-
-module_init(pfk_kc_pre_init);
-module_exit(pfk_kc_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Per-File-Key-KC driver");
diff --git a/security/pfe/pfk_kc.h b/security/pfe/pfk_kc.h
deleted file mode 100644
index dc4ad15..0000000
--- a/security/pfe/pfk_kc.h
+++ /dev/null
@@ -1,33 +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 PFK_KC_H_
-#define PFK_KC_H_
-
-#include <linux/types.h>
-
-int pfk_kc_init(void);
-int pfk_kc_deinit(void);
-int pfk_kc_load_key_start(const unsigned char *key, size_t key_size,
- const unsigned char *salt, size_t salt_size, u32 *key_index,
- bool async);
-void pfk_kc_load_key_end(const unsigned char *key, size_t key_size,
- const unsigned char *salt, size_t salt_size);
-int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size,
- const unsigned char *salt, size_t salt_size);
-int pfk_kc_remove_key(const unsigned char *key, size_t key_size);
-int pfk_kc_clear(void);
-void pfk_kc_clear_on_reset(void);
-extern char *saved_command_line;
-
-
-#endif /* PFK_KC_H_ */
diff --git a/security/security.c b/security/security.c
index e1f9e32..e43c50c 100644
--- a/security/security.c
+++ b/security/security.c
@@ -11,6 +11,7 @@
* (at your option) any later version.
*/
+#include <linux/bpf.h>
#include <linux/capability.h>
#include <linux/dcache.h>
#include <linux/module.h>
@@ -524,14 +525,6 @@
}
EXPORT_SYMBOL_GPL(security_inode_create);
-int security_inode_post_create(struct inode *dir, struct dentry *dentry,
- umode_t mode)
-{
- if (unlikely(IS_PRIVATE(dir)))
- return 0;
- return call_int_hook(inode_post_create, 0, dir, dentry, mode);
-}
-
int security_inode_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry)
{
@@ -1598,6 +1591,37 @@
}
#endif /* CONFIG_AUDIT */
+#ifdef CONFIG_BPF_SYSCALL
+int security_bpf(int cmd, union bpf_attr *attr, unsigned int size)
+{
+ return call_int_hook(bpf, 0, cmd, attr, size);
+}
+int security_bpf_map(struct bpf_map *map, fmode_t fmode)
+{
+ return call_int_hook(bpf_map, 0, map, fmode);
+}
+int security_bpf_prog(struct bpf_prog *prog)
+{
+ return call_int_hook(bpf_prog, 0, prog);
+}
+int security_bpf_map_alloc(struct bpf_map *map)
+{
+ return call_int_hook(bpf_map_alloc_security, 0, map);
+}
+int security_bpf_prog_alloc(struct bpf_prog_aux *aux)
+{
+ return call_int_hook(bpf_prog_alloc_security, 0, aux);
+}
+void security_bpf_map_free(struct bpf_map *map)
+{
+ call_void_hook(bpf_map_free_security, map);
+}
+void security_bpf_prog_free(struct bpf_prog_aux *aux)
+{
+ call_void_hook(bpf_prog_free_security, aux);
+}
+#endif /* CONFIG_BPF_SYSCALL */
+
struct security_hook_heads security_hook_heads __lsm_ro_after_init = {
.binder_set_context_mgr =
LIST_HEAD_INIT(security_hook_heads.binder_set_context_mgr),
@@ -1676,8 +1700,6 @@
.inode_init_security =
LIST_HEAD_INIT(security_hook_heads.inode_init_security),
.inode_create = LIST_HEAD_INIT(security_hook_heads.inode_create),
- .inode_post_create =
- LIST_HEAD_INIT(security_hook_heads.inode_post_create),
.inode_link = LIST_HEAD_INIT(security_hook_heads.inode_link),
.inode_unlink = LIST_HEAD_INIT(security_hook_heads.inode_unlink),
.inode_symlink =
@@ -1951,4 +1973,20 @@
.audit_rule_free =
LIST_HEAD_INIT(security_hook_heads.audit_rule_free),
#endif /* CONFIG_AUDIT */
+#ifdef CONFIG_BPF_SYSCALL
+ .bpf =
+ LIST_HEAD_INIT(security_hook_heads.bpf),
+ .bpf_map =
+ LIST_HEAD_INIT(security_hook_heads.bpf_map),
+ .bpf_prog =
+ LIST_HEAD_INIT(security_hook_heads.bpf_prog),
+ .bpf_map_alloc_security =
+ LIST_HEAD_INIT(security_hook_heads.bpf_map_alloc_security),
+ .bpf_map_free_security =
+ LIST_HEAD_INIT(security_hook_heads.bpf_map_free_security),
+ .bpf_prog_alloc_security =
+ LIST_HEAD_INIT(security_hook_heads.bpf_prog_alloc_security),
+ .bpf_prog_free_security =
+ LIST_HEAD_INIT(security_hook_heads.bpf_prog_free_security),
+#endif /* CONFIG_BPF_SYSCALL */
};
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e53e076..3b02b82 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -83,6 +83,7 @@
#include <linux/export.h>
#include <linux/msg.h>
#include <linux/shm.h>
+#include <linux/bpf.h>
#include "avc.h"
#include "objsec.h"
@@ -1763,6 +1764,10 @@
return inode_has_perm(cred, file_inode(file), av, &ad);
}
+#ifdef CONFIG_BPF_SYSCALL
+static int bpf_fd_pass(struct file *file, u32 sid);
+#endif
+
/* Check whether a task can use an open file descriptor to
access an inode in a given way. Check access to the
descriptor itself, and then use dentry_has_perm to
@@ -1793,6 +1798,12 @@
goto out;
}
+#ifdef CONFIG_BPF_SYSCALL
+ rc = bpf_fd_pass(file, cred_sid(cred));
+ if (rc)
+ return rc;
+#endif
+
/* av is zero if only checking access to the descriptor. */
rc = 0;
if (av)
@@ -2121,6 +2132,12 @@
return rc;
}
+#ifdef CONFIG_BPF_SYSCALL
+ rc = bpf_fd_pass(file, sid);
+ if (rc)
+ return rc;
+#endif
+
if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
@@ -6079,6 +6096,139 @@
#endif
+#ifdef CONFIG_BPF_SYSCALL
+static int selinux_bpf(int cmd, union bpf_attr *attr,
+ unsigned int size)
+{
+ u32 sid = current_sid();
+ int ret;
+
+ switch (cmd) {
+ case BPF_MAP_CREATE:
+ ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
+ NULL);
+ break;
+ case BPF_PROG_LOAD:
+ ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
+ NULL);
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static u32 bpf_map_fmode_to_av(fmode_t fmode)
+{
+ u32 av = 0;
+
+ if (fmode & FMODE_READ)
+ av |= BPF__MAP_READ;
+ if (fmode & FMODE_WRITE)
+ av |= BPF__MAP_WRITE;
+ return av;
+}
+
+/* This function will check the file pass through unix socket or binder to see
+ * if it is a bpf related object. And apply correspinding checks on the bpf
+ * object based on the type. The bpf maps and programs, not like other files and
+ * socket, are using a shared anonymous inode inside the kernel as their inode.
+ * So checking that inode cannot identify if the process have privilege to
+ * access the bpf object and that's why we have to add this additional check in
+ * selinux_file_receive and selinux_binder_transfer_files.
+ */
+static int bpf_fd_pass(struct file *file, u32 sid)
+{
+ struct bpf_security_struct *bpfsec;
+ struct bpf_prog *prog;
+ struct bpf_map *map;
+ int ret;
+
+ if (file->f_op == &bpf_map_fops) {
+ map = file->private_data;
+ bpfsec = map->security;
+ ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ bpf_map_fmode_to_av(file->f_mode), NULL);
+ if (ret)
+ return ret;
+ } else if (file->f_op == &bpf_prog_fops) {
+ prog = file->private_data;
+ bpfsec = prog->aux->security;
+ ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ BPF__PROG_RUN, NULL);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
+{
+ u32 sid = current_sid();
+ struct bpf_security_struct *bpfsec;
+
+ bpfsec = map->security;
+ return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ bpf_map_fmode_to_av(fmode), NULL);
+}
+
+static int selinux_bpf_prog(struct bpf_prog *prog)
+{
+ u32 sid = current_sid();
+ struct bpf_security_struct *bpfsec;
+
+ bpfsec = prog->aux->security;
+ return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ BPF__PROG_RUN, NULL);
+}
+
+static int selinux_bpf_map_alloc(struct bpf_map *map)
+{
+ struct bpf_security_struct *bpfsec;
+
+ bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+ if (!bpfsec)
+ return -ENOMEM;
+
+ bpfsec->sid = current_sid();
+ map->security = bpfsec;
+
+ return 0;
+}
+
+static void selinux_bpf_map_free(struct bpf_map *map)
+{
+ struct bpf_security_struct *bpfsec = map->security;
+
+ map->security = NULL;
+ kfree(bpfsec);
+}
+
+static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
+{
+ struct bpf_security_struct *bpfsec;
+
+ bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+ if (!bpfsec)
+ return -ENOMEM;
+
+ bpfsec->sid = current_sid();
+ aux->security = bpfsec;
+
+ return 0;
+}
+
+static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
+{
+ struct bpf_security_struct *bpfsec = aux->security;
+
+ aux->security = NULL;
+ kfree(bpfsec);
+}
+#endif
+
static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
@@ -6293,6 +6443,16 @@
LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
#endif
+
+#ifdef CONFIG_BPF_SYSCALL
+ LSM_HOOK_INIT(bpf, selinux_bpf),
+ LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
+ LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
+ LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
+ LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
+ LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
+ LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
+#endif
};
static __init int selinux_init(void)
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 1f1f4b2..963ff80 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -165,5 +165,7 @@
{ COMMON_CAP_PERMS, NULL } },
{ "cap2_userns",
{ COMMON_CAP2_PERMS, NULL } },
+ { "bpf",
+ {"map_create", "map_read", "map_write", "prog_load", "prog_run"} },
{ NULL }
};
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 13011038..43535cd 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -25,9 +25,8 @@
#include <linux/in.h>
#include <linux/spinlock.h>
#include <net/net_namespace.h>
-//#include "flask.h"
-//#include "avc.h"
-#include "security.h"
+#include "flask.h"
+#include "avc.h"
struct task_security_struct {
u32 osid; /* SID prior to last execve */
@@ -53,8 +52,6 @@
u32 sid; /* SID of this object */
u16 sclass; /* security class of this object */
unsigned char initialized; /* initialization flag */
- u32 tag; /* Per-File-Encryption tag */
- void *pfk_data; /* Per-File-Key data from ecryptfs */
struct mutex lock;
};
@@ -131,6 +128,10 @@
u32 sid; /* SID of key */
};
+struct bpf_security_struct {
+ u32 sid; /*SID of bpf obj creater*/
+};
+
extern unsigned int selinux_checkreqprot;
#endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index b8e98c1..308a286 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -12,6 +12,7 @@
#include <linux/dcache.h>
#include <linux/magic.h>
#include <linux/types.h>
+#include "flask.h"
#define SECSID_NULL 0x00000000 /* unspecified SID */
#define SECSID_WILD 0xffffffff /* wildcard SID */
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 051ee18..66ea81c 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -853,6 +853,9 @@
int index;
int rc;
+ if (!ss_initialized)
+ return 0;
+
read_lock(&policy_rwlock);
rc = -EINVAL;
@@ -1399,27 +1402,25 @@
if (!scontext_len)
return -EINVAL;
+ /* Copy the string to allow changes and ensure a NUL terminator */
+ scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags);
+ if (!scontext2)
+ return -ENOMEM;
+
if (!ss_initialized) {
int i;
for (i = 1; i < SECINITSID_NUM; i++) {
- if (!strcmp(initial_sid_to_string[i], scontext)) {
+ if (!strcmp(initial_sid_to_string[i], scontext2)) {
*sid = i;
- return 0;
+ goto out;
}
}
*sid = SECINITSID_KERNEL;
- return 0;
+ goto out;
}
*sid = SECSID_NULL;
- /* Copy the string so that we can modify the copy as we parse it. */
- scontext2 = kmalloc(scontext_len + 1, gfp_flags);
- if (!scontext2)
- return -ENOMEM;
- memcpy(scontext2, scontext, scontext_len);
- scontext2[scontext_len] = 0;
-
if (force) {
/* Save another copy for storing in uninterpreted form */
rc = -ENOMEM;
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 16f8124..5143801 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -115,6 +115,7 @@
return -ENOMEM;
runtime->substream = substream;
spin_lock_init(&runtime->lock);
+ mutex_init(&runtime->realloc_mutex);
init_waitqueue_head(&runtime->sleep);
INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work);
runtime->event = NULL;
@@ -636,8 +637,10 @@
struct snd_rawmidi_params * params)
{
char *newbuf;
+ char *oldbuf;
struct snd_rawmidi_runtime *runtime = substream->runtime;
-
+ unsigned long flags;
+
if (substream->append && substream->use_count > 1)
return -EBUSY;
snd_rawmidi_drain_output(substream);
@@ -648,13 +651,22 @@
return -EINVAL;
}
if (params->buffer_size != runtime->buffer_size) {
- newbuf = krealloc(runtime->buffer, params->buffer_size,
+ mutex_lock(&runtime->realloc_mutex);
+ newbuf = __krealloc(runtime->buffer, params->buffer_size,
GFP_KERNEL);
- if (!newbuf)
+ if (!newbuf) {
+ mutex_unlock(&runtime->realloc_mutex);
return -ENOMEM;
+ }
+ spin_lock_irqsave(&runtime->lock, flags);
+ oldbuf = runtime->buffer;
runtime->buffer = newbuf;
runtime->buffer_size = params->buffer_size;
runtime->avail = runtime->buffer_size;
+ spin_unlock_irqrestore(&runtime->lock, flags);
+ if (oldbuf != newbuf)
+ kfree(oldbuf);
+ mutex_unlock(&runtime->realloc_mutex);
}
runtime->avail_min = params->avail_min;
substream->active_sensing = !params->no_active_sensing;
@@ -666,7 +678,9 @@
struct snd_rawmidi_params * params)
{
char *newbuf;
+ char *oldbuf;
struct snd_rawmidi_runtime *runtime = substream->runtime;
+ unsigned long flags;
snd_rawmidi_drain_input(substream);
if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) {
@@ -676,12 +690,21 @@
return -EINVAL;
}
if (params->buffer_size != runtime->buffer_size) {
- newbuf = krealloc(runtime->buffer, params->buffer_size,
+ mutex_lock(&runtime->realloc_mutex);
+ newbuf = __krealloc(runtime->buffer, params->buffer_size,
GFP_KERNEL);
- if (!newbuf)
+ if (!newbuf) {
+ mutex_unlock(&runtime->realloc_mutex);
return -ENOMEM;
+ }
+ spin_lock_irqsave(&runtime->lock, flags);
+ oldbuf = runtime->buffer;
runtime->buffer = newbuf;
runtime->buffer_size = params->buffer_size;
+ spin_unlock_irqrestore(&runtime->lock, flags);
+ if (oldbuf != newbuf)
+ kfree(oldbuf);
+ mutex_unlock(&runtime->realloc_mutex);
}
runtime->avail_min = params->avail_min;
return 0;
@@ -954,6 +977,8 @@
unsigned long appl_ptr;
spin_lock_irqsave(&runtime->lock, flags);
+ if (userbuf)
+ mutex_lock(&runtime->realloc_mutex);
while (count > 0 && runtime->avail) {
count1 = runtime->buffer_size - runtime->appl_ptr;
if (count1 > count)
@@ -973,6 +998,7 @@
spin_unlock_irqrestore(&runtime->lock, flags);
if (copy_to_user(userbuf + result,
runtime->buffer + appl_ptr, count1)) {
+ mutex_unlock(&runtime->realloc_mutex);
return result > 0 ? result : -EFAULT;
}
spin_lock_irqsave(&runtime->lock, flags);
@@ -981,6 +1007,8 @@
count -= count1;
}
spin_unlock_irqrestore(&runtime->lock, flags);
+ if (userbuf)
+ mutex_unlock(&runtime->realloc_mutex);
return result;
}
@@ -1245,10 +1273,14 @@
return -EINVAL;
result = 0;
+ if (userbuf)
+ mutex_lock(&runtime->realloc_mutex);
spin_lock_irqsave(&runtime->lock, flags);
if (substream->append) {
if ((long)runtime->avail < count) {
spin_unlock_irqrestore(&runtime->lock, flags);
+ if (userbuf)
+ mutex_unlock(&runtime->realloc_mutex);
return -EAGAIN;
}
}
@@ -1284,6 +1316,8 @@
__end:
count1 = runtime->avail < runtime->buffer_size;
spin_unlock_irqrestore(&runtime->lock, flags);
+ if (userbuf)
+ mutex_unlock(&runtime->realloc_mutex);
if (count1)
snd_rawmidi_output_trigger(substream, 1);
return result;
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 16580a8..0b40861 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -999,7 +999,7 @@
{
struct snd_seq_client *client = file->private_data;
int written = 0, len;
- int err = -EINVAL;
+ int err;
struct snd_seq_event event;
if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))
@@ -1014,11 +1014,15 @@
/* allocate the pool now if the pool is not allocated yet */
if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) {
- if (snd_seq_pool_init(client->pool) < 0)
+ mutex_lock(&client->ioctl_mutex);
+ err = snd_seq_pool_init(client->pool);
+ mutex_unlock(&client->ioctl_mutex);
+ if (err < 0)
return -ENOMEM;
}
/* only process whole events */
+ err = -EINVAL;
while (count >= sizeof(struct snd_seq_event)) {
/* Read in the event header from the user */
len = sizeof(event);
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 11b9b2f..9ec4dba 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -1482,6 +1482,9 @@
} else if (ret_size != reply_data_size) {
codec_dbg(codec, "RetLen and HdrLen .NE.\n");
return -EINVAL;
+ } else if (!reply) {
+ codec_dbg(codec, "NULL reply\n");
+ return -EINVAL;
} else {
*reply_len = ret_size*sizeof(unsigned int);
memcpy(reply, scp_reply.data, *reply_len);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 71a058f..89c166b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -3130,6 +3130,19 @@
spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
}
+static void alc269_fixup_pincfg_U7x7_headset_mic(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ unsigned int cfg_headphone = snd_hda_codec_get_pincfg(codec, 0x21);
+ unsigned int cfg_headset_mic = snd_hda_codec_get_pincfg(codec, 0x19);
+
+ if (cfg_headphone && cfg_headset_mic == 0x411111f0)
+ snd_hda_codec_set_pincfg(codec, 0x19,
+ (cfg_headphone & ~AC_DEFCFG_DEVICE) |
+ (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT));
+}
+
static void alc269_fixup_hweq(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -4455,6 +4468,28 @@
}
}
+static void alc_fixup_tpt470_dock(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ static const struct hda_pintbl pincfgs[] = {
+ { 0x17, 0x21211010 }, /* dock headphone */
+ { 0x19, 0x21a11010 }, /* dock mic */
+ { }
+ };
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
+ /* Enable DOCK device */
+ snd_hda_codec_write(codec, 0x17, 0,
+ AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0);
+ /* Enable DOCK device */
+ snd_hda_codec_write(codec, 0x19, 0,
+ AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0);
+ snd_hda_apply_pincfgs(codec, pincfgs);
+ }
+}
+
static void alc_shutup_dell_xps13(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -4797,6 +4832,7 @@
ALC269_FIXUP_LIFEBOOK_EXTMIC,
ALC269_FIXUP_LIFEBOOK_HP_PIN,
ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT,
+ ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC,
ALC269_FIXUP_AMIC,
ALC269_FIXUP_DMIC,
ALC269VB_FIXUP_AMIC,
@@ -4877,6 +4913,7 @@
ALC292_FIXUP_TPT460,
ALC298_FIXUP_SPK_VOLUME,
ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
+ ALC298_FIXUP_TPT470_DOCK,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -4987,6 +5024,10 @@
.type = HDA_FIXUP_FUNC,
.v.func = alc269_fixup_pincfg_no_hp_to_lineout,
},
+ [ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_pincfg_U7x7_headset_mic,
+ },
[ALC269_FIXUP_AMIC] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -5568,6 +5609,12 @@
.chained = true,
.chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
},
+ [ALC298_FIXUP_TPT470_DOCK] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_tpt470_dock,
+ .chained = true,
+ .chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5704,6 +5751,7 @@
SND_PCI_QUIRK(0x10cf, 0x159f, "Lifebook E780", ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT),
SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN),
SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN),
+ SND_PCI_QUIRK(0x10cf, 0x1629, "Lifebook U7x7", ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC),
SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
@@ -5729,8 +5777,16 @@
SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x222d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x222e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2231, "Thinkpad T560", ALC292_FIXUP_TPT460),
SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460),
+ SND_PCI_QUIRK(0x17aa, 0x2245, "Thinkpad T470", ALC298_FIXUP_TPT470_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x2246, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x2247, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x224b, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
@@ -5749,7 +5805,12 @@
SND_PCI_QUIRK(0x17aa, 0x5050, "Thinkpad T560p", ALC292_FIXUP_TPT460),
SND_PCI_QUIRK(0x17aa, 0x5051, "Thinkpad L460", ALC292_FIXUP_TPT460),
SND_PCI_QUIRK(0x17aa, 0x5053, "Thinkpad T460", ALC292_FIXUP_TPT460),
+ SND_PCI_QUIRK(0x17aa, 0x505d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x505f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x5062, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
@@ -5994,6 +6055,11 @@
{0x14, 0x90170110},
{0x21, 0x02211020}),
SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+ {0x12, 0x90a60130},
+ {0x14, 0x90170110},
+ {0x14, 0x01011020},
+ {0x21, 0x0221101f}),
+ SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC256_STANDARD_PINS),
SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
{0x12, 0x90a60130},
@@ -6049,6 +6115,10 @@
{0x12, 0x90a60120},
{0x14, 0x90170110},
{0x21, 0x0321101f}),
+ SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
+ {0x12, 0xb7a60130},
+ {0x14, 0x90170110},
+ {0x21, 0x04211020}),
SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
ALC290_STANDARD_PINS,
{0x15, 0x04211040},
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c
index 712ed65..ebdf9bd 100644
--- a/sound/soc/codecs/pcm512x-spi.c
+++ b/sound/soc/codecs/pcm512x-spi.c
@@ -70,3 +70,7 @@
};
module_spi_driver(pcm512x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC PCM512x codec driver - SPI");
+MODULE_AUTHOR("Mark Brown <broonie@kernel.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index f608f8d2..dd88c2c 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -232,13 +232,19 @@
snprintf(prop, sizeof(prop), "%scpu", prefix);
cpu = of_get_child_by_name(node, prop);
+ if (!cpu) {
+ ret = -EINVAL;
+ dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
+ goto dai_link_of_err;
+ }
+
snprintf(prop, sizeof(prop), "%splat", prefix);
plat = of_get_child_by_name(node, prop);
snprintf(prop, sizeof(prop), "%scodec", prefix);
codec = of_get_child_by_name(node, prop);
- if (!cpu || !codec) {
+ if (!codec) {
ret = -EINVAL;
dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
goto dai_link_of_err;
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
index 3f8e6f0..dcf0369 100644
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -41,7 +41,8 @@
obj = acpi_evaluate_dsm(handle, OSC_UUID, 1, 1, NULL);
if (obj && obj->type == ACPI_TYPE_BUFFER) {
nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer;
- nhlt_table = (struct nhlt_acpi_table *)
+ if (nhlt_ptr->length)
+ nhlt_table = (struct nhlt_acpi_table *)
memremap(nhlt_ptr->min_addr, nhlt_ptr->length,
MEMREMAP_WB);
ACPI_FREE(obj);
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 974915c..08bfee4 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -476,6 +476,7 @@
case I2S_INTCR:
case I2S_XFER:
case I2S_CLR:
+ case I2S_TXDR:
case I2S_RXDR:
case I2S_FIFOLR:
case I2S_INTSR:
@@ -490,6 +491,9 @@
switch (reg) {
case I2S_INTSR:
case I2S_CLR:
+ case I2S_FIFOLR:
+ case I2S_TXDR:
+ case I2S_RXDR:
return true;
default:
return false;
@@ -499,6 +503,8 @@
static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case I2S_RXDR:
+ return true;
default:
return false;
}
diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
index fa8101d..f387d7b 100644
--- a/sound/soc/rockchip/rockchip_spdif.c
+++ b/sound/soc/rockchip/rockchip_spdif.c
@@ -318,26 +318,30 @@
spdif->mclk = devm_clk_get(&pdev->dev, "mclk");
if (IS_ERR(spdif->mclk)) {
dev_err(&pdev->dev, "Can't retrieve rk_spdif master clock\n");
- return PTR_ERR(spdif->mclk);
+ ret = PTR_ERR(spdif->mclk);
+ goto err_disable_hclk;
}
ret = clk_prepare_enable(spdif->mclk);
if (ret) {
dev_err(spdif->dev, "clock enable failed %d\n", ret);
- return ret;
+ goto err_disable_clocks;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(regs))
- return PTR_ERR(regs);
+ if (IS_ERR(regs)) {
+ ret = PTR_ERR(regs);
+ goto err_disable_clocks;
+ }
spdif->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "hclk", regs,
&rk_spdif_regmap_config);
if (IS_ERR(spdif->regmap)) {
dev_err(&pdev->dev,
"Failed to initialise managed register map\n");
- return PTR_ERR(spdif->regmap);
+ ret = PTR_ERR(spdif->regmap);
+ goto err_disable_clocks;
}
spdif->playback_dma_data.addr = res->start + SPDIF_SMPDR;
@@ -369,6 +373,10 @@
err_pm_runtime:
pm_runtime_disable(&pdev->dev);
+err_disable_clocks:
+ clk_disable_unprepare(spdif->mclk);
+err_disable_hclk:
+ clk_disable_unprepare(spdif->hclk);
return ret;
}
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 560cf4b..a9a43ac 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -699,9 +699,14 @@
struct rsnd_priv *priv)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io);
struct device *dev = rsnd_priv_to_dev(priv);
int irq = ssi->irq;
+ /* Do nothing if non SSI (= SSI parent, multi SSI) mod */
+ if (pure_ssi_mod != mod)
+ return 0;
+
/* PIO will request IRQ again */
devm_free_irq(dev, irq, mod);
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index ba9fc09..503aef8 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -164,3 +164,7 @@
};
module_platform_driver(snd_soc_mop500_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ASoC MOP500 board driver");
+MODULE_AUTHOR("Ola Lilja");
diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c
index f12c01d..d35ba77 100644
--- a/sound/soc/ux500/ux500_pcm.c
+++ b/sound/soc/ux500/ux500_pcm.c
@@ -165,3 +165,8 @@
return 0;
}
EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform);
+
+MODULE_AUTHOR("Ola Lilja");
+MODULE_AUTHOR("Roger Nilsson");
+MODULE_DESCRIPTION("ASoC UX500 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 98f879f..ce11cc9 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -356,17 +356,20 @@
int validx, int *value_ret)
{
struct snd_usb_audio *chip = cval->head.mixer->chip;
- unsigned char buf[4 + 3 * sizeof(__u32)]; /* enough space for one range */
+ /* enough space for one range */
+ unsigned char buf[sizeof(__u16) + 3 * sizeof(__u32)];
unsigned char *val;
- int idx = 0, ret, size;
+ int idx = 0, ret, val_size, size;
__u8 bRequest;
+ val_size = uac2_ctl_value_size(cval->val_type);
+
if (request == UAC_GET_CUR) {
bRequest = UAC2_CS_CUR;
- size = uac2_ctl_value_size(cval->val_type);
+ size = val_size;
} else {
bRequest = UAC2_CS_RANGE;
- size = sizeof(buf);
+ size = sizeof(__u16) + 3 * val_size;
}
memset(buf, 0, sizeof(buf));
@@ -399,16 +402,17 @@
val = buf + sizeof(__u16);
break;
case UAC_GET_MAX:
- val = buf + sizeof(__u16) * 2;
+ val = buf + sizeof(__u16) + val_size;
break;
case UAC_GET_RES:
- val = buf + sizeof(__u16) * 3;
+ val = buf + sizeof(__u16) + val_size * 2;
break;
default:
return -EINVAL;
}
- *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(val, sizeof(__u16)));
+ *value_ret = convert_signed_value(cval,
+ snd_usb_combine_bytes(val, val_size));
return 0;
}
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index dd81574..dc0a9ef 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -359,6 +359,15 @@
alts = &iface->altsetting[1];
goto add_sync_ep;
+ case USB_ID(0x1397, 0x0002):
+ ep = 0x81;
+ iface = usb_ifnum_to_if(dev, 1);
+
+ if (!iface || iface->num_altsetting == 0)
+ return -EINVAL;
+
+ alts = &iface->altsetting[1];
+ goto add_sync_ep;
}
if (attr == USB_ENDPOINT_SYNC_ASYNC &&
diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c
index 1c5b36d..ce1f0ad 100644
--- a/sound/usb/usb_audio_qmi_svc.c
+++ b/sound/usb/usb_audio_qmi_svc.c
@@ -762,25 +762,6 @@
struct intf_info *info)
{
- struct usb_host_endpoint *ep;
-
- if (info->data_ep_pipe) {
- ep = usb_pipe_endpoint(udev, info->data_ep_pipe);
- if (!ep)
- pr_debug("%s: no data ep\n", __func__);
- else
- usb_stop_endpoint(udev, ep);
- info->data_ep_pipe = 0;
- }
- if (info->sync_ep_pipe) {
- ep = usb_pipe_endpoint(udev, info->sync_ep_pipe);
- if (!ep)
- pr_debug("%s: no sync ep\n", __func__);
- else
- usb_stop_endpoint(udev, ep);
- info->sync_ep_pipe = 0;
- }
-
uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va,
info->data_xfer_ring_size, info->data_xfer_ring_size);
info->data_xfer_ring_va = 0;
@@ -987,6 +968,7 @@
struct snd_usb_audio *chip = NULL;
struct uaudio_qmi_svc *svc = uaudio_svc;
struct intf_info *info;
+ struct usb_host_endpoint *ep;
int pcm_format;
u8 pcm_card_num, pcm_dev_num, direction;
int info_idx = -EINVAL, ret = 0;
@@ -1057,6 +1039,29 @@
subs->cur_rate = req_msg->bit_rate;
uadev[pcm_card_num].ctrl_intf = chip->ctrl_intf;
+ if (!req_msg->enable) {
+ info = &uadev[pcm_card_num].info[info_idx];
+ if (info->data_ep_pipe) {
+ ep = usb_pipe_endpoint(uadev[pcm_card_num].udev,
+ info->data_ep_pipe);
+ if (!ep)
+ pr_debug("%s: no data ep\n", __func__);
+ else
+ usb_stop_endpoint(uadev[pcm_card_num].udev, ep);
+ info->data_ep_pipe = 0;
+ }
+
+ if (info->sync_ep_pipe) {
+ ep = usb_pipe_endpoint(uadev[pcm_card_num].udev,
+ info->sync_ep_pipe);
+ if (!ep)
+ pr_debug("%s: no sync ep\n", __func__);
+ else
+ usb_stop_endpoint(uadev[pcm_card_num].udev, ep);
+ info->sync_ep_pipe = 0;
+ }
+ }
+
ret = snd_usb_enable_audio_stream(subs, req_msg->enable);
if (!ret && req_msg->enable)
diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build
index 99c0ccd..e279a71 100644
--- a/tools/build/Makefile.build
+++ b/tools/build/Makefile.build
@@ -19,6 +19,16 @@
Q=@
endif
+ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4
+ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
+ quiet=silent_
+endif
+else # make-3.8x
+ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
+ quiet=silent_
+endif
+endif
+
build-dir := $(srctree)/tools/build
# Define $(fixdep) for dep-cmd function
diff --git a/tools/objtool/Documentation/stack-validation.txt b/tools/objtool/Documentation/stack-validation.txt
index 55a60d3..05536d8 100644
--- a/tools/objtool/Documentation/stack-validation.txt
+++ b/tools/objtool/Documentation/stack-validation.txt
@@ -321,11 +321,10 @@
2. If you're getting any other objtool error in a compiled .c file, it
may be because the file uses an asm() statement which has a "call"
instruction. An asm() statement with a call instruction must declare
- the use of the stack pointer in its output operand. For example, on
- x86_64:
+ the use of the stack pointer in its output operand. On x86_64, this
+ means adding the ASM_CALL_CONSTRAINT as an output constraint:
- register void *__sp asm("rsp");
- asm volatile("call func" : "+r" (__sp));
+ asm volatile("call func" : ASM_CALL_CONSTRAINT);
Otherwise the stack frame may not get created before the call.
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
index 9e5a02d..23cce5e 100644
--- a/tools/perf/bench/numa.c
+++ b/tools/perf/bench/numa.c
@@ -211,6 +211,47 @@
NULL
};
+/*
+ * To get number of numa nodes present.
+ */
+static int nr_numa_nodes(void)
+{
+ int i, nr_nodes = 0;
+
+ for (i = 0; i < g->p.nr_nodes; i++) {
+ if (numa_bitmask_isbitset(numa_nodes_ptr, i))
+ nr_nodes++;
+ }
+
+ return nr_nodes;
+}
+
+/*
+ * To check if given numa node is present.
+ */
+static int is_node_present(int node)
+{
+ return numa_bitmask_isbitset(numa_nodes_ptr, node);
+}
+
+/*
+ * To check given numa node has cpus.
+ */
+static bool node_has_cpus(int node)
+{
+ struct bitmask *cpu = numa_allocate_cpumask();
+ unsigned int i;
+
+ if (cpu && !numa_node_to_cpus(node, cpu)) {
+ for (i = 0; i < cpu->size; i++) {
+ if (numa_bitmask_isbitset(cpu, i))
+ return true;
+ }
+ }
+
+ return false; /* lets fall back to nocpus safely */
+}
+
static cpu_set_t bind_to_cpu(int target_cpu)
{
cpu_set_t orig_mask, mask;
@@ -239,12 +280,12 @@
static cpu_set_t bind_to_node(int target_node)
{
- int cpus_per_node = g->p.nr_cpus/g->p.nr_nodes;
+ int cpus_per_node = g->p.nr_cpus / nr_numa_nodes();
cpu_set_t orig_mask, mask;
int cpu;
int ret;
- BUG_ON(cpus_per_node*g->p.nr_nodes != g->p.nr_cpus);
+ BUG_ON(cpus_per_node * nr_numa_nodes() != g->p.nr_cpus);
BUG_ON(!cpus_per_node);
ret = sched_getaffinity(0, sizeof(orig_mask), &orig_mask);
@@ -644,7 +685,7 @@
int i;
for (i = 0; i < mul; i++) {
- if (t >= g->p.nr_tasks) {
+ if (t >= g->p.nr_tasks || !node_has_cpus(bind_node)) {
printf("\n# NOTE: ignoring bind NODEs starting at NODE#%d\n", bind_node);
goto out;
}
@@ -959,6 +1000,8 @@
sum = 0;
for (node = 0; node < g->p.nr_nodes; node++) {
+ if (!is_node_present(node))
+ continue;
nr = nodes[node];
nr_min = min(nr, nr_min);
nr_max = max(nr, nr_max);
@@ -979,8 +1022,11 @@
process_groups = 0;
for (node = 0; node < g->p.nr_nodes; node++) {
- int processes = count_node_processes(node);
+ int processes;
+ if (!is_node_present(node))
+ continue;
+ processes = count_node_processes(node);
nr = nodes[node];
tprintf(" %2d/%-2d", nr, processes);
@@ -1286,7 +1332,7 @@
printf("\n ###\n");
printf(" # %d %s will execute (on %d nodes, %d CPUs):\n",
- g->p.nr_tasks, g->p.nr_tasks == 1 ? "task" : "tasks", g->p.nr_nodes, g->p.nr_cpus);
+ g->p.nr_tasks, g->p.nr_tasks == 1 ? "task" : "tasks", nr_numa_nodes(), g->p.nr_cpus);
printf(" # %5dx %5ldMB global shared mem operations\n",
g->p.nr_loops, g->p.bytes_global/1024/1024);
printf(" # %5dx %5ldMB process shared mem operations\n",
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 0b613e7..c61e012 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -73,6 +73,7 @@
#include <linux/types.h>
static volatile int done;
+static volatile int resize;
#define HEADER_LINE_NR 5
@@ -82,10 +83,13 @@
}
static void perf_top__sig_winch(int sig __maybe_unused,
- siginfo_t *info __maybe_unused, void *arg)
+ siginfo_t *info __maybe_unused, void *arg __maybe_unused)
{
- struct perf_top *top = arg;
+ resize = 1;
+}
+static void perf_top__resize(struct perf_top *top)
+{
get_term_dimensions(&top->winsize);
perf_top__update_print_entries(top);
}
@@ -472,7 +476,7 @@
.sa_sigaction = perf_top__sig_winch,
.sa_flags = SA_SIGINFO,
};
- perf_top__sig_winch(SIGWINCH, NULL, top);
+ perf_top__resize(top);
sigaction(SIGWINCH, &act, NULL);
} else {
signal(SIGWINCH, SIG_DFL);
@@ -1003,6 +1007,11 @@
if (hits == top->samples)
ret = perf_evlist__poll(top->evlist, 100);
+
+ if (resize) {
+ perf_top__resize(top);
+ resize = 0;
+ }
}
ret = 0;
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
index 8abbef1..19edc1a 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -46,6 +46,16 @@
NO_SUBDIR = :
endif
+ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4
+ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
+ silent=1
+endif
+else # make-3.8x
+ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
+ silent=1
+endif
+endif
+
#
# Define a callable command for descending to a new directory
#
@@ -58,7 +68,7 @@
QUIET_SUBDIR0 = +$(MAKE) $(COMMAND_O) -C # space to separate -C and subdir
QUIET_SUBDIR1 =
-ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifneq ($(silent),1)
ifneq ($(V),1)
QUIET_CC = @echo ' CC '$@;
QUIET_CC_FPIC = @echo ' CC FPIC '$@;
diff --git a/tools/testing/selftests/vm/compaction_test.c b/tools/testing/selftests/vm/compaction_test.c
index 6d1437f..298f69e 100644
--- a/tools/testing/selftests/vm/compaction_test.c
+++ b/tools/testing/selftests/vm/compaction_test.c
@@ -136,6 +136,8 @@
printf("No of huge pages allocated = %d\n",
(atoi(nr_hugepages)));
+ lseek(fd, 0, SEEK_SET);
+
if (write(fd, initial_nr_hugepages, strlen(initial_nr_hugepages))
!= strlen(initial_nr_hugepages)) {
perror("Failed to write value to /proc/sys/vm/nr_hugepages\n");
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index 4af37bf..6eb5015 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -26,11 +26,13 @@
ifeq ($(CAN_BUILD_I386),1)
all: all_32
TEST_PROGS += $(BINARIES_32)
+EXTRA_CFLAGS += -DCAN_BUILD_32
endif
ifeq ($(CAN_BUILD_X86_64),1)
all: all_64
TEST_PROGS += $(BINARIES_64)
+EXTRA_CFLAGS += -DCAN_BUILD_64
endif
all_32: $(BINARIES_32)
diff --git a/tools/testing/selftests/x86/mpx-mini-test.c b/tools/testing/selftests/x86/mpx-mini-test.c
index 616ee96..79e1d13 100644
--- a/tools/testing/selftests/x86/mpx-mini-test.c
+++ b/tools/testing/selftests/x86/mpx-mini-test.c
@@ -315,11 +315,39 @@
return si->si_upper;
}
#else
+
+/*
+ * This deals with old version of _sigfault in some distros:
+ *
+
+old _sigfault:
+ struct {
+ void *si_addr;
+ } _sigfault;
+
+new _sigfault:
+ struct {
+ void __user *_addr;
+ int _trapno;
+ short _addr_lsb;
+ union {
+ struct {
+ void __user *_lower;
+ void __user *_upper;
+ } _addr_bnd;
+ __u32 _pkey;
+ };
+ } _sigfault;
+ *
+ */
+
static inline void **__si_bounds_hack(siginfo_t *si)
{
void *sigfault = &si->_sifields._sigfault;
void *end_sigfault = sigfault + sizeof(si->_sifields._sigfault);
- void **__si_lower = end_sigfault;
+ int *trapno = (int*)end_sigfault;
+ /* skip _trapno and _addr_lsb */
+ void **__si_lower = (void**)(trapno + 2);
return __si_lower;
}
@@ -331,7 +359,7 @@
static inline void *__si_bounds_upper(siginfo_t *si)
{
- return (*__si_bounds_hack(si)) + sizeof(void *);
+ return *(__si_bounds_hack(si) + 1);
}
#endif
diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c
index bdd58c7..2842a5f 100644
--- a/tools/testing/selftests/x86/protection_keys.c
+++ b/tools/testing/selftests/x86/protection_keys.c
@@ -381,34 +381,6 @@
return forkret;
}
-void davecmp(void *_a, void *_b, int len)
-{
- int i;
- unsigned long *a = _a;
- unsigned long *b = _b;
-
- for (i = 0; i < len / sizeof(*a); i++) {
- if (a[i] == b[i])
- continue;
-
- dprintf3("[%3d]: a: %016lx b: %016lx\n", i, a[i], b[i]);
- }
-}
-
-void dumpit(char *f)
-{
- int fd = open(f, O_RDONLY);
- char buf[100];
- int nr_read;
-
- dprintf2("maps fd: %d\n", fd);
- do {
- nr_read = read(fd, &buf[0], sizeof(buf));
- write(1, buf, nr_read);
- } while (nr_read > 0);
- close(fd);
-}
-
#define PKEY_DISABLE_ACCESS 0x1
#define PKEY_DISABLE_WRITE 0x2
diff --git a/tools/testing/selftests/x86/single_step_syscall.c b/tools/testing/selftests/x86/single_step_syscall.c
index a48da95..ddfdd63 100644
--- a/tools/testing/selftests/x86/single_step_syscall.c
+++ b/tools/testing/selftests/x86/single_step_syscall.c
@@ -119,7 +119,9 @@
int main()
{
+#ifdef CAN_BUILD_32
int tmp;
+#endif
sethandler(SIGTRAP, sigtrap, 0);
@@ -139,12 +141,13 @@
: : "c" (post_nop) : "r11");
check_result();
#endif
-
+#ifdef CAN_BUILD_32
printf("[RUN]\tSet TF and check int80\n");
set_eflags(get_eflags() | X86_EFLAGS_TF);
asm volatile ("int $0x80" : "=a" (tmp) : "a" (SYS_getpid)
: INT80_CLOBBERS);
check_result();
+#endif
/*
* This test is particularly interesting if fast syscalls use
diff --git a/tools/testing/selftests/x86/test_mremap_vdso.c b/tools/testing/selftests/x86/test_mremap_vdso.c
index bf0d687..64f11c8 100644
--- a/tools/testing/selftests/x86/test_mremap_vdso.c
+++ b/tools/testing/selftests/x86/test_mremap_vdso.c
@@ -90,8 +90,12 @@
vdso_size += PAGE_SIZE;
}
+#ifdef __i386__
/* Glibc is likely to explode now - exit with raw syscall */
asm volatile ("int $0x80" : : "a" (__NR_exit), "b" (!!ret));
+#else /* __x86_64__ */
+ syscall(SYS_exit, ret);
+#endif
} else {
int status;