diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-06-27 11:38:52 -0600 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-06-27 11:38:53 -0600 |
| commit | e195400eb58d48148c8aefab3e60e40f1346ea13 (patch) | |
| tree | 1ba37cded305fe158867733ab4243bcf04c4aab5 | |
| parent | 402636f926b48533bbb1589fe2ebe2e33ef80197 (diff) | |
| parent | fb5706b7462b0b855d10da12ed88ebf10a2e8643 (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
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(¶ms); 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)) { |
