summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-06-27 11:38:52 -0600
committerLinux Build Service Account <lnxbuild@localhost>2016-06-27 11:38:53 -0600
commite195400eb58d48148c8aefab3e60e40f1346ea13 (patch)
tree1ba37cded305fe158867733ab4243bcf04c4aab5
parent402636f926b48533bbb1589fe2ebe2e33ef80197 (diff)
parentfb5706b7462b0b855d10da12ed88ebf10a2e8643 (diff)
Promotion of kernel.lnx.4.4-160624.
CRs Change ID Subject -------------------------------------------------------------------------------------------------------------- 1032949 I3c64e6b96d569b4dc61805a53a0835db9142d55e usb: gadget: mtp: Increase RX transfer length to 1M 1030377 I867a4621315108aff17be852cfaadcfa945566a7 scsi: ufs-debugfs: add error state 1004236 I54fef744bdf08a346e4aef22c1280e928cdaf5d2 diag: Add support for multi connection logging 1032131 I35a8307001ac14e3ade733d5f41d6231fe63ebd0 soc: qcom: smem: Renaming smem item SMEM_SMEM_STATIC_LOG 1032889 I02fa5e3e25427c0ca474455fa2d2be9eb6ea4bd9 cfg80211: Bypass checkin the CHAN_RADAR if DFS_OFFLOAD i 1033849 Iadbaa5e71e4b220208a7275bf039a2a413349e42 arm: mm: fix pte allocation with CONFIG_FORCE_PAGES feat 1027585 I67eb4f162f944bbf4d9e55fb8fe93759e6b8ff91 ASoC: msm: qdsp6v2: DAP: Add check to validate data leng 1033060 I437fe28725d5c1ed06fe8b9735b04bbd84e92db1 regulator: cpr3-util: init panic notifier for CPRh contr 1033031 I2bbf6884cf83457bfb7e5369bb97614bd4beb150 clk: msm: osm: add panic handler to dump status register 1033830 I1b8a1492062bb9532700122878618989e5148647 Kconfig: Add menu choice option to reclaim virtual memor 1033849 Ie209fce6c310f911d8cf02d977e226660684a6ab arm: mm: consider only lowmem regions while remap 1023723 Ifd1df8ee04238db0338a7dd70eb5097af2d0eb62 msm: mdss: fix multi-rect validation properties 1033060 Ifdd03f27ed1135acd4470d891e1b5aca4a11dd65 ARM: dts: msm: add CPR panic register configuration for 1033850 Ieac0932d146f7fd992db9fd834b0e9aa3822f891 mm, sl[au]b: add __GFP_ATOMIC to the GFP reclaim mask 1004533 Id01b4f959c134af48c509ade61c7ec46401b4e70 regulator: cpr3: Add panic handler to dump register cont 1030443 Ic7204921fc82d5aea31c58fcbb668b296794b1c1 msm: mdss: Add dereference check for xlog vbif dump 1030443 Ie3970f29c7f1800c4457dc71a3f36a54e1cbdb91 ARM: dts: msm: Enable v4l2 rotator node on msm8996 1023326 Icc20967019996616a4eb2ebba6df47e7bc7188d7 regulator: Add snapshot of DT documentation for rpm-smd- 1033849 I9612a99b8e05a022f5ba7e568f21307cf66b5667 arm: Allow remapping lowmem as 4K pages Change-Id: I24aebc843a4cec8478f27027ae2b130ec09d8e67 CRs-Fixed: 1032131, 1033031, 1032949, 1032889, 1004236, 1033830, 1030443, 1030377, 1033849, 1023326, 1023723, 1004533, 1033850, 1033060, 1027585
-rw-r--r--Documentation/devicetree/bindings/regulator/cpr3-regulator.txt13
-rw-r--r--Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt7
-rw-r--r--Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt328
-rw-r--r--arch/arm/Kconfig23
-rw-r--r--arch/arm/Kconfig.debug11
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-mdss.dtsi103
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi10
-rw-r--r--arch/arm/mm/mmu.c114
-rw-r--r--arch/arm/mm/pageattr.c11
-rw-r--r--drivers/char/diag/diag_mux.c120
-rw-r--r--drivers/char/diag/diag_mux.h15
-rw-r--r--drivers/char/diag/diagchar.h20
-rw-r--r--drivers/char/diag/diagchar_core.c317
-rw-r--r--drivers/char/diag/diagfwd.c24
-rw-r--r--drivers/clk/msm/clock-osm.c50
-rw-r--r--drivers/regulator/cpr3-regulator.c47
-rw-r--r--drivers/regulator/cpr3-regulator.h34
-rw-r--r--drivers/regulator/cpr3-util.c72
-rw-r--r--drivers/scsi/ufs/ufs-debugfs.c47
-rw-r--r--drivers/scsi/ufs/ufs-debugfs.h6
-rw-r--r--drivers/scsi/ufs/ufshcd.c16
-rw-r--r--drivers/scsi/ufs/ufshcd.h2
-rw-r--r--drivers/usb/gadget/function/f_mtp.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_debug_xlog.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c33
-rw-r--r--include/soc/qcom/smem.h1
-rw-r--r--mm/internal.h3
-rw-r--r--net/wireless/chan.c11
-rw-r--r--sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c8
29 files changed, 1194 insertions, 257 deletions
diff --git a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
index 0a5ad543a2be..7d88e9fbd9c6 100644
--- a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
@@ -183,6 +183,19 @@ Platform independent properties:
This is the voltage that vdd-supply must be set to when
performing an aging measurement.
+- qcom,cpr-panic-reg-addr-list
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: Array of register addresses to be dumped when device resets.
+
+- qcom,cpr-panic-reg-name-list
+ Usage: optional, though only meaningful if
+ qcom,cpr-panic-reg-addr-list is specified
+ Value type: <prop-encoded-array>
+ Definition: Address names. Must be specified in the same order
+ as the corresponding addresses are specified in
+ the qcom,cpr-panic-reg-addr-list property.
+
=================================================
Second Level Nodes - CPR Threads for a Controller
=================================================
diff --git a/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt
index ff60d6e3ef7f..891feb571157 100644
--- a/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt
@@ -407,6 +407,13 @@ apc_cpr: cpr4-ctrl@b018000 {
qcom,cpr-step-quot-fixed = <16>;
qcom,cpr-voltage-settling-time = <1600>;
+ 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 = <1>;
diff --git a/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
new file mode 100644
index 000000000000..ccefc98e51e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
@@ -0,0 +1,328 @@
+Qualcomm RPM Regulators
+
+rpm-regulator-smd is a regulator driver which supports regulators inside of
+PMICs which are controlled by the RPM processor. Communication with the RPM
+processor takes place over SMD.
+
+Required structure:
+- RPM regulators must be described in two levels of devices nodes. The first
+ level describes the interface with the RPM. The second level describes
+ properties of one regulator framework interface (of potentially many) to
+ the regulator.
+
+[First Level Nodes]
+
+Required properties:
+- compatible: Must be "qcom,rpm-smd-regulator-resource"
+- qcom,resource-name: Resource name string for this regulator to be used in RPM
+ transactions. Length is 4 characters max.
+- qcom,resource-id: Resource instance ID for this regulator to be used in RPM
+ transactions.
+- qcom,regulator-type: Type of this regulator. Supported values are:
+ 0 = LDO
+ 1 = SMPS
+ 2 = VS
+ 3 = NCP
+ 4 = Buck or Boost (BoB)
+
+Optional properties:
+- qcom,allow-atomic: Flag specifying if atomic access is allowed for this
+ regulator. Supported values are:
+ 0 or not present = mutex locks used
+ 1 = spinlocks used
+- qcom,enable-time: Time in us to delay after enabling the regulator
+- qcom,hpm-min-load: Load current in uA which corresponds to the minimum load
+ which requires the regulator to be in high power mode.
+- qcom,apps-only: Flag which indicates that the regulator only has
+ consumers on the application processor. If this flag
+ is specified, then voltage and current updates are
+ only sent to the RPM if the regulator is enabled.
+- qcom,always-wait-for-ack: Flag which indicates that the application
+ processor must wait for an ACK or a NACK from the RPM
+ for every request sent for this regulator including
+ those which are for a strictly lower power state.
+
+[Second Level Nodes]
+
+Required properties:
+- compatible: Must be "qcom,rpm-smd-regulator"
+- regulator-name: A string used as a descriptive name for regulator outputs
+- qcom,set: Specifies which sets that requests made with this
+ regulator interface should be sent to. Regulator
+ requests sent in the active set take effect immediately.
+ Requests sent in the sleep set take effect when the Apps
+ processor transitions into RPM assisted power collapse.
+ Supported values are:
+ 1 = Active set only
+ 2 = Sleep set only
+ 3 = Both active and sleep sets
+
+
+
+Optional properties:
+- parent-supply: phandle to the parent supply/regulator node
+- qcom,system-load: Load in uA present on regulator that is not
+ captured by any consumer request
+- qcom,use-voltage-corner: Flag that signifies if regulator_set_voltage
+ calls should modify the corner parameter instead
+ of the voltage parameter. When used, voltages
+ specified inside of the regulator framework
+ represent corners that have been incremented by
+ 1. This value shift is necessary to work around
+ limitations in the regulator framework which
+ treat 0 uV as an error.
+- qcom,use-voltage-floor-corner: Flag that signifies if regulator_set_voltage
+ calls should modify the floor corner parameter
+ instead of the voltage parameter. When used,
+ voltages specified inside of the regulator
+ framework represent corners that have been
+ incremented by 1. The properties
+ qcom,use-voltage-corner and
+ qcom,use-voltage-floor-corner are mutually
+ exclusive. Only one may be specified for a
+ given regulator.
+- qcom,use-voltage-level: Flag that signifies if regulator_set_voltage
+ calls should modify the level parameter instead
+ of the voltage parameter.
+- qcom,use-voltage-floor-level: Flag that signifies if regulator_set_voltage
+ calls should modify the floor level parameter
+ instead of the voltage parameter.
+ The properties qcom,use-voltage-level and
+ qcom,use-voltage-floor-level are mutually
+ exclusive. Only one may be specified for a
+ given regulator.
+- qcom,use-pin-ctrl-voltage1: Flag which indicates that updates to voltage
+ should be sent to the pin control voltage 1
+ parameter. Only one pin may be specified per
+ regulator. This property only applies to BoB
+ type regulators.
+- qcom,use-pin-ctrl-voltage2: Flag which indicates that updates to voltage
+ should be sent to the pin control voltage 2
+ parameter. Only one pin may be specified per
+ regulator. This property only applies to BoB
+ type regulators.
+- qcom,use-pin-ctrl-voltage3: Flag which indicates that updates to voltage
+ should be sent to the pin control voltage 3
+ parameter. Only one pin may be specified per
+ regulator. This property only applies to BoB
+ type regulators.
+- qcom,always-send-voltage: Flag which indicates that updates to the
+ voltage, voltage corner or voltage level set
+ point should always be sent immediately to the
+ RPM. If this flag is not specified, then
+ voltage set point updates are only sent if the
+ given regulator has also been enabled by a
+ Linux consumer.
+- qcom,always-send-current: Flag which indicates that updates to the load
+ current should always be sent immediately to the
+ RPM. If this flag is not specified, then load
+ current updates are only sent if the given
+ regulator has also been enabled by a Linux
+ consumer.
+- qcom,send-defaults: Boolean flag which indicates that the initial
+ parameter values should be sent to the RPM
+ before consumers make their own requests. If
+ this flag is not specified, then initial
+ parameters values will only be sent after some
+ consumer makes a request.
+- qcom,enable-with-pin-ctrl: Double in which the first element corresponds to
+ the pin control enable parameter value to send
+ when all consumers have requested the regulator
+ to be disabled. The second element corresponds
+ to the pin control enable parameter value to
+ send when any consumer has requested the
+ regulator to be enabled. Each element supports
+ the same set of values as the
+ qcom,init-pin-ctrl-enable property listed below.
+
+The following properties specify initial values for parameters to be sent to the
+RPM in regulator requests.
+- qcom,init-enable: 0 = regulator disabled
+ 1 = regulator enabled
+- qcom,init-voltage: Voltage in uV
+- qcom,init-current: Current in mA
+- qcom,init-ldo-mode: Operating mode to be used with LDO regulators
+ Supported values are:
+ 0 = mode determined by current requests
+ 1 = force HPM (NPM)
+- qcom,init-smps-mode: Operating mode to be used with SMPS regulators
+ Supported values are:
+ 0 = auto; hardware determines mode
+ 1 = mode determined by current requests
+ 2 = force HPM (PWM)
+- qcom,init-bob-mode: Operating mode to be used with BoB regulators
+ Supported values are:
+ 0 = pass; use priority order
+ 1 = force PFM
+ 2 = auto; hardware determines mode
+ 3 = force PWM
+- qcom,init-pin-ctrl-enable: Bit mask specifying which hardware pins should be
+ used to enable the regulator, if any; supported
+ bits are:
+ 0 = ignore all hardware enable signals
+ BIT(0) = follow HW0_EN signal
+ BIT(1) = follow HW1_EN signal
+ BIT(2) = follow HW2_EN signal
+ BIT(3) = follow HW3_EN signal
+- qcom,init-pin-ctrl-mode: Bit mask specifying which hardware pins should be
+ used to force the regulator into high power
+ mode, if any. Supported bits are:
+ 0 = ignore all hardware enable signals
+ BIT(0) = follow HW0_EN signal
+ BIT(1) = follow HW1_EN signal
+ BIT(2) = follow HW2_EN signal
+ BIT(3) = follow HW3_EN signal
+ BIT(4) = follow PMIC awake state
+- qcom,init-pin-ctrl-voltage1: Minimum voltage in micro-volts to use while pin
+ control 1 is enabled. This property only
+ applies to BoB type regulators.
+- qcom,init-pin-ctrl-voltage2: Minimum voltage in micro-volts to use while pin
+ control 2 is enabled. This property only
+ applies to BoB type regulators.
+- qcom,init-pin-ctrl-voltage3: Minimum voltage in micro-volts to use while pin
+ control 3 is enabled. This property only
+ applies to BoB type regulators.
+- qcom,init-frequency: Switching frequency divisor for SMPS regulators.
+ Supported values are n = 0 to 31 where
+ freq = 19.2 MHz / (n + 1).
+- qcom,init-head-room: Voltage head room in mV required for the
+ regulator. This head room value should be used
+ in situations where the device connected to the
+ output of the regulator has low noise tolerance.
+ Note that the RPM independently enforces a
+ safety head room value for subregulated LDOs
+ which is sufficient to account for LDO drop-out
+ voltage.
+- qcom,init-quiet-mode: Specify that quiet mode is needed for an SMPS
+ regulator in order to have lower output noise.
+ Supported values are:
+ 0 = No quiet mode
+ 1 = Quiet mode
+ 2 = Super quiet mode
+- qcom,init-freq-reason: Consumer requiring specified frequency for an
+ SMPS regulator. Supported values are:
+ 0 = None
+ 1 = Bluetooth
+ 2 = GPS
+ 4 = WLAN
+ 8 = WAN
+- qcom,init-voltage-corner: Performance corner to use in order to determine
+ voltage set point. This value corresponds to
+ the actual value that will be sent and is not
+ incremented by 1 like the values used inside of
+ the regulator framework. The meaning of corner
+ values is set by the RPM. It is possible that
+ different regulators on a given platform or
+ similar regulators on different platforms will
+ utilize different corner values. These are
+ corner values supported on MSM8974 for PMIC
+ PM8841 SMPS 2 (VDD_Dig); nominal voltages for
+ these corners are also shown:
+ 0 = None (don't care)
+ 1 = Retention (0.5000 V)
+ 2 = SVS Krait (0.7250 V)
+ 3 = SVS SOC (0.8125 V)
+ 4 = Normal (0.9000 V)
+ 5 = Turbo (0.9875 V)
+ 6 = Super Turbo (1.0500 V)
+- qcom,init-disallow-bypass: Specify that bypass mode should not be used for a
+ given LDO regulator. When in bypass mode, an
+ LDO performs no regulation and acts as a simple
+ switch. The RPM can utilize this mode for an
+ LDO that is subregulated from an SMPS when it is
+ possible to reduce the SMPS voltage to the
+ desired LDO output level. Bypass mode may be
+ disallowed if lower LDO output noise is
+ required. Supported values are:
+ 0 = Allow RPM to utilize LDO bypass mode
+ if possible
+ 1 = Disallow LDO bypass mode
+- qcom,init-voltage-floor-corner: Minimum performance corner to use if any
+ processor in the system is awake. This property
+ supports the same values as
+ qcom,init-voltage-corner.
+- qcom,init-voltage-level: Performance level to use in order to determine
+ voltage set point. The meaning of level
+ values is set by the RPM. It is possible that
+ different regulators on a given platform or
+ similar regulators on different platforms will
+ utilize different level values. These are
+ level values supported on MSM8952 for PMIC
+ PM8952 SMPS 2 (VDD_Dig); nominal voltages for
+ these level are also shown:
+ 16 = Retention (0.5000 V)
+ 128 = SVS (1.0500 V)
+ 192 = SVS+ (1.1550 V)
+ 256 = Normal (1.2250 V)
+ 320 = Normal+ (1.2875 V)
+ 384 = Turbo (1.3500 V)
+- qcom,init-voltage-floor-level: Minimum performance level to use if any
+ processor in the system is awake. This property
+ supports the same values as
+ qcom,init-voltage-level.
+
+All properties specified within the core regulator framework can also be used in
+second level nodes. These bindings can be found in:
+Documentation/devicetree/bindings/regulator/regulator.txt.
+
+Examples:
+
+rpm-regulator-smpb1 {
+ qcom,resource-name = "smpb";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ compatible = "qcom,rpm-smd-regulator-resource";
+ status = "disabled";
+
+ pm8841_s1: regulator-s1 {
+ regulator-name = "8841_s1";
+ qcom,set = <3>;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1150000>;
+ qcom,init-voltage = <1150000>;
+ compatible = "qcom,rpm-smd-regulator";
+ };
+ pm8841_s1_ao: regulator-s1-ao {
+ regulator-name = "8841_s1_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1150000>;
+ compatible = "qcom,rpm-smd-regulator";
+ };
+ pm8841_s1_corner: regulator-s1-corner {
+ regulator-name = "8841_s1_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <6>;
+ qcom,init-voltage-corner = <3>;
+ qcom,use-voltage-corner;
+ compatible = "qcom,rpm-smd-regulator";
+ };
+};
+
+rpm-regulator-ldoa2 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ compatible = "qcom,rpm-smd-regulator-resource";
+
+ regulator-l2 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "8941_l2";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1225000>;
+ };
+ regulator-l2-pin-ctrl {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "8941_l2_pin_ctrl";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1225000>;
+ qcom,enable-with-pin-ctrl = <0 1>;
+ };
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 6b09a67c9a0d..863f2cd9096a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1768,6 +1768,29 @@ config ARM_MODULE_PLTS
source "mm/Kconfig"
+choice
+ prompt "Virtual Memory Reclaim"
+ default NO_VM_RECLAIM
+ help
+ Select the method of reclaiming virtual memory
+
+config ENABLE_VMALLOC_SAVING
+ bool "Reclaim memory for each subsystem"
+ help
+ Enable this config to reclaim the virtual space belonging
+ to any subsystem which is expected to have a lifetime of
+ the entire system. This feature allows lowmem to be non-
+ contiguous.
+
+config NO_VM_RECLAIM
+ bool "Do not reclaim memory"
+ help
+ Do not reclaim any memory. This might result in less lowmem
+ and wasting virtual memory space which could otherwise be
+ reclaimed by using any of the other two config options.
+
+endchoice
+
config FORCE_MAX_ZONEORDER
int "Maximum zone order"
default "12" if SOC_AM33XX
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 71afa854e1c4..b87d5d924238 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -76,6 +76,17 @@ config DEBUG_USER
8 - SIGSEGV faults
16 - SIGBUS faults
+config FORCE_PAGES
+ bool "Force lowmem to be mapped with 4K pages"
+ help
+ There are some advanced debug features that can only be done when
+ memory is mapped with pages instead of sections. Enable this option
+ to always map lowmem pages with pages. This may have a performance
+ cost due to increased TLB pressure.
+
+ If unsure say N.
+
+
# These options are only for real kernel hackers who want to get their hands dirty.
config DEBUG_LL
bool "Kernel low-level debugging functions (read help!)"
diff --git a/arch/arm/boot/dts/qcom/msm8996-mdss.dtsi b/arch/arm/boot/dts/qcom/msm8996-mdss.dtsi
index 5c01812d7d6e..3186f96b4275 100644
--- a/arch/arm/boot/dts/qcom/msm8996-mdss.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-mdss.dtsi
@@ -14,10 +14,11 @@
mdss_mdp: qcom,mdss_mdp@900000 {
compatible = "qcom,mdss_mdp";
reg = <0x00900000 0x90000>,
- <0x009b0000 0x1040>,
- <0x009b8000 0x1040>;
- reg-names = "mdp_phys", "vbif_phys", "vbif_nrt_phys";
+ <0x009b0000 0x1040>;
+ reg-names = "mdp_phys", "vbif_phys";
interrupts = <0 83 0>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
vdd-supply = <&gdsc_mdss>;
#address-cells = <1>;
@@ -65,12 +66,10 @@
0x00009000 0x0000B000>;
qcom,mdss-pipe-rgb-off = <0x00015000 0x00017000
0x00019000 0x0001B000>;
- qcom,mdss-pipe-dma-off = <0x00025000 0x00027000>;
qcom,mdss-pipe-cursor-off = <0x00035000 0x00037000>;
qcom,mdss-pipe-vig-xin-id = <0 4 8 12>;
qcom,mdss-pipe-rgb-xin-id = <1 5 9 13>;
- qcom,mdss-pipe-dma-xin-id = <2 10>;
qcom,mdss-pipe-cursor-xin-id = <7 7>;
/* These Offsets are relative to "mdp_phys + mdp-reg-offset" address */
@@ -82,19 +81,16 @@
<0x2B4 4 8>,
<0x2BC 4 8>,
<0x2C4 4 8>;
- qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x2AC 8 12>,
- <0x2B4 8 12>;
qcom,mdss-pipe-cursor-clk-ctrl-offsets = <0x3A8 16 15>,
<0x3B0 16 15>;
qcom,mdss-ctl-off = <0x00002000 0x00002200 0x00002400
- 0x00002600 0x00002800>;
+ 0x00002600>;
qcom,mdss-mixer-intf-off = <0x00045000 0x00046000
0x00047000 0x0004A000>;
- qcom,mdss-mixer-wb-off = <0x00048000 0x00049000>;
qcom,mdss-dspp-off = <0x00055000 0x00057000>;
- qcom,mdss-wb-off = <0x00065000 0x00065800 0x00066000>;
+ qcom,mdss-wb-off = <0x00066000>;
qcom,mdss-intf-off = <0x0006B000 0x0006B800
0x0006C000 0x0006C800>;
qcom,mdss-pingpong-off = <0x00071000 0x00071800
@@ -103,6 +99,7 @@
qcom,mdss-ppb-ctl-off = <0x00000330 0x00000338>;
qcom,mdss-ppb-cfg-off = <0x00000334 0x0000033C>;
qcom,mdss-has-pingpong-split;
+ qcom,mdss-has-separate-rotator;
qcom,mdss-ad-off = <0x0079000 0x00079800 0x0007a000>;
qcom,mdss-cdm-off = <0x0007a200>;
@@ -111,7 +108,6 @@
qcom,mdss-has-source-split;
qcom,mdss-highest-bank-bit = <0x2>;
qcom,mdss-has-decimation;
- qcom,mdss-has-rotator-downscale;
qcom,mdss-idle-power-collapse-enabled;
clocks = <&clock_mmss clk_mdss_ahb_clk>,
<&clock_mmss clk_mdss_axi_clk>,
@@ -248,19 +244,6 @@
"mdp_axi_clk";
};
- smmu_rot_unsec: qcom,smmu_rot_unsec_cb {
- compatible = "qcom,smmu_rot_unsec";
- iommus = <&rot_smmu 0>;
- reg = <0x00d09000 0xd00>;
- reg-names = "mmu_cb";
- gdsc-mmagic-mdss-supply = <&gdsc_mmagic_mdss>;
- clocks = <&clock_mmss clk_smmu_rot_ahb_clk>,
- <&clock_mmss clk_mmagic_mdss_axi_clk>,
- <&clock_mmss clk_smmu_rot_axi_clk>;
- clock-names = "rot_ahb_clk", "mmagic_mdss_axi_clk",
- "rot_axi_clk";
- };
-
smmu_mdp_sec: qcom,smmu_mdp_sec_cb {
compatible = "qcom,smmu_mdp_sec";
iommus = <&mdp_smmu 1>;
@@ -274,19 +257,6 @@
"mdp_axi_clk";
};
- smmu_rot_sec: qcom,smmu_rot_sec_cb {
- compatible = "qcom,smmu_rot_sec";
- iommus = <&rot_smmu 1>;
- reg = <0x00d0b000 0xd00>;
- reg-names = "mmu_cb";
- gdsc-mmagic-mdss-supply = <&gdsc_mmagic_mdss>;
- clocks = <&clock_mmss clk_smmu_rot_ahb_clk>,
- <&clock_mmss clk_mmagic_mdss_axi_clk>,
- <&clock_mmss clk_smmu_rot_axi_clk>;
- clock-names = "rot_ahb_clk", "mmagic_mdss_axi_clk",
- "rot_axi_clk";
- };
-
mdss_fb0: qcom,mdss_fb_primary {
cell-index = <0>;
compatible = "qcom,mdss-fb";
@@ -295,11 +265,6 @@
};
};
- mdss_fb1: qcom,mdss_fb_wfd {
- cell-index = <1>;
- compatible = "qcom,mdss-fb";
- };
-
mdss_fb2: qcom,mdss_fb_hdmi {
cell-index = <2>;
compatible = "qcom,mdss-fb";
@@ -492,7 +457,6 @@
compatible = "qcom,mdss_wb";
qcom,mdss_pan_res = <640 480>;
qcom,mdss_pan_bpp = <24>;
- qcom,mdss-fb-map = <&mdss_fb1>;
};
mdss_hdmi_tx: qcom,hdmi_tx@9a0000 {
@@ -530,11 +494,15 @@
};
mdss_rotator: qcom,mdss_rotator {
- compatible = "qcom,mdss_rotator";
- qcom,mdss-wb-count = <2>;
- qcom,mdss-has-downscale;
- qcom,mdss-has-ubwc;
- qcom,mdss-has-reg-bus;
+ compatible = "qcom,sde_rotator";
+ reg = <0x00900000 0x90000>,
+ <0x009b8000 0x1040>;
+ reg-names = "mdp_phys",
+ "rot_vbif_phys";
+ qcom,mdss-wb-count = <1>;
+ qcom,mdss-wb-id = <0>;
+ qcom,mdss-ctl-id = <4>;
+ qcom,mdss-highest-bank-bit = <0x2>;
/* Bus Scale Settings */
qcom,msm-bus,name = "mdss_rotator";
qcom,msm-bus,num-cases = <3>;
@@ -550,7 +518,42 @@
qcom,supply-names = "rot-mmagic-mdss-gdsc", "rot-vdd";
clocks = <&clock_mmss clk_mmss_misc_ahb_clk>,
- <&clock_mmss clk_mdss_rotator_vote_clk>;
- clock-names = "iface_clk", "rot_core_clk";
+ <&clock_mmss clk_mdss_rotator_vote_clk>,
+ <&clock_mmss clk_mdss_ahb_clk>,
+ <&clock_mmss clk_mdss_axi_clk>,
+ <&clock_mmss clk_mdp_clk_src>;
+ clock-names = "iface_clk", "rot_core_clk",
+ "mdss_ahb_clk", "mdss_axi_clk", "mdp_clk_src";
+
+ interrupt-parent = <&mdss_mdp>;
+ interrupts = <32 0>;
+
+ /* VBIF QoS remapper settings*/
+ qcom,mdss-rot-vbif-qos-setting = <1 1 1 1>;
+
+ qcom,mdss-default-ot-rd-limit = <32>;
+ qcom,mdss-default-ot-wr-limit = <16>;
+
+ smmu_rot_unsecure: qcom,smmu_rot_unsec_cb {
+ compatible = "qcom,smmu_sde_rot_unsec";
+ iommus = <&rot_smmu 0>;
+ gdsc-mdss-supply = <&gdsc_mmagic_mdss>;
+ clocks = <&clock_mmss clk_smmu_rot_ahb_clk>,
+ <&clock_mmss clk_mmagic_mdss_axi_clk>,
+ <&clock_mmss clk_smmu_rot_axi_clk>;
+ clock-names = "rot_ahb_clk", "mmagic_mdss_axi_clk",
+ "rot_axi_clk";
+ };
+
+ smmu_rot_secure: qcom,smmu_rot_sec_cb {
+ compatible = "qcom,smmu_sde_rot_sec";
+ iommus = <&rot_smmu 1>;
+ gdsc-mdss-supply = <&gdsc_mmagic_mdss>;
+ clocks = <&clock_mmss clk_smmu_rot_ahb_clk>,
+ <&clock_mmss clk_mmagic_mdss_axi_clk>,
+ <&clock_mmss clk_smmu_rot_axi_clk>;
+ clock-names = "rot_ahb_clk", "mmagic_mdss_axi_clk",
+ "rot_axi_clk";
+ };
};
};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi
index 7dc276bb5fdb..21dbb8143061 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi
@@ -614,6 +614,11 @@
qcom,cpr-enable;
qcom,cpr-hw-closed-loop;
+ qcom,cpr-panic-reg-addr-list =
+ <0x179cbaa4 0x17912c18>;
+ qcom,cpr-panic-reg-name-list =
+ "PWR_CPRH_STATUS", "APCLUS0_L2_SAW4_PMIC_STS";
+
thread@0 {
qcom,cpr-thread-id = <0>;
qcom,cpr-consecutive-up = <0>;
@@ -770,6 +775,11 @@
qcom,cpr-enable;
qcom,cpr-hw-closed-loop;
+ qcom,cpr-panic-reg-addr-list =
+ <0x179c7aa4 0x17812c18>;
+ qcom,cpr-panic-reg-name-list =
+ "PERF_CPRH_STATUS", "APCLUS1_L2_SAW4_PMIC_STS";
+
thread@0 {
qcom,cpr-thread-id = <0>;
qcom,cpr-consecutive-up = <0>;
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 9ab506ebff59..14bb5ac67588 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1574,6 +1574,119 @@ void __init early_paging_init(const struct machine_desc *mdesc)
#endif
+#ifdef CONFIG_FORCE_PAGES
+/*
+ * remap a PMD into pages
+ * We split a single pmd here none of this two pmd nonsense
+ */
+static noinline void __init split_pmd(pmd_t *pmd, unsigned long addr,
+ unsigned long end, unsigned long pfn,
+ const struct mem_type *type)
+{
+ pte_t *pte, *start_pte;
+ pmd_t *base_pmd;
+
+ base_pmd = pmd_offset(
+ pud_offset(pgd_offset(&init_mm, addr), addr), addr);
+
+ if (pmd_none(*base_pmd) || pmd_bad(*base_pmd)) {
+ start_pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
+#ifndef CONFIG_ARM_LPAE
+ /*
+ * Following is needed when new pte is allocated for pmd[1]
+ * cases, which may happen when base (start) address falls
+ * under pmd[1].
+ */
+ if (addr & SECTION_SIZE)
+ start_pte += pte_index(addr);
+#endif
+ } else {
+ start_pte = pte_offset_kernel(base_pmd, addr);
+ }
+
+ pte = start_pte;
+
+ do {
+ set_pte_ext(pte, pfn_pte(pfn, type->prot_pte), 0);
+ pfn++;
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+
+ *pmd = __pmd((__pa(start_pte) + PTE_HWTABLE_OFF) | type->prot_l1);
+ mb(); /* let pmd be programmed */
+ flush_pmd_entry(pmd);
+ flush_tlb_all();
+}
+
+/*
+ * It's significantly easier to remap as pages later after all memory is
+ * mapped. Everything is sections so all we have to do is split
+ */
+static void __init remap_pages(void)
+{
+ struct memblock_region *reg;
+
+ for_each_memblock(memory, reg) {
+ phys_addr_t phys_start = reg->base;
+ phys_addr_t phys_end = reg->base + reg->size;
+ unsigned long addr = (unsigned long)__va(phys_start);
+ unsigned long end = (unsigned long)__va(phys_end);
+ pmd_t *pmd = NULL;
+ unsigned long next;
+ unsigned long pfn = __phys_to_pfn(phys_start);
+ bool fixup = false;
+ unsigned long saved_start = addr;
+
+ if (phys_start > arm_lowmem_limit)
+ break;
+ if (phys_end > arm_lowmem_limit)
+ end = (unsigned long)__va(arm_lowmem_limit);
+ if (phys_start >= phys_end)
+ break;
+
+ pmd = pmd_offset(
+ pud_offset(pgd_offset(&init_mm, addr), addr), addr);
+
+#ifndef CONFIG_ARM_LPAE
+ if (addr & SECTION_SIZE) {
+ fixup = true;
+ pmd_empty_section_gap((addr - SECTION_SIZE) & PMD_MASK);
+ pmd++;
+ }
+
+ if (end & SECTION_SIZE)
+ pmd_empty_section_gap(end);
+#endif
+
+ do {
+ next = addr + SECTION_SIZE;
+
+ if (pmd_none(*pmd) || pmd_bad(*pmd))
+ split_pmd(pmd, addr, next, pfn,
+ &mem_types[MT_MEMORY_RWX]);
+ pmd++;
+ pfn += SECTION_SIZE >> PAGE_SHIFT;
+
+ } while (addr = next, addr < end);
+
+ if (fixup) {
+ /*
+ * Put a faulting page table here to avoid detecting no
+ * pmd when accessing an odd section boundary. This
+ * needs to be faulting to help catch errors and avoid
+ * speculation
+ */
+ pmd = pmd_off_k(saved_start);
+ pmd[0] = pmd[1] & ~1;
+ }
+ }
+}
+#else
+static void __init remap_pages(void)
+{
+
+}
+#endif
+
static void __init early_fixmap_shutdown(void)
{
int i;
@@ -1617,6 +1730,7 @@ void __init paging_init(const struct machine_desc *mdesc)
memblock_set_current_limit(arm_lowmem_limit);
dma_contiguous_remap();
early_fixmap_shutdown();
+ remap_pages();
devicemaps_init(mdesc);
kmap_init();
tcm_init();
diff --git a/arch/arm/mm/pageattr.c b/arch/arm/mm/pageattr.c
index cf30daff8932..ad5d4bfa5de6 100644
--- a/arch/arm/mm/pageattr.c
+++ b/arch/arm/mm/pageattr.c
@@ -49,11 +49,14 @@ static int change_memory_common(unsigned long addr, int numpages,
WARN_ON_ONCE(1);
}
- if (start < MODULES_VADDR || start >= MODULES_END)
- return -EINVAL;
+ if (!IS_ENABLED(CONFIG_FORCE_PAGES)) {
- if (end < MODULES_VADDR || start >= MODULES_END)
- return -EINVAL;
+ if (start < MODULES_VADDR || start >= MODULES_END)
+ return -EINVAL;
+
+ if (end < MODULES_VADDR || start >= MODULES_END)
+ return -EINVAL;
+ }
data.set_mask = set_mask;
data.clear_mask = clear_mask;
diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c
index e016acf4e12e..6586f5e0cf86 100644
--- a/drivers/char/diag/diag_mux.c
+++ b/drivers/char/diag/diag_mux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-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
@@ -23,11 +23,13 @@
#include <linux/spinlock.h>
#include <linux/ratelimit.h>
#include "diagchar.h"
+#include "diagfwd.h"
#include "diag_mux.h"
#include "diag_usb.h"
#include "diag_memorydevice.h"
-struct diag_logger_t *logger;
+
+struct diag_mux_state_t *diag_mux;
static struct diag_logger_t usb_logger;
static struct diag_logger_t md_logger;
@@ -49,11 +51,11 @@ static struct diag_logger_ops md_log_ops = {
int diag_mux_init()
{
- logger = kzalloc(NUM_MUX_PROC * sizeof(struct diag_logger_t),
+ diag_mux = kzalloc(sizeof(struct diag_mux_state_t),
GFP_KERNEL);
- if (!logger)
+ if (!diag_mux)
return -ENOMEM;
- kmemleak_not_leak(logger);
+ kmemleak_not_leak(diag_mux);
usb_logger.mode = DIAG_USB_MODE;
usb_logger.log_ops = &usb_log_ops;
@@ -66,13 +68,17 @@ int diag_mux_init()
* Set USB logging as the default logger. This is the mode
* Diag should be in when it initializes.
*/
- logger = &usb_logger;
+ diag_mux->usb_ptr = &usb_logger;
+ diag_mux->md_ptr = &md_logger;
+ diag_mux->logger = &usb_logger;
+ diag_mux->mux_mask = 0;
+ diag_mux->mode = DIAG_USB_MODE;
return 0;
}
void diag_mux_exit()
{
- kfree(logger);
+ kfree(diag_mux);
}
int diag_mux_register(int proc, int ctx, struct diag_mux_ops *ops)
@@ -106,19 +112,43 @@ int diag_mux_register(int proc, int ctx, struct diag_mux_ops *ops)
int diag_mux_queue_read(int proc)
{
+ struct diag_logger_t *logger = NULL;
+
if (proc < 0 || proc >= NUM_MUX_PROC)
return -EINVAL;
- if (!logger)
+ if (!diag_mux)
return -EIO;
- if (logger->log_ops && logger->log_ops->queue_read)
+
+ if (diag_mux->mode == DIAG_MULTI_MODE)
+ logger = diag_mux->usb_ptr;
+ else
+ logger = diag_mux->logger;
+
+ if (logger && logger->log_ops && logger->log_ops->queue_read)
return logger->log_ops->queue_read(proc);
+
return 0;
}
int diag_mux_write(int proc, unsigned char *buf, int len, int ctx)
{
+ struct diag_logger_t *logger = NULL;
+ int peripheral;
+
if (proc < 0 || proc >= NUM_MUX_PROC)
return -EINVAL;
+ if (!diag_mux)
+ return -EIO;
+
+ peripheral = GET_BUF_PERIPHERAL(ctx);
+ if (peripheral > NUM_PERIPHERALS)
+ return -EINVAL;
+
+ if (MD_PERIPHERAL_MASK(peripheral) & diag_mux->mux_mask)
+ logger = diag_mux->md_ptr;
+ else
+ logger = diag_mux->usb_ptr;
+
if (logger && logger->log_ops && logger->log_ops->write)
return logger->log_ops->write(proc, buf, len, ctx);
return 0;
@@ -126,38 +156,86 @@ int diag_mux_write(int proc, unsigned char *buf, int len, int ctx)
int diag_mux_close_peripheral(int proc, uint8_t peripheral)
{
+ struct diag_logger_t *logger = NULL;
if (proc < 0 || proc >= NUM_MUX_PROC)
return -EINVAL;
/* Peripheral should account for Apps data as well */
if (peripheral > NUM_PERIPHERALS)
return -EINVAL;
+ if (!diag_mux)
+ return -EIO;
+
+ if (MD_PERIPHERAL_MASK(peripheral) & diag_mux->mux_mask)
+ logger = diag_mux->md_ptr;
+ else
+ logger = diag_mux->logger;
+
if (logger && logger->log_ops && logger->log_ops->close_peripheral)
return logger->log_ops->close_peripheral(proc, peripheral);
return 0;
}
-int diag_mux_switch_logging(int new_mode)
+int diag_mux_switch_logging(int *req_mode, int *peripheral_mask)
{
- struct diag_logger_t *new_logger = NULL;
+ unsigned int new_mask = 0;
+
+ if (!req_mode)
+ return -EINVAL;
- switch (new_mode) {
+ if (*peripheral_mask <= 0 || *peripheral_mask > DIAG_CON_ALL) {
+ pr_err("diag: mask %d in %s\n", *peripheral_mask, __func__);
+ return -EINVAL;
+ }
+
+ switch (*req_mode) {
case DIAG_USB_MODE:
- new_logger = &usb_logger;
+ new_mask = ~(*peripheral_mask) & diag_mux->mux_mask;
+ if (new_mask != DIAG_CON_NONE)
+ *req_mode = DIAG_MULTI_MODE;
break;
case DIAG_MEMORY_DEVICE_MODE:
- new_logger = &md_logger;
+ new_mask = (*peripheral_mask) | diag_mux->mux_mask;
+ if (new_mask != DIAG_CON_ALL)
+ *req_mode = DIAG_MULTI_MODE;
break;
default:
- pr_err("diag: Invalid mode %d in %s\n", new_mode, __func__);
+ pr_err("diag: Invalid mode %d in %s\n", *req_mode, __func__);
return -EINVAL;
}
- if (logger) {
- logger->log_ops->close();
- logger = new_logger;
- logger->log_ops->open();
+ switch (diag_mux->mode) {
+ case DIAG_USB_MODE:
+ if (*req_mode == DIAG_MEMORY_DEVICE_MODE) {
+ diag_mux->usb_ptr->log_ops->close();
+ diag_mux->logger = diag_mux->md_ptr;
+ diag_mux->md_ptr->log_ops->open();
+ } else if (*req_mode == DIAG_MULTI_MODE) {
+ diag_mux->md_ptr->log_ops->open();
+ diag_mux->logger = NULL;
+ }
+ break;
+ case DIAG_MEMORY_DEVICE_MODE:
+ if (*req_mode == DIAG_USB_MODE) {
+ diag_mux->md_ptr->log_ops->close();
+ diag_mux->logger = diag_mux->usb_ptr;
+ diag_mux->usb_ptr->log_ops->open();
+ } else if (*req_mode == DIAG_MULTI_MODE) {
+ diag_mux->usb_ptr->log_ops->open();
+ diag_mux->logger = NULL;
+ }
+ break;
+ case DIAG_MULTI_MODE:
+ if (*req_mode == DIAG_USB_MODE) {
+ diag_mux->md_ptr->log_ops->close();
+ diag_mux->logger = diag_mux->usb_ptr;
+ } else if (*req_mode == DIAG_MEMORY_DEVICE_MODE) {
+ diag_mux->usb_ptr->log_ops->close();
+ diag_mux->logger = diag_mux->md_ptr;
+ }
+ break;
}
-
+ diag_mux->mode = *req_mode;
+ diag_mux->mux_mask = new_mask;
+ *peripheral_mask = new_mask;
return 0;
}
-
diff --git a/drivers/char/diag/diag_mux.h b/drivers/char/diag/diag_mux.h
index 97632d198494..e1fcebbe6fd1 100644
--- a/drivers/char/diag/diag_mux.h
+++ b/drivers/char/diag/diag_mux.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-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
@@ -13,6 +13,14 @@
#define DIAG_MUX_H
#include "diagchar.h"
+struct diag_mux_state_t {
+ struct diag_logger_t *logger;
+ struct diag_logger_t *usb_ptr;
+ struct diag_logger_t *md_ptr;
+ unsigned int mux_mask;
+ unsigned int mode;
+};
+
struct diag_mux_ops {
int (*open)(int id, int mode);
int (*close)(int id, int mode);
@@ -24,6 +32,7 @@ struct diag_mux_ops {
#define DIAG_USB_MODE 0
#define DIAG_MEMORY_DEVICE_MODE 1
#define DIAG_NO_LOGGING_MODE 2
+#define DIAG_MULTI_MODE 3
#define DIAG_MUX_LOCAL 0
#define DIAG_MUX_LOCAL_LAST 1
@@ -53,7 +62,7 @@ struct diag_logger_t {
struct diag_logger_ops *log_ops;
};
-extern struct diag_logger_t *logger;
+extern struct diag_mux_state_t *diag_mux;
int diag_mux_init(void);
void diag_mux_exit(void);
@@ -63,5 +72,5 @@ int diag_mux_write(int proc, unsigned char *buf, int len, int ctx);
int diag_mux_close_peripheral(int proc, uint8_t peripheral);
int diag_mux_open_all(struct diag_logger_t *logger);
int diag_mux_close_all(void);
-int diag_mux_switch_logging(int new_mode);
+int diag_mux_switch_logging(int *new_mode, int *peripheral_mask);
#endif
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index b021b99c6e9c..5d7b1e7fe757 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -59,11 +59,15 @@
#define DIAG_CTRL_MSG_F3_MASK 11
#define CONTROL_CHAR 0x7E
-#define DIAG_CON_APSS (0x0001) /* Bit mask for APSS */
-#define DIAG_CON_MPSS (0x0002) /* Bit mask for MPSS */
-#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */
-#define DIAG_CON_WCNSS (0x0008) /* Bit mask for WCNSS */
-#define DIAG_CON_SENSORS (0x0010) /* Bit mask for Sensors */
+#define DIAG_CON_APSS (0x0001) /* Bit mask for APSS */
+#define DIAG_CON_MPSS (0x0002) /* Bit mask for MPSS */
+#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */
+#define DIAG_CON_WCNSS (0x0008) /* Bit mask for WCNSS */
+#define DIAG_CON_SENSORS (0x0010) /* Bit mask for Sensors */
+#define DIAG_CON_NONE (0x0000) /* Bit mask for No SS*/
+#define DIAG_CON_ALL (DIAG_CON_APSS | DIAG_CON_MPSS \
+ | DIAG_CON_LPASS | DIAG_CON_WCNSS \
+ | DIAG_CON_SENSORS)
#define DIAG_STM_MODEM 0x01
#define DIAG_STM_LPASS 0x02
@@ -158,8 +162,7 @@
#define FEATURE_MASK_LEN 2
#define DIAG_MD_NONE 0
-#define DIAG_MD_NORMAL 1
-#define DIAG_MD_PERIPHERAL 2
+#define DIAG_MD_PERIPHERAL 1
/*
* The status bit masks when received in a signal handler are to be
@@ -561,6 +564,7 @@ struct diagchar_dev {
uint32_t dci_pkt_length;
int in_busy_dcipktdata;
int logging_mode;
+ int logging_mask;
int mask_check;
uint32_t md_session_mask;
uint8_t md_session_mode;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index edc104acb777..ecdbf9f9480e 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -369,6 +369,24 @@ fail:
return -ENOMEM;
}
+static uint32_t diag_translate_kernel_to_user_mask(uint32_t peripheral_mask)
+{
+ uint32_t ret = 0;
+
+ if (peripheral_mask & MD_PERIPHERAL_MASK(APPS_DATA))
+ ret |= DIAG_CON_APSS;
+ if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_MODEM))
+ ret |= DIAG_CON_MPSS;
+ if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_LPASS))
+ ret |= DIAG_CON_LPASS;
+ if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_WCNSS))
+ ret |= DIAG_CON_WCNSS;
+ if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_SENSORS))
+ ret |= DIAG_CON_SENSORS;
+
+ return ret;
+}
+
static void diag_close_logging_process(const int pid)
{
int i;
@@ -388,7 +406,8 @@ static void diag_close_logging_process(const int pid)
params.req_mode = USB_MODE;
params.mode_param = 0;
- params.peripheral_mask = 0;
+ params.peripheral_mask =
+ diag_translate_kernel_to_user_mask(session_peripheral_mask);
mutex_lock(&driver->diagchar_mutex);
diag_switch_logging(&params);
mutex_unlock(&driver->diagchar_mutex);
@@ -417,10 +436,11 @@ static int diag_remove_client_entry(struct file *file)
diagpriv_data = file->private_data;
- /* clean up any DCI registrations, if this is a DCI client
- * This will specially help in case of ungraceful exit of any DCI client
- * This call will remove any pending registrations of such client
- */
+ /*
+ * clean up any DCI registrations, if this is a DCI client
+ * This will specially help in case of ungraceful exit of any DCI client
+ * This call will remove any pending registrations of such client
+ */
mutex_lock(&driver->dci_mutex);
dci_entry = dci_lookup_client_entry_pid(current->tgid);
if (dci_entry)
@@ -1148,19 +1168,10 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc)
struct diag_md_session_t *new_session = NULL;
/*
- * If there is any session running in Normal mode
- * we cannot start a new session . If there is a
- * session running in Peripheral mode we cannot
- * start a new session in NORMAL mode. If a session is
- * running with a peripheral mask and a new session
- * request comes in with same peripheral mask value
- * then return invalid param
+ * If a session is running with a peripheral mask and a new session
+ * request comes in with same peripheral mask value then return
+ * invalid param
*/
- if (driver->md_session_mode == DIAG_MD_NORMAL)
- return -EINVAL;
- if (driver->md_session_mode == DIAG_MD_PERIPHERAL
- && mode == DIAG_MD_NORMAL)
- return -EINVAL;
if (driver->md_session_mode == DIAG_MD_PERIPHERAL &&
(driver->md_session_mask & peripheral_mask) != 0)
return -EINVAL;
@@ -1176,32 +1187,6 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc)
new_session->pid = current->tgid;
new_session->task = current;
- if (mode == DIAG_MD_NORMAL) {
- new_session->log_mask = &log_mask;
- new_session->event_mask = &event_mask;
- new_session->msg_mask = &msg_mask;
- for (i = 0; i < NUM_MD_SESSIONS; i++) {
- if (driver->md_session_map[i] != NULL) {
- DIAG_LOG(DIAG_DEBUG_USERSPACE,
- "another instance present for %d\n",
- i);
- err = -EEXIST;
- goto fail_normal;
- }
- new_session->peripheral_mask |= MD_PERIPHERAL_MASK(i);
- driver->md_session_mask |= MD_PERIPHERAL_MASK(i);
- driver->md_session_map[i] = new_session;
- }
- driver->md_session_mode = DIAG_MD_NORMAL;
- setup_timer(&new_session->hdlc_reset_timer,
- diag_md_hdlc_reset_timer_func,
- new_session->pid);
- DIAG_LOG(DIAG_DEBUG_USERSPACE,
- "created session in normal mode\n");
- mutex_unlock(&driver->md_session_lock);
- return 0;
- }
-
new_session->log_mask = kzalloc(sizeof(struct diag_mask_info),
GFP_KERNEL);
if (!new_session->log_mask) {
@@ -1251,10 +1236,11 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc)
new_session->peripheral_mask |= MD_PERIPHERAL_MASK(i);
driver->md_session_map[i] = new_session;
driver->md_session_mask |= MD_PERIPHERAL_MASK(i);
- setup_timer(&new_session->hdlc_reset_timer,
- diag_md_hdlc_reset_timer_func,
- new_session->pid);
}
+ setup_timer(&new_session->hdlc_reset_timer,
+ diag_md_hdlc_reset_timer_func,
+ new_session->pid);
+
driver->md_session_mode = DIAG_MD_PERIPHERAL;
mutex_unlock(&driver->md_session_lock);
DIAG_LOG(DIAG_DEBUG_USERSPACE,
@@ -1271,7 +1257,6 @@ fail_peripheral:
diag_msg_mask_free(new_session->msg_mask);
kfree(new_session->msg_mask);
new_session->msg_mask = NULL;
-fail_normal:
kfree(new_session);
new_session = NULL;
mutex_unlock(&driver->md_session_lock);
@@ -1292,19 +1277,17 @@ static void diag_md_session_close(struct diag_md_session_t *session_info)
continue;
driver->md_session_map[i] = NULL;
driver->md_session_mask &= ~session_info->peripheral_mask;
- if (driver->md_session_mode == DIAG_MD_NORMAL)
- continue;
- diag_log_mask_free(session_info->log_mask);
- kfree(session_info->log_mask);
- session_info->log_mask = NULL;
- diag_msg_mask_free(session_info->msg_mask);
- kfree(session_info->msg_mask);
- session_info->msg_mask = NULL;
- diag_event_mask_free(session_info->event_mask);
- kfree(session_info->event_mask);
- session_info->event_mask = NULL;
- del_timer(&session_info->hdlc_reset_timer);
}
+ diag_log_mask_free(session_info->log_mask);
+ kfree(session_info->log_mask);
+ session_info->log_mask = NULL;
+ diag_msg_mask_free(session_info->msg_mask);
+ kfree(session_info->msg_mask);
+ session_info->msg_mask = NULL;
+ diag_event_mask_free(session_info->event_mask);
+ kfree(session_info->event_mask);
+ session_info->event_mask = NULL;
+ del_timer(&session_info->hdlc_reset_timer);
for (i = 0; i < NUM_MD_SESSIONS && !found; i++) {
if (driver->md_session_map[i] != NULL)
@@ -1337,113 +1320,157 @@ struct diag_md_session_t *diag_md_session_get_peripheral(uint8_t peripheral)
return driver->md_session_map[peripheral];
}
+static int diag_md_peripheral_switch(struct diag_md_session_t *session_info,
+ int peripheral_mask, int req_mode) {
+ int i, bit = 0;
+
+ if (!session_info)
+ return -EINVAL;
+ if (req_mode != DIAG_USB_MODE || req_mode != DIAG_MEMORY_DEVICE_MODE)
+ return -EINVAL;
+
+ /*
+ * check that md_session_map for i == session_info,
+ * if not then race condition occurred and bail
+ */
+ mutex_lock(&driver->md_session_lock);
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ bit = MD_PERIPHERAL_MASK(i) & peripheral_mask;
+ if (!bit)
+ continue;
+ if (req_mode == DIAG_USB_MODE) {
+ if (driver->md_session_map[i] != session_info) {
+ mutex_unlock(&driver->md_session_lock);
+ return -EINVAL;
+ }
+ driver->md_session_map[i] = NULL;
+ driver->md_session_mask &= ~bit;
+ session_info->peripheral_mask &= ~bit;
+
+ } else {
+ if (driver->md_session_map[i] != NULL) {
+ mutex_unlock(&driver->md_session_lock);
+ return -EINVAL;
+ }
+ driver->md_session_map[i] = session_info;
+ driver->md_session_mask |= bit;
+ session_info->peripheral_mask |= bit;
+
+ }
+ }
+
+ driver->md_session_mode = DIAG_MD_PERIPHERAL;
+ mutex_unlock(&driver->md_session_lock);
+ DIAG_LOG(DIAG_DEBUG_USERSPACE, "Changed Peripherals:0x%x to mode:%d\n",
+ peripheral_mask, req_mode);
+}
+
static int diag_md_session_check(int curr_mode, int req_mode,
const struct diag_logging_mode_param_t *param,
uint8_t *change_mode)
{
- int err = 0;
+ int i, bit = 0, err = 0;
+ int change_mask = 0;
struct diag_md_session_t *session_info = NULL;
if (!param || !change_mode)
return -EIO;
- *change_mode = 1;
+ *change_mode = 0;
switch (curr_mode) {
case DIAG_USB_MODE:
case DIAG_MEMORY_DEVICE_MODE:
+ case DIAG_MULTI_MODE:
break;
default:
return -EINVAL;
}
- switch (req_mode) {
- case DIAG_USB_MODE:
- case DIAG_MEMORY_DEVICE_MODE:
- break;
- default:
+ if (req_mode != DIAG_USB_MODE && req_mode != DIAG_MEMORY_DEVICE_MODE)
return -EINVAL;
- }
- if (curr_mode == DIAG_USB_MODE) {
- if (req_mode == DIAG_USB_MODE) {
- /*
- * This case tries to change from USB mode to USB mode.
- * There is no change required. Return success.
- */
- *change_mode = 0;
+ if (req_mode == DIAG_USB_MODE) {
+ if (curr_mode == DIAG_USB_MODE)
+ return 0;
+ if (driver->md_session_mode == DIAG_MD_NONE
+ && driver->md_session_mask == 0 && driver->logging_mask) {
+ *change_mode = 1;
return 0;
}
/*
- * If there is no other mdlog process, return success.
- * Check if the peripheral interested in is active.
+ * curr_mode is either DIAG_MULTI_MODE or DIAG_MD_MODE
+ * Check if requested peripherals are already in usb mode
*/
- if (param->mode_param == DIAG_MD_NORMAL) {
- err = diag_md_session_create(DIAG_MD_NORMAL, 0,
- DIAG_LOCAL_PROC);
- return err;
- } else if (param->mode_param == DIAG_MD_PERIPHERAL &&
- (!(driver->md_session_mask &
- param->peripheral_mask))) {
- err = diag_md_session_create(DIAG_MD_PERIPHERAL,
- param->peripheral_mask,
- DIAG_LOCAL_PROC);
- return err;
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ bit = MD_PERIPHERAL_MASK(i) & param->peripheral_mask;
+ if (!bit)
+ continue;
+ if (bit & driver->logging_mask)
+ change_mask |= bit;
}
- DIAG_LOG(DIAG_DEBUG_USERSPACE,
- "an instance of mdlog is active\n");
- *change_mode = 0;
- return -EINVAL;
- } else if (curr_mode == DIAG_MEMORY_DEVICE_MODE) {
- if (req_mode == DIAG_USB_MODE) {
- if (driver->md_session_mask != 0 &&
- driver->md_session_mode == DIAG_MD_PERIPHERAL) {
- /*
- * An instance of mdlog is still running, Return
- * error.
- */
- DIAG_LOG(DIAG_DEBUG_USERSPACE,
- "another instance running\n");
- *change_mode = 0;
- return -EINVAL;
- }
- session_info = diag_md_session_get_pid(current->tgid);
- diag_md_session_close(session_info);
+ if (!change_mask)
return 0;
- }
- if (param->mode_param == DIAG_MD_NORMAL) {
- /*
- * The new client is asking for MD_NORMAL. We're
- * already in memory device mode - this must be
- * set by another active process. Return error
- * for this new client.
- */
+ /*
+ * Change is needed. Check if this md_session has set all the
+ * requested peripherals. If another md session set a requested
+ * peripheral then we cannot switch that peripheral to USB.
+ * If this session owns all the requested peripherals, then
+ * call function to switch the modes/masks for the md_session
+ */
+ session_info = diag_md_session_get_pid(current->tgid);
+ if (!session_info) {
+ *change_mode = 1;
+ return 0;
+ }
+ if ((change_mask & session_info->peripheral_mask)
+ != change_mask) {
DIAG_LOG(DIAG_DEBUG_USERSPACE,
- "unable to switch logging mode\n");
- *change_mode = 0;
+ "Another MD Session owns a requested peripheral\n");
return -EINVAL;
- } else if (param->mode_param == DIAG_MD_PERIPHERAL) {
- if (driver->md_session_mask & param->peripheral_mask) {
- /*
- * The new client is asking for a
- * specific peripheral. This case checks
- * if a client is exercising this
- * peripheral already. Return error
- * if the peripheral is already in use.
- */
+ }
+ *change_mode = 1;
+
+ /* If all peripherals are being set to USB Mode, call close */
+ if (~change_mask & session_info->peripheral_mask) {
+ err = diag_md_peripheral_switch(session_info,
+ change_mask, DIAG_USB_MODE);
+ } else
+ diag_md_session_close(session_info);
+
+ return err;
+
+ } else if (req_mode == DIAG_MEMORY_DEVICE_MODE) {
+ /*
+ * Get bit mask that represents what peripherals already have
+ * been set. Check that requested peripherals already set are
+ * owned by this md session
+ */
+ change_mask = driver->md_session_mask & param->peripheral_mask;
+ session_info = diag_md_session_get_pid(current->tgid);
+
+ if (session_info) {
+ if ((session_info->peripheral_mask & change_mask)
+ != change_mask) {
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "Another MD Session owns a requested peripheral\n");
+ return -EINVAL;
+ }
+ err = diag_md_peripheral_switch(session_info,
+ change_mask, DIAG_USB_MODE);
+ } else {
+ if (change_mask) {
DIAG_LOG(DIAG_DEBUG_USERSPACE,
- "another instance running\n");
- *change_mode = 0;
+ "Another MD Session owns a requested peripheral\n");
return -EINVAL;
}
err = diag_md_session_create(DIAG_MD_PERIPHERAL,
- param->peripheral_mask,
- DIAG_LOCAL_PROC);
- *change_mode = 0;
- return err;
+ param->peripheral_mask, DIAG_LOCAL_PROC);
}
+ *change_mode = 1;
+ return err;
}
return -EINVAL;
}
@@ -1477,17 +1504,14 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param)
if (!param)
return -EINVAL;
- if (param->mode_param == DIAG_MD_PERIPHERAL &&
- param->peripheral_mask == 0) {
+ if (!param->peripheral_mask) {
DIAG_LOG(DIAG_DEBUG_USERSPACE,
- "asking for peripehral mode with no mask being set\n");
+ "asking for mode switch with no peripheral mask set\n");
return -EINVAL;
}
- if (param->mode_param == DIAG_MD_PERIPHERAL) {
- peripheral_mask = diag_translate_mask(param->peripheral_mask);
- param->peripheral_mask = peripheral_mask;
- }
+ peripheral_mask = diag_translate_mask(param->peripheral_mask);
+ param->peripheral_mask = peripheral_mask;
switch (param->req_mode) {
case CALLBACK_MODE:
@@ -1507,8 +1531,8 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param)
curr_mode = driver->logging_mode;
DIAG_LOG(DIAG_DEBUG_USERSPACE,
- "request to switch logging from: %d to %d\n",
- curr_mode, new_mode);
+ "request to switch logging from %d mask:%0x to %d mask:%0x\n",
+ curr_mode, driver->md_session_mask, new_mode, peripheral_mask);
err = diag_md_session_check(curr_mode, new_mode, param, &do_switch);
if (err) {
@@ -1525,7 +1549,7 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param)
}
diag_ws_reset(DIAG_WS_MUX);
- err = diag_mux_switch_logging(new_mode);
+ err = diag_mux_switch_logging(&new_mode, &peripheral_mask);
if (err) {
pr_err("diag: In %s, unable to switch mode from %d to %d, err: %d\n",
__func__, curr_mode, new_mode, err);
@@ -1533,7 +1557,11 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param)
goto fail;
}
driver->logging_mode = new_mode;
+ driver->logging_mask = peripheral_mask;
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "Switch logging to %d mask:%0x\n", new_mode, peripheral_mask);
+ /* Update to take peripheral_mask */
if (new_mode != DIAG_MEMORY_DEVICE_MODE) {
diag_update_real_time_vote(DIAG_PROC_MEMORY_DEVICE,
MODE_REALTIME, ALL_PROC);
@@ -1839,10 +1867,8 @@ static int diag_ioctl_register_callback(unsigned long ioarg)
return -EINVAL;
}
- if (driver->md_session_mode == DIAG_MD_NORMAL ||
- driver->md_session_mode == DIAG_MD_PERIPHERAL) {
+ if (driver->md_session_mode == DIAG_MD_PERIPHERAL)
return -EIO;
- }
return err;
}
@@ -2737,7 +2763,8 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count,
mutex_lock(&driver->diagchar_mutex);
if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) &&
- (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE)) {
+ (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
+ driver->logging_mode == DIAG_MULTI_MODE)) {
pr_debug("diag: process woken up\n");
/*Copy the type of data being passed*/
data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index aa394f517163..aec4f965b13e 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -234,7 +234,7 @@ void chk_logging_wakeup(void)
* index as all the indices point to the same session
* structure.
*/
- if (driver->md_session_mode == DIAG_MD_NORMAL && j == 0)
+ if ((driver->md_session_mask == DIAG_CON_ALL) && (j == 0))
break;
}
}
@@ -278,7 +278,8 @@ static void pack_rsp_and_send(unsigned char *buf, int len)
* for responses. Make sure we don't miss previous wakeups for
* draining responses when we are in Memory Device Mode.
*/
- if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE)
+ if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
+ driver->logging_mode == DIAG_MULTI_MODE)
chk_logging_wakeup();
}
if (driver->rsp_buf_busy) {
@@ -346,7 +347,8 @@ static void encode_rsp_and_send(unsigned char *buf, int len)
* for responses. Make sure we don't miss previous wakeups for
* draining responses when we are in Memory Device Mode.
*/
- if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE)
+ if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
+ driver->logging_mode == DIAG_MULTI_MODE)
chk_logging_wakeup();
}
@@ -919,8 +921,13 @@ int diag_process_apps_pkt(unsigned char *buf, int len,
if (MD_PERIPHERAL_MASK(reg_item->proc) &
info->peripheral_mask)
write_len = diag_send_data(reg_item, buf, len);
- } else
- write_len = diag_send_data(reg_item, buf, len);
+ } else {
+ if (MD_PERIPHERAL_MASK(reg_item->proc) &
+ driver->logging_mask)
+ diag_send_error_rsp(buf, len);
+ else
+ write_len = diag_send_data(reg_item, buf, len);
+ }
mutex_unlock(&driver->cmd_reg_mutex);
return write_len;
}
@@ -1228,10 +1235,9 @@ static int diagfwd_mux_close(int id, int mode)
return -EINVAL;
}
- if ((mode == DIAG_USB_MODE &&
- driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) ||
- (mode == DIAG_MEMORY_DEVICE_MODE &&
- driver->logging_mode == DIAG_USB_MODE)) {
+ if ((driver->logging_mode == DIAG_MULTI_MODE &&
+ driver->md_session_mode == DIAG_MD_NONE) ||
+ (driver->md_session_mode == DIAG_MD_PERIPHERAL)) {
/*
* In this case the channel must not be closed. This case
* indicates that the USB is removed but there is a client
diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c
index 9e9368b197d8..598e52b54c99 100644
--- a/drivers/clk/msm/clock-osm.c
+++ b/drivers/clk/msm/clock-osm.c
@@ -105,6 +105,9 @@ enum clk_osm_trace_packet_id {
#define OSM_CORE_TABLE_SIZE 8192
#define OSM_REG_SIZE 32
+#define WDOG_DOMAIN_PSTATE_STATUS 0x1c00
+#define WDOG_PROGRAM_COUNTER 0x1c74
+
#define OSM_CYCLE_COUNTER_USE_XO_EDGE_EN BIT(8)
#define PLL_MODE 0x0
#define PLL_L_VAL 0x4
@@ -323,6 +326,7 @@ struct clk_osm {
enum clk_osm_trace_method trace_method;
enum clk_osm_trace_packet_id trace_id;
+ struct notifier_block panic_notifier;
u32 trace_periodic_timer;
bool trace_en;
};
@@ -2248,6 +2252,45 @@ exit:
debugfs_remove_recursive(c->debugfs);
}
+static int clk_osm_panic_callback(struct notifier_block *nfb,
+ unsigned long event,
+ void *data)
+{
+ void __iomem *virt_addr;
+ u32 value, reg;
+ struct clk_osm *c = container_of(nfb,
+ struct clk_osm,
+ panic_notifier);
+
+ reg = c->pbases[OSM_BASE] + WDOG_DOMAIN_PSTATE_STATUS;
+ virt_addr = ioremap(reg, 0x4);
+ if (virt_addr != NULL) {
+ value = readl_relaxed(virt_addr);
+ pr_err("DOM%d_PSTATE_STATUS[0x%08x]=0x%08x\n", c->cluster_num,
+ reg, value);
+ iounmap(virt_addr);
+ }
+
+ reg = c->pbases[OSM_BASE] + WDOG_PROGRAM_COUNTER;
+ virt_addr = ioremap(reg, 0x4);
+ if (virt_addr != NULL) {
+ value = readl_relaxed(virt_addr);
+ pr_err("DOM%d_PROGRAM_COUNTER[0x%08x]=0x%08x\n", c->cluster_num,
+ reg, value);
+ iounmap(virt_addr);
+ }
+
+ virt_addr = ioremap(c->apm_ctrl_status, 0x4);
+ if (virt_addr != NULL) {
+ value = readl_relaxed(virt_addr);
+ pr_err("APM_CTLER_STATUS_%d[0x%08x]=0x%08x\n", c->cluster_num,
+ c->apm_ctrl_status, value);
+ iounmap(virt_addr);
+ }
+
+ return NOTIFY_OK;
+}
+
static unsigned long init_rate = 300000000;
static unsigned long osm_clk_init_rate = 200000000;
@@ -2393,6 +2436,13 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
spin_lock_init(&pwrcl_clk.lock);
spin_lock_init(&perfcl_clk.lock);
+ pwrcl_clk.panic_notifier.notifier_call = clk_osm_panic_callback;
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &pwrcl_clk.panic_notifier);
+ perfcl_clk.panic_notifier.notifier_call = clk_osm_panic_callback;
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &perfcl_clk.panic_notifier);
+
rc = of_msm_clock_register(pdev->dev.of_node, cpu_clocks_osm,
ARRAY_SIZE(cpu_clocks_osm));
if (rc) {
diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c
index 9f5c67bc2d6f..c13e811a5d71 100644
--- a/drivers/regulator/cpr3-regulator.c
+++ b/drivers/regulator/cpr3-regulator.c
@@ -5881,6 +5881,42 @@ static int cpr3_regulator_validate_controller(struct cpr3_controller *ctrl)
}
/**
+ * cpr3_panic_callback() - panic notification callback function. This function
+ * is invoked when a kernel panic occurs.
+ * @nfb: Notifier block pointer of CPR3 controller
+ * @event: Value passed unmodified to notifier function
+ * @data: Pointer passed unmodified to notifier function
+ *
+ * Return: NOTIFY_OK
+ */
+static int cpr3_panic_callback(struct notifier_block *nfb,
+ unsigned long event, void *data)
+{
+ struct cpr3_controller *ctrl = container_of(nfb,
+ struct cpr3_controller, panic_notifier);
+ struct cpr3_panic_regs_info *regs_info = ctrl->panic_regs_info;
+ struct cpr3_reg_info *reg;
+ void __iomem *virt_addr;
+ int i = 0;
+
+ for (i = 0; i < regs_info->reg_count; i++) {
+ reg = &(regs_info->regs[i]);
+ virt_addr = ioremap(reg->addr, 0x4);
+ reg->value = readl_relaxed(virt_addr);
+ iounmap(virt_addr);
+ pr_err("%s[0x%08x] = 0x%08x\n", reg->name, reg->addr,
+ reg->value);
+ }
+ /*
+ * Barrier to ensure that the information has been updated in the
+ * structure.
+ */
+ mb();
+
+ return NOTIFY_OK;
+}
+
+/**
* cpr3_regulator_register() - register the regulators for a CPR3 controller and
* perform CPR hardware initialization
* @pdev: Platform device pointer for the CPR3 controller
@@ -6031,6 +6067,13 @@ int cpr3_regulator_register(struct platform_device *pdev,
list_add(&ctrl->list, &cpr3_controller_list);
mutex_unlock(&cpr3_controller_list_mutex);
+ if (ctrl->panic_regs_info) {
+ /* Register panic notification call back */
+ ctrl->panic_notifier.notifier_call = cpr3_panic_callback;
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &ctrl->panic_notifier);
+ }
+
return 0;
free_regulators:
@@ -6082,5 +6125,9 @@ int cpr3_regulator_unregister(struct cpr3_controller *ctrl)
for (j = 0; j < ctrl->thread[i].vreg_count; j++)
regulator_unregister(ctrl->thread[i].vreg[j].rdev);
+ if (ctrl->panic_notifier.notifier_call)
+ atomic_notifier_chain_unregister(&panic_notifier_list,
+ &ctrl->panic_notifier);
+
return 0;
}
diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h
index 0c4b6cb66805..d750b70519d1 100644
--- a/drivers/regulator/cpr3-regulator.h
+++ b/drivers/regulator/cpr3-regulator.h
@@ -494,6 +494,35 @@ struct cpr3_aging_sensor_info {
};
/**
+ * struct cpr3_reg_info - Register information data structure
+ * @name: Register name
+ * @addr: Register physical address
+ * @value: Register content
+ *
+ * This data structure is used to dump some critical register contents
+ * when the device crashes due to a kernel panic.
+ */
+struct cpr3_reg_info {
+ const char *name;
+ u32 addr;
+ u32 value;
+};
+
+/**
+ * struct cpr3_panic_regs_info - Data structure to dump critical register
+ * contents.
+ * @reg_count: Number of elements in the regs array
+ * @regs: Array of critical registers information
+ *
+ * This data structure is used to dump critical register contents when
+ * the device crashes due to a kernel panic.
+ */
+struct cpr3_panic_regs_info {
+ int reg_count;
+ struct cpr3_reg_info *regs;
+};
+
+/**
* struct cpr3_controller - CPR3 controller data structure
* @dev: Device pointer for the CPR3 controller device
* @name: Unique name for the CPR3 controller
@@ -662,6 +691,9 @@ struct cpr3_aging_sensor_info {
* VDD supply voltage to settle after being increased or
* decreased by step_volt microvolts which is used when
* SDELTA voltage margin adjustments are applied.
+ * @panic_regs_info: Array of panic registers information which provides the
+ * list of registers to dump when the device crashes.
+ * @panic_notifier: Notifier block registered to global panic notifier list.
*
* This structure contains both configuration and runtime state data. The
* elements cpr_allowed_sw, use_hw_closed_loop, aggr_corner, cpr_enabled,
@@ -755,6 +787,8 @@ struct cpr3_controller {
u32 temp_sensor_id_start;
u32 temp_sensor_id_end;
u32 voltage_settling_time;
+ struct cpr3_panic_regs_info *panic_regs_info;
+ struct notifier_block panic_notifier;
};
/* Used for rounding voltages to the closest physically available set point. */
diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c
index 164579344c81..34b51ec8cab8 100644
--- a/drivers/regulator/cpr3-util.c
+++ b/drivers/regulator/cpr3-util.c
@@ -1020,6 +1020,74 @@ static int cpr3_parse_irq_affinity(struct cpr3_controller *ctrl)
return 0;
}
+static int cpr3_panic_notifier_init(struct cpr3_controller *ctrl)
+{
+ struct device_node *node = ctrl->dev->of_node;
+ struct cpr3_panic_regs_info *panic_regs_info;
+ struct cpr3_reg_info *regs;
+ int i, reg_count, len, rc = 0;
+
+ if (!of_find_property(node, "qcom,cpr-panic-reg-addr-list", &len)) {
+ /* panic register address list not specified */
+ return rc;
+ }
+
+ reg_count = len / sizeof(u32);
+ if (!reg_count) {
+ cpr3_err(ctrl, "qcom,cpr-panic-reg-addr-list has invalid len = %d\n",
+ len);
+ return -EINVAL;
+ }
+
+ if (!of_find_property(node, "qcom,cpr-panic-reg-name-list", NULL)) {
+ cpr3_err(ctrl, "property qcom,cpr-panic-reg-name-list not specified\n");
+ return -EINVAL;
+ }
+
+ len = of_property_count_strings(node, "qcom,cpr-panic-reg-name-list");
+ if (reg_count != len) {
+ cpr3_err(ctrl, "qcom,cpr-panic-reg-name-list should have %d strings\n",
+ reg_count);
+ return -EINVAL;
+ }
+
+ panic_regs_info = devm_kzalloc(ctrl->dev, sizeof(*panic_regs_info),
+ GFP_KERNEL);
+ if (!panic_regs_info)
+ return -ENOMEM;
+
+ regs = devm_kcalloc(ctrl->dev, reg_count, sizeof(*regs), GFP_KERNEL);
+ if (!regs)
+ return -ENOMEM;
+
+ for (i = 0; i < reg_count; i++) {
+ rc = of_property_read_string_index(node,
+ "qcom,cpr-panic-reg-name-list", i,
+ &(regs[i].name));
+ if (rc) {
+ cpr3_err(ctrl, "error reading property qcom,cpr-panic-reg-name-list, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32_index(node,
+ "qcom,cpr-panic-reg-addr-list", i,
+ &(regs[i].addr));
+ if (rc) {
+ cpr3_err(ctrl, "error reading property qcom,cpr-panic-reg-addr-list, rc=%d\n",
+ rc);
+ return rc;
+ }
+ regs[i].value = 0xFFFFFFFF;
+ }
+
+ panic_regs_info->reg_count = reg_count;
+ panic_regs_info->regs = regs;
+ ctrl->panic_regs_info = panic_regs_info;
+
+ return rc;
+}
+
/**
* cpr3_parse_common_ctrl_data() - parse common CPR3 controller properties from
* device tree
@@ -1106,6 +1174,10 @@ int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl)
}
}
+ rc = cpr3_panic_notifier_init(ctrl);
+ if (rc)
+ return rc;
+
/*
* Regulator device handles are not necessary for CPRh controllers
* since communication with the regulators is completely managed
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index 0f2f9bd91e02..f3b4b6c08571 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -1433,6 +1433,41 @@ static const struct file_operations ufsdbg_reset_controller = {
.write = ufsdbg_reset_controller_write,
};
+static int ufsdbg_clear_err_state(void *data, u64 val)
+{
+ struct ufs_hba *hba = data;
+
+ if (!hba)
+ return -EINVAL;
+
+ /* clear the error state on any write attempt */
+ hba->debugfs_files.err_occurred = false;
+
+ return 0;
+}
+
+static int ufsdbg_read_err_state(void *data, u64 *val)
+{
+ struct ufs_hba *hba = data;
+
+ if (!hba)
+ return -EINVAL;
+
+ *val = hba->debugfs_files.err_occurred ? 1 : 0;
+
+ return 0;
+}
+
+void ufsdbg_set_err_state(struct ufs_hba *hba)
+{
+ hba->debugfs_files.err_occurred = true;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(ufsdbg_err_state,
+ ufsdbg_read_err_state,
+ ufsdbg_clear_err_state,
+ "%llu\n");
+
void ufsdbg_add_debugfs(struct ufs_hba *hba)
{
char root_name[sizeof("ufshcd00")];
@@ -1594,6 +1629,16 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba)
goto err;
}
+ hba->debugfs_files.err_state =
+ debugfs_create_file("err_state", S_IRUSR | S_IWUSR,
+ hba->debugfs_files.debugfs_root, hba,
+ &ufsdbg_err_state);
+ if (!hba->debugfs_files.err_state) {
+ dev_err(hba->dev,
+ "%s: failed create err_state debugfs entry", __func__);
+ goto err;
+ }
+
ufsdbg_setup_fault_injection(hba);
ufshcd_vops_add_debugfs(hba, hba->debugfs_files.debugfs_root);
diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index bf4d51ac8935..13848e8b72e0 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -37,6 +37,7 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba);
void ufsdbg_remove_debugfs(struct ufs_hba *hba);
void ufsdbg_pr_buf_to_std(struct ufs_hba *hba, int offset, int num_regs,
char *str, void *priv);
+void ufsdbg_set_err_state(struct ufs_hba *hba);
#else
static inline void ufsdbg_add_debugfs(struct ufs_hba *hba)
{
@@ -48,6 +49,9 @@ static inline void ufsdbg_pr_buf_to_std(struct ufs_hba *hba, int offset,
int num_regs, char *str, void *priv)
{
}
+void ufsdbg_set_err_state(struct ufs_hba *hba)
+{
+}
#endif
#ifdef CONFIG_UFS_FAULT_INJECTION
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 40dcaa8f0eee..ad679e5d3f76 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -71,6 +71,7 @@ static int ufshcd_tag_req_type(struct request *rq)
static void ufshcd_update_error_stats(struct ufs_hba *hba, int type)
{
+ ufsdbg_set_err_state(hba);
if (type < UFS_ERR_MAX)
hba->ufs_stats.err_stats[type]++;
}
@@ -2143,6 +2144,9 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
else
ret = -ETIMEDOUT;
+ if (ret)
+ ufsdbg_set_err_state(hba);
+
spin_lock_irqsave(hba->host->host_lock, flags);
hba->active_uic_cmd = NULL;
spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -2842,6 +2846,9 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
ufshcd_outstanding_req_clear(hba, lrbp->task_tag);
}
+ if (err)
+ ufsdbg_set_err_state(hba);
+
return err;
}
@@ -3874,6 +3881,9 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
ret = (status != PWR_OK) ? status : -1;
}
out:
+ if (ret)
+ ufsdbg_set_err_state(hba);
+
ufshcd_save_tstamp_of_last_dme_cmd(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
hba->active_uic_cmd = NULL;
@@ -4947,6 +4957,11 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
ocs == OCS_MISMATCH_DATA_BUF_SIZE);
ufshcd_print_trs(hba, 1 << lrbp->task_tag, print_prdt);
}
+
+ if ((host_byte(result) == DID_ERROR) ||
+ (host_byte(result) == DID_ABORT))
+ ufsdbg_set_err_state(hba);
+
return result;
}
@@ -5532,6 +5547,7 @@ static void ufshcd_err_handler(struct work_struct *work)
hba = container_of(work, struct ufs_hba, eh_work);
+ ufsdbg_set_err_state(hba);
pm_runtime_get_sync(hba->dev);
ufshcd_hold_all(hba);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 1ccda45743d6..a4ee3726edb0 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -543,6 +543,8 @@ struct debugfs_files {
u32 dme_local_attr_id;
u32 dme_peer_attr_id;
struct dentry *reset_controller;
+ struct dentry *err_state;
+ bool err_occurred;
#ifdef CONFIG_UFS_FAULT_INJECTION
struct dentry *err_inj_scenario;
struct dentry *err_inj_stats;
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index 6b3ed12ede73..3b3b1b011407 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -42,6 +42,7 @@
#include "configfs.h"
+#define MTP_RX_BUFFER_INIT_SIZE 1048576
#define MTP_BULK_BUFFER_SIZE 16384
#define INTR_BUFFER_SIZE 28
#define MAX_INST_NAME_LEN 40
@@ -77,7 +78,7 @@
#define MAX_ITERATION 100
-unsigned int mtp_rx_req_len = MTP_BULK_BUFFER_SIZE;
+unsigned int mtp_rx_req_len = MTP_RX_BUFFER_INIT_SIZE;
module_param(mtp_rx_req_len, uint, S_IRUGO | S_IWUSR);
unsigned int mtp_tx_req_len = MTP_BULK_BUFFER_SIZE;
diff --git a/drivers/video/fbdev/msm/mdss_debug_xlog.c b/drivers/video/fbdev/msm/mdss_debug_xlog.c
index c696832a96e8..a34bce1200d8 100644
--- a/drivers/video/fbdev/msm/mdss_debug_xlog.c
+++ b/drivers/video/fbdev/msm/mdss_debug_xlog.c
@@ -349,7 +349,7 @@ static void mdss_dump_vbif_debug_bus(u32 bus_dump_flag,
bus_size = mdata->nrt_vbif_dbg_bus_size;
}
- if (!dbg_bus || !bus_size)
+ if (!vbif_base || !dbg_bus || !bus_size)
return;
/* allocate memory for each test point */
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index 59283c815897..65b3b9739be6 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -662,6 +662,23 @@ exit_fail:
return ret;
}
+static int __validate_pipe_priorities(struct mdss_mdp_pipe *left,
+ struct mdss_mdp_pipe *right)
+{
+ if (left->multirect.num > right->multirect.num)
+ return -EINVAL;
+
+ if ((left->multirect.num == right->multirect.num) &&
+ (left->priority >= right->priority))
+ return -EINVAL;
+
+ if ((left->multirect.num < right->multirect.num) &&
+ (left->priority > right->priority))
+ return -EINVAL;
+
+ return 0;
+}
+
static int __configure_pipe_params(struct msm_fb_data_type *mfd,
struct mdss_mdp_validate_info_t *vinfo, struct mdss_mdp_pipe *pipe,
struct mdss_mdp_pipe *left_blend_pipe, bool is_single_layer,
@@ -773,10 +790,12 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd,
*/
if (mdata->has_src_split) {
if (left_blend_pipe) {
- if (pipe->priority <= left_blend_pipe->priority) {
- pr_err("priority limitation. left:%d right%d\n",
- left_blend_pipe->priority,
- pipe->priority);
+ if (__validate_pipe_priorities(left_blend_pipe, pipe)) {
+ pr_err("priority limitation. left:%d rect:%d, right:%d rect:%d\n",
+ left_blend_pipe->priority,
+ left_blend_pipe->multirect.num,
+ pipe->priority,
+ pipe->multirect.num);
ret = -EPERM;
goto end;
} else {
@@ -1521,12 +1540,6 @@ static bool __multirect_validate_properties(struct mdp_input_layer **layers,
return false;
}
- if (layers[0]->z_order == layers[1]->z_order) {
- pr_err("multirect layers cannot have same z_order=%d\n",
- layers[0]->z_order);
- return false;
- }
-
return true;
}
diff --git a/include/soc/qcom/smem.h b/include/soc/qcom/smem.h
index d8ee4d523880..9295532dec8a 100644
--- a/include/soc/qcom/smem.h
+++ b/include/soc/qcom/smem.h
@@ -78,6 +78,7 @@ enum {
SMEM_SMEM_LOG_EVENTS,
SMEM_XBL_LOADER_CORE_INFO,
SMEM_SMEM_STATIC_LOG_EVENTS,
+ SMEM_CHARGER_BATTERY_INFO = SMEM_SMEM_STATIC_LOG_EVENTS,
SMEM_SMEM_SLOW_CLOCK_SYNC,
SMEM_SMEM_SLOW_CLOCK_VALUE,
SMEM_BIO_LED_BUF,
diff --git a/mm/internal.h b/mm/internal.h
index 899f7b332a0b..55d4fa99b486 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -22,7 +22,8 @@
*/
#define GFP_RECLAIM_MASK (__GFP_RECLAIM|__GFP_HIGH|__GFP_IO|__GFP_FS|\
__GFP_NOWARN|__GFP_REPEAT|__GFP_NOFAIL|\
- __GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC)
+ __GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC|\
+ __GFP_ATOMIC)
/* The GFP flags allowed during early boot */
#define GFP_BOOT_MASK (__GFP_BITS_MASK & ~(__GFP_RECLAIM|__GFP_IO|__GFP_FS))
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index aaa590c0b491..cf14c7e22fb3 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -593,10 +593,17 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
for (freq = start_freq; freq <= end_freq; freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
- if (!c || c->flags & prohibited_flags)
+
+ if (!c)
+ return false;
+
+ if ((!(wiphy->flags & WIPHY_FLAG_DFS_OFFLOAD)) &&
+ (c->flags & prohibited_flags & IEEE80211_CHAN_RADAR))
return false;
- }
+ if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR)
+ return false;
+ }
return true;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
index fea7bb4e7331..379062eee285 100644
--- a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
@@ -1522,6 +1522,14 @@ static int msm_ds2_dap_get_param(u32 cmd, void *arg)
goto end;
}
+ /* Return if invalid length */
+ if (dolby_data->length >
+ (DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM - DOLBY_PARAM_PAYLOAD_SIZE)) {
+ pr_err("Invalid length %d", dolby_data->length);
+ rc = -EINVAL;
+ goto end;
+ }
+
for (i = 0; i < DS2_DEVICES_ALL; i++) {
if ((dev_map[i].active) &&
(dev_map[i].device_id & dolby_data->device_id)) {